mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-16 20:24:11 +00:00
Networking changes for 6.6.
Core ---- - Increase size limits for to-be-sent skb frag allocations. This allows tun, tap devices and packet sockets to better cope with large writes operations. - Store netdevs in an xarray, to simplify iterating over netdevs. - Refactor nexthop selection for multipath routes. - Improve sched class lifetime handling. - Add backup nexthop ID support for bridge. - Implement drop reasons support in openvswitch. - Several data races annotations and fixes. - Constify the sk parameter of routing functions. - Prepend kernel version to netconsole message. Protocols --------- - Implement support for TCP probing the peer being under memory pressure. - Remove hard coded limitation on IPv6 specific info placement inside the socket struct. - Get rid of sysctl_tcp_adv_win_scale and use an auto-estimated per socket scaling factor. - Scaling-up the IPv6 expired route GC via a separated list of expiring routes. - In-kernel support for the TLS alert protocol. - Better support for UDP reuseport with connected sockets. - Add NEXT-C-SID support for SRv6 End.X behavior, reducing the SR header size. - Get rid of additional ancillary per MPTCP connection struct socket. - Implement support for BPF-based MPTCP packet schedulers. - Format MPTCP subtests selftests results in TAP. - Several new SMC 2.1 features including unique experimental options, max connections per lgr negotiation, max links per lgr negotiation. BPF --- - Multi-buffer support in AF_XDP. - Add multi uprobe BPF links for attaching multiple uprobes and usdt probes, which is significantly faster and saves extra fds. - Implement an fd-based tc BPF attach API (TCX) and BPF link support on top of it. - Add SO_REUSEPORT support for TC bpf_sk_assign. - Support new instructions from cpu v4 to simplify the generated code and feature completeness, for x86, arm64, riscv64. - Support defragmenting IPv(4|6) packets in BPF. - Teach verifier actual bounds of bpf_get_smp_processor_id() and fix perf+libbpf issue related to custom section handling. - Introduce bpf map element count and enable it for all program types. - Add a BPF hook in sys_socket() to change the protocol ID from IPPROTO_TCP to IPPROTO_MPTCP to cover migration for legacy. - Introduce bpf_me_mcache_free_rcu() and fix OOM under stress. - Add uprobe support for the bpf_get_func_ip helper. - Check skb ownership against full socket. - Support for up to 12 arguments in BPF trampoline. - Extend link_info for kprobe_multi and perf_event links. Netfilter --------- - Speed-up process exit by aborting ruleset validation if a fatal signal is pending. - Allow NLA_POLICY_MASK to be used with BE16/BE32 types. Driver API ---------- - Page pool optimizations, to improve data locality and cache usage. - Introduce ndo_hwtstamp_get() and ndo_hwtstamp_set() to avoid the need for raw ioctl() handling in drivers. - Simplify genetlink dump operations (doit/dumpit) providing them the common information already populated in struct genl_info. - Extend and use the yaml devlink specs to [re]generate the split ops. - Introduce devlink selective dumps, to allow SF filtering SF based on handle and other attributes. - Add yaml netlink spec for netlink-raw families, allow route, link and address related queries via the ynl tool. - Remove phylink legacy mode support. - Support offload LED blinking to phy. - Add devlink port function attributes for IPsec. New hardware / drivers ---------------------- - Ethernet: - Broadcom ASP 2.0 (72165) ethernet controller - MediaTek MT7988 SoC - Texas Instruments AM654 SoC - Texas Instruments IEP driver - Atheros qca8081 phy - Marvell 88Q2110 phy - NXP TJA1120 phy - WiFi: - MediaTek mt7981 support - Can: - Kvaser SmartFusion2 PCI Express devices - Allwinner T113 controllers - Texas Instruments tcan4552/4553 chips - Bluetooth: - Intel Gale Peak - Qualcomm WCN3988 and WCN7850 - NXP AW693 and IW624 - Mediatek MT2925 Drivers ------- - Ethernet NICs: - nVidia/Mellanox: - mlx5: - support UDP encapsulation in packet offload mode - IPsec packet offload support in eswitch mode - improve aRFS observability by adding new set of counters - extends MACsec offload support to cover RoCE traffic - dynamic completion EQs - mlx4: - convert to use auxiliary bus instead of custom interface logic - Intel - ice: - implement switchdev bridge offload, even for LAG interfaces - implement SRIOV support for LAG interfaces - igc: - add support for multiple in-flight TX timestamps - Broadcom: - bnxt: - use the unified RX page pool buffers for XDP and non-XDP - use the NAPI skb allocation cache - OcteonTX2: - support Round Robin scheduling HTB offload - TC flower offload support for SPI field - Freescale: - add XDP_TX feature support - AMD: - ionic: add support for PCI FLR event - sfc: - basic conntrack offload - introduce eth, ipv4 and ipv6 pedit offloads - ST Microelectronics: - stmmac: maximze PTP timestamping resolution - Virtual NICs: - Microsoft vNIC: - batch ringing RX queue doorbell on receiving packets - add page pool for RX buffers - Virtio vNIC: - add per queue interrupt coalescing support - Google vNIC: - add queue-page-list mode support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add port range matching tc-flower offload - permit enslavement to netdevices with uppers - Ethernet embedded switches: - Marvell (mv88e6xxx): - convert to phylink_pcs - Renesas: - r8A779fx: add speed change support - rzn1: enables vlan support - Ethernet PHYs: - convert mv88e6xxx to phylink_pcs - WiFi: - Qualcomm Wi-Fi 7 (ath12k): - extremely High Throughput (EHT) PHY support - RealTek (rtl8xxxu): - enable AP mode for: RTL8192FU, RTL8710BU (RTL8188GU), RTL8192EU and RTL8723BU - RealTek (rtw89): - Introduce Time Averaged SAR (TAS) support - Connector: - support for event filtering Signed-off-by: Paolo Abeni <pabeni@redhat.com> -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmTt1ZoSHHBhYmVuaUBy ZWRoYXQuY29tAAoJECkkeY3MjxOkgFUP/REFaYWdWUvAzmWeezyx9dqgZMfSOjWq 9QvySiA94OAOcjIYkb7wfzQ5BBAZqaBQ/f8XqWwS1EDDDEBs8sP1cxmABKwW7Hsr qFRu2sOqLzKBk223d0jIgEocfQaFpGbF71gXoTlDivBjBi5UxWm9bF0XnbYWcKgO /QEvzNosi9uNdi85Fzmv62J6YzAdidEpwGsM7X2CfejwNRmStxAEg/NwvRR0Hyiq OJCo97omEgTRaUle8nc64PDx33u4h5kQ1BkaeHEv0rbE3hftFC2YPKn/InmqSFGz 6ew2xnrGPR37LCuAiCcIIv6yR7K0eu0iYJ7jXwZxBDqxGavEPuwWGBoCP6qFiitH ZLWhIrAUrdmSbySkTOCONhJ475qFAuQoYHYpZnX/bJZUHlSsb/9lwDJYJQGpVfd1 /daqJVSb7lhaifmNO1iNd/ibCIXq9zapwtkRwA897M8GkZBTsnVvazFld1Em+Se3 Bx6DSDUVBqVQ9fpZG2IAGD6odDwOzC1lF2IoceFvK9Ff6oE0psI+A0qNLMkHxZbW Qlo7LsNe53hpoCC+yHTfXX7e/X8eNt0EnCGOQJDusZ0Nr3K7H4LKFA0i8UBUK05n 4lKnnaSQW7GQgdofLWt103OMDR9GoDxpFsm7b1X9+AEk6Fz6tq50wWYeMZETUKYP DCW8VGFOZjZM =9CsR -----END PGP SIGNATURE----- Merge tag 'net-next-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Paolo Abeni: "Core: - Increase size limits for to-be-sent skb frag allocations. This allows tun, tap devices and packet sockets to better cope with large writes operations - Store netdevs in an xarray, to simplify iterating over netdevs - Refactor nexthop selection for multipath routes - Improve sched class lifetime handling - Add backup nexthop ID support for bridge - Implement drop reasons support in openvswitch - Several data races annotations and fixes - Constify the sk parameter of routing functions - Prepend kernel version to netconsole message Protocols: - Implement support for TCP probing the peer being under memory pressure - Remove hard coded limitation on IPv6 specific info placement inside the socket struct - Get rid of sysctl_tcp_adv_win_scale and use an auto-estimated per socket scaling factor - Scaling-up the IPv6 expired route GC via a separated list of expiring routes - In-kernel support for the TLS alert protocol - Better support for UDP reuseport with connected sockets - Add NEXT-C-SID support for SRv6 End.X behavior, reducing the SR header size - Get rid of additional ancillary per MPTCP connection struct socket - Implement support for BPF-based MPTCP packet schedulers - Format MPTCP subtests selftests results in TAP - Several new SMC 2.1 features including unique experimental options, max connections per lgr negotiation, max links per lgr negotiation BPF: - Multi-buffer support in AF_XDP - Add multi uprobe BPF links for attaching multiple uprobes and usdt probes, which is significantly faster and saves extra fds - Implement an fd-based tc BPF attach API (TCX) and BPF link support on top of it - Add SO_REUSEPORT support for TC bpf_sk_assign - Support new instructions from cpu v4 to simplify the generated code and feature completeness, for x86, arm64, riscv64 - Support defragmenting IPv(4|6) packets in BPF - Teach verifier actual bounds of bpf_get_smp_processor_id() and fix perf+libbpf issue related to custom section handling - Introduce bpf map element count and enable it for all program types - Add a BPF hook in sys_socket() to change the protocol ID from IPPROTO_TCP to IPPROTO_MPTCP to cover migration for legacy - Introduce bpf_me_mcache_free_rcu() and fix OOM under stress - Add uprobe support for the bpf_get_func_ip helper - Check skb ownership against full socket - Support for up to 12 arguments in BPF trampoline - Extend link_info for kprobe_multi and perf_event links Netfilter: - Speed-up process exit by aborting ruleset validation if a fatal signal is pending - Allow NLA_POLICY_MASK to be used with BE16/BE32 types Driver API: - Page pool optimizations, to improve data locality and cache usage - Introduce ndo_hwtstamp_get() and ndo_hwtstamp_set() to avoid the need for raw ioctl() handling in drivers - Simplify genetlink dump operations (doit/dumpit) providing them the common information already populated in struct genl_info - Extend and use the yaml devlink specs to [re]generate the split ops - Introduce devlink selective dumps, to allow SF filtering SF based on handle and other attributes - Add yaml netlink spec for netlink-raw families, allow route, link and address related queries via the ynl tool - Remove phylink legacy mode support - Support offload LED blinking to phy - Add devlink port function attributes for IPsec New hardware / drivers: - Ethernet: - Broadcom ASP 2.0 (72165) ethernet controller - MediaTek MT7988 SoC - Texas Instruments AM654 SoC - Texas Instruments IEP driver - Atheros qca8081 phy - Marvell 88Q2110 phy - NXP TJA1120 phy - WiFi: - MediaTek mt7981 support - Can: - Kvaser SmartFusion2 PCI Express devices - Allwinner T113 controllers - Texas Instruments tcan4552/4553 chips - Bluetooth: - Intel Gale Peak - Qualcomm WCN3988 and WCN7850 - NXP AW693 and IW624 - Mediatek MT2925 Drivers: - Ethernet NICs: - nVidia/Mellanox: - mlx5: - support UDP encapsulation in packet offload mode - IPsec packet offload support in eswitch mode - improve aRFS observability by adding new set of counters - extends MACsec offload support to cover RoCE traffic - dynamic completion EQs - mlx4: - convert to use auxiliary bus instead of custom interface logic - Intel - ice: - implement switchdev bridge offload, even for LAG interfaces - implement SRIOV support for LAG interfaces - igc: - add support for multiple in-flight TX timestamps - Broadcom: - bnxt: - use the unified RX page pool buffers for XDP and non-XDP - use the NAPI skb allocation cache - OcteonTX2: - support Round Robin scheduling HTB offload - TC flower offload support for SPI field - Freescale: - add XDP_TX feature support - AMD: - ionic: add support for PCI FLR event - sfc: - basic conntrack offload - introduce eth, ipv4 and ipv6 pedit offloads - ST Microelectronics: - stmmac: maximze PTP timestamping resolution - Virtual NICs: - Microsoft vNIC: - batch ringing RX queue doorbell on receiving packets - add page pool for RX buffers - Virtio vNIC: - add per queue interrupt coalescing support - Google vNIC: - add queue-page-list mode support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add port range matching tc-flower offload - permit enslavement to netdevices with uppers - Ethernet embedded switches: - Marvell (mv88e6xxx): - convert to phylink_pcs - Renesas: - r8A779fx: add speed change support - rzn1: enables vlan support - Ethernet PHYs: - convert mv88e6xxx to phylink_pcs - WiFi: - Qualcomm Wi-Fi 7 (ath12k): - extremely High Throughput (EHT) PHY support - RealTek (rtl8xxxu): - enable AP mode for: RTL8192FU, RTL8710BU (RTL8188GU), RTL8192EU and RTL8723BU - RealTek (rtw89): - Introduce Time Averaged SAR (TAS) support - Connector: - support for event filtering" * tag 'net-next-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1806 commits) net: ethernet: mtk_wed: minor change in wed_{tx,rx}info_show net: ethernet: mtk_wed: add some more info in wed_txinfo_show handler net: stmmac: clarify difference between "interface" and "phy_interface" r8152: add vendor/device ID pair for D-Link DUB-E250 devlink: move devlink_notify_register/unregister() to dev.c devlink: move small_ops definition into netlink.c devlink: move tracepoint definitions into core.c devlink: push linecard related code into separate file devlink: push rate related code into separate file devlink: push trap related code into separate file devlink: use tracepoint_enabled() helper devlink: push region related code into separate file devlink: push param related code into separate file devlink: push resource related code into separate file devlink: push dpipe related code into separate file devlink: move and rename devlink_dpipe_send_and_alloc_skb() helper devlink: push shared buffer related code into separate file devlink: push port related code into separate file devlink: push object register/unregister notifications into separate helpers inet: fix IP_TRANSPARENT error handling ...
This commit is contained in:
commit
bd6c11bc43
1855 changed files with 109685 additions and 46162 deletions
Documentation
bpf
core-api
devicetree/bindings/net
bluetooth
brcm,asp-v2.0.yamlbrcm,unimac-mdio.yamlcan
dsa
ethernet-controller.yamlmediatek,net.yamlmotorcomm,yt8xxx.yamloxnas-dwmac.txtqca,ar803x.yamlrockchip-dwmac.yamlti,icss-iep.yamlti,icssg-prueth.yamlwireless
xilinx_gmii2rgmii.txtxlnx,gmii-to-rgmii.yamlnetlink
networking
af_xdp.rst
device_drivers/ethernet
google
marvell
mellanox/mlx5
devlink
ip-sysctl.rstmptcp-sysctl.rstnetconsole.rstpage_pool.rstphy.rstxfrm_device.rstprocess
userspace-api/netlink
arch
arm64
powerpc
riscv/net
x86/net
drivers
block/drbd
bluetooth
btbcm.cbtintel.cbtintel.hbtmtk.cbtmtk.hbtmtkuart.cbtnxpuart.cbtqca.cbtqca.hbtrtl.cbtrtl.hbtusb.chci_h5.chci_ldisc.chci_nokia.chci_qca.c
connector
hid/bpf/entrypoints
infiniband
|
@ -140,11 +140,6 @@ A: Because if we picked one-to-one relationship to x64 it would have made
|
|||
it more complicated to support on arm64 and other archs. Also it
|
||||
needs div-by-zero runtime check.
|
||||
|
||||
Q: Why there is no BPF_SDIV for signed divide operation?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: Because it would be rarely used. llvm errors in such case and
|
||||
prints a suggestion to use unsigned divide instead.
|
||||
|
||||
Q: Why BPF has implicit prologue and epilogue?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A: Because architectures like sparc have register windows and in general
|
||||
|
|
|
@ -635,12 +635,12 @@ test coverage.
|
|||
|
||||
Q: clang flag for target bpf?
|
||||
-----------------------------
|
||||
Q: In some cases clang flag ``-target bpf`` is used but in other cases the
|
||||
Q: In some cases clang flag ``--target=bpf`` is used but in other cases the
|
||||
default clang target, which matches the underlying architecture, is used.
|
||||
What is the difference and when I should use which?
|
||||
|
||||
A: Although LLVM IR generation and optimization try to stay architecture
|
||||
independent, ``-target <arch>`` still has some impact on generated code:
|
||||
independent, ``--target=<arch>`` still has some impact on generated code:
|
||||
|
||||
- BPF program may recursively include header file(s) with file scope
|
||||
inline assembly codes. The default target can handle this well,
|
||||
|
@ -658,7 +658,7 @@ independent, ``-target <arch>`` still has some impact on generated code:
|
|||
The clang option ``-fno-jump-tables`` can be used to disable
|
||||
switch table generation.
|
||||
|
||||
- For clang ``-target bpf``, it is guaranteed that pointer or long /
|
||||
- For clang ``--target=bpf``, it is guaranteed that pointer or long /
|
||||
unsigned long types will always have a width of 64 bit, no matter
|
||||
whether underlying clang binary or default target (or kernel) is
|
||||
32 bit. However, when native clang target is used, then it will
|
||||
|
@ -668,7 +668,7 @@ independent, ``-target <arch>`` still has some impact on generated code:
|
|||
while the BPF LLVM back end still operates in 64 bit. The native
|
||||
target is mostly needed in tracing for the case of walking ``pt_regs``
|
||||
or other kernel structures where CPU's register width matters.
|
||||
Otherwise, ``clang -target bpf`` is generally recommended.
|
||||
Otherwise, ``clang --target=bpf`` is generally recommended.
|
||||
|
||||
You should use default target when:
|
||||
|
||||
|
@ -685,7 +685,7 @@ when:
|
|||
into these structures is verified by the BPF verifier and may result
|
||||
in verification failures if the native architecture is not aligned with
|
||||
the BPF architecture, e.g. 64-bit. An example of this is
|
||||
BPF_PROG_TYPE_SK_MSG require ``-target bpf``
|
||||
BPF_PROG_TYPE_SK_MSG require ``--target=bpf``
|
||||
|
||||
|
||||
.. Links
|
||||
|
|
|
@ -990,7 +990,7 @@ format.::
|
|||
} g2;
|
||||
int main() { return 0; }
|
||||
int test() { return 0; }
|
||||
-bash-4.4$ clang -c -g -O2 -target bpf t2.c
|
||||
-bash-4.4$ clang -c -g -O2 --target=bpf t2.c
|
||||
-bash-4.4$ readelf -S t2.o
|
||||
......
|
||||
[ 8] .BTF PROGBITS 0000000000000000 00000247
|
||||
|
@ -1000,7 +1000,7 @@ format.::
|
|||
[10] .rel.BTF.ext REL 0000000000000000 000007e0
|
||||
0000000000000040 0000000000000010 16 9 8
|
||||
......
|
||||
-bash-4.4$ clang -S -g -O2 -target bpf t2.c
|
||||
-bash-4.4$ clang -S -g -O2 --target=bpf t2.c
|
||||
-bash-4.4$ cat t2.s
|
||||
......
|
||||
.section .BTF,"",@progbits
|
||||
|
|
|
@ -12,9 +12,9 @@ that goes into great technical depth about the BPF Architecture.
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
instruction-set
|
||||
verifier
|
||||
libbpf/index
|
||||
standardization/index
|
||||
btf
|
||||
faq
|
||||
syscall_api
|
||||
|
@ -29,7 +29,6 @@ that goes into great technical depth about the BPF Architecture.
|
|||
bpf_licensing
|
||||
test_debug
|
||||
clang-notes
|
||||
linux-notes
|
||||
other
|
||||
redirect
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ For example, for the following code::
|
|||
return g1 + g2 + l1 + l2;
|
||||
}
|
||||
|
||||
Compiled with ``clang -target bpf -O2 -c test.c``, the following is
|
||||
Compiled with ``clang --target=bpf -O2 -c test.c``, the following is
|
||||
the code with ``llvm-objdump -dr test.o``::
|
||||
|
||||
0: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
|
||||
|
@ -157,7 +157,7 @@ and ``call`` instructions. For example::
|
|||
return gfunc(a, b) + lfunc(a, b) + global;
|
||||
}
|
||||
|
||||
Compiled with ``clang -target bpf -O2 -c test.c``, we will have
|
||||
Compiled with ``clang --target=bpf -O2 -c test.c``, we will have
|
||||
following code with `llvm-objdump -dr test.o``::
|
||||
|
||||
Disassembly of section .text:
|
||||
|
@ -203,7 +203,7 @@ The following is an example to show how R_BPF_64_ABS64 could be generated::
|
|||
int global() { return 0; }
|
||||
struct t { void *g; } gbl = { global };
|
||||
|
||||
Compiled with ``clang -target bpf -O2 -g -c test.c``, we will see a
|
||||
Compiled with ``clang --target=bpf -O2 -g -c test.c``, we will see a
|
||||
relocation below in ``.data`` section with command
|
||||
``llvm-readelf -r test.o``::
|
||||
|
||||
|
|
18
Documentation/bpf/standardization/index.rst
Normal file
18
Documentation/bpf/standardization/index.rst
Normal file
|
@ -0,0 +1,18 @@
|
|||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
===================
|
||||
BPF Standardization
|
||||
===================
|
||||
|
||||
This directory contains documents that are being iterated on as part of the BPF
|
||||
standardization effort with the IETF. See the `IETF BPF Working Group`_ page
|
||||
for the working group charter, documents, and more.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
instruction-set
|
||||
linux-notes
|
||||
|
||||
.. Links:
|
||||
.. _IETF BPF Working Group: https://datatracker.ietf.org/wg/bpf/about/
|
|
@ -10,9 +10,92 @@ This document specifies version 1.0 of the eBPF instruction set.
|
|||
Documentation conventions
|
||||
=========================
|
||||
|
||||
For brevity, this document uses the type notion "u64", "u32", etc.
|
||||
to mean an unsigned integer whose width is the specified number of bits,
|
||||
and "s32", etc. to mean a signed integer of the specified number of bits.
|
||||
For brevity and consistency, this document refers to families
|
||||
of types using a shorthand syntax and refers to several expository,
|
||||
mnemonic functions when describing the semantics of instructions.
|
||||
The range of valid values for those types and the semantics of those
|
||||
functions are defined in the following subsections.
|
||||
|
||||
Types
|
||||
-----
|
||||
This document refers to integer types with the notation `SN` to specify
|
||||
a type's signedness (`S`) and bit width (`N`), respectively.
|
||||
|
||||
.. table:: Meaning of signedness notation.
|
||||
|
||||
==== =========
|
||||
`S` Meaning
|
||||
==== =========
|
||||
`u` unsigned
|
||||
`s` signed
|
||||
==== =========
|
||||
|
||||
.. table:: Meaning of bit-width notation.
|
||||
|
||||
===== =========
|
||||
`N` Bit width
|
||||
===== =========
|
||||
`8` 8 bits
|
||||
`16` 16 bits
|
||||
`32` 32 bits
|
||||
`64` 64 bits
|
||||
`128` 128 bits
|
||||
===== =========
|
||||
|
||||
For example, `u32` is a type whose valid values are all the 32-bit unsigned
|
||||
numbers and `s16` is a types whose valid values are all the 16-bit signed
|
||||
numbers.
|
||||
|
||||
Functions
|
||||
---------
|
||||
* `htobe16`: Takes an unsigned 16-bit number in host-endian format and
|
||||
returns the equivalent number as an unsigned 16-bit number in big-endian
|
||||
format.
|
||||
* `htobe32`: Takes an unsigned 32-bit number in host-endian format and
|
||||
returns the equivalent number as an unsigned 32-bit number in big-endian
|
||||
format.
|
||||
* `htobe64`: Takes an unsigned 64-bit number in host-endian format and
|
||||
returns the equivalent number as an unsigned 64-bit number in big-endian
|
||||
format.
|
||||
* `htole16`: Takes an unsigned 16-bit number in host-endian format and
|
||||
returns the equivalent number as an unsigned 16-bit number in little-endian
|
||||
format.
|
||||
* `htole32`: Takes an unsigned 32-bit number in host-endian format and
|
||||
returns the equivalent number as an unsigned 32-bit number in little-endian
|
||||
format.
|
||||
* `htole64`: Takes an unsigned 64-bit number in host-endian format and
|
||||
returns the equivalent number as an unsigned 64-bit number in little-endian
|
||||
format.
|
||||
* `bswap16`: Takes an unsigned 16-bit number in either big- or little-endian
|
||||
format and returns the equivalent number with the same bit width but
|
||||
opposite endianness.
|
||||
* `bswap32`: Takes an unsigned 32-bit number in either big- or little-endian
|
||||
format and returns the equivalent number with the same bit width but
|
||||
opposite endianness.
|
||||
* `bswap64`: Takes an unsigned 64-bit number in either big- or little-endian
|
||||
format and returns the equivalent number with the same bit width but
|
||||
opposite endianness.
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
.. glossary::
|
||||
|
||||
Sign Extend
|
||||
To `sign extend an` ``X`` `-bit number, A, to a` ``Y`` `-bit number, B ,` means to
|
||||
|
||||
#. Copy all ``X`` bits from `A` to the lower ``X`` bits of `B`.
|
||||
#. Set the value of the remaining ``Y`` - ``X`` bits of `B` to the value of
|
||||
the most-significant bit of `A`.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
Sign extend an 8-bit number ``A`` to a 16-bit number ``B`` on a big-endian platform:
|
||||
::
|
||||
|
||||
A: 10000110
|
||||
B: 11111111 10000110
|
||||
|
||||
Registers and calling convention
|
||||
================================
|
||||
|
@ -154,24 +237,27 @@ otherwise identical operations.
|
|||
The 'code' field encodes the operation as below, where 'src' and 'dst' refer
|
||||
to the values of the source and destination registers, respectively.
|
||||
|
||||
======== ===== ==========================================================
|
||||
code value description
|
||||
======== ===== ==========================================================
|
||||
BPF_ADD 0x00 dst += src
|
||||
BPF_SUB 0x10 dst -= src
|
||||
BPF_MUL 0x20 dst \*= src
|
||||
BPF_DIV 0x30 dst = (src != 0) ? (dst / src) : 0
|
||||
BPF_OR 0x40 dst \|= src
|
||||
BPF_AND 0x50 dst &= src
|
||||
BPF_LSH 0x60 dst <<= (src & mask)
|
||||
BPF_RSH 0x70 dst >>= (src & mask)
|
||||
BPF_NEG 0x80 dst = ~src
|
||||
BPF_MOD 0x90 dst = (src != 0) ? (dst % src) : dst
|
||||
BPF_XOR 0xa0 dst ^= src
|
||||
BPF_MOV 0xb0 dst = src
|
||||
BPF_ARSH 0xc0 sign extending dst >>= (src & mask)
|
||||
BPF_END 0xd0 byte swap operations (see `Byte swap instructions`_ below)
|
||||
======== ===== ==========================================================
|
||||
========= ===== ======= ==========================================================
|
||||
code value offset description
|
||||
========= ===== ======= ==========================================================
|
||||
BPF_ADD 0x00 0 dst += src
|
||||
BPF_SUB 0x10 0 dst -= src
|
||||
BPF_MUL 0x20 0 dst \*= src
|
||||
BPF_DIV 0x30 0 dst = (src != 0) ? (dst / src) : 0
|
||||
BPF_SDIV 0x30 1 dst = (src != 0) ? (dst s/ src) : 0
|
||||
BPF_OR 0x40 0 dst \|= src
|
||||
BPF_AND 0x50 0 dst &= src
|
||||
BPF_LSH 0x60 0 dst <<= (src & mask)
|
||||
BPF_RSH 0x70 0 dst >>= (src & mask)
|
||||
BPF_NEG 0x80 0 dst = -dst
|
||||
BPF_MOD 0x90 0 dst = (src != 0) ? (dst % src) : dst
|
||||
BPF_SMOD 0x90 1 dst = (src != 0) ? (dst s% src) : dst
|
||||
BPF_XOR 0xa0 0 dst ^= src
|
||||
BPF_MOV 0xb0 0 dst = src
|
||||
BPF_MOVSX 0xb0 8/16/32 dst = (s8,s16,s32)src
|
||||
BPF_ARSH 0xc0 0 :term:`sign extending<Sign Extend>` dst >>= (src & mask)
|
||||
BPF_END 0xd0 0 byte swap operations (see `Byte swap instructions`_ below)
|
||||
========= ===== ======= ==========================================================
|
||||
|
||||
Underflow and overflow are allowed during arithmetic operations, meaning
|
||||
the 64-bit or 32-bit value will wrap. If eBPF program execution would
|
||||
|
@ -198,47 +284,75 @@ where '(u32)' indicates that the upper 32 bits are zeroed.
|
|||
|
||||
dst = dst ^ imm32
|
||||
|
||||
Also note that the division and modulo operations are unsigned. Thus, for
|
||||
``BPF_ALU``, 'imm' is first interpreted as an unsigned 32-bit value, whereas
|
||||
for ``BPF_ALU64``, 'imm' is first sign extended to 64 bits and the result
|
||||
interpreted as an unsigned 64-bit value. There are no instructions for
|
||||
signed division or modulo.
|
||||
Note that most instructions have instruction offset of 0. Only three instructions
|
||||
(``BPF_SDIV``, ``BPF_SMOD``, ``BPF_MOVSX``) have a non-zero offset.
|
||||
|
||||
The division and modulo operations support both unsigned and signed flavors.
|
||||
|
||||
For unsigned operations (``BPF_DIV`` and ``BPF_MOD``), for ``BPF_ALU``,
|
||||
'imm' is interpreted as a 32-bit unsigned value. For ``BPF_ALU64``,
|
||||
'imm' is first :term:`sign extended<Sign Extend>` from 32 to 64 bits, and then
|
||||
interpreted as a 64-bit unsigned value.
|
||||
|
||||
For signed operations (``BPF_SDIV`` and ``BPF_SMOD``), for ``BPF_ALU``,
|
||||
'imm' is interpreted as a 32-bit signed value. For ``BPF_ALU64``, 'imm'
|
||||
is first :term:`sign extended<Sign Extend>` from 32 to 64 bits, and then
|
||||
interpreted as a 64-bit signed value.
|
||||
|
||||
The ``BPF_MOVSX`` instruction does a move operation with sign extension.
|
||||
``BPF_ALU | BPF_MOVSX`` :term:`sign extends<Sign Extend>` 8-bit and 16-bit operands into 32
|
||||
bit operands, and zeroes the remaining upper 32 bits.
|
||||
``BPF_ALU64 | BPF_MOVSX`` :term:`sign extends<Sign Extend>` 8-bit, 16-bit, and 32-bit
|
||||
operands into 64 bit operands.
|
||||
|
||||
Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31)
|
||||
for 32-bit operations.
|
||||
|
||||
Byte swap instructions
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
----------------------
|
||||
|
||||
The byte swap instructions use an instruction class of ``BPF_ALU`` and a 4-bit
|
||||
'code' field of ``BPF_END``.
|
||||
The byte swap instructions use instruction classes of ``BPF_ALU`` and ``BPF_ALU64``
|
||||
and a 4-bit 'code' field of ``BPF_END``.
|
||||
|
||||
The byte swap instructions operate on the destination register
|
||||
only and do not use a separate source register or immediate value.
|
||||
|
||||
The 1-bit source operand field in the opcode is used to select what byte
|
||||
order the operation convert from or to:
|
||||
For ``BPF_ALU``, the 1-bit source operand field in the opcode is used to
|
||||
select what byte order the operation converts from or to. For
|
||||
``BPF_ALU64``, the 1-bit source operand field in the opcode is reserved
|
||||
and must be set to 0.
|
||||
|
||||
========= ===== =================================================
|
||||
source value description
|
||||
========= ===== =================================================
|
||||
BPF_TO_LE 0x00 convert between host byte order and little endian
|
||||
BPF_TO_BE 0x08 convert between host byte order and big endian
|
||||
========= ===== =================================================
|
||||
========= ========= ===== =================================================
|
||||
class source value description
|
||||
========= ========= ===== =================================================
|
||||
BPF_ALU BPF_TO_LE 0x00 convert between host byte order and little endian
|
||||
BPF_ALU BPF_TO_BE 0x08 convert between host byte order and big endian
|
||||
BPF_ALU64 Reserved 0x00 do byte swap unconditionally
|
||||
========= ========= ===== =================================================
|
||||
|
||||
The 'imm' field encodes the width of the swap operations. The following widths
|
||||
are supported: 16, 32 and 64.
|
||||
|
||||
Examples:
|
||||
|
||||
``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16 means::
|
||||
``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means::
|
||||
|
||||
dst = htole16(dst)
|
||||
dst = htole32(dst)
|
||||
dst = htole64(dst)
|
||||
|
||||
``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 64 means::
|
||||
``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 16/32/64 means::
|
||||
|
||||
dst = htobe16(dst)
|
||||
dst = htobe32(dst)
|
||||
dst = htobe64(dst)
|
||||
|
||||
``BPF_ALU64 | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means::
|
||||
|
||||
dst = bswap16(dst)
|
||||
dst = bswap32(dst)
|
||||
dst = bswap64(dst)
|
||||
|
||||
Jump instructions
|
||||
-----------------
|
||||
|
||||
|
@ -249,7 +363,8 @@ The 'code' field encodes the operation as below:
|
|||
======== ===== === =========================================== =========================================
|
||||
code value src description notes
|
||||
======== ===== === =========================================== =========================================
|
||||
BPF_JA 0x0 0x0 PC += offset BPF_JMP only
|
||||
BPF_JA 0x0 0x0 PC += offset BPF_JMP class
|
||||
BPF_JA 0x0 0x0 PC += imm BPF_JMP32 class
|
||||
BPF_JEQ 0x1 any PC += offset if dst == src
|
||||
BPF_JGT 0x2 any PC += offset if dst > src unsigned
|
||||
BPF_JGE 0x3 any PC += offset if dst >= src unsigned
|
||||
|
@ -278,6 +393,19 @@ Example:
|
|||
|
||||
where 's>=' indicates a signed '>=' comparison.
|
||||
|
||||
``BPF_JA | BPF_K | BPF_JMP32`` (0x06) means::
|
||||
|
||||
gotol +imm
|
||||
|
||||
where 'imm' means the branch offset comes from insn 'imm' field.
|
||||
|
||||
Note that there are two flavors of ``BPF_JA`` instructions. The
|
||||
``BPF_JMP`` class permits a 16-bit jump offset specified by the 'offset'
|
||||
field, whereas the ``BPF_JMP32`` class permits a 32-bit jump offset
|
||||
specified by the 'imm' field. A > 16-bit conditional jump may be
|
||||
converted to a < 16-bit conditional jump plus a 32-bit unconditional
|
||||
jump.
|
||||
|
||||
Helper functions
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -320,6 +448,7 @@ The mode modifier is one of:
|
|||
BPF_ABS 0x20 legacy BPF packet access (absolute) `Legacy BPF Packet access instructions`_
|
||||
BPF_IND 0x40 legacy BPF packet access (indirect) `Legacy BPF Packet access instructions`_
|
||||
BPF_MEM 0x60 regular load and store operations `Regular load and store operations`_
|
||||
BPF_MEMSX 0x80 sign-extension load operations `Sign-extension load operations`_
|
||||
BPF_ATOMIC 0xc0 atomic operations `Atomic operations`_
|
||||
============= ===== ==================================== =============
|
||||
|
||||
|
@ -350,9 +479,23 @@ instructions that transfer data between a register and memory.
|
|||
|
||||
``BPF_MEM | <size> | BPF_LDX`` means::
|
||||
|
||||
dst = *(size *) (src + offset)
|
||||
dst = *(unsigned size *) (src + offset)
|
||||
|
||||
Where size is one of: ``BPF_B``, ``BPF_H``, ``BPF_W``, or ``BPF_DW``.
|
||||
Where size is one of: ``BPF_B``, ``BPF_H``, ``BPF_W``, or ``BPF_DW`` and
|
||||
'unsigned size' is one of u8, u16, u32 or u64.
|
||||
|
||||
Sign-extension load operations
|
||||
------------------------------
|
||||
|
||||
The ``BPF_MEMSX`` mode modifier is used to encode :term:`sign-extension<Sign Extend>` load
|
||||
instructions that transfer data between a register and memory.
|
||||
|
||||
``BPF_MEMSX | <size> | BPF_LDX`` means::
|
||||
|
||||
dst = *(signed size *) (src + offset)
|
||||
|
||||
Where size is one of: ``BPF_B``, ``BPF_H`` or ``BPF_W``, and
|
||||
'signed size' is one of s8, s16 or s32.
|
||||
|
||||
Atomic operations
|
||||
-----------------
|
|
@ -45,7 +45,8 @@ On Linux, this integer is a BTF ID.
|
|||
Legacy BPF Packet access instructions
|
||||
=====================================
|
||||
|
||||
As mentioned in the `ISA standard documentation <instruction-set.rst#legacy-bpf-packet-access-instructions>`_,
|
||||
As mentioned in the `ISA standard documentation
|
||||
<instruction-set.html#legacy-bpf-packet-access-instructions>`_,
|
||||
Linux has special eBPF instructions for access to packet data that have been
|
||||
carried over from classic BPF to retain the performance of legacy socket
|
||||
filters running in the eBPF interpreter.
|
|
@ -67,10 +67,11 @@ Globals
|
|||
kernel-policy
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Defines if the kernel validation policy is per operation (``per-op``)
|
||||
or for the entire family (``global``). New families should use ``per-op``
|
||||
(default) to be able to narrow down the attributes accepted by a specific
|
||||
command.
|
||||
Defines whether the kernel validation policy is ``global`` i.e. the same for all
|
||||
operations of the family, defined for each operation individually - ``per-op``,
|
||||
or separately for each operation and operation type (do vs dump) - ``split``.
|
||||
New families should use ``per-op`` (default) to be able to narrow down the
|
||||
attributes accepted by a specific command.
|
||||
|
||||
checks
|
||||
------
|
||||
|
|
|
@ -19,12 +19,14 @@ properties:
|
|||
- qcom,qca2066-bt
|
||||
- qcom,qca6174-bt
|
||||
- qcom,qca9377-bt
|
||||
- qcom,wcn3988-bt
|
||||
- qcom,wcn3990-bt
|
||||
- qcom,wcn3991-bt
|
||||
- qcom,wcn3998-bt
|
||||
- qcom,qca6390-bt
|
||||
- qcom,wcn6750-bt
|
||||
- qcom,wcn6855-bt
|
||||
- qcom,wcn7850-bt
|
||||
|
||||
enable-gpios:
|
||||
maxItems: 1
|
||||
|
@ -57,6 +59,9 @@ properties:
|
|||
vddaon-supply:
|
||||
description: VDD_AON supply regulator handle
|
||||
|
||||
vdddig-supply:
|
||||
description: VDD_DIG supply regulator handle
|
||||
|
||||
vddbtcxmx-supply:
|
||||
description: VDD_BT_CXMX supply regulator handle
|
||||
|
||||
|
@ -72,6 +77,9 @@ properties:
|
|||
vddrfa1p2-supply:
|
||||
description: VDD_RFA_1P2 supply regulator handle
|
||||
|
||||
vddrfa1p9-supply:
|
||||
description: VDD_RFA_1P9 supply regulator handle
|
||||
|
||||
vddrfa2p2-supply:
|
||||
description: VDD_RFA_2P2 supply regulator handle
|
||||
|
||||
|
@ -111,6 +119,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,wcn3988-bt
|
||||
- qcom,wcn3990-bt
|
||||
- qcom,wcn3991-bt
|
||||
- qcom,wcn3998-bt
|
||||
|
@ -155,6 +164,22 @@ allOf:
|
|||
- vddrfa0p8-supply
|
||||
- vddrfa1p2-supply
|
||||
- vddrfa1p7-supply
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,wcn7850-bt
|
||||
then:
|
||||
required:
|
||||
- enable-gpios
|
||||
- swctrl-gpios
|
||||
- vddio-supply
|
||||
- vddaon-supply
|
||||
- vdddig-supply
|
||||
- vddrfa0p8-supply
|
||||
- vddrfa1p2-supply
|
||||
- vddrfa1p9-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
155
Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml
Normal file
155
Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml
Normal file
|
@ -0,0 +1,155 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/brcm,asp-v2.0.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom ASP 2.0 Ethernet controller
|
||||
|
||||
maintainers:
|
||||
- Justin Chen <justin.chen@broadcom.com>
|
||||
- Florian Fainelli <florian.fainelli@broadcom.com>
|
||||
|
||||
description: Broadcom Ethernet controller first introduced with 72165
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm74165-asp
|
||||
- const: brcm,asp-v2.1
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm72165-asp
|
||||
- const: brcm,asp-v2.0
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
"#size-cells":
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ranges: true
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: RX/TX interrupt
|
||||
- description: Port 0 Wake-on-LAN
|
||||
- description: Port 1 Wake-on-LAN
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
ethernet-ports:
|
||||
type: object
|
||||
properties:
|
||||
"#address-cells":
|
||||
const: 1
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^port@[0-9]+$":
|
||||
type: object
|
||||
|
||||
$ref: ethernet-controller.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: Port number
|
||||
|
||||
brcm,channel:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
ASP Channel Number
|
||||
|
||||
The depacketizer channel that consumes packets from
|
||||
the unimac/port.
|
||||
|
||||
required:
|
||||
- reg
|
||||
- brcm,channel
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^mdio@[0-9a-f]+$":
|
||||
type: object
|
||||
$ref: brcm,unimac-mdio.yaml
|
||||
|
||||
description:
|
||||
ASP internal UniMAC MDIO bus
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- ranges
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
ethernet@9c00000 {
|
||||
compatible = "brcm,bcm72165-asp", "brcm,asp-v2.0";
|
||||
reg = <0x9c00000 0x1fff14>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ranges = <0x0 0x9c00000 0x1fff14>;
|
||||
clocks = <&scmi 14>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
mdio@c614 {
|
||||
compatible = "brcm,asp-v2.0-mdio";
|
||||
reg = <0xc614 0x8>;
|
||||
reg-names = "mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy0: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@ce14 {
|
||||
compatible = "brcm,asp-v2.0-mdio";
|
||||
reg = <0xce14 0x8>;
|
||||
reg-names = "mdio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy1: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
brcm,channel = <8>;
|
||||
phy-mode = "rgmii";
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
brcm,channel = <9>;
|
||||
phy-mode = "rgmii";
|
||||
phy-handle = <&phy1>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -22,6 +22,8 @@ properties:
|
|||
- brcm,genet-mdio-v3
|
||||
- brcm,genet-mdio-v4
|
||||
- brcm,genet-mdio-v5
|
||||
- brcm,asp-v2.0-mdio
|
||||
- brcm,asp-v2.1-mdio
|
||||
- brcm,unimac-mdio
|
||||
|
||||
reg:
|
||||
|
|
|
@ -21,6 +21,7 @@ properties:
|
|||
- const: allwinner,sun4i-a10-can
|
||||
- const: allwinner,sun4i-a10-can
|
||||
- const: allwinner,sun8i-r40-can
|
||||
- const: allwinner,sun20i-d1-can
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -37,8 +38,9 @@ properties:
|
|||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun8i-r40-can
|
||||
enum:
|
||||
- allwinner,sun8i-r40-can
|
||||
- allwinner,sun20i-d1-can
|
||||
|
||||
then:
|
||||
required:
|
||||
|
|
|
@ -122,8 +122,6 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- bosch,mram-cfg
|
||||
|
@ -132,6 +130,7 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
// Example with interrupts
|
||||
#include <dt-bindings/clock/imx6sx-clock.h>
|
||||
can@20e8000 {
|
||||
compatible = "bosch,m_can";
|
||||
|
@ -149,4 +148,21 @@ examples:
|
|||
};
|
||||
};
|
||||
|
||||
- |
|
||||
// Example with timer polling
|
||||
#include <dt-bindings/clock/imx6sx-clock.h>
|
||||
can@20e8000 {
|
||||
compatible = "bosch,m_can";
|
||||
reg = <0x020e8000 0x4000>, <0x02298000 0x4000>;
|
||||
reg-names = "m_can", "message_ram";
|
||||
clocks = <&clks IMX6SX_CLK_CANFD>,
|
||||
<&clks IMX6SX_CLK_CANFD>;
|
||||
clock-names = "hclk", "cclk";
|
||||
bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>;
|
||||
|
||||
can-transceiver {
|
||||
max-bitrate = <5000000>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
|
@ -4,7 +4,10 @@ Texas Instruments TCAN4x5x CAN Controller
|
|||
This file provides device node information for the TCAN4x5x interface contains.
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,tcan4x5x"
|
||||
- compatible:
|
||||
"ti,tcan4552", "ti,tcan4x5x"
|
||||
"ti,tcan4553", "ti,tcan4x5x" or
|
||||
"ti,tcan4x5x"
|
||||
- reg: 0
|
||||
- #address-cells: 1
|
||||
- #size-cells: 0
|
||||
|
@ -21,8 +24,10 @@ Optional properties:
|
|||
- reset-gpios: Hardwired output GPIO. If not defined then software
|
||||
reset.
|
||||
- device-state-gpios: Input GPIO that indicates if the device is in
|
||||
a sleep state or if the device is active.
|
||||
- device-wake-gpios: Wake up GPIO to wake up the TCAN device.
|
||||
a sleep state or if the device is active. Not
|
||||
available with tcan4552/4553.
|
||||
- device-wake-gpios: Wake up GPIO to wake up the TCAN device. Not
|
||||
available with tcan4552/4553.
|
||||
|
||||
Example:
|
||||
tcan4x5x: tcan4x5x@0 {
|
||||
|
|
|
@ -46,6 +46,9 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: CAN Tx mailbox buffer count (CAN FD)
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
@ -36,7 +36,7 @@ additionalProperties: true
|
|||
$defs:
|
||||
ethernet-ports:
|
||||
description: A DSA switch without any extra port properties
|
||||
$ref: '#/'
|
||||
$ref: '#'
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
|
|
|
@ -20,7 +20,7 @@ which is at a different MDIO base address in different switch families.
|
|||
6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321,
|
||||
6341, 6350, 6351, 6352
|
||||
- "marvell,mv88e6190" : Switch has base address 0x00. Use with models:
|
||||
6163, 6190, 6190X, 6191, 6290, 6390, 6390X
|
||||
6190, 6190X, 6191, 6290, 6361, 6390, 6390X
|
||||
- "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model:
|
||||
6220, 6250
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ properties:
|
|||
- mii
|
||||
- gmii
|
||||
- sgmii
|
||||
- psgmii
|
||||
- qsgmii
|
||||
- qusgmii
|
||||
- tbi
|
||||
|
|
|
@ -19,10 +19,12 @@ properties:
|
|||
enum:
|
||||
- mediatek,mt2701-eth
|
||||
- mediatek,mt7623-eth
|
||||
- mediatek,mt7621-eth
|
||||
- mediatek,mt7622-eth
|
||||
- mediatek,mt7629-eth
|
||||
- mediatek,mt7981-eth
|
||||
- mediatek,mt7986-eth
|
||||
- mediatek,mt7988-eth
|
||||
- ralink,rt5350-eth
|
||||
|
||||
reg:
|
||||
|
@ -32,7 +34,7 @@ properties:
|
|||
clock-names: true
|
||||
|
||||
interrupts:
|
||||
minItems: 3
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
power-domains:
|
||||
|
@ -60,6 +62,12 @@ properties:
|
|||
Phandle to the mediatek hifsys controller used to provide various clocks
|
||||
and reset to the system.
|
||||
|
||||
mediatek,infracfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon node that handles the path from GMAC to
|
||||
PHY variants.
|
||||
|
||||
mediatek,sgmiisys:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
minItems: 1
|
||||
|
@ -121,6 +129,8 @@ allOf:
|
|||
- const: gp1
|
||||
- const: gp2
|
||||
|
||||
mediatek,infracfg: false
|
||||
|
||||
mediatek,pctl:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
|
@ -131,6 +141,32 @@ allOf:
|
|||
|
||||
mediatek,wed-pcie: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt7621-eth
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ethif
|
||||
- const: fe
|
||||
|
||||
mediatek,infracfg: false
|
||||
|
||||
mediatek,wed: false
|
||||
|
||||
mediatek,wed-pcie: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -159,6 +195,8 @@ allOf:
|
|||
- const: sgmii_ck
|
||||
- const: eth2pll
|
||||
|
||||
mediatek,infracfg: false
|
||||
|
||||
mediatek,sgmiisys:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
|
@ -204,12 +242,6 @@ allOf:
|
|||
- const: sgmii_ck
|
||||
- const: eth2pll
|
||||
|
||||
mediatek,infracfg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon node that handles the path from GMAC to
|
||||
PHY variants.
|
||||
|
||||
mediatek,sgmiisys:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
@ -250,6 +282,8 @@ allOf:
|
|||
- const: netsys0
|
||||
- const: netsys1
|
||||
|
||||
mediatek,infracfg: false
|
||||
|
||||
mediatek,sgmiisys:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
@ -286,6 +320,67 @@ allOf:
|
|||
- const: netsys0
|
||||
- const: netsys1
|
||||
|
||||
mediatek,infracfg: false
|
||||
|
||||
mediatek,sgmiisys:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt7988-eth
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 4
|
||||
|
||||
clocks:
|
||||
minItems: 34
|
||||
maxItems: 34
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: crypto
|
||||
- const: fe
|
||||
- const: gp2
|
||||
- const: gp1
|
||||
- const: gp3
|
||||
- const: ethwarp_wocpu2
|
||||
- const: ethwarp_wocpu1
|
||||
- const: ethwarp_wocpu0
|
||||
- const: esw
|
||||
- const: netsys0
|
||||
- const: netsys1
|
||||
- const: sgmii_tx250m
|
||||
- const: sgmii_rx250m
|
||||
- const: sgmii2_tx250m
|
||||
- const: sgmii2_rx250m
|
||||
- const: top_usxgmii0_sel
|
||||
- const: top_usxgmii1_sel
|
||||
- const: top_sgm0_sel
|
||||
- const: top_sgm1_sel
|
||||
- const: top_xfi_phy0_xtal_sel
|
||||
- const: top_xfi_phy1_xtal_sel
|
||||
- const: top_eth_gmii_sel
|
||||
- const: top_eth_refck_50m_sel
|
||||
- const: top_eth_sys_200m_sel
|
||||
- const: top_eth_sys_sel
|
||||
- const: top_eth_xgmii_sel
|
||||
- const: top_eth_mii_sel
|
||||
- const: top_netsys_sel
|
||||
- const: top_netsys_500m_sel
|
||||
- const: top_netsys_pao_2x_sel
|
||||
- const: top_netsys_sync_250m_sel
|
||||
- const: top_netsys_ppefb_250m_sel
|
||||
- const: top_netsys_warp_sel
|
||||
- const: wocpu1
|
||||
- const: wocpu0
|
||||
- const: xgp1
|
||||
- const: xgp2
|
||||
- const: xgp3
|
||||
|
||||
mediatek,sgmiisys:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
|
|
@ -52,6 +52,40 @@ properties:
|
|||
for a timer.
|
||||
type: boolean
|
||||
|
||||
motorcomm,rx-clk-drv-microamp:
|
||||
description: |
|
||||
drive strength of rx_clk rgmii pad.
|
||||
The YT8531 RGMII LDO voltage supports 1.8V/3.3V, and the LDO voltage can
|
||||
be configured with hardware pull-up resistors to match the SOC voltage
|
||||
(usually 1.8V).
|
||||
The software can read the registers to obtain the LDO voltage and configure
|
||||
the legal drive strength(curren).
|
||||
=====================================================
|
||||
| voltage | current Available (uA) |
|
||||
| 1.8v | 1200 2100 2700 2910 3110 3600 3970 4350 |
|
||||
| 3.3v | 3070 4080 4370 4680 5020 5450 5740 6140 |
|
||||
=====================================================
|
||||
enum: [ 1200, 2100, 2700, 2910, 3070, 3110, 3600, 3970,
|
||||
4080, 4350, 4370, 4680, 5020, 5450, 5740, 6140 ]
|
||||
default: 2910
|
||||
|
||||
motorcomm,rx-data-drv-microamp:
|
||||
description: |
|
||||
drive strength of rx_data/rx_ctl rgmii pad.
|
||||
The YT8531 RGMII LDO voltage supports 1.8V/3.3V, and the LDO voltage can
|
||||
be configured with hardware pull-up resistors to match the SOC voltage
|
||||
(usually 1.8V).
|
||||
The software can read the registers to obtain the LDO voltage and configure
|
||||
the legal drive strength(curren).
|
||||
=====================================================
|
||||
| voltage | current Available (uA) |
|
||||
| 1.8v | 1200 2100 2700 2910 3110 3600 3970 4350 |
|
||||
| 3.3v | 3070 4080 4370 4680 5020 5450 5740 6140 |
|
||||
=====================================================
|
||||
enum: [ 1200, 2100, 2700, 2910, 3070, 3110, 3600, 3970,
|
||||
4080, 4350, 4370, 4680, 5020, 5450, 5740, 6140 ]
|
||||
default: 2910
|
||||
|
||||
motorcomm,tx-clk-adj-enabled:
|
||||
description: |
|
||||
This configuration is mainly to adapt to VF2 with JH7110 SoC.
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
* Oxford Semiconductor OXNAS DWMAC Ethernet controller
|
||||
|
||||
The device inherits all the properties of the dwmac/stmmac devices
|
||||
described in the file stmmac.txt in the current directory with the
|
||||
following changes.
|
||||
|
||||
Required properties on all platforms:
|
||||
|
||||
- compatible: For the OX820 SoC, it should be :
|
||||
- "oxsemi,ox820-dwmac" to select glue
|
||||
- "snps,dwmac-3.512" to select IP version.
|
||||
For the OX810SE SoC, it should be :
|
||||
- "oxsemi,ox810se-dwmac" to select glue
|
||||
- "snps,dwmac-3.512" to select IP version.
|
||||
|
||||
- clocks: Should contain phandles to the following clocks
|
||||
- clock-names: Should contain the following:
|
||||
- "stmmaceth" for the host clock - see stmmac.txt
|
||||
- "gmac" for the peripheral gate clock
|
||||
|
||||
- oxsemi,sys-ctrl: a phandle to the system controller syscon node
|
||||
|
||||
Example :
|
||||
|
||||
etha: ethernet@40400000 {
|
||||
compatible = "oxsemi,ox820-dwmac", "snps,dwmac-3.512";
|
||||
reg = <0x40400000 0x2000>;
|
||||
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq", "eth_wake_irq";
|
||||
mac-address = [000000000000]; /* Filled in by U-Boot */
|
||||
phy-mode = "rgmii";
|
||||
|
||||
clocks = <&stdclk CLK_820_ETHA>, <&gmacclk>;
|
||||
clock-names = "gmac", "stmmaceth";
|
||||
resets = <&reset RESET_MAC>;
|
||||
|
||||
/* Regmap for sys registers */
|
||||
oxsemi,sys-ctrl = <&sys>;
|
||||
|
||||
};
|
|
@ -75,6 +75,7 @@ properties:
|
|||
description:
|
||||
Initial data for the VDDIO regulator. Set this to 1.5V or 1.8V.
|
||||
$ref: /schemas/regulator/regulator.yaml
|
||||
unevaluatedProperties: false
|
||||
|
||||
vddh-regulator:
|
||||
type: object
|
||||
|
@ -82,6 +83,7 @@ properties:
|
|||
Dummy subnode to model the external connection of the PHY VDDH
|
||||
regulator to VDDIO.
|
||||
$ref: /schemas/regulator/regulator.yaml
|
||||
unevaluatedProperties: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ properties:
|
|||
"output" means GMAC provides the reference clock.
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [input, output]
|
||||
default: input
|
||||
|
||||
rockchip,grf:
|
||||
description: The phandle of the syscon node for the general register file.
|
||||
|
|
45
Documentation/devicetree/bindings/net/ti,icss-iep.yaml
Normal file
45
Documentation/devicetree/bindings/net/ti,icss-iep.yaml
Normal file
|
@ -0,0 +1,45 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/ti,icss-iep.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ICSS Industrial Ethernet Peripheral (IEP) module
|
||||
|
||||
maintainers:
|
||||
- Md Danish Anwar <danishanwar@ti.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- ti,am642-icss-iep
|
||||
- ti,j721e-icss-iep
|
||||
- const: ti,am654-icss-iep
|
||||
|
||||
- const: ti,am654-icss-iep
|
||||
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description: phandle to the IEP source clock
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
/* AM65x */
|
||||
icssg0_iep0: iep@2e000 {
|
||||
compatible = "ti,am654-icss-iep";
|
||||
reg = <0x2e000 0x1000>;
|
||||
clocks = <&icssg0_iepclk_mux>;
|
||||
};
|
193
Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml
Normal file
193
Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml
Normal file
|
@ -0,0 +1,193 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/ti,icssg-prueth.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments ICSSG PRUSS Ethernet
|
||||
|
||||
maintainers:
|
||||
- Md Danish Anwar <danishanwar@ti.com>
|
||||
|
||||
description:
|
||||
Ethernet based on the Programmable Real-Time Unit and Industrial
|
||||
Communication Subsystem.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/remoteproc/ti,pru-consumer.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,am654-icssg-prueth # for AM65x SoC family
|
||||
|
||||
sram:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to MSMC SRAM node
|
||||
|
||||
dmas:
|
||||
maxItems: 10
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx0-0
|
||||
- const: tx0-1
|
||||
- const: tx0-2
|
||||
- const: tx0-3
|
||||
- const: tx1-0
|
||||
- const: tx1-1
|
||||
- const: tx1-2
|
||||
- const: tx1-3
|
||||
- const: rx0
|
||||
- const: rx1
|
||||
|
||||
ti,mii-g-rt:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to MII_G_RT module's syscon regmap.
|
||||
|
||||
ti,mii-rt:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to MII_RT module's syscon regmap
|
||||
|
||||
ti,iep:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
maxItems: 2
|
||||
items:
|
||||
maxItems: 1
|
||||
description:
|
||||
phandle to IEP (Industrial Ethernet Peripheral) for ICSSG
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
description:
|
||||
Interrupt specifiers to TX timestamp IRQ.
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: tx_ts0
|
||||
- const: tx_ts1
|
||||
|
||||
ethernet-ports:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#address-cells':
|
||||
const: 1
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
^port@[0-1]$:
|
||||
type: object
|
||||
description: ICSSG PRUETH external ports
|
||||
$ref: ethernet-controller.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- enum: [0, 1]
|
||||
description: ICSSG PRUETH port number
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
ti,syscon-rgmii-delay:
|
||||
items:
|
||||
- items:
|
||||
- description: phandle to system controller node
|
||||
- description: The offset to ICSSG control register
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description:
|
||||
phandle to system controller node and register offset
|
||||
to ICSSG control register for RGMII transmit delay
|
||||
|
||||
required:
|
||||
- reg
|
||||
anyOf:
|
||||
- required:
|
||||
- port@0
|
||||
- required:
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- sram
|
||||
- dmas
|
||||
- dma-names
|
||||
- ethernet-ports
|
||||
- ti,mii-g-rt
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
/* Example k3-am654 base board SR2.0, dual-emac */
|
||||
pruss2_eth: ethernet {
|
||||
compatible = "ti,am654-icssg-prueth";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&icssg2_rgmii_pins_default>;
|
||||
sram = <&msmc_ram>;
|
||||
|
||||
ti,prus = <&pru2_0>, <&rtu2_0>, <&tx_pru2_0>,
|
||||
<&pru2_1>, <&rtu2_1>, <&tx_pru2_1>;
|
||||
firmware-name = "ti-pruss/am65x-pru0-prueth-fw.elf",
|
||||
"ti-pruss/am65x-rtu0-prueth-fw.elf",
|
||||
"ti-pruss/am65x-txpru0-prueth-fw.elf",
|
||||
"ti-pruss/am65x-pru1-prueth-fw.elf",
|
||||
"ti-pruss/am65x-rtu1-prueth-fw.elf",
|
||||
"ti-pruss/am65x-txpru1-prueth-fw.elf";
|
||||
ti,pruss-gp-mux-sel = <2>, /* MII mode */
|
||||
<2>,
|
||||
<2>,
|
||||
<2>, /* MII mode */
|
||||
<2>,
|
||||
<2>;
|
||||
dmas = <&main_udmap 0xc300>, /* egress slice 0 */
|
||||
<&main_udmap 0xc301>, /* egress slice 0 */
|
||||
<&main_udmap 0xc302>, /* egress slice 0 */
|
||||
<&main_udmap 0xc303>, /* egress slice 0 */
|
||||
<&main_udmap 0xc304>, /* egress slice 1 */
|
||||
<&main_udmap 0xc305>, /* egress slice 1 */
|
||||
<&main_udmap 0xc306>, /* egress slice 1 */
|
||||
<&main_udmap 0xc307>, /* egress slice 1 */
|
||||
<&main_udmap 0x4300>, /* ingress slice 0 */
|
||||
<&main_udmap 0x4301>; /* ingress slice 1 */
|
||||
dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3",
|
||||
"tx1-0", "tx1-1", "tx1-2", "tx1-3",
|
||||
"rx0", "rx1";
|
||||
ti,mii-g-rt = <&icssg2_mii_g_rt>;
|
||||
ti,iep = <&icssg2_iep0>, <&icssg2_iep1>;
|
||||
interrupt-parent = <&icssg2_intc>;
|
||||
interrupts = <24 0 2>, <25 1 3>;
|
||||
interrupt-names = "tx_ts0", "tx_ts1";
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pruss2_emac0: port@0 {
|
||||
reg = <0>;
|
||||
phy-handle = <&pruss2_eth0_phy>;
|
||||
phy-mode = "rgmii-id";
|
||||
interrupts-extended = <&icssg2_intc 24>;
|
||||
ti,syscon-rgmii-delay = <&scm_conf 0x4120>;
|
||||
/* Filled in by bootloader */
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
};
|
||||
|
||||
pruss2_emac1: port@1 {
|
||||
reg = <1>;
|
||||
phy-handle = <&pruss2_eth1_phy>;
|
||||
phy-mode = "rgmii-id";
|
||||
interrupts-extended = <&icssg2_intc 25>;
|
||||
ti,syscon-rgmii-delay = <&scm_conf 0x4124>;
|
||||
/* Filled in by bootloader */
|
||||
local-mac-address = [00 00 00 00 00 00];
|
||||
};
|
||||
};
|
||||
};
|
|
@ -28,6 +28,7 @@ properties:
|
|||
- mediatek,mt76
|
||||
- mediatek,mt7628-wmac
|
||||
- mediatek,mt7622-wmac
|
||||
- mediatek,mt7981-wmac
|
||||
- mediatek,mt7986-wmac
|
||||
|
||||
reg:
|
||||
|
@ -71,6 +72,14 @@ properties:
|
|||
|
||||
ieee80211-freq-limit: true
|
||||
|
||||
nvmem-cells:
|
||||
items:
|
||||
- description: NVMEM cell with EEPROM
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: eeprom
|
||||
|
||||
mediatek,eeprom-data:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
|
@ -84,6 +93,7 @@ properties:
|
|||
- description: offset containing EEPROM data
|
||||
description:
|
||||
Phandle to a MTD partition + offset containing EEPROM data
|
||||
deprecated: true
|
||||
|
||||
big-endian:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
@ -258,7 +268,8 @@ examples:
|
|||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <6>;
|
||||
|
||||
mediatek,mtd-eeprom = <&factory 0x0>;
|
||||
nvmem-cells = <&eeprom>;
|
||||
nvmem-cell-names = "eeprom";
|
||||
};
|
||||
|
||||
- |
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
XILINX GMIITORGMII Converter Driver Device Tree Bindings
|
||||
--------------------------------------------------------
|
||||
|
||||
The Gigabit Media Independent Interface (GMII) to Reduced Gigabit Media
|
||||
Independent Interface (RGMII) core provides the RGMII between RGMII-compliant
|
||||
Ethernet physical media devices (PHY) and the Gigabit Ethernet controller.
|
||||
This core can be used in all three modes of operation(10/100/1000 Mb/s).
|
||||
The Management Data Input/Output (MDIO) interface is used to configure the
|
||||
Speed of operation. This core can switch dynamically between the three
|
||||
Different speed modes by configuring the conveter register through mdio write.
|
||||
|
||||
This converter sits between the ethernet MAC and the external phy.
|
||||
MAC <==> GMII2RGMII <==> RGMII_PHY
|
||||
|
||||
For more details about mdio please refer phy.txt file in the same directory.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "xlnx,gmii-to-rgmii-1.0"
|
||||
- reg : The ID number for the phy, usually a small integer
|
||||
- phy-handle : Should point to the external phy device.
|
||||
See ethernet.txt file in the same directory.
|
||||
|
||||
Example:
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
phy: ethernet-phy@0 {
|
||||
......
|
||||
};
|
||||
gmiitorgmii: gmiitorgmii@8 {
|
||||
compatible = "xlnx,gmii-to-rgmii-1.0";
|
||||
reg = <8>;
|
||||
phy-handle = <&phy>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/xlnx,gmii-to-rgmii.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx GMII to RGMII Converter
|
||||
|
||||
maintainers:
|
||||
- Harini Katakam <harini.katakam@amd.com>
|
||||
|
||||
description:
|
||||
The Gigabit Media Independent Interface (GMII) to Reduced Gigabit Media
|
||||
Independent Interface (RGMII) core provides the RGMII between RGMII-compliant
|
||||
ethernet physical media devices (PHY) and the Gigabit Ethernet controller.
|
||||
This core can be used in all three modes of operation(10/100/1000 Mb/s).
|
||||
The Management Data Input/Output (MDIO) interface is used to configure the
|
||||
speed of operation. This core can switch dynamically between the three
|
||||
different speed modes by configuring the converter register through mdio write.
|
||||
The core cannot function without an external phy connected to it.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: xlnx,gmii-to-rgmii-1.0
|
||||
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 31
|
||||
description: The ID number for the phy.
|
||||
|
||||
phy-handle:
|
||||
$ref: ethernet-controller.yaml#/properties/phy-handle
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- phy-handle
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy: ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
gmiitorgmii@8 {
|
||||
compatible = "xlnx,gmii-to-rgmii-1.0";
|
||||
reg = <8>;
|
||||
phy-handle = <&phy>;
|
||||
};
|
||||
};
|
|
@ -41,7 +41,7 @@ properties:
|
|||
description: Name of the define for the family name.
|
||||
type: string
|
||||
c-version-name:
|
||||
description: Name of the define for the verion of the family.
|
||||
description: Name of the define for the version of the family.
|
||||
type: string
|
||||
max-by-define:
|
||||
description: Makes the number of attributes and commands be specified by a define, not an enum value.
|
||||
|
@ -274,7 +274,7 @@ properties:
|
|||
description: Kernel attribute validation flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump ]
|
||||
enum: [ strict, dump, dump-strict ]
|
||||
do: &subop-type
|
||||
description: Main command handler.
|
||||
type: object
|
||||
|
|
|
@ -41,7 +41,7 @@ properties:
|
|||
description: Name of the define for the family name.
|
||||
type: string
|
||||
c-version-name:
|
||||
description: Name of the define for the verion of the family.
|
||||
description: Name of the define for the version of the family.
|
||||
type: string
|
||||
max-by-define:
|
||||
description: Makes the number of attributes and commands be specified by a define, not an enum value.
|
||||
|
@ -321,7 +321,7 @@ properties:
|
|||
description: Kernel attribute validation flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump ]
|
||||
enum: [ strict, dump, dump-strict ]
|
||||
# Start genetlink-legacy
|
||||
fixed-header: *fixed-header
|
||||
# End genetlink-legacy
|
||||
|
|
|
@ -243,7 +243,7 @@ properties:
|
|||
description: Kernel attribute validation flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump ]
|
||||
enum: [ strict, dump, dump-strict ]
|
||||
do: &subop-type
|
||||
description: Main command handler.
|
||||
type: object
|
||||
|
|
410
Documentation/netlink/netlink-raw.yaml
Normal file
410
Documentation/netlink/netlink-raw.yaml
Normal file
|
@ -0,0 +1,410 @@
|
|||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://kernel.org/schemas/netlink/netlink-raw.yaml#
|
||||
$schema: https://json-schema.org/draft-07/schema
|
||||
|
||||
# Common defines
|
||||
$defs:
|
||||
uint:
|
||||
type: integer
|
||||
minimum: 0
|
||||
len-or-define:
|
||||
type: [ string, integer ]
|
||||
pattern: ^[0-9A-Za-z_]+( - 1)?$
|
||||
minimum: 0
|
||||
|
||||
# Schema for specs
|
||||
title: Protocol
|
||||
description: Specification of a raw netlink protocol
|
||||
type: object
|
||||
required: [ name, doc, attribute-sets, operations ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
description: Name of the netlink family.
|
||||
type: string
|
||||
doc:
|
||||
type: string
|
||||
protocol:
|
||||
description: Schema compatibility level.
|
||||
enum: [ netlink-raw ] # Trim
|
||||
# Start netlink-raw
|
||||
protonum:
|
||||
description: Protocol number to use for netlink-raw
|
||||
type: integer
|
||||
# End netlink-raw
|
||||
uapi-header:
|
||||
description: Path to the uAPI header, default is linux/${family-name}.h
|
||||
type: string
|
||||
# Start genetlink-c
|
||||
c-family-name:
|
||||
description: Name of the define for the family name.
|
||||
type: string
|
||||
c-version-name:
|
||||
description: Name of the define for the version of the family.
|
||||
type: string
|
||||
max-by-define:
|
||||
description: Makes the number of attributes and commands be specified by a define, not an enum value.
|
||||
type: boolean
|
||||
# End genetlink-c
|
||||
# Start genetlink-legacy
|
||||
kernel-policy:
|
||||
description: |
|
||||
Defines if the input policy in the kernel is global, per-operation, or split per operation type.
|
||||
Default is split.
|
||||
enum: [ split, per-op, global ]
|
||||
# End genetlink-legacy
|
||||
|
||||
definitions:
|
||||
description: List of type and constant definitions (enums, flags, defines).
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ type, name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
header:
|
||||
description: For C-compatible languages, header which already defines this value.
|
||||
type: string
|
||||
type:
|
||||
enum: [ const, enum, flags, struct ] # Trim
|
||||
doc:
|
||||
type: string
|
||||
# For const
|
||||
value:
|
||||
description: For const - the value.
|
||||
type: [ string, integer ]
|
||||
# For enum and flags
|
||||
value-start:
|
||||
description: For enum or flags the literal initializer for the first value.
|
||||
type: [ string, integer ]
|
||||
entries:
|
||||
description: For enum or flags array of values.
|
||||
type: array
|
||||
items:
|
||||
oneOf:
|
||||
- type: string
|
||||
- type: object
|
||||
required: [ name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
value:
|
||||
type: integer
|
||||
doc:
|
||||
type: string
|
||||
render-max:
|
||||
description: Render the max members for this enum.
|
||||
type: boolean
|
||||
# Start genetlink-c
|
||||
enum-name:
|
||||
description: Name for enum, if empty no name will be used.
|
||||
type: [ string, "null" ]
|
||||
name-prefix:
|
||||
description: For enum the prefix of the values, optional.
|
||||
type: string
|
||||
# End genetlink-c
|
||||
# Start genetlink-legacy
|
||||
members:
|
||||
description: List of struct members. Only scalars and strings members allowed.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name, type ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
description: The netlink attribute type
|
||||
enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string, binary ]
|
||||
len:
|
||||
$ref: '#/$defs/len-or-define'
|
||||
byte-order:
|
||||
enum: [ little-endian, big-endian ]
|
||||
doc:
|
||||
description: Documentation for the struct member attribute.
|
||||
type: string
|
||||
enum:
|
||||
description: Name of the enum type used for the attribute.
|
||||
type: string
|
||||
enum-as-flags:
|
||||
description: |
|
||||
Treat the enum as flags. In most cases enum is either used as flags or as values.
|
||||
Sometimes, however, both forms are necessary, in which case header contains the enum
|
||||
form while specific attributes may request to convert the values into a bitfield.
|
||||
type: boolean
|
||||
display-hint: &display-hint
|
||||
description: |
|
||||
Optional format indicator that is intended only for choosing
|
||||
the right formatting mechanism when displaying values of this
|
||||
type.
|
||||
enum: [ hex, mac, fddi, ipv4, ipv6, uuid ]
|
||||
# End genetlink-legacy
|
||||
|
||||
attribute-sets:
|
||||
description: Definition of attribute spaces for this family.
|
||||
type: array
|
||||
items:
|
||||
description: Definition of a single attribute space.
|
||||
type: object
|
||||
required: [ name, attributes ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
description: |
|
||||
Name used when referring to this space in other definitions, not used outside of the spec.
|
||||
type: string
|
||||
name-prefix:
|
||||
description: |
|
||||
Prefix for the C enum name of the attributes. Default family[name]-set[name]-a-
|
||||
type: string
|
||||
enum-name:
|
||||
description: Name for the enum type of the attribute.
|
||||
type: string
|
||||
doc:
|
||||
description: Documentation of the space.
|
||||
type: string
|
||||
subset-of:
|
||||
description: |
|
||||
Name of another space which this is a logical part of. Sub-spaces can be used to define
|
||||
a limited group of attributes which are used in a nest.
|
||||
type: string
|
||||
# Start genetlink-c
|
||||
attr-cnt-name:
|
||||
description: The explicit name for constant holding the count of attributes (last attr + 1).
|
||||
type: string
|
||||
attr-max-name:
|
||||
description: The explicit name for last member of attribute enum.
|
||||
type: string
|
||||
# End genetlink-c
|
||||
attributes:
|
||||
description: List of attributes in the space.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name, type ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type: &attr-type
|
||||
description: The netlink attribute type
|
||||
enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
|
||||
string, nest, array-nest, nest-type-value ]
|
||||
doc:
|
||||
description: Documentation of the attribute.
|
||||
type: string
|
||||
value:
|
||||
description: Value for the enum item representing this attribute in the uAPI.
|
||||
$ref: '#/$defs/uint'
|
||||
type-value:
|
||||
description: Name of the value extracted from the type of a nest-type-value attribute.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
byte-order:
|
||||
enum: [ little-endian, big-endian ]
|
||||
multi-attr:
|
||||
type: boolean
|
||||
nested-attributes:
|
||||
description: Name of the space (sub-space) used inside the attribute.
|
||||
type: string
|
||||
enum:
|
||||
description: Name of the enum type used for the attribute.
|
||||
type: string
|
||||
enum-as-flags:
|
||||
description: |
|
||||
Treat the enum as flags. In most cases enum is either used as flags or as values.
|
||||
Sometimes, however, both forms are necessary, in which case header contains the enum
|
||||
form while specific attributes may request to convert the values into a bitfield.
|
||||
type: boolean
|
||||
checks:
|
||||
description: Kernel input validation.
|
||||
type: object
|
||||
additionalProperties: False
|
||||
properties:
|
||||
flags-mask:
|
||||
description: Name of the flags constant on which to base mask (unsigned scalar types only).
|
||||
type: string
|
||||
min:
|
||||
description: Min value for an integer attribute.
|
||||
type: integer
|
||||
min-len:
|
||||
description: Min length for a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
max-len:
|
||||
description: Max length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
sub-type: *attr-type
|
||||
display-hint: *display-hint
|
||||
# Start genetlink-c
|
||||
name-prefix:
|
||||
type: string
|
||||
# End genetlink-c
|
||||
# Start genetlink-legacy
|
||||
struct:
|
||||
description: Name of the struct type used for the attribute.
|
||||
type: string
|
||||
# End genetlink-legacy
|
||||
|
||||
# Make sure name-prefix does not appear in subsets (subsets inherit naming)
|
||||
dependencies:
|
||||
name-prefix:
|
||||
not:
|
||||
required: [ subset-of ]
|
||||
subset-of:
|
||||
not:
|
||||
required: [ name-prefix ]
|
||||
|
||||
operations:
|
||||
description: Operations supported by the protocol.
|
||||
type: object
|
||||
required: [ list ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
enum-model:
|
||||
description: |
|
||||
The model of assigning values to the operations.
|
||||
"unified" is the recommended model where all message types belong
|
||||
to a single enum.
|
||||
"directional" has the messages sent to the kernel and from the kernel
|
||||
enumerated separately.
|
||||
enum: [ unified, directional ] # Trim
|
||||
name-prefix:
|
||||
description: |
|
||||
Prefix for the C enum name of the command. The name is formed by concatenating
|
||||
the prefix with the upper case name of the command, with dashes replaced by underscores.
|
||||
type: string
|
||||
enum-name:
|
||||
description: Name for the enum type with commands.
|
||||
type: string
|
||||
async-prefix:
|
||||
description: Same as name-prefix but used to render notifications and events to separate enum.
|
||||
type: string
|
||||
async-enum:
|
||||
description: Name for the enum type with notifications/events.
|
||||
type: string
|
||||
# Start genetlink-legacy
|
||||
fixed-header: &fixed-header
|
||||
description: |
|
||||
Name of the structure defining the optional fixed-length protocol
|
||||
header. This header is placed in a message after the netlink and
|
||||
genetlink headers and before any attributes.
|
||||
type: string
|
||||
# End genetlink-legacy
|
||||
list:
|
||||
description: List of commands
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: False
|
||||
required: [ name, doc ]
|
||||
properties:
|
||||
name:
|
||||
description: Name of the operation, also defining its C enum value in uAPI.
|
||||
type: string
|
||||
doc:
|
||||
description: Documentation for the command.
|
||||
type: string
|
||||
value:
|
||||
description: Value for the enum in the uAPI.
|
||||
$ref: '#/$defs/uint'
|
||||
attribute-set:
|
||||
description: |
|
||||
Attribute space from which attributes directly in the requests and replies
|
||||
to this command are defined.
|
||||
type: string
|
||||
flags: &cmd_flags
|
||||
description: Command flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ admin-perm ]
|
||||
dont-validate:
|
||||
description: Kernel attribute validation flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump ]
|
||||
# Start genetlink-legacy
|
||||
fixed-header: *fixed-header
|
||||
# End genetlink-legacy
|
||||
do: &subop-type
|
||||
description: Main command handler.
|
||||
type: object
|
||||
additionalProperties: False
|
||||
properties:
|
||||
request: &subop-attr-list
|
||||
description: Definition of the request message for a given command.
|
||||
type: object
|
||||
additionalProperties: False
|
||||
properties:
|
||||
attributes:
|
||||
description: |
|
||||
Names of attributes from the attribute-set (not full attribute
|
||||
definitions, just names).
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
# Start genetlink-legacy
|
||||
value:
|
||||
description: |
|
||||
ID of this message if value for request and response differ,
|
||||
i.e. requests and responses have different message enums.
|
||||
$ref: '#/$defs/uint'
|
||||
# End genetlink-legacy
|
||||
reply: *subop-attr-list
|
||||
pre:
|
||||
description: Hook for a function to run before the main callback (pre_doit or start).
|
||||
type: string
|
||||
post:
|
||||
description: Hook for a function to run after the main callback (post_doit or done).
|
||||
type: string
|
||||
dump: *subop-type
|
||||
notify:
|
||||
description: Name of the command sharing the reply type with this notification.
|
||||
type: string
|
||||
event:
|
||||
type: object
|
||||
additionalProperties: False
|
||||
properties:
|
||||
attributes:
|
||||
description: Explicit list of the attributes for the notification.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
mcgrp:
|
||||
description: Name of the multicast group generating given notification.
|
||||
type: string
|
||||
mcast-groups:
|
||||
description: List of multicast groups.
|
||||
type: object
|
||||
required: [ list ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
list:
|
||||
description: List of groups.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
description: |
|
||||
The name for the group, used to form the define and the value of the define.
|
||||
type: string
|
||||
# Start genetlink-c
|
||||
c-define-name:
|
||||
description: Override for the name of the define in C uAPI.
|
||||
type: string
|
||||
# End genetlink-c
|
||||
flags: *cmd_flags
|
||||
# Start netlink-raw
|
||||
value:
|
||||
description: Value of the netlink multicast group in the uAPI.
|
||||
type: integer
|
||||
# End netlink-raw
|
|
@ -6,6 +6,16 @@ protocol: genetlink-legacy
|
|||
|
||||
doc: Partial family for Devlink.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: enum
|
||||
name: sb-pool-type
|
||||
entries:
|
||||
-
|
||||
name: ingress
|
||||
-
|
||||
name: egress
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: devlink
|
||||
|
@ -24,6 +34,46 @@ attribute-sets:
|
|||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: sb-index
|
||||
type: u32
|
||||
value: 11
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: sb-pool-index
|
||||
type: u16
|
||||
value: 17
|
||||
|
||||
-
|
||||
name: sb-pool-type
|
||||
type: u8
|
||||
enum: sb-pool-type
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: sb-tc-index
|
||||
type: u16
|
||||
value: 22
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: param-name
|
||||
type: string
|
||||
value: 81
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: region-name
|
||||
type: string
|
||||
value: 88
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: info-driver-name
|
||||
type: string
|
||||
|
@ -55,10 +105,35 @@ attribute-sets:
|
|||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: health-reporter-name
|
||||
type: string
|
||||
value: 115
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: trap-name
|
||||
type: string
|
||||
value: 130
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: trap-group-name
|
||||
type: string
|
||||
value: 135
|
||||
|
||||
-
|
||||
name: reload-failed
|
||||
type: u8
|
||||
value: 136
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: trap-policer-id
|
||||
type: u32
|
||||
value: 142
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
|
@ -103,6 +178,21 @@ attribute-sets:
|
|||
type: nest
|
||||
multi-attr: true
|
||||
nested-attributes: dl-reload-act-stats
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: rate-node-name
|
||||
type: string
|
||||
value: 168
|
||||
|
||||
# TODO: fill in the attributes in between
|
||||
|
||||
-
|
||||
name: linecard-index
|
||||
type: u32
|
||||
value: 171
|
||||
|
||||
-
|
||||
name: dl-dev-stats
|
||||
subset-of: devlink
|
||||
|
@ -165,8 +255,13 @@ operations:
|
|||
name: get
|
||||
doc: Get devlink instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
- dump
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 1
|
||||
attributes: &dev-id-attrs
|
||||
|
@ -183,18 +278,212 @@ operations:
|
|||
dump:
|
||||
reply: *get-reply
|
||||
|
||||
-
|
||||
name: port-get
|
||||
doc: Get devlink port instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit-port
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 5
|
||||
attributes: &port-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- port-index
|
||||
reply:
|
||||
value: 7
|
||||
attributes: *port-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply:
|
||||
value: 3 # due to a bug, port dump returns DEVLINK_CMD_NEW
|
||||
attributes: *port-id-attrs
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: sb-get
|
||||
doc: Get shared buffer instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 11
|
||||
attributes: &sb-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- sb-index
|
||||
reply: &sb-get-reply
|
||||
value: 11
|
||||
attributes: *sb-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *sb-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: sb-pool-get
|
||||
doc: Get shared buffer pool instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 15
|
||||
attributes: &sb-pool-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
reply: &sb-pool-get-reply
|
||||
value: 15
|
||||
attributes: *sb-pool-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *sb-pool-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: sb-port-pool-get
|
||||
doc: Get shared buffer port-pool combinations and threshold.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit-port
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 19
|
||||
attributes: &sb-port-pool-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- port-index
|
||||
- sb-index
|
||||
- sb-pool-index
|
||||
reply: &sb-port-pool-get-reply
|
||||
value: 19
|
||||
attributes: *sb-port-pool-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *sb-port-pool-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: sb-tc-pool-bind-get
|
||||
doc: Get shared buffer port-TC to pool bindings and threshold.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit-port
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 23
|
||||
attributes: &sb-tc-pool-bind-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- port-index
|
||||
- sb-index
|
||||
- sb-pool-type
|
||||
- sb-tc-index
|
||||
reply: &sb-tc-pool-bind-get-reply
|
||||
value: 23
|
||||
attributes: *sb-tc-pool-bind-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *sb-tc-pool-bind-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: param-get
|
||||
doc: Get param instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 38
|
||||
attributes: ¶m-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- param-name
|
||||
reply: ¶m-get-reply
|
||||
value: 38
|
||||
attributes: *param-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *param-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: region-get
|
||||
doc: Get region instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit-port-optional
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 42
|
||||
attributes: ®ion-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- port-index
|
||||
- region-name
|
||||
reply: ®ion-get-reply
|
||||
value: 42
|
||||
attributes: *region-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *region-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: info-get
|
||||
doc: Get device information, like driver name, hardware and firmware versions etc.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
- dump
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 51
|
||||
attributes: *dev-id-attrs
|
||||
reply:
|
||||
reply: &info-get-reply
|
||||
value: 51
|
||||
attributes:
|
||||
- bus-name
|
||||
|
@ -204,3 +493,181 @@ operations:
|
|||
- info-version-fixed
|
||||
- info-version-running
|
||||
- info-version-stored
|
||||
dump:
|
||||
reply: *info-get-reply
|
||||
|
||||
-
|
||||
name: health-reporter-get
|
||||
doc: Get health reporter instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit-port-optional
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
attributes: &health-reporter-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- port-index
|
||||
- health-reporter-name
|
||||
reply: &health-reporter-get-reply
|
||||
attributes: *health-reporter-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *port-id-attrs
|
||||
reply: *health-reporter-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: trap-get
|
||||
doc: Get trap instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 61
|
||||
attributes: &trap-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- trap-name
|
||||
reply: &trap-get-reply
|
||||
value: 61
|
||||
attributes: *trap-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *trap-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: trap-group-get
|
||||
doc: Get trap group instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 65
|
||||
attributes: &trap-group-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- trap-group-name
|
||||
reply: &trap-group-get-reply
|
||||
value: 65
|
||||
attributes: *trap-group-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *trap-group-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: trap-policer-get
|
||||
doc: Get trap policer instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 69
|
||||
attributes: &trap-policer-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- trap-policer-id
|
||||
reply: &trap-policer-get-reply
|
||||
value: 69
|
||||
attributes: *trap-policer-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *trap-policer-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: rate-get
|
||||
doc: Get rate instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 74
|
||||
attributes: &rate-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- port-index
|
||||
- rate-node-name
|
||||
reply: &rate-get-reply
|
||||
value: 74
|
||||
attributes: *rate-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *rate-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: linecard-get
|
||||
doc: Get line card instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 78
|
||||
attributes: &linecard-id-attrs
|
||||
- bus-name
|
||||
- dev-name
|
||||
- linecard-index
|
||||
reply: &linecard-get-reply
|
||||
value: 78
|
||||
attributes: *linecard-id-attrs
|
||||
dump:
|
||||
request:
|
||||
attributes: *dev-id-attrs
|
||||
reply: *linecard-get-reply
|
||||
|
||||
# TODO: fill in the operations in between
|
||||
|
||||
-
|
||||
name: selftests-get
|
||||
doc: Get device selftest instances.
|
||||
attribute-set: devlink
|
||||
dont-validate:
|
||||
- strict
|
||||
- dump
|
||||
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
request:
|
||||
value: 82
|
||||
attributes: *dev-id-attrs
|
||||
reply: &selftests-get-reply
|
||||
value: 82
|
||||
attributes: *dev-id-attrs
|
||||
dump:
|
||||
reply: *selftests-get-reply
|
||||
|
|
|
@ -107,16 +107,16 @@ operations:
|
|||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
request: &select_attrs
|
||||
request: &select_attrs
|
||||
attributes:
|
||||
- af
|
||||
- ifindex
|
||||
- port
|
||||
- peer_port
|
||||
- local_v4
|
||||
- peer_v4
|
||||
- local_v6
|
||||
- peer_v6
|
||||
- af
|
||||
- ifindex
|
||||
- port
|
||||
- peer_port
|
||||
- local_v4
|
||||
- peer_v4
|
||||
- local_v6
|
||||
- peer_v6
|
||||
|
||||
-
|
||||
name: get
|
||||
|
|
|
@ -14,7 +14,7 @@ definitions:
|
|||
-
|
||||
name: basic
|
||||
doc:
|
||||
XDP feautues set supported by all drivers
|
||||
XDP features set supported by all drivers
|
||||
(XDP_ABORTED, XDP_DROP, XDP_PASS, XDP_TX)
|
||||
-
|
||||
name: redirect
|
||||
|
@ -62,6 +62,12 @@ attribute-sets:
|
|||
type: u64
|
||||
enum: xdp-act
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: xdp-zc-max-segs
|
||||
doc: max fragment count supported by ZC driver
|
||||
type: u32
|
||||
checks:
|
||||
min: 1
|
||||
|
||||
operations:
|
||||
list:
|
||||
|
@ -77,6 +83,7 @@ operations:
|
|||
attributes:
|
||||
- ifindex
|
||||
- xdp-features
|
||||
- xdp-zc-max-segs
|
||||
dump:
|
||||
reply: *dev-all
|
||||
-
|
||||
|
|
|
@ -81,6 +81,10 @@ attribute-sets:
|
|||
name-prefix: ovs-vport-attr-
|
||||
enum-name: ovs-vport-attr
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: port-no
|
||||
type: u32
|
||||
|
@ -120,10 +124,35 @@ attribute-sets:
|
|||
operations:
|
||||
name-prefix: ovs-vport-cmd-
|
||||
list:
|
||||
-
|
||||
name: new
|
||||
doc: Create a new OVS vport
|
||||
attribute-set: vport
|
||||
fixed-header: ovs-header
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- name
|
||||
- type
|
||||
- upcall-pid
|
||||
- dp-ifindex
|
||||
- ifindex
|
||||
- options
|
||||
-
|
||||
name: del
|
||||
doc: Delete existing OVS vport from a data path
|
||||
attribute-set: vport
|
||||
fixed-header: ovs-header
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- dp-ifindex
|
||||
- port-no
|
||||
- type
|
||||
- name
|
||||
-
|
||||
name: get
|
||||
doc: Get / dump OVS vport configuration and state
|
||||
value: 3
|
||||
attribute-set: vport
|
||||
fixed-header: ovs-header
|
||||
do: &vport-get-op
|
||||
|
|
179
Documentation/netlink/specs/rt_addr.yaml
Normal file
179
Documentation/netlink/specs/rt_addr.yaml
Normal file
|
@ -0,0 +1,179 @@
|
|||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
|
||||
name: rt-addr
|
||||
protocol: netlink-raw
|
||||
protonum: 0
|
||||
|
||||
doc:
|
||||
Address configuration over rtnetlink.
|
||||
|
||||
definitions:
|
||||
-
|
||||
name: ifaddrmsg
|
||||
type: struct
|
||||
members:
|
||||
-
|
||||
name: ifa-family
|
||||
type: u8
|
||||
-
|
||||
name: ifa-prefixlen
|
||||
type: u8
|
||||
-
|
||||
name: ifa-flags
|
||||
type: u8
|
||||
enum: ifa-flags
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: ifa-scope
|
||||
type: u8
|
||||
-
|
||||
name: ifa-index
|
||||
type: u32
|
||||
-
|
||||
name: ifa-cacheinfo
|
||||
type: struct
|
||||
members:
|
||||
-
|
||||
name: ifa-prefered
|
||||
type: u32
|
||||
-
|
||||
name: ifa-valid
|
||||
type: u32
|
||||
-
|
||||
name: cstamp
|
||||
type: u32
|
||||
-
|
||||
name: tstamp
|
||||
type: u32
|
||||
|
||||
-
|
||||
name: ifa-flags
|
||||
type: flags
|
||||
entries:
|
||||
-
|
||||
name: secondary
|
||||
-
|
||||
name: nodad
|
||||
-
|
||||
name: optimistic
|
||||
-
|
||||
name: dadfailed
|
||||
-
|
||||
name: homeaddress
|
||||
-
|
||||
name: deprecated
|
||||
-
|
||||
name: tentative
|
||||
-
|
||||
name: permanent
|
||||
-
|
||||
name: managetempaddr
|
||||
-
|
||||
name: noprefixroute
|
||||
-
|
||||
name: mcautojoin
|
||||
-
|
||||
name: stable-privacy
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: addr-attrs
|
||||
attributes:
|
||||
-
|
||||
name: ifa-address
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: ifa-local
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: ifa-label
|
||||
type: string
|
||||
-
|
||||
name: ifa-broadcast
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: ifa-anycast
|
||||
type: binary
|
||||
-
|
||||
name: ifa-cacheinfo
|
||||
type: binary
|
||||
struct: ifa-cacheinfo
|
||||
-
|
||||
name: ifa-multicast
|
||||
type: binary
|
||||
-
|
||||
name: ifa-flags
|
||||
type: u32
|
||||
enum: ifa-flags
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: ifa-rt-priority
|
||||
type: u32
|
||||
-
|
||||
name: ifa-target-netnsid
|
||||
type: binary
|
||||
-
|
||||
name: ifa-proto
|
||||
type: u8
|
||||
|
||||
|
||||
operations:
|
||||
fixed-header: ifaddrmsg
|
||||
enum-model: directional
|
||||
list:
|
||||
-
|
||||
name: newaddr
|
||||
doc: Add new address
|
||||
attribute-set: addr-attrs
|
||||
do:
|
||||
request:
|
||||
value: 20
|
||||
attributes: &ifaddr-all
|
||||
- ifa-family
|
||||
- ifa-flags
|
||||
- ifa-prefixlen
|
||||
- ifa-scope
|
||||
- ifa-index
|
||||
- ifa-address
|
||||
- ifa-label
|
||||
- ifa-local
|
||||
- ifa-cacheinfo
|
||||
-
|
||||
name: deladdr
|
||||
doc: Remove address
|
||||
attribute-set: addr-attrs
|
||||
do:
|
||||
request:
|
||||
value: 21
|
||||
attributes:
|
||||
- ifa-family
|
||||
- ifa-flags
|
||||
- ifa-prefixlen
|
||||
- ifa-scope
|
||||
- ifa-index
|
||||
- ifa-address
|
||||
- ifa-local
|
||||
-
|
||||
name: getaddr
|
||||
doc: Dump address information.
|
||||
attribute-set: addr-attrs
|
||||
dump:
|
||||
request:
|
||||
value: 22
|
||||
attributes:
|
||||
- ifa-index
|
||||
reply:
|
||||
value: 20
|
||||
attributes: *ifaddr-all
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: rtnlgrp-ipv4-ifaddr
|
||||
value: 5
|
||||
-
|
||||
name: rtnlgrp-ipv6-ifaddr
|
||||
value: 9
|
1432
Documentation/netlink/specs/rt_link.yaml
Normal file
1432
Documentation/netlink/specs/rt_link.yaml
Normal file
File diff suppressed because it is too large
Load diff
327
Documentation/netlink/specs/rt_route.yaml
Normal file
327
Documentation/netlink/specs/rt_route.yaml
Normal file
|
@ -0,0 +1,327 @@
|
|||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
|
||||
name: rt-route
|
||||
protocol: netlink-raw
|
||||
protonum: 0
|
||||
|
||||
doc:
|
||||
Route configuration over rtnetlink.
|
||||
|
||||
definitions:
|
||||
-
|
||||
name: rtm-type
|
||||
name-prefix: rtn-
|
||||
type: enum
|
||||
entries:
|
||||
- unspec
|
||||
- unicast
|
||||
- local
|
||||
- broadcast
|
||||
- anycast
|
||||
- multicast
|
||||
- blackhole
|
||||
- unreachable
|
||||
- prohibit
|
||||
- throw
|
||||
- nat
|
||||
- xresolve
|
||||
-
|
||||
name: rtmsg
|
||||
type: struct
|
||||
members:
|
||||
-
|
||||
name: rtm-family
|
||||
type: u8
|
||||
-
|
||||
name: rtm-dst-len
|
||||
type: u8
|
||||
-
|
||||
name: rtm-src-len
|
||||
type: u8
|
||||
-
|
||||
name: rtm-tos
|
||||
type: u8
|
||||
-
|
||||
name: rtm-table
|
||||
type: u8
|
||||
-
|
||||
name: rtm-protocol
|
||||
type: u8
|
||||
-
|
||||
name: rtm-scope
|
||||
type: u8
|
||||
-
|
||||
name: rtm-type
|
||||
type: u8
|
||||
enum: rtm-type
|
||||
-
|
||||
name: rtm-flags
|
||||
type: u32
|
||||
-
|
||||
name: rta-cacheinfo
|
||||
type: struct
|
||||
members:
|
||||
-
|
||||
name: rta-clntref
|
||||
type: u32
|
||||
-
|
||||
name: rta-lastuse
|
||||
type: u32
|
||||
-
|
||||
name: rta-expires
|
||||
type: u32
|
||||
-
|
||||
name: rta-error
|
||||
type: u32
|
||||
-
|
||||
name: rta-used
|
||||
type: u32
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: route-attrs
|
||||
attributes:
|
||||
-
|
||||
name: rta-dst
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: rta-src
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: rta-iif
|
||||
type: u32
|
||||
-
|
||||
name: rta-oif
|
||||
type: u32
|
||||
-
|
||||
name: rta-gateway
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: rta-priority
|
||||
type: u32
|
||||
-
|
||||
name: rta-prefsrc
|
||||
type: binary
|
||||
display-hint: ipv4
|
||||
-
|
||||
name: rta-metrics
|
||||
type: nest
|
||||
nested-attributes: rta-metrics
|
||||
-
|
||||
name: rta-multipath
|
||||
type: binary
|
||||
-
|
||||
name: rta-protoinfo # not used
|
||||
type: binary
|
||||
-
|
||||
name: rta-flow
|
||||
type: u32
|
||||
-
|
||||
name: rta-cacheinfo
|
||||
type: binary
|
||||
struct: rta-cacheinfo
|
||||
-
|
||||
name: rta-session # not used
|
||||
type: binary
|
||||
-
|
||||
name: rta-mp-algo # not used
|
||||
type: binary
|
||||
-
|
||||
name: rta-table
|
||||
type: u32
|
||||
-
|
||||
name: rta-mark
|
||||
type: u32
|
||||
-
|
||||
name: rta-mfc-stats
|
||||
type: binary
|
||||
-
|
||||
name: rta-via
|
||||
type: binary
|
||||
-
|
||||
name: rta-newdst
|
||||
type: binary
|
||||
-
|
||||
name: rta-pref
|
||||
type: u8
|
||||
-
|
||||
name: rta-encap-type
|
||||
type: u16
|
||||
-
|
||||
name: rta-encap
|
||||
type: binary # tunnel specific nest
|
||||
-
|
||||
name: rta-expires
|
||||
type: u32
|
||||
-
|
||||
name: rta-pad
|
||||
type: binary
|
||||
-
|
||||
name: rta-uid
|
||||
type: u32
|
||||
-
|
||||
name: rta-ttl-propagate
|
||||
type: u8
|
||||
-
|
||||
name: rta-ip-proto
|
||||
type: u8
|
||||
-
|
||||
name: rta-sport
|
||||
type: u16
|
||||
-
|
||||
name: rta-dport
|
||||
type: u16
|
||||
-
|
||||
name: rta-nh-id
|
||||
type: u32
|
||||
-
|
||||
name: rta-metrics
|
||||
attributes:
|
||||
-
|
||||
name: rtax-unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: rtax-lock
|
||||
type: u32
|
||||
-
|
||||
name: rtax-mtu
|
||||
type: u32
|
||||
-
|
||||
name: rtax-window
|
||||
type: u32
|
||||
-
|
||||
name: rtax-rtt
|
||||
type: u32
|
||||
-
|
||||
name: rtax-rttvar
|
||||
type: u32
|
||||
-
|
||||
name: rtax-ssthresh
|
||||
type: u32
|
||||
-
|
||||
name: rtax-cwnd
|
||||
type: u32
|
||||
-
|
||||
name: rtax-advmss
|
||||
type: u32
|
||||
-
|
||||
name: rtax-reordering
|
||||
type: u32
|
||||
-
|
||||
name: rtax-hoplimit
|
||||
type: u32
|
||||
-
|
||||
name: rtax-initcwnd
|
||||
type: u32
|
||||
-
|
||||
name: rtax-features
|
||||
type: u32
|
||||
-
|
||||
name: rtax-rto-min
|
||||
type: u32
|
||||
-
|
||||
name: rtax-initrwnd
|
||||
type: u32
|
||||
-
|
||||
name: rtax-quickack
|
||||
type: u32
|
||||
-
|
||||
name: rtax-cc-algo
|
||||
type: string
|
||||
-
|
||||
name: rtax-fastopen-no-cookie
|
||||
type: u32
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
list:
|
||||
-
|
||||
name: getroute
|
||||
doc: Dump route information.
|
||||
attribute-set: route-attrs
|
||||
fixed-header: rtmsg
|
||||
do:
|
||||
request:
|
||||
value: 26
|
||||
attributes:
|
||||
- rtm-family
|
||||
- rta-src
|
||||
- rtm-src-len
|
||||
- rta-dst
|
||||
- rtm-dst-len
|
||||
- rta-iif
|
||||
- rta-oif
|
||||
- rta-ip-proto
|
||||
- rta-sport
|
||||
- rta-dport
|
||||
- rta-mark
|
||||
- rta-uid
|
||||
reply:
|
||||
value: 24
|
||||
attributes: &all-route-attrs
|
||||
- rtm-family
|
||||
- rtm-dst-len
|
||||
- rtm-src-len
|
||||
- rtm-tos
|
||||
- rtm-table
|
||||
- rtm-protocol
|
||||
- rtm-scope
|
||||
- rtm-type
|
||||
- rtm-flags
|
||||
- rta-dst
|
||||
- rta-src
|
||||
- rta-iif
|
||||
- rta-oif
|
||||
- rta-gateway
|
||||
- rta-priority
|
||||
- rta-prefsrc
|
||||
- rta-metrics
|
||||
- rta-multipath
|
||||
- rta-flow
|
||||
- rta-cacheinfo
|
||||
- rta-table
|
||||
- rta-mark
|
||||
- rta-mfc-stats
|
||||
- rta-via
|
||||
- rta-newdst
|
||||
- rta-pref
|
||||
- rta-encap-type
|
||||
- rta-encap
|
||||
- rta-expires
|
||||
- rta-pad
|
||||
- rta-uid
|
||||
- rta-ttl-propagate
|
||||
- rta-ip-proto
|
||||
- rta-sport
|
||||
- rta-dport
|
||||
- rta-nh-id
|
||||
dump:
|
||||
request:
|
||||
value: 26
|
||||
attributes:
|
||||
- rtm-family
|
||||
reply:
|
||||
value: 24
|
||||
attributes: *all-route-attrs
|
||||
-
|
||||
name: newroute
|
||||
doc: Create a new route
|
||||
attribute-set: route-attrs
|
||||
fixed-header: rtmsg
|
||||
do:
|
||||
request:
|
||||
value: 24
|
||||
attributes: *all-route-attrs
|
||||
-
|
||||
name: delroute
|
||||
doc: Delete an existing route
|
||||
attribute-set: route-attrs
|
||||
fixed-header: rtmsg
|
||||
do:
|
||||
request:
|
||||
value: 25
|
||||
attributes: *all-route-attrs
|
|
@ -462,8 +462,92 @@ XDP_OPTIONS getsockopt
|
|||
Gets options from an XDP socket. The only one supported so far is
|
||||
XDP_OPTIONS_ZEROCOPY which tells you if zero-copy is on or not.
|
||||
|
||||
Multi-Buffer Support
|
||||
====================
|
||||
|
||||
With multi-buffer support, programs using AF_XDP sockets can receive
|
||||
and transmit packets consisting of multiple buffers both in copy and
|
||||
zero-copy mode. For example, a packet can consist of two
|
||||
frames/buffers, one with the header and the other one with the data,
|
||||
or a 9K Ethernet jumbo frame can be constructed by chaining together
|
||||
three 4K frames.
|
||||
|
||||
Some definitions:
|
||||
|
||||
* A packet consists of one or more frames
|
||||
|
||||
* A descriptor in one of the AF_XDP rings always refers to a single
|
||||
frame. In the case the packet consists of a single frame, the
|
||||
descriptor refers to the whole packet.
|
||||
|
||||
To enable multi-buffer support for an AF_XDP socket, use the new bind
|
||||
flag XDP_USE_SG. If this is not provided, all multi-buffer packets
|
||||
will be dropped just as before. Note that the XDP program loaded also
|
||||
needs to be in multi-buffer mode. This can be accomplished by using
|
||||
"xdp.frags" as the section name of the XDP program used.
|
||||
|
||||
To represent a packet consisting of multiple frames, a new flag called
|
||||
XDP_PKT_CONTD is introduced in the options field of the Rx and Tx
|
||||
descriptors. If it is true (1) the packet continues with the next
|
||||
descriptor and if it is false (0) it means this is the last descriptor
|
||||
of the packet. Why the reverse logic of end-of-packet (eop) flag found
|
||||
in many NICs? Just to preserve compatibility with non-multi-buffer
|
||||
applications that have this bit set to false for all packets on Rx,
|
||||
and the apps set the options field to zero for Tx, as anything else
|
||||
will be treated as an invalid descriptor.
|
||||
|
||||
These are the semantics for producing packets onto AF_XDP Tx ring
|
||||
consisting of multiple frames:
|
||||
|
||||
* When an invalid descriptor is found, all the other
|
||||
descriptors/frames of this packet are marked as invalid and not
|
||||
completed. The next descriptor is treated as the start of a new
|
||||
packet, even if this was not the intent (because we cannot guess
|
||||
the intent). As before, if your program is producing invalid
|
||||
descriptors you have a bug that must be fixed.
|
||||
|
||||
* Zero length descriptors are treated as invalid descriptors.
|
||||
|
||||
* For copy mode, the maximum supported number of frames in a packet is
|
||||
equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all
|
||||
descriptors accumulated so far are dropped and treated as
|
||||
invalid. To produce an application that will work on any system
|
||||
regardless of this config setting, limit the number of frags to 18,
|
||||
as the minimum value of the config is 17.
|
||||
|
||||
* For zero-copy mode, the limit is up to what the NIC HW
|
||||
supports. Usually at least five on the NICs we have checked. We
|
||||
consciously chose to not enforce a rigid limit (such as
|
||||
CONFIG_MAX_SKB_FRAGS + 1) for zero-copy mode, as it would have
|
||||
resulted in copy actions under the hood to fit into what limit the
|
||||
NIC supports. Kind of defeats the purpose of zero-copy mode. How to
|
||||
probe for this limit is explained in the "probe for multi-buffer
|
||||
support" section.
|
||||
|
||||
On the Rx path in copy-mode, the xsk core copies the XDP data into
|
||||
multiple descriptors, if needed, and sets the XDP_PKT_CONTD flag as
|
||||
detailed before. Zero-copy mode works the same, though the data is not
|
||||
copied. When the application gets a descriptor with the XDP_PKT_CONTD
|
||||
flag set to one, it means that the packet consists of multiple buffers
|
||||
and it continues with the next buffer in the following
|
||||
descriptor. When a descriptor with XDP_PKT_CONTD == 0 is received, it
|
||||
means that this is the last buffer of the packet. AF_XDP guarantees
|
||||
that only a complete packet (all frames in the packet) is sent to the
|
||||
application. If there is not enough space in the AF_XDP Rx ring, all
|
||||
frames of the packet will be dropped.
|
||||
|
||||
If application reads a batch of descriptors, using for example the libxdp
|
||||
interfaces, it is not guaranteed that the batch will end with a full
|
||||
packet. It might end in the middle of a packet and the rest of the
|
||||
buffers of that packet will arrive at the beginning of the next batch,
|
||||
since the libxdp interface does not read the whole ring (unless you
|
||||
have an enormous batch size or a very small ring size).
|
||||
|
||||
An example program each for Rx and Tx multi-buffer support can be found
|
||||
later in this document.
|
||||
|
||||
Usage
|
||||
=====
|
||||
-----
|
||||
|
||||
In order to use AF_XDP sockets two parts are needed. The
|
||||
user-space application and the XDP program. For a complete setup and
|
||||
|
@ -541,6 +625,131 @@ like this:
|
|||
But please use the libbpf functions as they are optimized and ready to
|
||||
use. Will make your life easier.
|
||||
|
||||
Usage Multi-Buffer Rx
|
||||
---------------------
|
||||
|
||||
Here is a simple Rx path pseudo-code example (using libxdp interfaces
|
||||
for simplicity). Error paths have been excluded to keep it short:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void rx_packets(struct xsk_socket_info *xsk)
|
||||
{
|
||||
static bool new_packet = true;
|
||||
u32 idx_rx = 0, idx_fq = 0;
|
||||
static char *pkt;
|
||||
|
||||
int rcvd = xsk_ring_cons__peek(&xsk->rx, opt_batch_size, &idx_rx);
|
||||
|
||||
xsk_ring_prod__reserve(&xsk->umem->fq, rcvd, &idx_fq);
|
||||
|
||||
for (int i = 0; i < rcvd; i++) {
|
||||
struct xdp_desc *desc = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++);
|
||||
char *frag = xsk_umem__get_data(xsk->umem->buffer, desc->addr);
|
||||
bool eop = !(desc->options & XDP_PKT_CONTD);
|
||||
|
||||
if (new_packet)
|
||||
pkt = frag;
|
||||
else
|
||||
add_frag_to_pkt(pkt, frag);
|
||||
|
||||
if (eop)
|
||||
process_pkt(pkt);
|
||||
|
||||
new_packet = eop;
|
||||
|
||||
*xsk_ring_prod__fill_addr(&xsk->umem->fq, idx_fq++) = desc->addr;
|
||||
}
|
||||
|
||||
xsk_ring_prod__submit(&xsk->umem->fq, rcvd);
|
||||
xsk_ring_cons__release(&xsk->rx, rcvd);
|
||||
}
|
||||
|
||||
Usage Multi-Buffer Tx
|
||||
---------------------
|
||||
|
||||
Here is an example Tx path pseudo-code (using libxdp interfaces for
|
||||
simplicity) ignoring that the umem is finite in size, and that we
|
||||
eventually will run out of packets to send. Also assumes pkts.addr
|
||||
points to a valid location in the umem.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void tx_packets(struct xsk_socket_info *xsk, struct pkt *pkts,
|
||||
int batch_size)
|
||||
{
|
||||
u32 idx, i, pkt_nb = 0;
|
||||
|
||||
xsk_ring_prod__reserve(&xsk->tx, batch_size, &idx);
|
||||
|
||||
for (i = 0; i < batch_size;) {
|
||||
u64 addr = pkts[pkt_nb].addr;
|
||||
u32 len = pkts[pkt_nb].size;
|
||||
|
||||
do {
|
||||
struct xdp_desc *tx_desc;
|
||||
|
||||
tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i++);
|
||||
tx_desc->addr = addr;
|
||||
|
||||
if (len > xsk_frame_size) {
|
||||
tx_desc->len = xsk_frame_size;
|
||||
tx_desc->options = XDP_PKT_CONTD;
|
||||
} else {
|
||||
tx_desc->len = len;
|
||||
tx_desc->options = 0;
|
||||
pkt_nb++;
|
||||
}
|
||||
len -= tx_desc->len;
|
||||
addr += xsk_frame_size;
|
||||
|
||||
if (i == batch_size) {
|
||||
/* Remember len, addr, pkt_nb for next iteration.
|
||||
* Skipped for simplicity.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} while (len);
|
||||
}
|
||||
|
||||
xsk_ring_prod__submit(&xsk->tx, i);
|
||||
}
|
||||
|
||||
Probing for Multi-Buffer Support
|
||||
--------------------------------
|
||||
|
||||
To discover if a driver supports multi-buffer AF_XDP in SKB or DRV
|
||||
mode, use the XDP_FEATURES feature of netlink in linux/netdev.h to
|
||||
query for NETDEV_XDP_ACT_RX_SG support. This is the same flag as for
|
||||
querying for XDP multi-buffer support. If XDP supports multi-buffer in
|
||||
a driver, then AF_XDP will also support that in SKB and DRV mode.
|
||||
|
||||
To discover if a driver supports multi-buffer AF_XDP in zero-copy
|
||||
mode, use XDP_FEATURES and first check the NETDEV_XDP_ACT_XSK_ZEROCOPY
|
||||
flag. If it is set, it means that at least zero-copy is supported and
|
||||
you should go and check the netlink attribute
|
||||
NETDEV_A_DEV_XDP_ZC_MAX_SEGS in linux/netdev.h. An unsigned integer
|
||||
value will be returned stating the max number of frags that are
|
||||
supported by this device in zero-copy mode. These are the possible
|
||||
return values:
|
||||
|
||||
1: Multi-buffer for zero-copy is not supported by this device, as max
|
||||
one fragment supported means that multi-buffer is not possible.
|
||||
|
||||
>=2: Multi-buffer is supported in zero-copy mode for this device. The
|
||||
returned number signifies the max number of frags supported.
|
||||
|
||||
For an example on how these are used through libbpf, please take a
|
||||
look at tools/testing/selftests/bpf/xskxceiver.c.
|
||||
|
||||
Multi-Buffer Support for Zero-Copy Drivers
|
||||
------------------------------------------
|
||||
|
||||
Zero-copy drivers usually use the batched APIs for Rx and Tx
|
||||
processing. Note that the Tx batch API guarantees that it will provide
|
||||
a batch of Tx descriptors that ends with full packet at the end. This
|
||||
to facilitate extending a zero-copy driver with multi-buffer support.
|
||||
|
||||
Sample application
|
||||
==================
|
||||
|
||||
|
|
|
@ -52,6 +52,15 @@ Descriptor Formats
|
|||
GVE supports two descriptor formats: GQI and DQO. These two formats have
|
||||
entirely different descriptors, which will be described below.
|
||||
|
||||
Addressing Mode
|
||||
------------------
|
||||
GVE supports two addressing modes: QPL and RDA.
|
||||
QPL ("queue-page-list") mode communicates data through a set of
|
||||
pre-registered pages.
|
||||
|
||||
For RDA ("raw DMA addressing") mode, the set of pages is dynamic.
|
||||
Therefore, the packet buffers can be anywhere in guest memory.
|
||||
|
||||
Registers
|
||||
---------
|
||||
All registers are MMIO.
|
||||
|
|
|
@ -332,3 +332,11 @@ Setup HTB offload
|
|||
# tc class add dev <interface> parent 1: classid 1:1 htb rate 10Gbit prio 1
|
||||
|
||||
# tc class add dev <interface> parent 1: classid 1:2 htb rate 10Gbit prio 7
|
||||
|
||||
4. Create tc classes with same priorities and different quantum::
|
||||
|
||||
# tc class add dev <interface> parent 1: classid 1:1 htb rate 10Gbit prio 2 quantum 409600
|
||||
|
||||
# tc class add dev <interface> parent 1: classid 1:2 htb rate 10Gbit prio 2 quantum 188416
|
||||
|
||||
# tc class add dev <interface> parent 1: classid 1:3 htb rate 10Gbit prio 2 quantum 32768
|
||||
|
|
|
@ -346,6 +346,24 @@ the software port.
|
|||
- The number of receive packets with CQE compression on ring i [#accel]_.
|
||||
- Acceleration
|
||||
|
||||
* - `rx[i]_arfs_add`
|
||||
- The number of aRFS flow rules added to the device for direct RQ steering
|
||||
on ring i [#accel]_.
|
||||
- Acceleration
|
||||
|
||||
* - `rx[i]_arfs_request_in`
|
||||
- Number of flow rules that have been requested to move into ring i for
|
||||
direct RQ steering [#accel]_.
|
||||
- Acceleration
|
||||
|
||||
* - `rx[i]_arfs_request_out`
|
||||
- Number of flow rules that have been requested to move out of ring i [#accel]_.
|
||||
- Acceleration
|
||||
|
||||
* - `rx[i]_arfs_expired`
|
||||
- Number of flow rules that have been expired and removed [#accel]_.
|
||||
- Acceleration
|
||||
|
||||
* - `rx[i]_arfs_err`
|
||||
- Number of flow rules that failed to be added to the flow table.
|
||||
- Error
|
||||
|
@ -445,11 +463,6 @@ the software port.
|
|||
context.
|
||||
- Error
|
||||
|
||||
* - `rx[i]_xsk_arfs_err`
|
||||
- aRFS (accelerated Receive Flow Steering) does not occur in the XSK RQ
|
||||
context, so this counter should never increment.
|
||||
- Error
|
||||
|
||||
* - `rx[i]_xdp_tx_xmit`
|
||||
- The number of packets forwarded back to the port due to XDP program
|
||||
`XDP_TX` action (bouncing). these packets are not counted by other
|
||||
|
@ -683,6 +696,12 @@ the software port.
|
|||
time protocol.
|
||||
- Error
|
||||
|
||||
* - `ptp_cq[i]_late_cqe`
|
||||
- Number of times a CQE has been delivered on the PTP timestamping CQ when
|
||||
the CQE was not expected since a certain amount of time had elapsed where
|
||||
the device typically ensures not posting the CQE.
|
||||
- Error
|
||||
|
||||
.. [#ring_global] The corresponding ring and global counters do not share the
|
||||
same name (i.e. do not follow the common naming scheme).
|
||||
|
||||
|
|
|
@ -1,313 +0,0 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
.. include:: <isonum.txt>
|
||||
|
||||
=======
|
||||
Devlink
|
||||
=======
|
||||
|
||||
:Copyright: |copy| 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
Contents
|
||||
========
|
||||
|
||||
- `Info`_
|
||||
- `Parameters`_
|
||||
- `Health reporters`_
|
||||
|
||||
Info
|
||||
====
|
||||
|
||||
The devlink info reports the running and stored firmware versions on device.
|
||||
It also prints the device PSID which represents the HCA board type ID.
|
||||
|
||||
User command example::
|
||||
|
||||
$ devlink dev info pci/0000:00:06.0
|
||||
pci/0000:00:06.0:
|
||||
driver mlx5_core
|
||||
versions:
|
||||
fixed:
|
||||
fw.psid MT_0000000009
|
||||
running:
|
||||
fw.version 16.26.0100
|
||||
stored:
|
||||
fw.version 16.26.0100
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
flow_steering_mode: Device flow steering mode
|
||||
---------------------------------------------
|
||||
The flow steering mode parameter controls the flow steering mode of the driver.
|
||||
Two modes are supported:
|
||||
|
||||
1. 'dmfs' - Device managed flow steering.
|
||||
2. 'smfs' - Software/Driver managed flow steering.
|
||||
|
||||
In DMFS mode, the HW steering entities are created and managed through the
|
||||
Firmware.
|
||||
In SMFS mode, the HW steering entities are created and managed though by
|
||||
the driver directly into hardware without firmware intervention.
|
||||
|
||||
SMFS mode is faster and provides better rule insertion rate compared to default DMFS mode.
|
||||
|
||||
User command examples:
|
||||
|
||||
- Set SMFS flow steering mode::
|
||||
|
||||
$ devlink dev param set pci/0000:06:00.0 name flow_steering_mode value "smfs" cmode runtime
|
||||
|
||||
- Read device flow steering mode::
|
||||
|
||||
$ devlink dev param show pci/0000:06:00.0 name flow_steering_mode
|
||||
pci/0000:06:00.0:
|
||||
name flow_steering_mode type driver-specific
|
||||
values:
|
||||
cmode runtime value smfs
|
||||
|
||||
enable_roce: RoCE enablement state
|
||||
----------------------------------
|
||||
If the device supports RoCE disablement, RoCE enablement state controls device
|
||||
support for RoCE capability. Otherwise, the control occurs in the driver stack.
|
||||
When RoCE is disabled at the driver level, only raw ethernet QPs are supported.
|
||||
|
||||
To change RoCE enablement state, a user must change the driverinit cmode value
|
||||
and run devlink reload.
|
||||
|
||||
User command examples:
|
||||
|
||||
- Disable RoCE::
|
||||
|
||||
$ devlink dev param set pci/0000:06:00.0 name enable_roce value false cmode driverinit
|
||||
$ devlink dev reload pci/0000:06:00.0
|
||||
|
||||
- Read RoCE enablement state::
|
||||
|
||||
$ devlink dev param show pci/0000:06:00.0 name enable_roce
|
||||
pci/0000:06:00.0:
|
||||
name enable_roce type generic
|
||||
values:
|
||||
cmode driverinit value true
|
||||
|
||||
esw_port_metadata: Eswitch port metadata state
|
||||
----------------------------------------------
|
||||
When applicable, disabling eswitch metadata can increase packet rate
|
||||
up to 20% depending on the use case and packet sizes.
|
||||
|
||||
Eswitch port metadata state controls whether to internally tag packets with
|
||||
metadata. Metadata tagging must be enabled for multi-port RoCE, failover
|
||||
between representors and stacked devices.
|
||||
By default metadata is enabled on the supported devices in E-switch.
|
||||
Metadata is applicable only for E-switch in switchdev mode and
|
||||
users may disable it when NONE of the below use cases will be in use:
|
||||
|
||||
1. HCA is in Dual/multi-port RoCE mode.
|
||||
2. VF/SF representor bonding (Usually used for Live migration)
|
||||
3. Stacked devices
|
||||
|
||||
When metadata is disabled, the above use cases will fail to initialize if
|
||||
users try to enable them.
|
||||
|
||||
- Show eswitch port metadata::
|
||||
|
||||
$ devlink dev param show pci/0000:06:00.0 name esw_port_metadata
|
||||
pci/0000:06:00.0:
|
||||
name esw_port_metadata type driver-specific
|
||||
values:
|
||||
cmode runtime value true
|
||||
|
||||
- Disable eswitch port metadata::
|
||||
|
||||
$ devlink dev param set pci/0000:06:00.0 name esw_port_metadata value false cmode runtime
|
||||
|
||||
- Change eswitch mode to switchdev mode where after choosing the metadata value::
|
||||
|
||||
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
|
||||
|
||||
hairpin_num_queues: Number of hairpin queues
|
||||
--------------------------------------------
|
||||
We refer to a TC NIC rule that involves forwarding as "hairpin".
|
||||
|
||||
Hairpin queues are mlx5 hardware specific implementation for hardware
|
||||
forwarding of such packets.
|
||||
|
||||
- Show the number of hairpin queues::
|
||||
|
||||
$ devlink dev param show pci/0000:06:00.0 name hairpin_num_queues
|
||||
pci/0000:06:00.0:
|
||||
name hairpin_num_queues type driver-specific
|
||||
values:
|
||||
cmode driverinit value 2
|
||||
|
||||
- Change the number of hairpin queues::
|
||||
|
||||
$ devlink dev param set pci/0000:06:00.0 name hairpin_num_queues value 4 cmode driverinit
|
||||
|
||||
hairpin_queue_size: Size of the hairpin queues
|
||||
----------------------------------------------
|
||||
Control the size of the hairpin queues.
|
||||
|
||||
- Show the size of the hairpin queues::
|
||||
|
||||
$ devlink dev param show pci/0000:06:00.0 name hairpin_queue_size
|
||||
pci/0000:06:00.0:
|
||||
name hairpin_queue_size type driver-specific
|
||||
values:
|
||||
cmode driverinit value 1024
|
||||
|
||||
- Change the size (in packets) of the hairpin queues::
|
||||
|
||||
$ devlink dev param set pci/0000:06:00.0 name hairpin_queue_size value 512 cmode driverinit
|
||||
|
||||
Health reporters
|
||||
================
|
||||
|
||||
tx reporter
|
||||
-----------
|
||||
The tx reporter is responsible for reporting and recovering of the following two error scenarios:
|
||||
|
||||
- tx timeout
|
||||
Report on kernel tx timeout detection.
|
||||
Recover by searching lost interrupts.
|
||||
- tx error completion
|
||||
Report on error tx completion.
|
||||
Recover by flushing the tx queue and reset it.
|
||||
|
||||
tx reporter also support on demand diagnose callback, on which it provides
|
||||
real time information of its send queues status.
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Diagnose send queues status::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.0 reporter tx
|
||||
|
||||
.. note::
|
||||
This command has valid output only when interface is up, otherwise the command has empty output.
|
||||
|
||||
- Show number of tx errors indicated, number of recover flows ended successfully,
|
||||
is autorecover enabled and graceful period from last recover::
|
||||
|
||||
$ devlink health show pci/0000:82:00.0 reporter tx
|
||||
|
||||
rx reporter
|
||||
-----------
|
||||
The rx reporter is responsible for reporting and recovering of the following two error scenarios:
|
||||
|
||||
- rx queues' initialization (population) timeout
|
||||
Population of rx queues' descriptors on ring initialization is done
|
||||
in napi context via triggering an irq. In case of a failure to get
|
||||
the minimum amount of descriptors, a timeout would occur, and
|
||||
descriptors could be recovered by polling the EQ (Event Queue).
|
||||
- rx completions with errors (reported by HW on interrupt context)
|
||||
Report on rx completion error.
|
||||
Recover (if needed) by flushing the related queue and reset it.
|
||||
|
||||
rx reporter also supports on demand diagnose callback, on which it
|
||||
provides real time information of its receive queues' status.
|
||||
|
||||
- Diagnose rx queues' status and corresponding completion queue::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.0 reporter rx
|
||||
|
||||
NOTE: This command has valid output only when interface is up. Otherwise, the command has empty output.
|
||||
|
||||
- Show number of rx errors indicated, number of recover flows ended successfully,
|
||||
is autorecover enabled, and graceful period from last recover::
|
||||
|
||||
$ devlink health show pci/0000:82:00.0 reporter rx
|
||||
|
||||
fw reporter
|
||||
-----------
|
||||
The fw reporter implements `diagnose` and `dump` callbacks.
|
||||
It follows symptoms of fw error such as fw syndrome by triggering
|
||||
fw core dump and storing it into the dump buffer.
|
||||
The fw reporter diagnose command can be triggered any time by the user to check
|
||||
current fw status.
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Check fw heath status::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.0 reporter fw
|
||||
|
||||
- Read FW core dump if already stored or trigger new one::
|
||||
|
||||
$ devlink health dump show pci/0000:82:00.0 reporter fw
|
||||
|
||||
.. note::
|
||||
This command can run only on the PF which has fw tracer ownership,
|
||||
running it on other PF or any VF will return "Operation not permitted".
|
||||
|
||||
fw fatal reporter
|
||||
-----------------
|
||||
The fw fatal reporter implements `dump` and `recover` callbacks.
|
||||
It follows fatal errors indications by CR-space dump and recover flow.
|
||||
The CR-space dump uses vsc interface which is valid even if the FW command
|
||||
interface is not functional, which is the case in most FW fatal errors.
|
||||
The recover function runs recover flow which reloads the driver and triggers fw
|
||||
reset if needed.
|
||||
On firmware error, the health buffer is dumped into the dmesg. The log
|
||||
level is derived from the error's severity (given in health buffer).
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Run fw recover flow manually::
|
||||
|
||||
$ devlink health recover pci/0000:82:00.0 reporter fw_fatal
|
||||
|
||||
- Read FW CR-space dump if already stored or trigger new one::
|
||||
|
||||
$ devlink health dump show pci/0000:82:00.1 reporter fw_fatal
|
||||
|
||||
.. note::
|
||||
This command can run only on PF.
|
||||
|
||||
vnic reporter
|
||||
-------------
|
||||
The vnic reporter implements only the `diagnose` callback.
|
||||
It is responsible for querying the vnic diagnostic counters from fw and displaying
|
||||
them in realtime.
|
||||
|
||||
Description of the vnic counters:
|
||||
|
||||
- total_q_under_processor_handle
|
||||
number of queues in an error state due to
|
||||
an async error or errored command.
|
||||
- send_queue_priority_update_flow
|
||||
number of QP/SQ priority/SL update events.
|
||||
- cq_overrun
|
||||
number of times CQ entered an error state due to an overflow.
|
||||
- async_eq_overrun
|
||||
number of times an EQ mapped to async events was overrun.
|
||||
comp_eq_overrun number of times an EQ mapped to completion events was
|
||||
overrun.
|
||||
- quota_exceeded_command
|
||||
number of commands issued and failed due to quota exceeded.
|
||||
- invalid_command
|
||||
number of commands issued and failed dues to any reason other than quota
|
||||
exceeded.
|
||||
- nic_receive_steering_discard
|
||||
number of packets that completed RX flow
|
||||
steering but were discarded due to a mismatch in flow table.
|
||||
- generated_pkt_steering_fail
|
||||
number of packets generated by the VNIC experiencing unexpected steering
|
||||
failure (at any point in steering flow).
|
||||
- handled_pkt_steering_fail
|
||||
number of packets handled by the VNIC experiencing unexpected steering
|
||||
failure (at any point in steering flow owned by the VNIC, including the FDB
|
||||
for the eswitch owner).
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Diagnose PF/VF vnic counters::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.1 reporter vnic
|
||||
|
||||
- Diagnose representor vnic counters (performed by supplying devlink port of the
|
||||
representor, which can be obtained via devlink port command)::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.1/65537 reporter vnic
|
||||
|
||||
.. note::
|
||||
This command can run over all interfaces such as PF/VF and representor ports.
|
|
@ -13,7 +13,6 @@ Contents:
|
|||
:maxdepth: 2
|
||||
|
||||
kconfig
|
||||
devlink
|
||||
switchdev
|
||||
tracepoints
|
||||
counters
|
||||
|
|
|
@ -36,7 +36,7 @@ Enabling the driver and kconfig options
|
|||
|
||||
**CONFIG_MLX5_CORE_EN_DCB=(y/n)**:
|
||||
|
||||
| Enables `Data Center Bridging (DCB) Support <https://community.mellanox.com/s/article/howto-auto-config-pfc-and-ets-on-connectx-4-via-lldp-dcbx>`_.
|
||||
| Enables `Data Center Bridging (DCB) Support <https://enterprise-support.nvidia.com/s/article/howto-auto-config-pfc-and-ets-on-connectx-4-via-lldp-dcbx>`_.
|
||||
|
||||
|
||||
**CONFIG_MLX5_CORE_IPOIB=(y/n)**
|
||||
|
@ -59,12 +59,12 @@ Enabling the driver and kconfig options
|
|||
**CONFIG_MLX5_EN_ARFS=(y/n)**
|
||||
|
||||
| Enables Hardware-accelerated receive flow steering (arfs) support, and ntuple filtering.
|
||||
| https://community.mellanox.com/s/article/howto-configure-arfs-on-connectx-4
|
||||
| https://enterprise-support.nvidia.com/s/article/howto-configure-arfs-on-connectx-4
|
||||
|
||||
|
||||
**CONFIG_MLX5_EN_IPSEC=(y/n)**
|
||||
|
||||
| Enables `IPSec XFRM cryptography-offload acceleration <https://support.mellanox.com/s/article/ConnectX-6DX-Bluefield-2-IPsec-HW-Full-Offload-Configuration-Guide>`_.
|
||||
| Enables :ref:`IPSec XFRM cryptography-offload acceleration <xfrm_device>`.
|
||||
|
||||
|
||||
**CONFIG_MLX5_EN_MACSEC=(y/n)**
|
||||
|
@ -87,8 +87,8 @@ Enabling the driver and kconfig options
|
|||
|
||||
| Ethernet SRIOV E-Switch support in ConnectX NIC. E-Switch provides internal SRIOV packet steering
|
||||
| and switching for the enabled VFs and PF in two available modes:
|
||||
| 1) `Legacy SRIOV mode (L2 mac vlan steering based) <https://community.mellanox.com/s/article/howto-configure-sr-iov-for-connectx-4-connectx-5-with-kvm--ethernet-x>`_.
|
||||
| 2) `Switchdev mode (eswitch offloads) <https://www.mellanox.com/related-docs/prod_software/ASAP2_Hardware_Offloading_for_vSwitches_User_Manual_v4.4.pdf>`_.
|
||||
| 1) `Legacy SRIOV mode (L2 mac vlan steering based) <https://enterprise-support.nvidia.com/s/article/HowTo-Configure-SR-IOV-for-ConnectX-4-ConnectX-5-ConnectX-6-with-KVM-Ethernet>`_.
|
||||
| 2) :ref:`Switchdev mode (eswitch offloads) <switchdev>`.
|
||||
|
||||
|
||||
**CONFIG_MLX5_FPGA=(y/n)**
|
||||
|
@ -101,13 +101,13 @@ Enabling the driver and kconfig options
|
|||
|
||||
**CONFIG_MLX5_INFINIBAND=(y/n/m)** (module mlx5_ib.ko)
|
||||
|
||||
| Provides low-level InfiniBand/RDMA and `RoCE <https://community.mellanox.com/s/article/recommended-network-configuration-examples-for-roce-deployment>`_ support.
|
||||
| Provides low-level InfiniBand/RDMA and `RoCE <https://enterprise-support.nvidia.com/s/article/recommended-network-configuration-examples-for-roce-deployment>`_ support.
|
||||
|
||||
|
||||
**CONFIG_MLX5_MPFS=(y/n)**
|
||||
|
||||
| Ethernet Multi-Physical Function Switch (MPFS) support in ConnectX NIC.
|
||||
| MPFs is required for when `Multi-Host <http://www.mellanox.com/page/multihost>`_ configuration is enabled to allow passing
|
||||
| MPFs is required for when `Multi-Host <https://www.nvidia.com/en-us/networking/multi-host/>`_ configuration is enabled to allow passing
|
||||
| user configured unicast MAC addresses to the requesting PF.
|
||||
|
||||
|
||||
|
|
|
@ -190,6 +190,26 @@ explicitly enable the VF migratable capability.
|
|||
mlx5 driver support devlink port function attr mechanism to setup migratable
|
||||
capability. (refer to Documentation/networking/devlink/devlink-port.rst)
|
||||
|
||||
IPsec crypto capability setup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
User who wants mlx5 PCI VFs to be able to perform IPsec crypto offloading need
|
||||
to explicitly enable the VF ipsec_crypto capability. Enabling IPsec capability
|
||||
for VFs is supported starting with ConnectX6dx devices and above. When a VF has
|
||||
IPsec capability enabled, any IPsec offloading is blocked on the PF.
|
||||
|
||||
mlx5 driver support devlink port function attr mechanism to setup ipsec_crypto
|
||||
capability. (refer to Documentation/networking/devlink/devlink-port.rst)
|
||||
|
||||
IPsec packet capability setup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
User who wants mlx5 PCI VFs to be able to perform IPsec packet offloading need
|
||||
to explicitly enable the VF ipsec_packet capability. Enabling IPsec capability
|
||||
for VFs is supported starting with ConnectX6dx devices and above. When a VF has
|
||||
IPsec capability enabled, any IPsec offloading is blocked on the PF.
|
||||
|
||||
mlx5 driver support devlink port function attr mechanism to setup ipsec_packet
|
||||
capability. (refer to Documentation/networking/devlink/devlink-port.rst)
|
||||
|
||||
SF state setup
|
||||
--------------
|
||||
|
||||
|
|
|
@ -128,6 +128,12 @@ Users may also set the RoCE capability of the function using
|
|||
Users may also set the function as migratable using
|
||||
'devlink port function set migratable' command.
|
||||
|
||||
Users may also set the IPsec crypto capability of the function using
|
||||
`devlink port function set ipsec_crypto` command.
|
||||
|
||||
Users may also set the IPsec packet capability of the function using
|
||||
`devlink port function set ipsec_packet` command.
|
||||
|
||||
Function attributes
|
||||
===================
|
||||
|
||||
|
@ -240,6 +246,55 @@ Attach VF to the VM.
|
|||
Start the VM.
|
||||
Perform live migration.
|
||||
|
||||
IPsec crypto capability setup
|
||||
-----------------------------
|
||||
When user enables IPsec crypto capability for a VF, user application can offload
|
||||
XFRM state crypto operation (Encrypt/Decrypt) to this VF.
|
||||
|
||||
When IPsec crypto capability is disabled (default) for a VF, the XFRM state is
|
||||
processed in software by the kernel.
|
||||
|
||||
- Get IPsec crypto capability of the VF device::
|
||||
|
||||
$ devlink port show pci/0000:06:00.0/2
|
||||
pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1
|
||||
function:
|
||||
hw_addr 00:00:00:00:00:00 ipsec_crypto disabled
|
||||
|
||||
- Set IPsec crypto capability of the VF device::
|
||||
|
||||
$ devlink port function set pci/0000:06:00.0/2 ipsec_crypto enable
|
||||
|
||||
$ devlink port show pci/0000:06:00.0/2
|
||||
pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1
|
||||
function:
|
||||
hw_addr 00:00:00:00:00:00 ipsec_crypto enabled
|
||||
|
||||
IPsec packet capability setup
|
||||
-----------------------------
|
||||
When user enables IPsec packet capability for a VF, user application can offload
|
||||
XFRM state and policy crypto operation (Encrypt/Decrypt) to this VF, as well as
|
||||
IPsec encapsulation.
|
||||
|
||||
When IPsec packet capability is disabled (default) for a VF, the XFRM state and
|
||||
policy is processed in software by the kernel.
|
||||
|
||||
- Get IPsec packet capability of the VF device::
|
||||
|
||||
$ devlink port show pci/0000:06:00.0/2
|
||||
pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1
|
||||
function:
|
||||
hw_addr 00:00:00:00:00:00 ipsec_packet disabled
|
||||
|
||||
- Set IPsec packet capability of the VF device::
|
||||
|
||||
$ devlink port function set pci/0000:06:00.0/2 ipsec_packet enable
|
||||
|
||||
$ devlink port show pci/0000:06:00.0/2
|
||||
pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1
|
||||
function:
|
||||
hw_addr 00:00:00:00:00:00 ipsec_packet enabled
|
||||
|
||||
Subfunction
|
||||
============
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ Parameters
|
|||
* - ``enable_roce``
|
||||
- driverinit
|
||||
- Type: Boolean
|
||||
|
||||
If the device supports RoCE disablement, RoCE enablement state controls
|
||||
device support for RoCE capability. Otherwise, the control occurs in the
|
||||
driver stack. When RoCE is disabled at the driver level, only raw
|
||||
ethernet QPs are supported.
|
||||
* - ``io_eq_size``
|
||||
- driverinit
|
||||
- The range is between 64 and 4096.
|
||||
|
@ -48,6 +53,9 @@ parameters.
|
|||
* ``smfs`` Software managed flow steering. In SMFS mode, the HW
|
||||
steering entities are created and manage through the driver without
|
||||
firmware intervention.
|
||||
|
||||
SMFS mode is faster and provides better rule insertion rate compared to
|
||||
default DMFS mode.
|
||||
* - ``fdb_large_groups``
|
||||
- u32
|
||||
- driverinit
|
||||
|
@ -71,7 +79,24 @@ parameters.
|
|||
deprecated.
|
||||
|
||||
Default: disabled
|
||||
* - ``esw_port_metadata``
|
||||
- Boolean
|
||||
- runtime
|
||||
- When applicable, disabling eswitch metadata can increase packet rate up
|
||||
to 20% depending on the use case and packet sizes.
|
||||
|
||||
Eswitch port metadata state controls whether to internally tag packets
|
||||
with metadata. Metadata tagging must be enabled for multi-port RoCE,
|
||||
failover between representors and stacked devices. By default metadata is
|
||||
enabled on the supported devices in E-switch. Metadata is applicable only
|
||||
for E-switch in switchdev mode and users may disable it when NONE of the
|
||||
below use cases will be in use:
|
||||
1. HCA is in Dual/multi-port RoCE mode.
|
||||
2. VF/SF representor bonding (Usually used for Live migration)
|
||||
3. Stacked devices
|
||||
|
||||
When metadata is disabled, the above use cases will fail to initialize if
|
||||
users try to enable them.
|
||||
* - ``hairpin_num_queues``
|
||||
- u32
|
||||
- driverinit
|
||||
|
@ -104,3 +129,160 @@ The ``mlx5`` driver reports the following versions
|
|||
* - ``fw.version``
|
||||
- stored, running
|
||||
- Three digit major.minor.subminor firmware version number.
|
||||
|
||||
Health reporters
|
||||
================
|
||||
|
||||
tx reporter
|
||||
-----------
|
||||
The tx reporter is responsible for reporting and recovering of the following three error scenarios:
|
||||
|
||||
- tx timeout
|
||||
Report on kernel tx timeout detection.
|
||||
Recover by searching lost interrupts.
|
||||
- tx error completion
|
||||
Report on error tx completion.
|
||||
Recover by flushing the tx queue and reset it.
|
||||
- tx PTP port timestamping CQ unhealthy
|
||||
Report too many CQEs never delivered on port ts CQ.
|
||||
Recover by flushing and re-creating all PTP channels.
|
||||
|
||||
tx reporter also support on demand diagnose callback, on which it provides
|
||||
real time information of its send queues status.
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Diagnose send queues status::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.0 reporter tx
|
||||
|
||||
.. note::
|
||||
This command has valid output only when interface is up, otherwise the command has empty output.
|
||||
|
||||
- Show number of tx errors indicated, number of recover flows ended successfully,
|
||||
is autorecover enabled and graceful period from last recover::
|
||||
|
||||
$ devlink health show pci/0000:82:00.0 reporter tx
|
||||
|
||||
rx reporter
|
||||
-----------
|
||||
The rx reporter is responsible for reporting and recovering of the following two error scenarios:
|
||||
|
||||
- rx queues' initialization (population) timeout
|
||||
Population of rx queues' descriptors on ring initialization is done
|
||||
in napi context via triggering an irq. In case of a failure to get
|
||||
the minimum amount of descriptors, a timeout would occur, and
|
||||
descriptors could be recovered by polling the EQ (Event Queue).
|
||||
- rx completions with errors (reported by HW on interrupt context)
|
||||
Report on rx completion error.
|
||||
Recover (if needed) by flushing the related queue and reset it.
|
||||
|
||||
rx reporter also supports on demand diagnose callback, on which it
|
||||
provides real time information of its receive queues' status.
|
||||
|
||||
- Diagnose rx queues' status and corresponding completion queue::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.0 reporter rx
|
||||
|
||||
.. note::
|
||||
This command has valid output only when interface is up. Otherwise, the command has empty output.
|
||||
|
||||
- Show number of rx errors indicated, number of recover flows ended successfully,
|
||||
is autorecover enabled, and graceful period from last recover::
|
||||
|
||||
$ devlink health show pci/0000:82:00.0 reporter rx
|
||||
|
||||
fw reporter
|
||||
-----------
|
||||
The fw reporter implements `diagnose` and `dump` callbacks.
|
||||
It follows symptoms of fw error such as fw syndrome by triggering
|
||||
fw core dump and storing it into the dump buffer.
|
||||
The fw reporter diagnose command can be triggered any time by the user to check
|
||||
current fw status.
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Check fw heath status::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.0 reporter fw
|
||||
|
||||
- Read FW core dump if already stored or trigger new one::
|
||||
|
||||
$ devlink health dump show pci/0000:82:00.0 reporter fw
|
||||
|
||||
.. note::
|
||||
This command can run only on the PF which has fw tracer ownership,
|
||||
running it on other PF or any VF will return "Operation not permitted".
|
||||
|
||||
fw fatal reporter
|
||||
-----------------
|
||||
The fw fatal reporter implements `dump` and `recover` callbacks.
|
||||
It follows fatal errors indications by CR-space dump and recover flow.
|
||||
The CR-space dump uses vsc interface which is valid even if the FW command
|
||||
interface is not functional, which is the case in most FW fatal errors.
|
||||
The recover function runs recover flow which reloads the driver and triggers fw
|
||||
reset if needed.
|
||||
On firmware error, the health buffer is dumped into the dmesg. The log
|
||||
level is derived from the error's severity (given in health buffer).
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Run fw recover flow manually::
|
||||
|
||||
$ devlink health recover pci/0000:82:00.0 reporter fw_fatal
|
||||
|
||||
- Read FW CR-space dump if already stored or trigger new one::
|
||||
|
||||
$ devlink health dump show pci/0000:82:00.1 reporter fw_fatal
|
||||
|
||||
.. note::
|
||||
This command can run only on PF.
|
||||
|
||||
vnic reporter
|
||||
-------------
|
||||
The vnic reporter implements only the `diagnose` callback.
|
||||
It is responsible for querying the vnic diagnostic counters from fw and displaying
|
||||
them in realtime.
|
||||
|
||||
Description of the vnic counters:
|
||||
|
||||
- total_q_under_processor_handle
|
||||
number of queues in an error state due to
|
||||
an async error or errored command.
|
||||
- send_queue_priority_update_flow
|
||||
number of QP/SQ priority/SL update events.
|
||||
- cq_overrun
|
||||
number of times CQ entered an error state due to an overflow.
|
||||
- async_eq_overrun
|
||||
number of times an EQ mapped to async events was overrun.
|
||||
comp_eq_overrun number of times an EQ mapped to completion events was
|
||||
overrun.
|
||||
- quota_exceeded_command
|
||||
number of commands issued and failed due to quota exceeded.
|
||||
- invalid_command
|
||||
number of commands issued and failed dues to any reason other than quota
|
||||
exceeded.
|
||||
- nic_receive_steering_discard
|
||||
number of packets that completed RX flow
|
||||
steering but were discarded due to a mismatch in flow table.
|
||||
- generated_pkt_steering_fail
|
||||
number of packets generated by the VNIC experiencing unexpected steering
|
||||
failure (at any point in steering flow).
|
||||
- handled_pkt_steering_fail
|
||||
number of packets handled by the VNIC experiencing unexpected steering
|
||||
failure (at any point in steering flow owned by the VNIC, including the FDB
|
||||
for the eswitch owner).
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Diagnose PF/VF vnic counters::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.1 reporter vnic
|
||||
|
||||
- Diagnose representor vnic counters (performed by supplying devlink port of the
|
||||
representor, which can be obtained via devlink port command)::
|
||||
|
||||
$ devlink health diagnose pci/0000:82:00.1/65537 reporter vnic
|
||||
|
||||
.. note::
|
||||
This command can run over all interfaces such as PF/VF and representor ports.
|
||||
|
|
|
@ -321,6 +321,7 @@ tcp_abort_on_overflow - BOOLEAN
|
|||
option can harm clients of your server.
|
||||
|
||||
tcp_adv_win_scale - INTEGER
|
||||
Obsolete since linux-6.6
|
||||
Count buffering overhead as bytes/2^tcp_adv_win_scale
|
||||
(if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
|
||||
if it is <= 0.
|
||||
|
@ -2287,6 +2288,14 @@ accept_ra_min_hop_limit - INTEGER
|
|||
|
||||
Default: 1
|
||||
|
||||
accept_ra_min_lft - INTEGER
|
||||
Minimum acceptable lifetime value in Router Advertisement.
|
||||
|
||||
RA sections with a lifetime less than this value shall be
|
||||
ignored. Zero lifetimes stay unaffected.
|
||||
|
||||
Default: 0
|
||||
|
||||
accept_ra_pinfo - BOOLEAN
|
||||
Learn Prefix Information in Router Advertisement.
|
||||
|
||||
|
|
|
@ -74,3 +74,11 @@ stale_loss_cnt - INTEGER
|
|||
This is a per-namespace sysctl.
|
||||
|
||||
Default: 4
|
||||
|
||||
scheduler - STRING
|
||||
Select the scheduler of your choice.
|
||||
|
||||
Support for selection of different schedulers. This is a per-namespace
|
||||
sysctl.
|
||||
|
||||
Default: "default"
|
||||
|
|
|
@ -13,6 +13,8 @@ IPv6 support by Cong Wang <xiyou.wangcong@gmail.com>, Jan 1 2013
|
|||
|
||||
Extended console support by Tejun Heo <tj@kernel.org>, May 1 2015
|
||||
|
||||
Release prepend support by Breno Leitao <leitao@debian.org>, Jul 7 2023
|
||||
|
||||
Please send bug reports to Matt Mackall <mpm@selenic.com>
|
||||
Satyam Sharma <satyam.sharma@gmail.com>, and Cong Wang <xiyou.wangcong@gmail.com>
|
||||
|
||||
|
@ -34,10 +36,11 @@ Sender and receiver configuration:
|
|||
It takes a string configuration parameter "netconsole" in the
|
||||
following format::
|
||||
|
||||
netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
|
||||
netconsole=[+][r][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
|
||||
|
||||
where
|
||||
+ if present, enable extended console support
|
||||
r if present, prepend kernel version (release) to the message
|
||||
src-port source for UDP packets (defaults to 6665)
|
||||
src-ip source IP to use (interface address)
|
||||
dev network interface (eth0)
|
||||
|
@ -125,6 +128,7 @@ The interface exposes these parameters of a netconsole target to userspace:
|
|||
============== ================================= ============
|
||||
enabled Is this target currently enabled? (read-write)
|
||||
extended Extended mode enabled (read-write)
|
||||
release Prepend kernel release to message (read-write)
|
||||
dev_name Local network interface name (read-write)
|
||||
local_port Source UDP port to use (read-write)
|
||||
remote_port Remote agent's UDP port (read-write)
|
||||
|
@ -165,6 +169,11 @@ following format which is the same as /dev/kmsg::
|
|||
|
||||
<level>,<sequnum>,<timestamp>,<contflag>;<message text>
|
||||
|
||||
If 'r' (release) feature is enabled, the kernel release version is
|
||||
prepended to the start of the message. Example::
|
||||
|
||||
6.4.0,6,444,501151268,-;netconsole: network logging started
|
||||
|
||||
Non printable characters in <message text> are escaped using "\xff"
|
||||
notation. If the message contains optional dictionary, verbatim
|
||||
newline is used as the delimiter.
|
||||
|
|
|
@ -4,22 +4,8 @@
|
|||
Page Pool API
|
||||
=============
|
||||
|
||||
The page_pool allocator is optimized for the XDP mode that uses one frame
|
||||
per-page, but it can fallback on the regular page allocator APIs.
|
||||
|
||||
Basic use involves replacing alloc_pages() calls with the
|
||||
page_pool_alloc_pages() call. Drivers should use page_pool_dev_alloc_pages()
|
||||
replacing dev_alloc_pages().
|
||||
|
||||
API keeps track of in-flight pages, in order to let API user know
|
||||
when it is safe to free a page_pool object. Thus, API users
|
||||
must run page_pool_release_page() when a page is leaving the page_pool or
|
||||
call page_pool_put_page() where appropriate in order to maintain correct
|
||||
accounting.
|
||||
|
||||
API user must call page_pool_put_page() once on a page, as it
|
||||
will either recycle the page, or in case of refcnt > 1, it will
|
||||
release the DMA mapping and in-flight state accounting.
|
||||
.. kernel-doc:: include/net/page_pool/helpers.h
|
||||
:doc: page_pool allocator
|
||||
|
||||
Architecture overview
|
||||
=====================
|
||||
|
@ -64,87 +50,68 @@ This lockless guarantee naturally comes from running under a NAPI softirq.
|
|||
The protection doesn't strictly have to be NAPI, any guarantee that allocating
|
||||
a page will cause no race conditions is enough.
|
||||
|
||||
* page_pool_create(): Create a pool.
|
||||
* flags: PP_FLAG_DMA_MAP, PP_FLAG_DMA_SYNC_DEV
|
||||
* order: 2^order pages on allocation
|
||||
* pool_size: size of the ptr_ring
|
||||
* nid: preferred NUMA node for allocation
|
||||
* dev: struct device. Used on DMA operations
|
||||
* dma_dir: DMA direction
|
||||
* max_len: max DMA sync memory size
|
||||
* offset: DMA address offset
|
||||
.. kernel-doc:: net/core/page_pool.c
|
||||
:identifiers: page_pool_create
|
||||
|
||||
* page_pool_put_page(): The outcome of this depends on the page refcnt. If the
|
||||
driver bumps the refcnt > 1 this will unmap the page. If the page refcnt is 1
|
||||
the allocator owns the page and will try to recycle it in one of the pool
|
||||
caches. If PP_FLAG_DMA_SYNC_DEV is set, the page will be synced for_device
|
||||
using dma_sync_single_range_for_device().
|
||||
.. kernel-doc:: include/net/page_pool/types.h
|
||||
:identifiers: struct page_pool_params
|
||||
|
||||
* page_pool_put_full_page(): Similar to page_pool_put_page(), but will DMA sync
|
||||
for the entire memory area configured in area pool->max_len.
|
||||
.. kernel-doc:: include/net/page_pool/helpers.h
|
||||
:identifiers: page_pool_put_page page_pool_put_full_page
|
||||
page_pool_recycle_direct page_pool_dev_alloc_pages
|
||||
page_pool_get_dma_addr page_pool_get_dma_dir
|
||||
|
||||
* page_pool_recycle_direct(): Similar to page_pool_put_full_page() but caller
|
||||
must guarantee safe context (e.g NAPI), since it will recycle the page
|
||||
directly into the pool fast cache.
|
||||
.. kernel-doc:: net/core/page_pool.c
|
||||
:identifiers: page_pool_put_page_bulk page_pool_get_stats
|
||||
|
||||
* page_pool_release_page(): Unmap the page (if mapped) and account for it on
|
||||
in-flight counters.
|
||||
DMA sync
|
||||
--------
|
||||
Driver is always responsible for syncing the pages for the CPU.
|
||||
Drivers may choose to take care of syncing for the device as well
|
||||
or set the ``PP_FLAG_DMA_SYNC_DEV`` flag to request that pages
|
||||
allocated from the page pool are already synced for the device.
|
||||
|
||||
* page_pool_dev_alloc_pages(): Get a page from the page allocator or page_pool
|
||||
caches.
|
||||
If ``PP_FLAG_DMA_SYNC_DEV`` is set, the driver must inform the core what portion
|
||||
of the buffer has to be synced. This allows the core to avoid syncing the entire
|
||||
page when the drivers knows that the device only accessed a portion of the page.
|
||||
|
||||
* page_pool_get_dma_addr(): Retrieve the stored DMA address.
|
||||
Most drivers will reserve headroom in front of the frame. This part
|
||||
of the buffer is not touched by the device, so to avoid syncing
|
||||
it drivers can set the ``offset`` field in struct page_pool_params
|
||||
appropriately.
|
||||
|
||||
* page_pool_get_dma_dir(): Retrieve the stored DMA direction.
|
||||
For pages recycled on the XDP xmit and skb paths the page pool will
|
||||
use the ``max_len`` member of struct page_pool_params to decide how
|
||||
much of the page needs to be synced (starting at ``offset``).
|
||||
When directly freeing pages in the driver (page_pool_put_page())
|
||||
the ``dma_sync_size`` argument specifies how much of the buffer needs
|
||||
to be synced.
|
||||
|
||||
* page_pool_put_page_bulk(): Tries to refill a number of pages into the
|
||||
ptr_ring cache holding ptr_ring producer lock. If the ptr_ring is full,
|
||||
page_pool_put_page_bulk() will release leftover pages to the page allocator.
|
||||
page_pool_put_page_bulk() is suitable to be run inside the driver NAPI tx
|
||||
completion loop for the XDP_REDIRECT use case.
|
||||
Please note the caller must not use data area after running
|
||||
page_pool_put_page_bulk(), as this function overwrites it.
|
||||
If in doubt set ``offset`` to 0, ``max_len`` to ``PAGE_SIZE`` and
|
||||
pass -1 as ``dma_sync_size``. That combination of arguments is always
|
||||
correct.
|
||||
|
||||
* page_pool_get_stats(): Retrieve statistics about the page_pool. This API
|
||||
is only available if the kernel has been configured with
|
||||
``CONFIG_PAGE_POOL_STATS=y``. A pointer to a caller allocated ``struct
|
||||
page_pool_stats`` structure is passed to this API which is filled in. The
|
||||
caller can then report those stats to the user (perhaps via ethtool,
|
||||
debugfs, etc.). See below for an example usage of this API.
|
||||
Note that the syncing parameters are for the entire page.
|
||||
This is important to remember when using fragments (``PP_FLAG_PAGE_FRAG``),
|
||||
where allocated buffers may be smaller than a full page.
|
||||
Unless the driver author really understands page pool internals
|
||||
it's recommended to always use ``offset = 0``, ``max_len = PAGE_SIZE``
|
||||
with fragmented page pools.
|
||||
|
||||
Stats API and structures
|
||||
------------------------
|
||||
If the kernel is configured with ``CONFIG_PAGE_POOL_STATS=y``, the API
|
||||
``page_pool_get_stats()`` and structures described below are available. It
|
||||
takes a pointer to a ``struct page_pool`` and a pointer to a ``struct
|
||||
page_pool_stats`` allocated by the caller.
|
||||
page_pool_get_stats() and structures described below are available.
|
||||
It takes a pointer to a ``struct page_pool`` and a pointer to a struct
|
||||
page_pool_stats allocated by the caller.
|
||||
|
||||
The API will fill in the provided ``struct page_pool_stats`` with
|
||||
The API will fill in the provided struct page_pool_stats with
|
||||
statistics about the page_pool.
|
||||
|
||||
The stats structure has the following fields::
|
||||
|
||||
struct page_pool_stats {
|
||||
struct page_pool_alloc_stats alloc_stats;
|
||||
struct page_pool_recycle_stats recycle_stats;
|
||||
};
|
||||
|
||||
|
||||
The ``struct page_pool_alloc_stats`` has the following fields:
|
||||
* ``fast``: successful fast path allocations
|
||||
* ``slow``: slow path order-0 allocations
|
||||
* ``slow_high_order``: slow path high order allocations
|
||||
* ``empty``: ptr ring is empty, so a slow path allocation was forced.
|
||||
* ``refill``: an allocation which triggered a refill of the cache
|
||||
* ``waive``: pages obtained from the ptr ring that cannot be added to
|
||||
the cache due to a NUMA mismatch.
|
||||
|
||||
The ``struct page_pool_recycle_stats`` has the following fields:
|
||||
* ``cached``: recycling placed page in the page pool cache
|
||||
* ``cache_full``: page pool cache was full
|
||||
* ``ring``: page placed into the ptr ring
|
||||
* ``ring_full``: page released from page pool because the ptr ring was full
|
||||
* ``released_refcnt``: page released (and not recycled) because refcnt > 1
|
||||
.. kernel-doc:: include/net/page_pool/types.h
|
||||
:identifiers: struct page_pool_recycle_stats
|
||||
struct page_pool_alloc_stats
|
||||
struct page_pool_stats
|
||||
|
||||
Coding examples
|
||||
===============
|
||||
|
@ -194,7 +161,7 @@ NAPI poller
|
|||
if XDP_DROP:
|
||||
page_pool_recycle_direct(page_pool, page);
|
||||
} else (packet_is_skb) {
|
||||
page_pool_release_page(page_pool, page);
|
||||
skb_mark_for_recycle(skb);
|
||||
new_page = page_pool_dev_alloc_pages(page_pool);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -323,6 +323,10 @@ Some of the interface modes are described below:
|
|||
contrast with the 1000BASE-X phy mode used for Clause 38 and 39 PMDs, this
|
||||
interface mode has different autonegotiation and only supports full duplex.
|
||||
|
||||
``PHY_INTERFACE_MODE_PSGMII``
|
||||
This is the Penta SGMII mode, it is similar to QSGMII but it combines 5
|
||||
SGMII lines into a single link compared to 4 on QSGMII.
|
||||
|
||||
Pause frames / flow control
|
||||
===========================
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. _xfrm_device:
|
||||
|
||||
===============================================
|
||||
XFRM device - offloading the IPsec computations
|
||||
|
|
|
@ -167,6 +167,8 @@ Asking the maintainer for status updates on your
|
|||
patch is a good way to ensure your patch is ignored or pushed to the
|
||||
bottom of the priority list.
|
||||
|
||||
.. _Changes requested:
|
||||
|
||||
Changes requested
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -359,6 +361,10 @@ Make sure you address all the feedback in your new posting. Do not post a new
|
|||
version of the code if the discussion about the previous version is still
|
||||
ongoing, unless directly instructed by a reviewer.
|
||||
|
||||
The new version of patches should be posted as a separate thread,
|
||||
not as a reply to the previous posting. Change log should include a link
|
||||
to the previous posting (see :ref:`Changes requested`).
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
|
|
|
@ -8,11 +8,8 @@ This document describes the many additional quirks and properties
|
|||
required to describe older Generic Netlink families which form
|
||||
the ``genetlink-legacy`` protocol level.
|
||||
|
||||
The spec is a work in progress, some of the quirks are just documented
|
||||
for future reference.
|
||||
|
||||
Specification (defined)
|
||||
=======================
|
||||
Specification
|
||||
=============
|
||||
|
||||
Attribute type nests
|
||||
--------------------
|
||||
|
@ -156,16 +153,27 @@ it will be allocated 3 for the request (``a`` is the previous operation
|
|||
with a request section and the value of 2) and 8 for response (``c`` is
|
||||
the previous operation in the "from-kernel" direction).
|
||||
|
||||
Other quirks (todo)
|
||||
===================
|
||||
Other quirks
|
||||
============
|
||||
|
||||
Structures
|
||||
----------
|
||||
|
||||
Legacy families can define C structures both to be used as the contents of
|
||||
an attribute and as a fixed message header. Structures are defined in
|
||||
``definitions`` and referenced in operations or attributes. Note that
|
||||
structures defined in YAML are implicitly packed according to C
|
||||
``definitions`` and referenced in operations or attributes.
|
||||
|
||||
members
|
||||
~~~~~~~
|
||||
|
||||
- ``name`` - The attribute name of the struct member
|
||||
- ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``,
|
||||
``s16``, ``s32``, ``s64``, ``string`` or ``binary``.
|
||||
- ``byte-order`` - ``big-endian`` or ``little-endian``
|
||||
- ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for
|
||||
:ref:`attribute definitions <attribute_properties>`
|
||||
|
||||
Note that structures defined in YAML are implicitly packed according to C
|
||||
conventions. For example, the following struct is 4 bytes, not 6 bytes:
|
||||
|
||||
.. code-block:: c
|
||||
|
|
|
@ -14,5 +14,6 @@ Netlink documentation for users.
|
|||
specs
|
||||
c-code-gen
|
||||
genetlink-legacy
|
||||
netlink-raw
|
||||
|
||||
See also :ref:`Documentation/core-api/netlink.rst <kernel_netlink>`.
|
||||
|
|
58
Documentation/userspace-api/netlink/netlink-raw.rst
Normal file
58
Documentation/userspace-api/netlink/netlink-raw.rst
Normal file
|
@ -0,0 +1,58 @@
|
|||
.. SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
======================================================
|
||||
Netlink specification support for raw Netlink families
|
||||
======================================================
|
||||
|
||||
This document describes the additional properties required by raw Netlink
|
||||
families such as ``NETLINK_ROUTE`` which use the ``netlink-raw`` protocol
|
||||
specification.
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
The netlink-raw schema extends the :doc:`genetlink-legacy <genetlink-legacy>`
|
||||
schema with properties that are needed to specify the protocol numbers and
|
||||
multicast IDs used by raw netlink families. See :ref:`classic_netlink` for more
|
||||
information.
|
||||
|
||||
Globals
|
||||
-------
|
||||
|
||||
protonum
|
||||
~~~~~~~~
|
||||
|
||||
The ``protonum`` property is used to specify the protocol number to use when
|
||||
opening a netlink socket.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
|
||||
name: rt-addr
|
||||
protocol: netlink-raw
|
||||
protonum: 0 # part of the NETLINK_ROUTE protocol
|
||||
|
||||
|
||||
Multicast group properties
|
||||
--------------------------
|
||||
|
||||
value
|
||||
~~~~~
|
||||
|
||||
The ``value`` property is used to specify the group ID to use for multicast
|
||||
group registration.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: rtnlgrp-ipv4-ifaddr
|
||||
value: 5
|
||||
-
|
||||
name: rtnlgrp-ipv6-ifaddr
|
||||
value: 9
|
||||
-
|
||||
name: rtnlgrp-mctp-ifaddr
|
||||
value: 34
|
|
@ -68,6 +68,10 @@ The following sections describe the properties of the most modern ``genetlink``
|
|||
schema. See the documentation of :doc:`genetlink-c <c-code-gen>`
|
||||
for information on how C names are derived from name properties.
|
||||
|
||||
See also :ref:`Documentation/core-api/netlink.rst <kernel_netlink>` for
|
||||
information on the Netlink specification properties that are only relevant to
|
||||
the kernel space and not part of the user space API.
|
||||
|
||||
genetlink
|
||||
=========
|
||||
|
||||
|
@ -180,6 +184,8 @@ attributes
|
|||
|
||||
List of attributes in the set.
|
||||
|
||||
.. _attribute_properties:
|
||||
|
||||
Attribute properties
|
||||
--------------------
|
||||
|
||||
|
@ -264,6 +270,13 @@ a C array of u32 values can be specified with ``type: binary`` and
|
|||
``sub-type: u32``. Binary types and legacy array formats are described in
|
||||
more detail in :doc:`genetlink-legacy`.
|
||||
|
||||
display-hint
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Optional format indicator that is intended only for choosing the right
|
||||
formatting mechanism when displaying values of this type. Currently supported
|
||||
hints are ``hex``, ``mac``, ``fddi``, ``ipv4``, ``ipv6`` and ``uuid``.
|
||||
|
||||
operations
|
||||
----------
|
||||
|
||||
|
|
41
MAINTAINERS
41
MAINTAINERS
|
@ -3697,6 +3697,7 @@ F: include/linux/filter.h
|
|||
F: include/linux/tnum.h
|
||||
F: kernel/bpf/core.c
|
||||
F: kernel/bpf/dispatcher.c
|
||||
F: kernel/bpf/mprog.c
|
||||
F: kernel/bpf/syscall.c
|
||||
F: kernel/bpf/tnum.c
|
||||
F: kernel/bpf/trampoline.c
|
||||
|
@ -3707,7 +3708,7 @@ R: David Vernet <void@manifault.com>
|
|||
L: bpf@vger.kernel.org
|
||||
L: bpf@ietf.org
|
||||
S: Maintained
|
||||
F: Documentation/bpf/instruction-set.rst
|
||||
F: Documentation/bpf/standardization/
|
||||
|
||||
BPF [GENERAL] (Safe Dynamic Programs and Tools)
|
||||
M: Alexei Starovoitov <ast@kernel.org>
|
||||
|
@ -3715,7 +3716,7 @@ M: Daniel Borkmann <daniel@iogearbox.net>
|
|||
M: Andrii Nakryiko <andrii@kernel.org>
|
||||
R: Martin KaFai Lau <martin.lau@linux.dev>
|
||||
R: Song Liu <song@kernel.org>
|
||||
R: Yonghong Song <yhs@fb.com>
|
||||
R: Yonghong Song <yonghong.song@linux.dev>
|
||||
R: John Fastabend <john.fastabend@gmail.com>
|
||||
R: KP Singh <kpsingh@kernel.org>
|
||||
R: Stanislav Fomichev <sdf@google.com>
|
||||
|
@ -3754,7 +3755,7 @@ F: tools/lib/bpf/
|
|||
F: tools/testing/selftests/bpf/
|
||||
|
||||
BPF [ITERATOR]
|
||||
M: Yonghong Song <yhs@fb.com>
|
||||
M: Yonghong Song <yonghong.song@linux.dev>
|
||||
L: bpf@vger.kernel.org
|
||||
S: Maintained
|
||||
F: kernel/bpf/*iter.c
|
||||
|
@ -3790,13 +3791,15 @@ L: netdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: kernel/bpf/bpf_struct*
|
||||
|
||||
BPF [NETWORKING] (tc BPF, sock_addr)
|
||||
BPF [NETWORKING] (tcx & tc BPF, sock_addr)
|
||||
M: Martin KaFai Lau <martin.lau@linux.dev>
|
||||
M: Daniel Borkmann <daniel@iogearbox.net>
|
||||
R: John Fastabend <john.fastabend@gmail.com>
|
||||
L: bpf@vger.kernel.org
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: include/net/tcx.h
|
||||
F: kernel/bpf/tcx.c
|
||||
F: net/core/filter.c
|
||||
F: net/sched/act_bpf.c
|
||||
F: net/sched/cls_bpf.c
|
||||
|
@ -3848,6 +3851,15 @@ S: Maintained
|
|||
F: kernel/bpf/stackmap.c
|
||||
F: kernel/trace/bpf_trace.c
|
||||
|
||||
BROADCOM ASP 2.0 ETHERNET DRIVER
|
||||
M: Justin Chen <justin.chen@broadcom.com>
|
||||
M: Florian Fainelli <florian.fainelli@broadcom.com>
|
||||
L: bcm-kernel-feedback-list@broadcom.com
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml
|
||||
F: drivers/net/ethernet/broadcom/asp2/
|
||||
|
||||
BROADCOM B44 10/100 ETHERNET DRIVER
|
||||
M: Michael Chan <michael.chan@broadcom.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -7610,6 +7622,13 @@ L: linux-mmc@vger.kernel.org
|
|||
S: Supported
|
||||
F: drivers/mmc/host/cqhci*
|
||||
|
||||
EMS CPC-PCI CAN DRIVER
|
||||
M: Gerhard Uttenthaler <uttenthaler@ems-wuensche.com>
|
||||
M: support@ems-wuensche.com
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/can/sja1000/ems_pci.c
|
||||
|
||||
EMULEX 10Gbps iSCSI - OneConnect DRIVER
|
||||
M: Ketan Mukadam <ketan.mukadam@broadcom.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
|
@ -7749,6 +7768,7 @@ F: include/linux/mii.h
|
|||
F: include/linux/of_net.h
|
||||
F: include/linux/phy.h
|
||||
F: include/linux/phy_fixed.h
|
||||
F: include/linux/phylib_stubs.h
|
||||
F: include/linux/platform_data/mdio-bcm-unimac.h
|
||||
F: include/linux/platform_data/mdio-gpio.h
|
||||
F: include/trace/events/mdio.h
|
||||
|
@ -8368,7 +8388,6 @@ L: linuxppc-dev@lists.ozlabs.org
|
|||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/freescale/fs_enet/
|
||||
F: include/linux/fs_enet_pd.h
|
||||
|
||||
FREESCALE SOC SOUND DRIVERS
|
||||
M: Shengjiu Wang <shengjiu.wang@gmail.com>
|
||||
|
@ -14684,7 +14703,7 @@ F: drivers/rtc/rtc-ntxec.c
|
|||
F: include/linux/mfd/ntxec.h
|
||||
|
||||
NETRONOME ETHERNET DRIVERS
|
||||
M: Simon Horman <simon.horman@corigine.com>
|
||||
M: Louis Peens <louis.peens@corigine.com>
|
||||
R: Jakub Kicinski <kuba@kernel.org>
|
||||
L: oss-drivers@corigine.com
|
||||
S: Maintained
|
||||
|
@ -16057,7 +16076,7 @@ M: Ilias Apalodimas <ilias.apalodimas@linaro.org>
|
|||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/networking/page_pool.rst
|
||||
F: include/net/page_pool.h
|
||||
F: include/net/page_pool/
|
||||
F: include/trace/events/page_pool.h
|
||||
F: net/core/page_pool.c
|
||||
|
||||
|
@ -17210,6 +17229,13 @@ F: drivers/ptp/*
|
|||
F: include/linux/ptp_cl*
|
||||
K: (?:\b|_)ptp(?:\b|_)
|
||||
|
||||
PTP MOCKUP CLOCK SUPPORT
|
||||
M: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/ptp/ptp_mock.c
|
||||
F: include/linux/ptp_mock.h
|
||||
|
||||
PTP VIRTUAL CLOCK SUPPORT
|
||||
M: Yangbo Lu <yangbo.lu@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -22972,6 +22998,7 @@ S: Maintained
|
|||
W: https://www.net-swift.com
|
||||
F: Documentation/networking/device_drivers/ethernet/wangxun/*
|
||||
F: drivers/net/ethernet/wangxun/
|
||||
F: drivers/net/pcs/pcs-xpcs-wx.c
|
||||
|
||||
WATCHDOG DEVICE DRIVERS
|
||||
M: Wim Van Sebroeck <wim@linux-watchdog.org>
|
||||
|
|
|
@ -186,6 +186,8 @@ enum aarch64_insn_ldst_type {
|
|||
AARCH64_INSN_LDST_LOAD_ACQ_EX,
|
||||
AARCH64_INSN_LDST_STORE_EX,
|
||||
AARCH64_INSN_LDST_STORE_REL_EX,
|
||||
AARCH64_INSN_LDST_SIGNED_LOAD_IMM_OFFSET,
|
||||
AARCH64_INSN_LDST_SIGNED_LOAD_REG_OFFSET,
|
||||
};
|
||||
|
||||
enum aarch64_insn_adsb_type {
|
||||
|
@ -324,6 +326,7 @@ __AARCH64_INSN_FUNCS(prfm, 0x3FC00000, 0x39800000)
|
|||
__AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000)
|
||||
__AARCH64_INSN_FUNCS(store_imm, 0x3FC00000, 0x39000000)
|
||||
__AARCH64_INSN_FUNCS(load_imm, 0x3FC00000, 0x39400000)
|
||||
__AARCH64_INSN_FUNCS(signed_load_imm, 0X3FC00000, 0x39800000)
|
||||
__AARCH64_INSN_FUNCS(store_pre, 0x3FE00C00, 0x38000C00)
|
||||
__AARCH64_INSN_FUNCS(load_pre, 0x3FE00C00, 0x38400C00)
|
||||
__AARCH64_INSN_FUNCS(store_post, 0x3FE00C00, 0x38000400)
|
||||
|
@ -337,6 +340,7 @@ __AARCH64_INSN_FUNCS(ldset, 0x3F20FC00, 0x38203000)
|
|||
__AARCH64_INSN_FUNCS(swp, 0x3F20FC00, 0x38208000)
|
||||
__AARCH64_INSN_FUNCS(cas, 0x3FA07C00, 0x08A07C00)
|
||||
__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
|
||||
__AARCH64_INSN_FUNCS(signed_ldr_reg, 0X3FE0FC00, 0x38A0E800)
|
||||
__AARCH64_INSN_FUNCS(ldr_imm, 0x3FC00000, 0x39400000)
|
||||
__AARCH64_INSN_FUNCS(ldr_lit, 0xBF000000, 0x18000000)
|
||||
__AARCH64_INSN_FUNCS(ldrsw_lit, 0xFF000000, 0x98000000)
|
||||
|
|
|
@ -385,6 +385,9 @@ u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg,
|
|||
case AARCH64_INSN_LDST_LOAD_REG_OFFSET:
|
||||
insn = aarch64_insn_get_ldr_reg_value();
|
||||
break;
|
||||
case AARCH64_INSN_LDST_SIGNED_LOAD_REG_OFFSET:
|
||||
insn = aarch64_insn_get_signed_ldr_reg_value();
|
||||
break;
|
||||
case AARCH64_INSN_LDST_STORE_REG_OFFSET:
|
||||
insn = aarch64_insn_get_str_reg_value();
|
||||
break;
|
||||
|
@ -430,6 +433,9 @@ u32 aarch64_insn_gen_load_store_imm(enum aarch64_insn_register reg,
|
|||
case AARCH64_INSN_LDST_LOAD_IMM_OFFSET:
|
||||
insn = aarch64_insn_get_ldr_imm_value();
|
||||
break;
|
||||
case AARCH64_INSN_LDST_SIGNED_LOAD_IMM_OFFSET:
|
||||
insn = aarch64_insn_get_signed_load_imm_value();
|
||||
break;
|
||||
case AARCH64_INSN_LDST_STORE_IMM_OFFSET:
|
||||
insn = aarch64_insn_get_str_imm_value();
|
||||
break;
|
||||
|
|
|
@ -59,10 +59,13 @@
|
|||
AARCH64_INSN_LDST_##type##_REG_OFFSET)
|
||||
#define A64_STRB(Wt, Xn, Xm) A64_LS_REG(Wt, Xn, Xm, 8, STORE)
|
||||
#define A64_LDRB(Wt, Xn, Xm) A64_LS_REG(Wt, Xn, Xm, 8, LOAD)
|
||||
#define A64_LDRSB(Xt, Xn, Xm) A64_LS_REG(Xt, Xn, Xm, 8, SIGNED_LOAD)
|
||||
#define A64_STRH(Wt, Xn, Xm) A64_LS_REG(Wt, Xn, Xm, 16, STORE)
|
||||
#define A64_LDRH(Wt, Xn, Xm) A64_LS_REG(Wt, Xn, Xm, 16, LOAD)
|
||||
#define A64_LDRSH(Xt, Xn, Xm) A64_LS_REG(Xt, Xn, Xm, 16, SIGNED_LOAD)
|
||||
#define A64_STR32(Wt, Xn, Xm) A64_LS_REG(Wt, Xn, Xm, 32, STORE)
|
||||
#define A64_LDR32(Wt, Xn, Xm) A64_LS_REG(Wt, Xn, Xm, 32, LOAD)
|
||||
#define A64_LDRSW(Xt, Xn, Xm) A64_LS_REG(Xt, Xn, Xm, 32, SIGNED_LOAD)
|
||||
#define A64_STR64(Xt, Xn, Xm) A64_LS_REG(Xt, Xn, Xm, 64, STORE)
|
||||
#define A64_LDR64(Xt, Xn, Xm) A64_LS_REG(Xt, Xn, Xm, 64, LOAD)
|
||||
|
||||
|
@ -73,10 +76,13 @@
|
|||
AARCH64_INSN_LDST_##type##_IMM_OFFSET)
|
||||
#define A64_STRBI(Wt, Xn, imm) A64_LS_IMM(Wt, Xn, imm, 8, STORE)
|
||||
#define A64_LDRBI(Wt, Xn, imm) A64_LS_IMM(Wt, Xn, imm, 8, LOAD)
|
||||
#define A64_LDRSBI(Xt, Xn, imm) A64_LS_IMM(Xt, Xn, imm, 8, SIGNED_LOAD)
|
||||
#define A64_STRHI(Wt, Xn, imm) A64_LS_IMM(Wt, Xn, imm, 16, STORE)
|
||||
#define A64_LDRHI(Wt, Xn, imm) A64_LS_IMM(Wt, Xn, imm, 16, LOAD)
|
||||
#define A64_LDRSHI(Xt, Xn, imm) A64_LS_IMM(Xt, Xn, imm, 16, SIGNED_LOAD)
|
||||
#define A64_STR32I(Wt, Xn, imm) A64_LS_IMM(Wt, Xn, imm, 32, STORE)
|
||||
#define A64_LDR32I(Wt, Xn, imm) A64_LS_IMM(Wt, Xn, imm, 32, LOAD)
|
||||
#define A64_LDRSWI(Xt, Xn, imm) A64_LS_IMM(Xt, Xn, imm, 32, SIGNED_LOAD)
|
||||
#define A64_STR64I(Xt, Xn, imm) A64_LS_IMM(Xt, Xn, imm, 64, STORE)
|
||||
#define A64_LDR64I(Xt, Xn, imm) A64_LS_IMM(Xt, Xn, imm, 64, LOAD)
|
||||
|
||||
|
@ -186,6 +192,11 @@
|
|||
#define A64_UXTH(sf, Rd, Rn) A64_UBFM(sf, Rd, Rn, 0, 15)
|
||||
#define A64_UXTW(sf, Rd, Rn) A64_UBFM(sf, Rd, Rn, 0, 31)
|
||||
|
||||
/* Sign extend */
|
||||
#define A64_SXTB(sf, Rd, Rn) A64_SBFM(sf, Rd, Rn, 0, 7)
|
||||
#define A64_SXTH(sf, Rd, Rn) A64_SBFM(sf, Rd, Rn, 0, 15)
|
||||
#define A64_SXTW(sf, Rd, Rn) A64_SBFM(sf, Rd, Rn, 0, 31)
|
||||
|
||||
/* Move wide (immediate) */
|
||||
#define A64_MOVEW(sf, Rd, imm16, shift, type) \
|
||||
aarch64_insn_gen_movewide(Rd, imm16, shift, \
|
||||
|
@ -223,6 +234,7 @@
|
|||
#define A64_DATA2(sf, Rd, Rn, Rm, type) aarch64_insn_gen_data2(Rd, Rn, Rm, \
|
||||
A64_VARIANT(sf), AARCH64_INSN_DATA2_##type)
|
||||
#define A64_UDIV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, UDIV)
|
||||
#define A64_SDIV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, SDIV)
|
||||
#define A64_LSLV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, LSLV)
|
||||
#define A64_LSRV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, LSRV)
|
||||
#define A64_ASRV(sf, Rd, Rn, Rm) A64_DATA2(sf, Rd, Rn, Rm, ASRV)
|
||||
|
|
|
@ -715,7 +715,8 @@ static int add_exception_handler(const struct bpf_insn *insn,
|
|||
/* First pass */
|
||||
return 0;
|
||||
|
||||
if (BPF_MODE(insn->code) != BPF_PROBE_MEM)
|
||||
if (BPF_MODE(insn->code) != BPF_PROBE_MEM &&
|
||||
BPF_MODE(insn->code) != BPF_PROBE_MEMSX)
|
||||
return 0;
|
||||
|
||||
if (!ctx->prog->aux->extable ||
|
||||
|
@ -779,12 +780,26 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
|||
u8 dst_adj;
|
||||
int off_adj;
|
||||
int ret;
|
||||
bool sign_extend;
|
||||
|
||||
switch (code) {
|
||||
/* dst = src */
|
||||
case BPF_ALU | BPF_MOV | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOV | BPF_X:
|
||||
emit(A64_MOV(is64, dst, src), ctx);
|
||||
switch (insn->off) {
|
||||
case 0:
|
||||
emit(A64_MOV(is64, dst, src), ctx);
|
||||
break;
|
||||
case 8:
|
||||
emit(A64_SXTB(is64, dst, src), ctx);
|
||||
break;
|
||||
case 16:
|
||||
emit(A64_SXTH(is64, dst, src), ctx);
|
||||
break;
|
||||
case 32:
|
||||
emit(A64_SXTW(is64, dst, src), ctx);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* dst = dst OP src */
|
||||
case BPF_ALU | BPF_ADD | BPF_X:
|
||||
|
@ -813,11 +828,17 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
|||
break;
|
||||
case BPF_ALU | BPF_DIV | BPF_X:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
emit(A64_UDIV(is64, dst, dst, src), ctx);
|
||||
if (!off)
|
||||
emit(A64_UDIV(is64, dst, dst, src), ctx);
|
||||
else
|
||||
emit(A64_SDIV(is64, dst, dst, src), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_MOD | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
emit(A64_UDIV(is64, tmp, dst, src), ctx);
|
||||
if (!off)
|
||||
emit(A64_UDIV(is64, tmp, dst, src), ctx);
|
||||
else
|
||||
emit(A64_SDIV(is64, tmp, dst, src), ctx);
|
||||
emit(A64_MSUB(is64, dst, dst, tmp, src), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_LSH | BPF_X:
|
||||
|
@ -840,11 +861,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
|||
/* dst = BSWAP##imm(dst) */
|
||||
case BPF_ALU | BPF_END | BPF_FROM_LE:
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
||||
case BPF_ALU64 | BPF_END | BPF_FROM_LE:
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
if (BPF_SRC(code) == BPF_FROM_BE)
|
||||
if (BPF_CLASS(code) == BPF_ALU && BPF_SRC(code) == BPF_FROM_BE)
|
||||
goto emit_bswap_uxt;
|
||||
#else /* !CONFIG_CPU_BIG_ENDIAN */
|
||||
if (BPF_SRC(code) == BPF_FROM_LE)
|
||||
if (BPF_CLASS(code) == BPF_ALU && BPF_SRC(code) == BPF_FROM_LE)
|
||||
goto emit_bswap_uxt;
|
||||
#endif
|
||||
switch (imm) {
|
||||
|
@ -943,12 +965,18 @@ emit_bswap_uxt:
|
|||
case BPF_ALU | BPF_DIV | BPF_K:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K:
|
||||
emit_a64_mov_i(is64, tmp, imm, ctx);
|
||||
emit(A64_UDIV(is64, dst, dst, tmp), ctx);
|
||||
if (!off)
|
||||
emit(A64_UDIV(is64, dst, dst, tmp), ctx);
|
||||
else
|
||||
emit(A64_SDIV(is64, dst, dst, tmp), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_MOD | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
emit_a64_mov_i(is64, tmp2, imm, ctx);
|
||||
emit(A64_UDIV(is64, tmp, dst, tmp2), ctx);
|
||||
if (!off)
|
||||
emit(A64_UDIV(is64, tmp, dst, tmp2), ctx);
|
||||
else
|
||||
emit(A64_SDIV(is64, tmp, dst, tmp2), ctx);
|
||||
emit(A64_MSUB(is64, dst, dst, tmp, tmp2), ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_LSH | BPF_K:
|
||||
|
@ -966,7 +994,11 @@ emit_bswap_uxt:
|
|||
|
||||
/* JUMP off */
|
||||
case BPF_JMP | BPF_JA:
|
||||
jmp_offset = bpf2a64_offset(i, off, ctx);
|
||||
case BPF_JMP32 | BPF_JA:
|
||||
if (BPF_CLASS(code) == BPF_JMP)
|
||||
jmp_offset = bpf2a64_offset(i, off, ctx);
|
||||
else
|
||||
jmp_offset = bpf2a64_offset(i, imm, ctx);
|
||||
check_imm26(jmp_offset);
|
||||
emit(A64_B(jmp_offset), ctx);
|
||||
break;
|
||||
|
@ -1122,7 +1154,7 @@ emit_cond_jmp:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* LDX: dst = *(size *)(src + off) */
|
||||
/* LDX: dst = (u64)*(unsigned size *)(src + off) */
|
||||
case BPF_LDX | BPF_MEM | BPF_W:
|
||||
case BPF_LDX | BPF_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_MEM | BPF_B:
|
||||
|
@ -1131,6 +1163,13 @@ emit_cond_jmp:
|
|||
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
|
||||
case BPF_LDX | BPF_PROBE_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_PROBE_MEM | BPF_B:
|
||||
/* LDXS: dst_reg = (s64)*(signed size *)(src_reg + off) */
|
||||
case BPF_LDX | BPF_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_W:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_W:
|
||||
if (ctx->fpb_offset > 0 && src == fp) {
|
||||
src_adj = fpb;
|
||||
off_adj = off + ctx->fpb_offset;
|
||||
|
@ -1138,29 +1177,49 @@ emit_cond_jmp:
|
|||
src_adj = src;
|
||||
off_adj = off;
|
||||
}
|
||||
sign_extend = (BPF_MODE(insn->code) == BPF_MEMSX ||
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEMSX);
|
||||
switch (BPF_SIZE(code)) {
|
||||
case BPF_W:
|
||||
if (is_lsi_offset(off_adj, 2)) {
|
||||
emit(A64_LDR32I(dst, src_adj, off_adj), ctx);
|
||||
if (sign_extend)
|
||||
emit(A64_LDRSWI(dst, src_adj, off_adj), ctx);
|
||||
else
|
||||
emit(A64_LDR32I(dst, src_adj, off_adj), ctx);
|
||||
} else {
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_LDR32(dst, src, tmp), ctx);
|
||||
if (sign_extend)
|
||||
emit(A64_LDRSW(dst, src_adj, off_adj), ctx);
|
||||
else
|
||||
emit(A64_LDR32(dst, src, tmp), ctx);
|
||||
}
|
||||
break;
|
||||
case BPF_H:
|
||||
if (is_lsi_offset(off_adj, 1)) {
|
||||
emit(A64_LDRHI(dst, src_adj, off_adj), ctx);
|
||||
if (sign_extend)
|
||||
emit(A64_LDRSHI(dst, src_adj, off_adj), ctx);
|
||||
else
|
||||
emit(A64_LDRHI(dst, src_adj, off_adj), ctx);
|
||||
} else {
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_LDRH(dst, src, tmp), ctx);
|
||||
if (sign_extend)
|
||||
emit(A64_LDRSH(dst, src, tmp), ctx);
|
||||
else
|
||||
emit(A64_LDRH(dst, src, tmp), ctx);
|
||||
}
|
||||
break;
|
||||
case BPF_B:
|
||||
if (is_lsi_offset(off_adj, 0)) {
|
||||
emit(A64_LDRBI(dst, src_adj, off_adj), ctx);
|
||||
if (sign_extend)
|
||||
emit(A64_LDRSBI(dst, src_adj, off_adj), ctx);
|
||||
else
|
||||
emit(A64_LDRBI(dst, src_adj, off_adj), ctx);
|
||||
} else {
|
||||
emit_a64_mov_i(1, tmp, off, ctx);
|
||||
emit(A64_LDRB(dst, src, tmp), ctx);
|
||||
if (sign_extend)
|
||||
emit(A64_LDRSB(dst, src, tmp), ctx);
|
||||
else
|
||||
emit(A64_LDRB(dst, src, tmp), ctx);
|
||||
}
|
||||
break;
|
||||
case BPF_DW:
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs_enet_pd.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/time.h>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/fs_enet_pd.h>
|
||||
#include <linux/fs_uart_pd.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/mii.h>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/fs_enet_pd.h>
|
||||
#include <linux/fs_uart_pd.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/mii.h>
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/phy.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/fs_enet_pd.h>
|
||||
#include <linux/fs_uart_pd.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
|
@ -37,8 +36,6 @@
|
|||
#include <asm/cpm2.h>
|
||||
#include <asm/fsl_hcalls.h> /* For the Freescale hypervisor */
|
||||
|
||||
extern void init_fcc_ioports(struct fs_platform_info*);
|
||||
extern void init_fec_ioports(struct fs_platform_info*);
|
||||
extern void init_smc_ioports(struct fs_uart_platform_info*);
|
||||
static phys_addr_t immrbase = -1;
|
||||
|
||||
|
|
|
@ -431,11 +431,21 @@ static inline u32 rv_mulhu(u8 rd, u8 rs1, u8 rs2)
|
|||
return rv_r_insn(1, rs2, rs1, 3, rd, 0x33);
|
||||
}
|
||||
|
||||
static inline u32 rv_div(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 4, rd, 0x33);
|
||||
}
|
||||
|
||||
static inline u32 rv_divu(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 5, rd, 0x33);
|
||||
}
|
||||
|
||||
static inline u32 rv_rem(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 6, rd, 0x33);
|
||||
}
|
||||
|
||||
static inline u32 rv_remu(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 7, rd, 0x33);
|
||||
|
@ -501,6 +511,16 @@ static inline u32 rv_ble(u8 rs1, u8 rs2, u16 imm12_1)
|
|||
return rv_bge(rs2, rs1, imm12_1);
|
||||
}
|
||||
|
||||
static inline u32 rv_lb(u8 rd, u16 imm11_0, u8 rs1)
|
||||
{
|
||||
return rv_i_insn(imm11_0, rs1, 0, rd, 0x03);
|
||||
}
|
||||
|
||||
static inline u32 rv_lh(u8 rd, u16 imm11_0, u8 rs1)
|
||||
{
|
||||
return rv_i_insn(imm11_0, rs1, 1, rd, 0x03);
|
||||
}
|
||||
|
||||
static inline u32 rv_lw(u8 rd, u16 imm11_0, u8 rs1)
|
||||
{
|
||||
return rv_i_insn(imm11_0, rs1, 2, rd, 0x03);
|
||||
|
@ -766,11 +786,21 @@ static inline u32 rv_mulw(u8 rd, u8 rs1, u8 rs2)
|
|||
return rv_r_insn(1, rs2, rs1, 0, rd, 0x3b);
|
||||
}
|
||||
|
||||
static inline u32 rv_divw(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 4, rd, 0x3b);
|
||||
}
|
||||
|
||||
static inline u32 rv_divuw(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 5, rd, 0x3b);
|
||||
}
|
||||
|
||||
static inline u32 rv_remw(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 6, rd, 0x3b);
|
||||
}
|
||||
|
||||
static inline u32 rv_remuw(u8 rd, u8 rs1, u8 rs2)
|
||||
{
|
||||
return rv_r_insn(1, rs2, rs1, 7, rd, 0x3b);
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <asm/patch.h>
|
||||
#include "bpf_jit.h"
|
||||
|
||||
#define RV_FENTRY_NINSNS 2
|
||||
|
||||
#define RV_REG_TCC RV_REG_A6
|
||||
#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */
|
||||
|
||||
|
@ -241,7 +243,7 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
|
|||
if (!is_tail_call)
|
||||
emit_mv(RV_REG_A0, RV_REG_A5, ctx);
|
||||
emit_jalr(RV_REG_ZERO, is_tail_call ? RV_REG_T3 : RV_REG_RA,
|
||||
is_tail_call ? 20 : 0, /* skip reserved nops and TCC init */
|
||||
is_tail_call ? (RV_FENTRY_NINSNS + 1) * 4 : 0, /* skip reserved nops and TCC init */
|
||||
ctx);
|
||||
}
|
||||
|
||||
|
@ -578,7 +580,8 @@ static int add_exception_handler(const struct bpf_insn *insn,
|
|||
unsigned long pc;
|
||||
off_t offset;
|
||||
|
||||
if (!ctx->insns || !ctx->prog->aux->extable || BPF_MODE(insn->code) != BPF_PROBE_MEM)
|
||||
if (!ctx->insns || !ctx->prog->aux->extable ||
|
||||
(BPF_MODE(insn->code) != BPF_PROBE_MEM && BPF_MODE(insn->code) != BPF_PROBE_MEMSX))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(ctx->nexentries >= ctx->prog->aux->num_exentries))
|
||||
|
@ -618,32 +621,7 @@ static int add_exception_handler(const struct bpf_insn *insn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gen_call_or_nops(void *target, void *ip, u32 *insns)
|
||||
{
|
||||
s64 rvoff;
|
||||
int i, ret;
|
||||
struct rv_jit_context ctx;
|
||||
|
||||
ctx.ninsns = 0;
|
||||
ctx.insns = (u16 *)insns;
|
||||
|
||||
if (!target) {
|
||||
for (i = 0; i < 4; i++)
|
||||
emit(rv_nop(), &ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rvoff = (s64)(target - (ip + 4));
|
||||
emit(rv_sd(RV_REG_SP, -8, RV_REG_RA), &ctx);
|
||||
ret = emit_jump_and_link(RV_REG_RA, rvoff, false, &ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
emit(rv_ld(RV_REG_RA, -8, RV_REG_SP), &ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_jump_or_nops(void *target, void *ip, u32 *insns)
|
||||
static int gen_jump_or_nops(void *target, void *ip, u32 *insns, bool is_call)
|
||||
{
|
||||
s64 rvoff;
|
||||
struct rv_jit_context ctx;
|
||||
|
@ -658,38 +636,35 @@ static int gen_jump_or_nops(void *target, void *ip, u32 *insns)
|
|||
}
|
||||
|
||||
rvoff = (s64)(target - ip);
|
||||
return emit_jump_and_link(RV_REG_ZERO, rvoff, false, &ctx);
|
||||
return emit_jump_and_link(is_call ? RV_REG_T0 : RV_REG_ZERO, rvoff, false, &ctx);
|
||||
}
|
||||
|
||||
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
|
||||
void *old_addr, void *new_addr)
|
||||
{
|
||||
u32 old_insns[4], new_insns[4];
|
||||
u32 old_insns[RV_FENTRY_NINSNS], new_insns[RV_FENTRY_NINSNS];
|
||||
bool is_call = poke_type == BPF_MOD_CALL;
|
||||
int (*gen_insns)(void *target, void *ip, u32 *insns);
|
||||
int ninsns = is_call ? 4 : 2;
|
||||
int ret;
|
||||
|
||||
if (!is_bpf_text_address((unsigned long)ip))
|
||||
if (!is_kernel_text((unsigned long)ip) &&
|
||||
!is_bpf_text_address((unsigned long)ip))
|
||||
return -ENOTSUPP;
|
||||
|
||||
gen_insns = is_call ? gen_call_or_nops : gen_jump_or_nops;
|
||||
|
||||
ret = gen_insns(old_addr, ip, old_insns);
|
||||
ret = gen_jump_or_nops(old_addr, ip, old_insns, is_call);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (memcmp(ip, old_insns, ninsns * 4))
|
||||
if (memcmp(ip, old_insns, RV_FENTRY_NINSNS * 4))
|
||||
return -EFAULT;
|
||||
|
||||
ret = gen_insns(new_addr, ip, new_insns);
|
||||
ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&text_mutex);
|
||||
if (memcmp(ip, new_insns, ninsns * 4))
|
||||
ret = patch_text(ip, new_insns, ninsns);
|
||||
if (memcmp(ip, new_insns, RV_FENTRY_NINSNS * 4))
|
||||
ret = patch_text(ip, new_insns, RV_FENTRY_NINSNS);
|
||||
mutex_unlock(&text_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
|
@ -787,8 +762,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
int i, ret, offset;
|
||||
int *branches_off = NULL;
|
||||
int stack_size = 0, nregs = m->nr_args;
|
||||
int retaddr_off, fp_off, retval_off, args_off;
|
||||
int nregs_off, ip_off, run_ctx_off, sreg_off;
|
||||
int retval_off, args_off, nregs_off, ip_off, run_ctx_off, sreg_off;
|
||||
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
|
||||
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
|
||||
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
|
||||
|
@ -796,13 +770,27 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
bool save_ret;
|
||||
u32 insn;
|
||||
|
||||
/* Generated trampoline stack layout:
|
||||
/* Two types of generated trampoline stack layout:
|
||||
*
|
||||
* FP - 8 [ RA of parent func ] return address of parent
|
||||
* 1. trampoline called from function entry
|
||||
* --------------------------------------
|
||||
* FP + 8 [ RA to parent func ] return address to parent
|
||||
* function
|
||||
* FP - retaddr_off [ RA of traced func ] return address of traced
|
||||
* FP + 0 [ FP of parent func ] frame pointer of parent
|
||||
* function
|
||||
* FP - fp_off [ FP of parent func ]
|
||||
* FP - 8 [ T0 to traced func ] return address of traced
|
||||
* function
|
||||
* FP - 16 [ FP of traced func ] frame pointer of traced
|
||||
* function
|
||||
* --------------------------------------
|
||||
*
|
||||
* 2. trampoline called directly
|
||||
* --------------------------------------
|
||||
* FP - 8 [ RA to caller func ] return address to caller
|
||||
* function
|
||||
* FP - 16 [ FP of caller func ] frame pointer of caller
|
||||
* function
|
||||
* --------------------------------------
|
||||
*
|
||||
* FP - retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
|
||||
* BPF_TRAMP_F_RET_FENTRY_RET
|
||||
|
@ -833,14 +821,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
if (nregs > 8)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* room for parent function return address */
|
||||
stack_size += 8;
|
||||
|
||||
stack_size += 8;
|
||||
retaddr_off = stack_size;
|
||||
|
||||
stack_size += 8;
|
||||
fp_off = stack_size;
|
||||
/* room of trampoline frame to store return address and frame pointer */
|
||||
stack_size += 16;
|
||||
|
||||
save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET);
|
||||
if (save_ret) {
|
||||
|
@ -867,12 +849,29 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
|
||||
stack_size = round_up(stack_size, 16);
|
||||
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, -stack_size, ctx);
|
||||
if (func_addr) {
|
||||
/* For the trampoline called from function entry,
|
||||
* the frame of traced function and the frame of
|
||||
* trampoline need to be considered.
|
||||
*/
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, -16, ctx);
|
||||
emit_sd(RV_REG_SP, 8, RV_REG_RA, ctx);
|
||||
emit_sd(RV_REG_SP, 0, RV_REG_FP, ctx);
|
||||
emit_addi(RV_REG_FP, RV_REG_SP, 16, ctx);
|
||||
|
||||
emit_sd(RV_REG_SP, stack_size - retaddr_off, RV_REG_RA, ctx);
|
||||
emit_sd(RV_REG_SP, stack_size - fp_off, RV_REG_FP, ctx);
|
||||
|
||||
emit_addi(RV_REG_FP, RV_REG_SP, stack_size, ctx);
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, -stack_size, ctx);
|
||||
emit_sd(RV_REG_SP, stack_size - 8, RV_REG_T0, ctx);
|
||||
emit_sd(RV_REG_SP, stack_size - 16, RV_REG_FP, ctx);
|
||||
emit_addi(RV_REG_FP, RV_REG_SP, stack_size, ctx);
|
||||
} else {
|
||||
/* For the trampoline called directly, just handle
|
||||
* the frame of trampoline.
|
||||
*/
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, -stack_size, ctx);
|
||||
emit_sd(RV_REG_SP, stack_size - 8, RV_REG_RA, ctx);
|
||||
emit_sd(RV_REG_SP, stack_size - 16, RV_REG_FP, ctx);
|
||||
emit_addi(RV_REG_FP, RV_REG_SP, stack_size, ctx);
|
||||
}
|
||||
|
||||
/* callee saved register S1 to pass start time */
|
||||
emit_sd(RV_REG_FP, -sreg_off, RV_REG_S1, ctx);
|
||||
|
@ -890,7 +889,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
|
||||
/* skip to actual body of traced function */
|
||||
if (flags & BPF_TRAMP_F_SKIP_FRAME)
|
||||
orig_call += 16;
|
||||
orig_call += RV_FENTRY_NINSNS * 4;
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
emit_imm(RV_REG_A0, (const s64)im, ctx);
|
||||
|
@ -967,17 +966,30 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
|
||||
emit_ld(RV_REG_S1, -sreg_off, RV_REG_FP, ctx);
|
||||
|
||||
if (flags & BPF_TRAMP_F_SKIP_FRAME)
|
||||
/* return address of parent function */
|
||||
if (func_addr) {
|
||||
/* trampoline called from function entry */
|
||||
emit_ld(RV_REG_T0, stack_size - 8, RV_REG_SP, ctx);
|
||||
emit_ld(RV_REG_FP, stack_size - 16, RV_REG_SP, ctx);
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, stack_size, ctx);
|
||||
|
||||
emit_ld(RV_REG_RA, 8, RV_REG_SP, ctx);
|
||||
emit_ld(RV_REG_FP, 0, RV_REG_SP, ctx);
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, 16, ctx);
|
||||
|
||||
if (flags & BPF_TRAMP_F_SKIP_FRAME)
|
||||
/* return to parent function */
|
||||
emit_jalr(RV_REG_ZERO, RV_REG_RA, 0, ctx);
|
||||
else
|
||||
/* return to traced function */
|
||||
emit_jalr(RV_REG_ZERO, RV_REG_T0, 0, ctx);
|
||||
} else {
|
||||
/* trampoline called directly */
|
||||
emit_ld(RV_REG_RA, stack_size - 8, RV_REG_SP, ctx);
|
||||
else
|
||||
/* return address of traced function */
|
||||
emit_ld(RV_REG_RA, stack_size - retaddr_off, RV_REG_SP, ctx);
|
||||
emit_ld(RV_REG_FP, stack_size - 16, RV_REG_SP, ctx);
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, stack_size, ctx);
|
||||
|
||||
emit_ld(RV_REG_FP, stack_size - fp_off, RV_REG_SP, ctx);
|
||||
emit_addi(RV_REG_SP, RV_REG_SP, stack_size, ctx);
|
||||
|
||||
emit_jalr(RV_REG_ZERO, RV_REG_RA, 0, ctx);
|
||||
emit_jalr(RV_REG_ZERO, RV_REG_RA, 0, ctx);
|
||||
}
|
||||
|
||||
ret = ctx->ninsns;
|
||||
out:
|
||||
|
@ -1035,7 +1047,19 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
|
|||
emit_zext_32(rd, ctx);
|
||||
break;
|
||||
}
|
||||
emit_mv(rd, rs, ctx);
|
||||
switch (insn->off) {
|
||||
case 0:
|
||||
emit_mv(rd, rs, ctx);
|
||||
break;
|
||||
case 8:
|
||||
case 16:
|
||||
emit_slli(RV_REG_T1, rs, 64 - insn->off, ctx);
|
||||
emit_srai(rd, RV_REG_T1, 64 - insn->off, ctx);
|
||||
break;
|
||||
case 32:
|
||||
emit_addiw(rd, rs, 0, ctx);
|
||||
break;
|
||||
}
|
||||
if (!is64 && !aux->verifier_zext)
|
||||
emit_zext_32(rd, ctx);
|
||||
break;
|
||||
|
@ -1083,13 +1107,19 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
|
|||
break;
|
||||
case BPF_ALU | BPF_DIV | BPF_X:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
emit(is64 ? rv_divu(rd, rd, rs) : rv_divuw(rd, rd, rs), ctx);
|
||||
if (off)
|
||||
emit(is64 ? rv_div(rd, rd, rs) : rv_divw(rd, rd, rs), ctx);
|
||||
else
|
||||
emit(is64 ? rv_divu(rd, rd, rs) : rv_divuw(rd, rd, rs), ctx);
|
||||
if (!is64 && !aux->verifier_zext)
|
||||
emit_zext_32(rd, ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_MOD | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
emit(is64 ? rv_remu(rd, rd, rs) : rv_remuw(rd, rd, rs), ctx);
|
||||
if (off)
|
||||
emit(is64 ? rv_rem(rd, rd, rs) : rv_remw(rd, rd, rs), ctx);
|
||||
else
|
||||
emit(is64 ? rv_remu(rd, rd, rs) : rv_remuw(rd, rd, rs), ctx);
|
||||
if (!is64 && !aux->verifier_zext)
|
||||
emit_zext_32(rd, ctx);
|
||||
break;
|
||||
|
@ -1138,6 +1168,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
|
|||
break;
|
||||
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
||||
case BPF_ALU64 | BPF_END | BPF_FROM_LE:
|
||||
emit_li(RV_REG_T2, 0, ctx);
|
||||
|
||||
emit_andi(RV_REG_T1, rd, 0xff, ctx);
|
||||
|
@ -1260,16 +1291,24 @@ out_be:
|
|||
case BPF_ALU | BPF_DIV | BPF_K:
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K:
|
||||
emit_imm(RV_REG_T1, imm, ctx);
|
||||
emit(is64 ? rv_divu(rd, rd, RV_REG_T1) :
|
||||
rv_divuw(rd, rd, RV_REG_T1), ctx);
|
||||
if (off)
|
||||
emit(is64 ? rv_div(rd, rd, RV_REG_T1) :
|
||||
rv_divw(rd, rd, RV_REG_T1), ctx);
|
||||
else
|
||||
emit(is64 ? rv_divu(rd, rd, RV_REG_T1) :
|
||||
rv_divuw(rd, rd, RV_REG_T1), ctx);
|
||||
if (!is64 && !aux->verifier_zext)
|
||||
emit_zext_32(rd, ctx);
|
||||
break;
|
||||
case BPF_ALU | BPF_MOD | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
emit_imm(RV_REG_T1, imm, ctx);
|
||||
emit(is64 ? rv_remu(rd, rd, RV_REG_T1) :
|
||||
rv_remuw(rd, rd, RV_REG_T1), ctx);
|
||||
if (off)
|
||||
emit(is64 ? rv_rem(rd, rd, RV_REG_T1) :
|
||||
rv_remw(rd, rd, RV_REG_T1), ctx);
|
||||
else
|
||||
emit(is64 ? rv_remu(rd, rd, RV_REG_T1) :
|
||||
rv_remuw(rd, rd, RV_REG_T1), ctx);
|
||||
if (!is64 && !aux->verifier_zext)
|
||||
emit_zext_32(rd, ctx);
|
||||
break;
|
||||
|
@ -1303,7 +1342,11 @@ out_be:
|
|||
|
||||
/* JUMP off */
|
||||
case BPF_JMP | BPF_JA:
|
||||
rvoff = rv_offset(i, off, ctx);
|
||||
case BPF_JMP32 | BPF_JA:
|
||||
if (BPF_CLASS(code) == BPF_JMP)
|
||||
rvoff = rv_offset(i, off, ctx);
|
||||
else
|
||||
rvoff = rv_offset(i, imm, ctx);
|
||||
ret = emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1475,7 +1518,7 @@ out_be:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* LDX: dst = *(size *)(src + off) */
|
||||
/* LDX: dst = *(unsigned size *)(src + off) */
|
||||
case BPF_LDX | BPF_MEM | BPF_B:
|
||||
case BPF_LDX | BPF_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_MEM | BPF_W:
|
||||
|
@ -1484,14 +1527,28 @@ out_be:
|
|||
case BPF_LDX | BPF_PROBE_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
|
||||
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
|
||||
/* LDSX: dst = *(signed size *)(src + off) */
|
||||
case BPF_LDX | BPF_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_W:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_W:
|
||||
{
|
||||
int insn_len, insns_start;
|
||||
bool sign_ext;
|
||||
|
||||
sign_ext = BPF_MODE(insn->code) == BPF_MEMSX ||
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEMSX;
|
||||
|
||||
switch (BPF_SIZE(code)) {
|
||||
case BPF_B:
|
||||
if (is_12b_int(off)) {
|
||||
insns_start = ctx->ninsns;
|
||||
emit(rv_lbu(rd, off, rs), ctx);
|
||||
if (sign_ext)
|
||||
emit(rv_lb(rd, off, rs), ctx);
|
||||
else
|
||||
emit(rv_lbu(rd, off, rs), ctx);
|
||||
insn_len = ctx->ninsns - insns_start;
|
||||
break;
|
||||
}
|
||||
|
@ -1499,15 +1556,19 @@ out_be:
|
|||
emit_imm(RV_REG_T1, off, ctx);
|
||||
emit_add(RV_REG_T1, RV_REG_T1, rs, ctx);
|
||||
insns_start = ctx->ninsns;
|
||||
emit(rv_lbu(rd, 0, RV_REG_T1), ctx);
|
||||
if (sign_ext)
|
||||
emit(rv_lb(rd, 0, RV_REG_T1), ctx);
|
||||
else
|
||||
emit(rv_lbu(rd, 0, RV_REG_T1), ctx);
|
||||
insn_len = ctx->ninsns - insns_start;
|
||||
if (insn_is_zext(&insn[1]))
|
||||
return 1;
|
||||
break;
|
||||
case BPF_H:
|
||||
if (is_12b_int(off)) {
|
||||
insns_start = ctx->ninsns;
|
||||
emit(rv_lhu(rd, off, rs), ctx);
|
||||
if (sign_ext)
|
||||
emit(rv_lh(rd, off, rs), ctx);
|
||||
else
|
||||
emit(rv_lhu(rd, off, rs), ctx);
|
||||
insn_len = ctx->ninsns - insns_start;
|
||||
break;
|
||||
}
|
||||
|
@ -1515,15 +1576,19 @@ out_be:
|
|||
emit_imm(RV_REG_T1, off, ctx);
|
||||
emit_add(RV_REG_T1, RV_REG_T1, rs, ctx);
|
||||
insns_start = ctx->ninsns;
|
||||
emit(rv_lhu(rd, 0, RV_REG_T1), ctx);
|
||||
if (sign_ext)
|
||||
emit(rv_lh(rd, 0, RV_REG_T1), ctx);
|
||||
else
|
||||
emit(rv_lhu(rd, 0, RV_REG_T1), ctx);
|
||||
insn_len = ctx->ninsns - insns_start;
|
||||
if (insn_is_zext(&insn[1]))
|
||||
return 1;
|
||||
break;
|
||||
case BPF_W:
|
||||
if (is_12b_int(off)) {
|
||||
insns_start = ctx->ninsns;
|
||||
emit(rv_lwu(rd, off, rs), ctx);
|
||||
if (sign_ext)
|
||||
emit(rv_lw(rd, off, rs), ctx);
|
||||
else
|
||||
emit(rv_lwu(rd, off, rs), ctx);
|
||||
insn_len = ctx->ninsns - insns_start;
|
||||
break;
|
||||
}
|
||||
|
@ -1531,10 +1596,11 @@ out_be:
|
|||
emit_imm(RV_REG_T1, off, ctx);
|
||||
emit_add(RV_REG_T1, RV_REG_T1, rs, ctx);
|
||||
insns_start = ctx->ninsns;
|
||||
emit(rv_lwu(rd, 0, RV_REG_T1), ctx);
|
||||
if (sign_ext)
|
||||
emit(rv_lw(rd, 0, RV_REG_T1), ctx);
|
||||
else
|
||||
emit(rv_lwu(rd, 0, RV_REG_T1), ctx);
|
||||
insn_len = ctx->ninsns - insns_start;
|
||||
if (insn_is_zext(&insn[1]))
|
||||
return 1;
|
||||
break;
|
||||
case BPF_DW:
|
||||
if (is_12b_int(off)) {
|
||||
|
@ -1555,6 +1621,9 @@ out_be:
|
|||
ret = add_exception_handler(insn, ctx, rd, insn_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
/* speculation barrier */
|
||||
|
@ -1691,8 +1760,8 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx)
|
|||
|
||||
store_offset = stack_adjust - 8;
|
||||
|
||||
/* reserve 4 nop insns */
|
||||
for (i = 0; i < 4; i++)
|
||||
/* nops reserved for auipc+jalr pair */
|
||||
for (i = 0; i < RV_FENTRY_NINSNS; i++)
|
||||
emit(rv_nop(), ctx);
|
||||
|
||||
/* First instruction is always setting the tail-call-counter
|
||||
|
|
|
@ -701,6 +701,38 @@ static void emit_mov_reg(u8 **pprog, bool is64, u32 dst_reg, u32 src_reg)
|
|||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void emit_movsx_reg(u8 **pprog, int num_bits, bool is64, u32 dst_reg,
|
||||
u32 src_reg)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
if (is64) {
|
||||
/* movs[b,w,l]q dst, src */
|
||||
if (num_bits == 8)
|
||||
EMIT4(add_2mod(0x48, src_reg, dst_reg), 0x0f, 0xbe,
|
||||
add_2reg(0xC0, src_reg, dst_reg));
|
||||
else if (num_bits == 16)
|
||||
EMIT4(add_2mod(0x48, src_reg, dst_reg), 0x0f, 0xbf,
|
||||
add_2reg(0xC0, src_reg, dst_reg));
|
||||
else if (num_bits == 32)
|
||||
EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x63,
|
||||
add_2reg(0xC0, src_reg, dst_reg));
|
||||
} else {
|
||||
/* movs[b,w]l dst, src */
|
||||
if (num_bits == 8) {
|
||||
EMIT4(add_2mod(0x40, src_reg, dst_reg), 0x0f, 0xbe,
|
||||
add_2reg(0xC0, src_reg, dst_reg));
|
||||
} else if (num_bits == 16) {
|
||||
if (is_ereg(dst_reg) || is_ereg(src_reg))
|
||||
EMIT1(add_2mod(0x40, src_reg, dst_reg));
|
||||
EMIT3(add_2mod(0x0f, src_reg, dst_reg), 0xbf,
|
||||
add_2reg(0xC0, src_reg, dst_reg));
|
||||
}
|
||||
}
|
||||
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
/* Emit the suffix (ModR/M etc) for addressing *(ptr_reg + off) and val_reg */
|
||||
static void emit_insn_suffix(u8 **pprog, u32 ptr_reg, u32 val_reg, int off)
|
||||
{
|
||||
|
@ -779,6 +811,29 @@ static void emit_ldx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
|
|||
*pprog = prog;
|
||||
}
|
||||
|
||||
/* LDSX: dst_reg = *(s8*)(src_reg + off) */
|
||||
static void emit_ldsx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
switch (size) {
|
||||
case BPF_B:
|
||||
/* Emit 'movsx rax, byte ptr [rax + off]' */
|
||||
EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x0F, 0xBE);
|
||||
break;
|
||||
case BPF_H:
|
||||
/* Emit 'movsx rax, word ptr [rax + off]' */
|
||||
EMIT3(add_2mod(0x48, src_reg, dst_reg), 0x0F, 0xBF);
|
||||
break;
|
||||
case BPF_W:
|
||||
/* Emit 'movsx rax, dword ptr [rax+0x14]' */
|
||||
EMIT2(add_2mod(0x48, src_reg, dst_reg), 0x63);
|
||||
break;
|
||||
}
|
||||
emit_insn_suffix(&prog, src_reg, dst_reg, off);
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
/* STX: *(u8*)(dst_reg + off) = src_reg */
|
||||
static void emit_stx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
|
||||
{
|
||||
|
@ -1028,9 +1083,14 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
|||
|
||||
case BPF_ALU64 | BPF_MOV | BPF_X:
|
||||
case BPF_ALU | BPF_MOV | BPF_X:
|
||||
emit_mov_reg(&prog,
|
||||
BPF_CLASS(insn->code) == BPF_ALU64,
|
||||
dst_reg, src_reg);
|
||||
if (insn->off == 0)
|
||||
emit_mov_reg(&prog,
|
||||
BPF_CLASS(insn->code) == BPF_ALU64,
|
||||
dst_reg, src_reg);
|
||||
else
|
||||
emit_movsx_reg(&prog, insn->off,
|
||||
BPF_CLASS(insn->code) == BPF_ALU64,
|
||||
dst_reg, src_reg);
|
||||
break;
|
||||
|
||||
/* neg dst */
|
||||
|
@ -1134,15 +1194,26 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
|||
/* mov rax, dst_reg */
|
||||
emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);
|
||||
|
||||
/*
|
||||
* xor edx, edx
|
||||
* equivalent to 'xor rdx, rdx', but one byte less
|
||||
*/
|
||||
EMIT2(0x31, 0xd2);
|
||||
if (insn->off == 0) {
|
||||
/*
|
||||
* xor edx, edx
|
||||
* equivalent to 'xor rdx, rdx', but one byte less
|
||||
*/
|
||||
EMIT2(0x31, 0xd2);
|
||||
|
||||
/* div src_reg */
|
||||
maybe_emit_1mod(&prog, src_reg, is64);
|
||||
EMIT2(0xF7, add_1reg(0xF0, src_reg));
|
||||
/* div src_reg */
|
||||
maybe_emit_1mod(&prog, src_reg, is64);
|
||||
EMIT2(0xF7, add_1reg(0xF0, src_reg));
|
||||
} else {
|
||||
if (BPF_CLASS(insn->code) == BPF_ALU)
|
||||
EMIT1(0x99); /* cdq */
|
||||
else
|
||||
EMIT2(0x48, 0x99); /* cqo */
|
||||
|
||||
/* idiv src_reg */
|
||||
maybe_emit_1mod(&prog, src_reg, is64);
|
||||
EMIT2(0xF7, add_1reg(0xF8, src_reg));
|
||||
}
|
||||
|
||||
if (BPF_OP(insn->code) == BPF_MOD &&
|
||||
dst_reg != BPF_REG_3)
|
||||
|
@ -1262,6 +1333,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
|||
break;
|
||||
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
||||
case BPF_ALU64 | BPF_END | BPF_FROM_LE:
|
||||
switch (imm32) {
|
||||
case 16:
|
||||
/* Emit 'ror %ax, 8' to swap lower 2 bytes */
|
||||
|
@ -1370,9 +1442,17 @@ st: if (is_imm8(insn->off))
|
|||
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
|
||||
case BPF_LDX | BPF_MEM | BPF_DW:
|
||||
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
|
||||
/* LDXS: dst_reg = *(s8*)(src_reg + off) */
|
||||
case BPF_LDX | BPF_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_W:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_PROBE_MEMSX | BPF_W:
|
||||
insn_off = insn->off;
|
||||
|
||||
if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
|
||||
if (BPF_MODE(insn->code) == BPF_PROBE_MEM ||
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEMSX) {
|
||||
/* Conservatively check that src_reg + insn->off is a kernel address:
|
||||
* src_reg + insn->off >= TASK_SIZE_MAX + PAGE_SIZE
|
||||
* src_reg is used as scratch for src_reg += insn->off and restored
|
||||
|
@ -1415,8 +1495,13 @@ st: if (is_imm8(insn->off))
|
|||
start_of_ldx = prog;
|
||||
end_of_jmp[-1] = start_of_ldx - end_of_jmp;
|
||||
}
|
||||
emit_ldx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn_off);
|
||||
if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
|
||||
if (BPF_MODE(insn->code) == BPF_PROBE_MEMSX ||
|
||||
BPF_MODE(insn->code) == BPF_MEMSX)
|
||||
emit_ldsx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn_off);
|
||||
else
|
||||
emit_ldx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn_off);
|
||||
if (BPF_MODE(insn->code) == BPF_PROBE_MEM ||
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEMSX) {
|
||||
struct exception_table_entry *ex;
|
||||
u8 *_insn = image + proglen + (start_of_ldx - temp);
|
||||
s64 delta;
|
||||
|
@ -1730,16 +1815,24 @@ emit_cond_jmp: /* Convert BPF opcode to x86 */
|
|||
break;
|
||||
|
||||
case BPF_JMP | BPF_JA:
|
||||
if (insn->off == -1)
|
||||
/* -1 jmp instructions will always jump
|
||||
* backwards two bytes. Explicitly handling
|
||||
* this case avoids wasting too many passes
|
||||
* when there are long sequences of replaced
|
||||
* dead code.
|
||||
*/
|
||||
jmp_offset = -2;
|
||||
else
|
||||
jmp_offset = addrs[i + insn->off] - addrs[i];
|
||||
case BPF_JMP32 | BPF_JA:
|
||||
if (BPF_CLASS(insn->code) == BPF_JMP) {
|
||||
if (insn->off == -1)
|
||||
/* -1 jmp instructions will always jump
|
||||
* backwards two bytes. Explicitly handling
|
||||
* this case avoids wasting too many passes
|
||||
* when there are long sequences of replaced
|
||||
* dead code.
|
||||
*/
|
||||
jmp_offset = -2;
|
||||
else
|
||||
jmp_offset = addrs[i + insn->off] - addrs[i];
|
||||
} else {
|
||||
if (insn->imm == -1)
|
||||
jmp_offset = -2;
|
||||
else
|
||||
jmp_offset = addrs[i + insn->imm] - addrs[i];
|
||||
}
|
||||
|
||||
if (!jmp_offset) {
|
||||
/*
|
||||
|
@ -1857,59 +1950,177 @@ emit_jmp:
|
|||
return proglen;
|
||||
}
|
||||
|
||||
static void save_regs(const struct btf_func_model *m, u8 **prog, int nr_regs,
|
||||
int stack_size)
|
||||
static void clean_stack_garbage(const struct btf_func_model *m,
|
||||
u8 **pprog, int nr_stack_slots,
|
||||
int stack_size)
|
||||
{
|
||||
int i, j, arg_size;
|
||||
bool next_same_struct = false;
|
||||
int arg_size, off;
|
||||
u8 *prog;
|
||||
|
||||
/* Generally speaking, the compiler will pass the arguments
|
||||
* on-stack with "push" instruction, which will take 8-byte
|
||||
* on the stack. In this case, there won't be garbage values
|
||||
* while we copy the arguments from origin stack frame to current
|
||||
* in BPF_DW.
|
||||
*
|
||||
* However, sometimes the compiler will only allocate 4-byte on
|
||||
* the stack for the arguments. For now, this case will only
|
||||
* happen if there is only one argument on-stack and its size
|
||||
* not more than 4 byte. In this case, there will be garbage
|
||||
* values on the upper 4-byte where we store the argument on
|
||||
* current stack frame.
|
||||
*
|
||||
* arguments on origin stack:
|
||||
*
|
||||
* stack_arg_1(4-byte) xxx(4-byte)
|
||||
*
|
||||
* what we copy:
|
||||
*
|
||||
* stack_arg_1(8-byte): stack_arg_1(origin) xxx
|
||||
*
|
||||
* and the xxx is the garbage values which we should clean here.
|
||||
*/
|
||||
if (nr_stack_slots != 1)
|
||||
return;
|
||||
|
||||
/* the size of the last argument */
|
||||
arg_size = m->arg_size[m->nr_args - 1];
|
||||
if (arg_size <= 4) {
|
||||
off = -(stack_size - 4);
|
||||
prog = *pprog;
|
||||
/* mov DWORD PTR [rbp + off], 0 */
|
||||
if (!is_imm8(off))
|
||||
EMIT2_off32(0xC7, 0x85, off);
|
||||
else
|
||||
EMIT3(0xC7, 0x45, off);
|
||||
EMIT(0, 4);
|
||||
*pprog = prog;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the count of the regs that are used to pass arguments */
|
||||
static int get_nr_used_regs(const struct btf_func_model *m)
|
||||
{
|
||||
int i, arg_regs, nr_used_regs = 0;
|
||||
|
||||
for (i = 0; i < min_t(int, m->nr_args, MAX_BPF_FUNC_ARGS); i++) {
|
||||
arg_regs = (m->arg_size[i] + 7) / 8;
|
||||
if (nr_used_regs + arg_regs <= 6)
|
||||
nr_used_regs += arg_regs;
|
||||
|
||||
if (nr_used_regs >= 6)
|
||||
break;
|
||||
}
|
||||
|
||||
return nr_used_regs;
|
||||
}
|
||||
|
||||
static void save_args(const struct btf_func_model *m, u8 **prog,
|
||||
int stack_size, bool for_call_origin)
|
||||
{
|
||||
int arg_regs, first_off = 0, nr_regs = 0, nr_stack_slots = 0;
|
||||
int i, j;
|
||||
|
||||
/* Store function arguments to stack.
|
||||
* For a function that accepts two pointers the sequence will be:
|
||||
* mov QWORD PTR [rbp-0x10],rdi
|
||||
* mov QWORD PTR [rbp-0x8],rsi
|
||||
*/
|
||||
for (i = 0, j = 0; i < min(nr_regs, 6); i++) {
|
||||
/* The arg_size is at most 16 bytes, enforced by the verifier. */
|
||||
arg_size = m->arg_size[j];
|
||||
if (arg_size > 8) {
|
||||
arg_size = 8;
|
||||
next_same_struct = !next_same_struct;
|
||||
for (i = 0; i < min_t(int, m->nr_args, MAX_BPF_FUNC_ARGS); i++) {
|
||||
arg_regs = (m->arg_size[i] + 7) / 8;
|
||||
|
||||
/* According to the research of Yonghong, struct members
|
||||
* should be all in register or all on the stack.
|
||||
* Meanwhile, the compiler will pass the argument on regs
|
||||
* if the remaining regs can hold the argument.
|
||||
*
|
||||
* Disorder of the args can happen. For example:
|
||||
*
|
||||
* struct foo_struct {
|
||||
* long a;
|
||||
* int b;
|
||||
* };
|
||||
* int foo(char, char, char, char, char, struct foo_struct,
|
||||
* char);
|
||||
*
|
||||
* the arg1-5,arg7 will be passed by regs, and arg6 will
|
||||
* by stack.
|
||||
*/
|
||||
if (nr_regs + arg_regs > 6) {
|
||||
/* copy function arguments from origin stack frame
|
||||
* into current stack frame.
|
||||
*
|
||||
* The starting address of the arguments on-stack
|
||||
* is:
|
||||
* rbp + 8(push rbp) +
|
||||
* 8(return addr of origin call) +
|
||||
* 8(return addr of the caller)
|
||||
* which means: rbp + 24
|
||||
*/
|
||||
for (j = 0; j < arg_regs; j++) {
|
||||
emit_ldx(prog, BPF_DW, BPF_REG_0, BPF_REG_FP,
|
||||
nr_stack_slots * 8 + 0x18);
|
||||
emit_stx(prog, BPF_DW, BPF_REG_FP, BPF_REG_0,
|
||||
-stack_size);
|
||||
|
||||
if (!nr_stack_slots)
|
||||
first_off = stack_size;
|
||||
stack_size -= 8;
|
||||
nr_stack_slots++;
|
||||
}
|
||||
} else {
|
||||
/* Only copy the arguments on-stack to current
|
||||
* 'stack_size' and ignore the regs, used to
|
||||
* prepare the arguments on-stack for orign call.
|
||||
*/
|
||||
if (for_call_origin) {
|
||||
nr_regs += arg_regs;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy the arguments from regs into stack */
|
||||
for (j = 0; j < arg_regs; j++) {
|
||||
emit_stx(prog, BPF_DW, BPF_REG_FP,
|
||||
nr_regs == 5 ? X86_REG_R9 : BPF_REG_1 + nr_regs,
|
||||
-stack_size);
|
||||
stack_size -= 8;
|
||||
nr_regs++;
|
||||
}
|
||||
}
|
||||
|
||||
emit_stx(prog, bytes_to_bpf_size(arg_size),
|
||||
BPF_REG_FP,
|
||||
i == 5 ? X86_REG_R9 : BPF_REG_1 + i,
|
||||
-(stack_size - i * 8));
|
||||
|
||||
j = next_same_struct ? j : j + 1;
|
||||
}
|
||||
|
||||
clean_stack_garbage(m, prog, nr_stack_slots, first_off);
|
||||
}
|
||||
|
||||
static void restore_regs(const struct btf_func_model *m, u8 **prog, int nr_regs,
|
||||
static void restore_regs(const struct btf_func_model *m, u8 **prog,
|
||||
int stack_size)
|
||||
{
|
||||
int i, j, arg_size;
|
||||
bool next_same_struct = false;
|
||||
int i, j, arg_regs, nr_regs = 0;
|
||||
|
||||
/* Restore function arguments from stack.
|
||||
* For a function that accepts two pointers the sequence will be:
|
||||
* EMIT4(0x48, 0x8B, 0x7D, 0xF0); mov rdi,QWORD PTR [rbp-0x10]
|
||||
* EMIT4(0x48, 0x8B, 0x75, 0xF8); mov rsi,QWORD PTR [rbp-0x8]
|
||||
*
|
||||
* The logic here is similar to what we do in save_args()
|
||||
*/
|
||||
for (i = 0, j = 0; i < min(nr_regs, 6); i++) {
|
||||
/* The arg_size is at most 16 bytes, enforced by the verifier. */
|
||||
arg_size = m->arg_size[j];
|
||||
if (arg_size > 8) {
|
||||
arg_size = 8;
|
||||
next_same_struct = !next_same_struct;
|
||||
for (i = 0; i < min_t(int, m->nr_args, MAX_BPF_FUNC_ARGS); i++) {
|
||||
arg_regs = (m->arg_size[i] + 7) / 8;
|
||||
if (nr_regs + arg_regs <= 6) {
|
||||
for (j = 0; j < arg_regs; j++) {
|
||||
emit_ldx(prog, BPF_DW,
|
||||
nr_regs == 5 ? X86_REG_R9 : BPF_REG_1 + nr_regs,
|
||||
BPF_REG_FP,
|
||||
-stack_size);
|
||||
stack_size -= 8;
|
||||
nr_regs++;
|
||||
}
|
||||
} else {
|
||||
stack_size -= 8 * arg_regs;
|
||||
}
|
||||
|
||||
emit_ldx(prog, bytes_to_bpf_size(arg_size),
|
||||
i == 5 ? X86_REG_R9 : BPF_REG_1 + i,
|
||||
BPF_REG_FP,
|
||||
-(stack_size - i * 8));
|
||||
|
||||
j = next_same_struct ? j : j + 1;
|
||||
if (nr_regs >= 6)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1938,7 +2149,10 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
|
|||
/* arg1: mov rdi, progs[i] */
|
||||
emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, (u32) (long) p);
|
||||
/* arg2: lea rsi, [rbp - ctx_cookie_off] */
|
||||
EMIT4(0x48, 0x8D, 0x75, -run_ctx_off);
|
||||
if (!is_imm8(-run_ctx_off))
|
||||
EMIT3_off32(0x48, 0x8D, 0xB5, -run_ctx_off);
|
||||
else
|
||||
EMIT4(0x48, 0x8D, 0x75, -run_ctx_off);
|
||||
|
||||
if (emit_rsb_call(&prog, bpf_trampoline_enter(p), prog))
|
||||
return -EINVAL;
|
||||
|
@ -1954,7 +2168,10 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
|
|||
emit_nops(&prog, 2);
|
||||
|
||||
/* arg1: lea rdi, [rbp - stack_size] */
|
||||
EMIT4(0x48, 0x8D, 0x7D, -stack_size);
|
||||
if (!is_imm8(-stack_size))
|
||||
EMIT3_off32(0x48, 0x8D, 0xBD, -stack_size);
|
||||
else
|
||||
EMIT4(0x48, 0x8D, 0x7D, -stack_size);
|
||||
/* arg2: progs[i]->insnsi for interpreter */
|
||||
if (!p->jited)
|
||||
emit_mov_imm64(&prog, BPF_REG_2,
|
||||
|
@ -1984,7 +2201,10 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
|
|||
/* arg2: mov rsi, rbx <- start time in nsec */
|
||||
emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6);
|
||||
/* arg3: lea rdx, [rbp - run_ctx_off] */
|
||||
EMIT4(0x48, 0x8D, 0x55, -run_ctx_off);
|
||||
if (!is_imm8(-run_ctx_off))
|
||||
EMIT3_off32(0x48, 0x8D, 0x95, -run_ctx_off);
|
||||
else
|
||||
EMIT4(0x48, 0x8D, 0x55, -run_ctx_off);
|
||||
if (emit_rsb_call(&prog, bpf_trampoline_exit(p), prog))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -2136,7 +2356,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
void *func_addr)
|
||||
{
|
||||
int i, ret, nr_regs = m->nr_args, stack_size = 0;
|
||||
int regs_off, nregs_off, ip_off, run_ctx_off;
|
||||
int regs_off, nregs_off, ip_off, run_ctx_off, arg_stack_off, rbx_off;
|
||||
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
|
||||
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
|
||||
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
|
||||
|
@ -2150,8 +2370,10 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG)
|
||||
nr_regs += (m->arg_size[i] + 7) / 8 - 1;
|
||||
|
||||
/* x86-64 supports up to 6 arguments. 7+ can be added in the future */
|
||||
if (nr_regs > 6)
|
||||
/* x86-64 supports up to MAX_BPF_FUNC_ARGS arguments. 1-6
|
||||
* are passed through regs, the remains are through stack.
|
||||
*/
|
||||
if (nr_regs > MAX_BPF_FUNC_ARGS)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* Generated trampoline stack layout:
|
||||
|
@ -2170,7 +2392,14 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
*
|
||||
* RBP - ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
|
||||
*
|
||||
* RBP - rbx_off [ rbx value ] always
|
||||
*
|
||||
* RBP - run_ctx_off [ bpf_tramp_run_ctx ]
|
||||
*
|
||||
* [ stack_argN ] BPF_TRAMP_F_CALL_ORIG
|
||||
* [ ... ]
|
||||
* [ stack_arg2 ]
|
||||
* RBP - arg_stack_off [ stack_arg1 ]
|
||||
*/
|
||||
|
||||
/* room for return value of orig_call or fentry prog */
|
||||
|
@ -2190,9 +2419,26 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
|
||||
ip_off = stack_size;
|
||||
|
||||
stack_size += 8;
|
||||
rbx_off = stack_size;
|
||||
|
||||
stack_size += (sizeof(struct bpf_tramp_run_ctx) + 7) & ~0x7;
|
||||
run_ctx_off = stack_size;
|
||||
|
||||
if (nr_regs > 6 && (flags & BPF_TRAMP_F_CALL_ORIG)) {
|
||||
/* the space that used to pass arguments on-stack */
|
||||
stack_size += (nr_regs - get_nr_used_regs(m)) * 8;
|
||||
/* make sure the stack pointer is 16-byte aligned if we
|
||||
* need pass arguments on stack, which means
|
||||
* [stack_size + 8(rbp) + 8(rip) + 8(origin rip)]
|
||||
* should be 16-byte aligned. Following code depend on
|
||||
* that stack_size is already 8-byte aligned.
|
||||
*/
|
||||
stack_size += (stack_size % 16) ? 0 : 8;
|
||||
}
|
||||
|
||||
arg_stack_off = stack_size;
|
||||
|
||||
if (flags & BPF_TRAMP_F_SKIP_FRAME) {
|
||||
/* skip patched call instruction and point orig_call to actual
|
||||
* body of the kernel function.
|
||||
|
@ -2212,8 +2458,14 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
x86_call_depth_emit_accounting(&prog, NULL);
|
||||
EMIT1(0x55); /* push rbp */
|
||||
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
||||
EMIT4(0x48, 0x83, 0xEC, stack_size); /* sub rsp, stack_size */
|
||||
EMIT1(0x53); /* push rbx */
|
||||
if (!is_imm8(stack_size))
|
||||
/* sub rsp, stack_size */
|
||||
EMIT3_off32(0x48, 0x81, 0xEC, stack_size);
|
||||
else
|
||||
/* sub rsp, stack_size */
|
||||
EMIT4(0x48, 0x83, 0xEC, stack_size);
|
||||
/* mov QWORD PTR [rbp - rbx_off], rbx */
|
||||
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_6, -rbx_off);
|
||||
|
||||
/* Store number of argument registers of the traced function:
|
||||
* mov rax, nr_regs
|
||||
|
@ -2231,7 +2483,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -ip_off);
|
||||
}
|
||||
|
||||
save_regs(m, &prog, nr_regs, regs_off);
|
||||
save_args(m, &prog, regs_off, false);
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
/* arg1: mov rdi, im */
|
||||
|
@ -2261,7 +2513,8 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
}
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
restore_regs(m, &prog, nr_regs, regs_off);
|
||||
restore_regs(m, &prog, regs_off);
|
||||
save_args(m, &prog, arg_stack_off, true);
|
||||
|
||||
if (flags & BPF_TRAMP_F_ORIG_STACK) {
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, 8);
|
||||
|
@ -2302,7 +2555,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
}
|
||||
|
||||
if (flags & BPF_TRAMP_F_RESTORE_REGS)
|
||||
restore_regs(m, &prog, nr_regs, regs_off);
|
||||
restore_regs(m, &prog, regs_off);
|
||||
|
||||
/* This needs to be done regardless. If there were fmod_ret programs,
|
||||
* the return value is only updated on the stack and still needs to be
|
||||
|
@ -2321,7 +2574,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
|||
if (save_ret)
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8);
|
||||
|
||||
EMIT1(0x5B); /* pop rbx */
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, -rbx_off);
|
||||
EMIT1(0xC9); /* leave */
|
||||
if (flags & BPF_TRAMP_F_SKIP_FRAME)
|
||||
/* skip our return address and return to parent */
|
||||
|
|
|
@ -159,7 +159,7 @@ static int drbd_msg_sprintf_info(struct sk_buff *skb, const char *fmt, ...)
|
|||
static int drbd_adm_prepare(struct drbd_config_context *adm_ctx,
|
||||
struct sk_buff *skb, struct genl_info *info, unsigned flags)
|
||||
{
|
||||
struct drbd_genlmsghdr *d_in = info->userhdr;
|
||||
struct drbd_genlmsghdr *d_in = genl_info_userhdr(info);
|
||||
const u8 cmd = info->genlhdr->cmd;
|
||||
int err;
|
||||
|
||||
|
@ -1396,8 +1396,9 @@ static void drbd_suspend_al(struct drbd_device *device)
|
|||
|
||||
static bool should_set_defaults(struct genl_info *info)
|
||||
{
|
||||
unsigned flags = ((struct drbd_genlmsghdr*)info->userhdr)->flags;
|
||||
return 0 != (flags & DRBD_GENL_F_SET_DEFAULTS);
|
||||
struct drbd_genlmsghdr *dh = genl_info_userhdr(info);
|
||||
|
||||
return 0 != (dh->flags & DRBD_GENL_F_SET_DEFAULTS);
|
||||
}
|
||||
|
||||
static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
|
||||
|
@ -4276,7 +4277,7 @@ static void device_to_info(struct device_info *info,
|
|||
int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct drbd_config_context adm_ctx;
|
||||
struct drbd_genlmsghdr *dh = info->userhdr;
|
||||
struct drbd_genlmsghdr *dh = genl_info_userhdr(info);
|
||||
enum drbd_ret_code retcode;
|
||||
|
||||
retcode = drbd_adm_prepare(&adm_ctx, skb, info, DRBD_ADM_NEED_RESOURCE);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}})
|
||||
#define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}})
|
||||
#define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}})
|
||||
#define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}})
|
||||
#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
|
||||
#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
|
||||
#define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}})
|
||||
|
@ -115,6 +116,9 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
|
|||
*
|
||||
* The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller
|
||||
* with no configured address.
|
||||
*
|
||||
* The address AA:AA:AA:AA:AA:AA indicates a BCM43430A1 controller
|
||||
* with no configured address.
|
||||
*/
|
||||
if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
|
||||
!bacmp(&bda->bdaddr, BDADDR_BCM20702A1) ||
|
||||
|
@ -124,6 +128,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
|
|||
!bacmp(&bda->bdaddr, BDADDR_BCM4334B0) ||
|
||||
!bacmp(&bda->bdaddr, BDADDR_BCM4345C5) ||
|
||||
!bacmp(&bda->bdaddr, BDADDR_BCM43430A0) ||
|
||||
!bacmp(&bda->bdaddr, BDADDR_BCM43430A1) ||
|
||||
!bacmp(&bda->bdaddr, BDADDR_BCM43341B)) {
|
||||
/* Try falling back to BDADDR EFI variable */
|
||||
if (btbcm_set_bdaddr_from_efi(hdev) != 0) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -27,6 +28,11 @@
|
|||
|
||||
#define BTINTEL_PPAG_NAME "PPAG"
|
||||
|
||||
enum {
|
||||
DSM_SET_WDISABLE2_DELAY = 1,
|
||||
DSM_SET_RESET_METHOD = 3,
|
||||
};
|
||||
|
||||
/* structure to store the PPAG data read from ACPI table */
|
||||
struct btintel_ppag {
|
||||
u32 domain;
|
||||
|
@ -49,6 +55,10 @@ static struct {
|
|||
u32 fw_build_num;
|
||||
} coredump_info;
|
||||
|
||||
static const guid_t btintel_guid_dsm =
|
||||
GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233,
|
||||
0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9);
|
||||
|
||||
int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_rp_read_bd_addr *bda;
|
||||
|
@ -470,6 +480,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
|
|||
case 0x18: /* Slr */
|
||||
case 0x19: /* Slr-F */
|
||||
case 0x1b: /* Mgr */
|
||||
case 0x1c: /* Gale Peak (GaP) */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
|
||||
|
@ -2390,7 +2401,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
|||
{
|
||||
struct btintel_ppag ppag;
|
||||
struct sk_buff *skb;
|
||||
struct btintel_loc_aware_reg ppag_cmd;
|
||||
struct hci_ppag_enable_cmd ppag_cmd;
|
||||
acpi_handle handle;
|
||||
|
||||
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
|
||||
|
@ -2398,6 +2409,8 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
|||
case 0x504: /* Hrp2 */
|
||||
case 0x202: /* Jfp2 */
|
||||
case 0x201: /* Jfp1 */
|
||||
bt_dev_dbg(hdev, "PPAG not supported for Intel CNVr (0x%3x)",
|
||||
ver->cnvr_top & 0xFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2423,27 +2436,142 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
|||
}
|
||||
|
||||
if (ppag.domain != 0x12) {
|
||||
bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth");
|
||||
bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */
|
||||
if (!(ppag.mode & BIT(0))) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: disabled");
|
||||
/* PPAG mode
|
||||
* BIT 0 : 0 Disabled in EU
|
||||
* 1 Enabled in EU
|
||||
* BIT 1 : 0 Disabled in China
|
||||
* 1 Enabled in China
|
||||
*/
|
||||
if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS");
|
||||
return;
|
||||
}
|
||||
|
||||
ppag_cmd.mcc = cpu_to_le32(0);
|
||||
ppag_cmd.sel = cpu_to_le32(0); /* 0 - Enable , 1 - Disable, 2 - Testing mode */
|
||||
ppag_cmd.delta = cpu_to_le32(0);
|
||||
skb = __hci_cmd_sync(hdev, 0xfe19, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
|
||||
ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb));
|
||||
return;
|
||||
}
|
||||
bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int btintel_acpi_reset_method(struct hci_dev *hdev)
|
||||
{
|
||||
int ret = 0;
|
||||
acpi_status status;
|
||||
union acpi_object *p, *ref;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
bt_dev_err(hdev, "Failed to run _PRR method");
|
||||
ret = -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
p = buffer.pointer;
|
||||
|
||||
if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) {
|
||||
bt_dev_err(hdev, "Invalid arguments");
|
||||
ret = -EINVAL;
|
||||
goto exit_on_error;
|
||||
}
|
||||
|
||||
ref = &p->package.elements[0];
|
||||
if (ref->type != ACPI_TYPE_LOCAL_REFERENCE) {
|
||||
bt_dev_err(hdev, "Invalid object type: 0x%x", ref->type);
|
||||
ret = -EINVAL;
|
||||
goto exit_on_error;
|
||||
}
|
||||
|
||||
status = acpi_evaluate_object(ref->reference.handle, "_RST", NULL, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
bt_dev_err(hdev, "Failed to run_RST method");
|
||||
ret = -ENODEV;
|
||||
goto exit_on_error;
|
||||
}
|
||||
|
||||
exit_on_error:
|
||||
kfree(buffer.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void btintel_set_dsm_reset_method(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver_tlv)
|
||||
{
|
||||
struct btintel_data *data = hci_get_priv(hdev);
|
||||
acpi_handle handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
|
||||
u8 reset_payload[4] = {0x01, 0x00, 0x01, 0x00};
|
||||
union acpi_object *obj, argv4;
|
||||
enum {
|
||||
RESET_TYPE_WDISABLE2,
|
||||
RESET_TYPE_VSEC
|
||||
};
|
||||
|
||||
handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
|
||||
|
||||
if (!handle) {
|
||||
bt_dev_dbg(hdev, "No support for bluetooth device in ACPI firmware");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!acpi_has_method(handle, "_PRR")) {
|
||||
bt_dev_err(hdev, "No support for _PRR ACPI method");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ver_tlv->cnvi_top & 0xfff) {
|
||||
case 0x910: /* GalePeak2 */
|
||||
reset_payload[2] = RESET_TYPE_VSEC;
|
||||
break;
|
||||
default:
|
||||
/* WDISABLE2 is the default reset method */
|
||||
reset_payload[2] = RESET_TYPE_WDISABLE2;
|
||||
|
||||
if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
|
||||
BIT(DSM_SET_WDISABLE2_DELAY))) {
|
||||
bt_dev_err(hdev, "No dsm support to set reset delay");
|
||||
return;
|
||||
}
|
||||
argv4.integer.type = ACPI_TYPE_INTEGER;
|
||||
/* delay required to toggle BT power */
|
||||
argv4.integer.value = 160;
|
||||
obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
|
||||
DSM_SET_WDISABLE2_DELAY, &argv4);
|
||||
if (!obj) {
|
||||
bt_dev_err(hdev, "Failed to call dsm to set reset delay");
|
||||
return;
|
||||
}
|
||||
ACPI_FREE(obj);
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "DSM reset method type: 0x%02x", reset_payload[2]);
|
||||
|
||||
if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
|
||||
DSM_SET_RESET_METHOD)) {
|
||||
bt_dev_warn(hdev, "No support for dsm to set reset method");
|
||||
return;
|
||||
}
|
||||
argv4.buffer.type = ACPI_TYPE_BUFFER;
|
||||
argv4.buffer.length = sizeof(reset_payload);
|
||||
argv4.buffer.pointer = reset_payload;
|
||||
|
||||
obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
|
||||
DSM_SET_RESET_METHOD, &argv4);
|
||||
if (!obj) {
|
||||
bt_dev_err(hdev, "Failed to call dsm to set reset method");
|
||||
return;
|
||||
}
|
||||
ACPI_FREE(obj);
|
||||
data->acpi_reset_method = btintel_acpi_reset_method;
|
||||
}
|
||||
|
||||
static int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver)
|
||||
{
|
||||
|
@ -2528,6 +2656,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
|
|||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
hci_set_msft_opcode(hdev, 0xFC1E);
|
||||
break;
|
||||
default:
|
||||
|
@ -2658,6 +2787,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
|||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
|
||||
&hdev->quirks);
|
||||
|
||||
/* These variants don't seem to support LE Coded PHY */
|
||||
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
|
||||
|
||||
/* Setup MSFT Extension support */
|
||||
btintel_set_msft_opcode(hdev, ver.hw_variant);
|
||||
|
||||
|
@ -2729,6 +2861,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
|||
*/
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
|
||||
/* These variants don't seem to support LE Coded PHY */
|
||||
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
|
||||
|
||||
/* Set Valid LE States quirk */
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
|
||||
|
@ -2742,6 +2877,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
|||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1b:
|
||||
case 0x1c:
|
||||
/* Display version information of TLV type */
|
||||
btintel_version_info_tlv(hdev, &ver_tlv);
|
||||
|
||||
|
@ -2757,6 +2893,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
|||
/* Setup MSFT Extension support */
|
||||
btintel_set_msft_opcode(hdev,
|
||||
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
|
||||
btintel_set_dsm_reset_method(hdev, &ver_tlv);
|
||||
|
||||
err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
|
||||
btintel_register_devcoredump_support(hdev);
|
||||
|
@ -2824,6 +2961,80 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_configure_setup);
|
||||
|
||||
static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct intel_tlv *tlv = (void *)&skb->data[5];
|
||||
|
||||
/* The first event is always an event type TLV */
|
||||
if (tlv->type != INTEL_TLV_TYPE_ID)
|
||||
goto recv_frame;
|
||||
|
||||
switch (tlv->val[0]) {
|
||||
case INTEL_TLV_SYSTEM_EXCEPTION:
|
||||
case INTEL_TLV_FATAL_EXCEPTION:
|
||||
case INTEL_TLV_DEBUG_EXCEPTION:
|
||||
case INTEL_TLV_TEST_EXCEPTION:
|
||||
/* Generate devcoredump from exception */
|
||||
if (!hci_devcd_init(hdev, skb->len)) {
|
||||
hci_devcd_append(hdev, skb);
|
||||
hci_devcd_complete(hdev);
|
||||
} else {
|
||||
bt_dev_err(hdev, "Failed to generate devcoredump");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
|
||||
}
|
||||
|
||||
recv_frame:
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
|
||||
|
||||
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
|
||||
hdr->plen > 0) {
|
||||
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
|
||||
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
|
||||
|
||||
if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
|
||||
switch (skb->data[2]) {
|
||||
case 0x02:
|
||||
/* When switching to the operational firmware
|
||||
* the device sends a vendor specific event
|
||||
* indicating that the bootup completed.
|
||||
*/
|
||||
btintel_bootup(hdev, ptr, len);
|
||||
break;
|
||||
case 0x06:
|
||||
/* When the firmware loading completes the
|
||||
* device sends out a vendor specific event
|
||||
* indicating the result of the firmware
|
||||
* loading.
|
||||
*/
|
||||
btintel_secure_send_result(hdev, ptr, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle all diagnostics events separately. May still call
|
||||
* hci_recv_frame.
|
||||
*/
|
||||
if (len >= sizeof(diagnostics_hdr) &&
|
||||
memcmp(&skb->data[2], diagnostics_hdr,
|
||||
sizeof(diagnostics_hdr)) == 0) {
|
||||
return btintel_diagnostics(hdev, skb);
|
||||
}
|
||||
}
|
||||
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_recv_event);
|
||||
|
||||
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len)
|
||||
{
|
||||
const struct intel_bootup *evt = ptr;
|
||||
|
|
|
@ -137,10 +137,9 @@ struct intel_offload_use_cases {
|
|||
__u8 preset[8];
|
||||
} __packed;
|
||||
|
||||
struct btintel_loc_aware_reg {
|
||||
__le32 mcc;
|
||||
__le32 sel;
|
||||
__le32 delta;
|
||||
#define INTEL_OP_PPAG_CMD 0xFE0B
|
||||
struct hci_ppag_enable_cmd {
|
||||
__le32 ppag_enable_flags;
|
||||
} __packed;
|
||||
|
||||
#define INTEL_TLV_TYPE_ID 0x01
|
||||
|
@ -166,12 +165,14 @@ enum {
|
|||
INTEL_BROKEN_SHUTDOWN_LED,
|
||||
INTEL_ROM_LEGACY,
|
||||
INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
|
||||
INTEL_ACPI_RESET_ACTIVE,
|
||||
|
||||
__INTEL_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct btintel_data {
|
||||
DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
|
||||
int (*acpi_reset_method)(struct hci_dev *hdev);
|
||||
};
|
||||
|
||||
#define btintel_set_flag(hdev, nr) \
|
||||
|
@ -220,6 +221,7 @@ int btintel_read_boot_params(struct hci_dev *hdev,
|
|||
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
|
||||
const struct firmware *fw, u32 *boot_param);
|
||||
int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name);
|
||||
int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
|
||||
void btintel_secure_send_result(struct hci_dev *hdev,
|
||||
const void *ptr, unsigned int len);
|
||||
|
|
|
@ -53,10 +53,61 @@ struct btmtk_section_map {
|
|||
};
|
||||
} __packed;
|
||||
|
||||
static void btmtk_coredump(struct hci_dev *hdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL);
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Coredump failed (%d)", err);
|
||||
}
|
||||
|
||||
static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmediatek_data *data = hci_get_priv(hdev);
|
||||
char buf[80];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
|
||||
data->dev_id);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
|
||||
data->cd_info.fw_version);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Driver: %s\n",
|
||||
data->cd_info.driver_name);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Vendor: MediaTek\n");
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
|
||||
{
|
||||
struct btmediatek_data *data = hci_get_priv(hdev);
|
||||
|
||||
switch (state) {
|
||||
case HCI_DEVCOREDUMP_IDLE:
|
||||
data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
|
||||
break;
|
||||
case HCI_DEVCOREDUMP_ACTIVE:
|
||||
data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE;
|
||||
break;
|
||||
case HCI_DEVCOREDUMP_TIMEOUT:
|
||||
case HCI_DEVCOREDUMP_ABORT:
|
||||
case HCI_DEVCOREDUMP_DONE:
|
||||
data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
|
||||
btmtk_reset_sync(hdev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
|
||||
wmt_cmd_sync_func_t wmt_cmd_sync)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
struct btmtk_patch_header *hdr;
|
||||
struct btmtk_global_desc *globaldesc = NULL;
|
||||
struct btmtk_section_map *sectionmap;
|
||||
const struct firmware *fw;
|
||||
|
@ -75,9 +126,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
|
|||
|
||||
fw_ptr = fw->data;
|
||||
fw_bin_ptr = fw_ptr;
|
||||
hdr = (struct btmtk_patch_header *)fw_ptr;
|
||||
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
|
||||
section_num = le32_to_cpu(globaldesc->section_num);
|
||||
|
||||
bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
|
||||
le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
|
||||
|
||||
for (i = 0; i < section_num; i++) {
|
||||
first_block = 1;
|
||||
fw_ptr = fw_bin_ptr;
|
||||
|
@ -280,6 +335,83 @@ int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(btmtk_set_bdaddr);
|
||||
|
||||
void btmtk_reset_sync(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmediatek_data *reset_work = hci_get_priv(hdev);
|
||||
int err;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL);
|
||||
if (err)
|
||||
bt_dev_err(hdev, "failed to reset (%d)", err);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btmtk_reset_sync);
|
||||
|
||||
int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
|
||||
u32 fw_version)
|
||||
{
|
||||
struct btmediatek_data *data = hci_get_priv(hdev);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data->cd_info.fw_version = fw_version;
|
||||
data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
|
||||
data->cd_info.driver_name = name;
|
||||
|
||||
return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr,
|
||||
btmtk_coredump_notify);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btmtk_register_coredump);
|
||||
|
||||
int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmediatek_data *data = hci_get_priv(hdev);
|
||||
int err;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
|
||||
return 0;
|
||||
|
||||
switch (data->cd_info.state) {
|
||||
case HCI_DEVCOREDUMP_IDLE:
|
||||
err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
|
||||
if (err < 0)
|
||||
break;
|
||||
data->cd_info.cnt = 0;
|
||||
|
||||
/* It is supposed coredump can be done within 5 seconds */
|
||||
schedule_delayed_work(&hdev->dump.dump_timeout,
|
||||
msecs_to_jiffies(5000));
|
||||
fallthrough;
|
||||
case HCI_DEVCOREDUMP_ACTIVE:
|
||||
default:
|
||||
err = hci_devcd_append(hdev, skb);
|
||||
if (err < 0)
|
||||
break;
|
||||
data->cd_info.cnt++;
|
||||
|
||||
/* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
|
||||
if (data->cd_info.cnt > MTK_COREDUMP_NUM &&
|
||||
skb->len > MTK_COREDUMP_END_LEN)
|
||||
if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
|
||||
MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) {
|
||||
bt_dev_info(hdev, "Mediatek coredump end");
|
||||
hci_devcd_complete(hdev);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
kfree_skb(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btmtk_process_coredump);
|
||||
|
||||
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
|
||||
MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
|
||||
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
|
||||
|
@ -289,3 +421,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7622);
|
|||
MODULE_FIRMWARE(FIRMWARE_MT7663);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7961);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7925);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
|
||||
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
|
||||
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
|
||||
#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
|
||||
|
||||
#define HCI_EV_WMT 0xe4
|
||||
#define HCI_WMT_MAX_EVENT_SIZE 64
|
||||
|
@ -21,6 +22,11 @@
|
|||
#define MT7921_DLSTATUS 0x7c053c10
|
||||
#define BT_DL_STATE BIT(1)
|
||||
|
||||
#define MTK_COREDUMP_SIZE (1024 * 1000)
|
||||
#define MTK_COREDUMP_END "coredump end"
|
||||
#define MTK_COREDUMP_END_LEN (sizeof(MTK_COREDUMP_END))
|
||||
#define MTK_COREDUMP_NUM 255
|
||||
|
||||
enum {
|
||||
BTMTK_WMT_PATCH_DWNLD = 0x1,
|
||||
BTMTK_WMT_TEST = 0x2,
|
||||
|
@ -119,6 +125,21 @@ struct btmtk_hci_wmt_params {
|
|||
u32 *status;
|
||||
};
|
||||
|
||||
typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
|
||||
|
||||
struct btmtk_coredump_info {
|
||||
const char *driver_name;
|
||||
u32 fw_version;
|
||||
u16 cnt;
|
||||
int state;
|
||||
};
|
||||
|
||||
struct btmediatek_data {
|
||||
u32 dev_id;
|
||||
btmtk_reset_sync_func_t reset_sync;
|
||||
struct btmtk_coredump_info cd_info;
|
||||
};
|
||||
|
||||
typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
|
||||
struct btmtk_hci_wmt_params *);
|
||||
|
||||
|
@ -131,6 +152,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
|
|||
|
||||
int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
|
||||
wmt_cmd_sync_func_t wmt_cmd_sync);
|
||||
|
||||
void btmtk_reset_sync(struct hci_dev *hdev);
|
||||
|
||||
int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
|
||||
u32 fw_version);
|
||||
|
||||
int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
#else
|
||||
|
||||
static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
|
||||
|
@ -151,4 +179,18 @@ static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void btmtk_reset_sync(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
|
||||
u32 fw_version)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
|
@ -28,17 +28,34 @@
|
|||
#define BTNXPUART_FW_DOWNLOADING 2
|
||||
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
|
||||
#define BTNXPUART_SERDEV_OPEN 4
|
||||
#define BTNXPUART_IR_IN_PROGRESS 5
|
||||
|
||||
#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
|
||||
#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
|
||||
#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin"
|
||||
#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin"
|
||||
#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se"
|
||||
#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin"
|
||||
/* NXP HW err codes */
|
||||
#define BTNXPUART_IR_HW_ERR 0xb0
|
||||
|
||||
#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
|
||||
#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
|
||||
#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin"
|
||||
#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin"
|
||||
#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se"
|
||||
#define FIRMWARE_IW624 "nxp/uartiw624_bt.bin"
|
||||
#define FIRMWARE_SECURE_IW624 "nxp/uartiw624_bt.bin.se"
|
||||
#define FIRMWARE_AW693 "nxp/uartaw693_bt.bin"
|
||||
#define FIRMWARE_SECURE_AW693 "nxp/uartaw693_bt.bin.se"
|
||||
#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin"
|
||||
|
||||
#define CHIP_ID_W9098 0x5c03
|
||||
#define CHIP_ID_IW416 0x7201
|
||||
#define CHIP_ID_IW612 0x7601
|
||||
#define CHIP_ID_IW624a 0x8000
|
||||
#define CHIP_ID_IW624c 0x8001
|
||||
#define CHIP_ID_AW693 0x8200
|
||||
|
||||
#define FW_SECURE_MASK 0xc0
|
||||
#define FW_OPEN 0x00
|
||||
#define FW_AUTH_ILLEGAL 0x40
|
||||
#define FW_AUTH_PLAIN 0x80
|
||||
#define FW_AUTH_ENC 0xc0
|
||||
|
||||
#define HCI_NXP_PRI_BAUDRATE 115200
|
||||
#define HCI_NXP_SEC_BAUDRATE 3000000
|
||||
|
@ -143,6 +160,7 @@ struct btnxpuart_dev {
|
|||
u32 fw_v1_sent_bytes;
|
||||
u32 fw_v3_offset_correction;
|
||||
u32 fw_v1_expected_len;
|
||||
u32 boot_reg_offset;
|
||||
wait_queue_head_t fw_dnld_done_wait_q;
|
||||
wait_queue_head_t check_boot_sign_wait_q;
|
||||
|
||||
|
@ -366,39 +384,13 @@ static void ps_timeout_func(struct timer_list *t)
|
|||
}
|
||||
}
|
||||
|
||||
static int ps_init_work(struct hci_dev *hdev)
|
||||
static void ps_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
|
||||
psdata->ps_state = PS_STATE_AWAKE;
|
||||
psdata->target_ps_mode = DEFAULT_PS_MODE;
|
||||
psdata->hdev = hdev;
|
||||
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
|
||||
psdata->c2h_wakeup_gpio = 0xff;
|
||||
|
||||
switch (DEFAULT_H2C_WAKEUP_MODE) {
|
||||
case WAKEUP_METHOD_DTR:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
|
||||
break;
|
||||
case WAKEUP_METHOD_BREAK:
|
||||
default:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
|
||||
break;
|
||||
}
|
||||
psdata->cur_psmode = PS_MODE_DISABLE;
|
||||
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
|
||||
INIT_WORK(&psdata->work, ps_work_func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps_init_timer(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
|
||||
}
|
||||
|
||||
|
@ -501,19 +493,31 @@ static void ps_init(struct hci_dev *hdev)
|
|||
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0);
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
switch (psdata->h2c_wakeupmode) {
|
||||
psdata->ps_state = PS_STATE_AWAKE;
|
||||
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
|
||||
psdata->c2h_wakeup_gpio = 0xff;
|
||||
|
||||
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
|
||||
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
|
||||
switch (DEFAULT_H2C_WAKEUP_MODE) {
|
||||
case WAKEUP_METHOD_DTR:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
|
||||
serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
|
||||
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
|
||||
break;
|
||||
case WAKEUP_METHOD_BREAK:
|
||||
default:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
|
||||
serdev_device_break_ctl(nxpdev->serdev, -1);
|
||||
usleep_range(5000, 10000);
|
||||
serdev_device_break_ctl(nxpdev->serdev, 0);
|
||||
usleep_range(5000, 10000);
|
||||
break;
|
||||
}
|
||||
|
||||
psdata->cur_psmode = PS_MODE_DISABLE;
|
||||
psdata->target_ps_mode = DEFAULT_PS_MODE;
|
||||
|
||||
if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode)
|
||||
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
|
||||
if (psdata->cur_psmode != psdata->target_ps_mode)
|
||||
|
@ -529,6 +533,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
|||
nxpdev->fw_dnld_v1_offset = 0;
|
||||
nxpdev->fw_v1_sent_bytes = 0;
|
||||
nxpdev->fw_v1_expected_len = HDR_LEN;
|
||||
nxpdev->boot_reg_offset = 0;
|
||||
nxpdev->fw_v3_offset_correction = 0;
|
||||
nxpdev->baudrate_changed = false;
|
||||
nxpdev->timeout_changed = false;
|
||||
|
@ -538,7 +543,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
|||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
nxpdev->current_baudrate = HCI_NXP_PRI_BAUDRATE;
|
||||
|
||||
/* Wait till FW is downloaded and CTS becomes low */
|
||||
/* Wait till FW is downloaded */
|
||||
err = wait_event_interruptible_timeout(nxpdev->fw_dnld_done_wait_q,
|
||||
!test_bit(BTNXPUART_FW_DOWNLOADING,
|
||||
&nxpdev->tx_state),
|
||||
|
@ -549,16 +554,11 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
|||
}
|
||||
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
err = serdev_device_wait_for_cts(nxpdev->serdev, 1, 60000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "CTS is still high. FW Download failed.");
|
||||
return err;
|
||||
}
|
||||
release_firmware(nxpdev->fw);
|
||||
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
|
||||
|
||||
/* Allow the downloaded FW to initialize */
|
||||
usleep_range(800 * USEC_PER_MSEC, 1 * USEC_PER_SEC);
|
||||
msleep(1200);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -582,6 +582,12 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
|
|||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct nxp_bootloader_cmd nxp_cmd5;
|
||||
struct uart_config uart_config;
|
||||
u32 clkdivaddr = CLKDIVADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartdivaddr = UARTDIVADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartmcraddr = UARTMCRADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartreinitaddr = UARTREINITADDR - nxpdev->boot_reg_offset;
|
||||
u32 uarticraddr = UARTICRADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartfcraddr = UARTFCRADDR - nxpdev->boot_reg_offset;
|
||||
|
||||
if (req_len == sizeof(nxp_cmd5)) {
|
||||
nxp_cmd5.header = __cpu_to_le32(5);
|
||||
|
@ -594,17 +600,17 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
|
|||
serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd5, sizeof(nxp_cmd5));
|
||||
nxpdev->fw_v3_offset_correction += req_len;
|
||||
} else if (req_len == sizeof(uart_config)) {
|
||||
uart_config.clkdiv.address = __cpu_to_le32(CLKDIVADDR);
|
||||
uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr);
|
||||
uart_config.clkdiv.value = __cpu_to_le32(0x00c00000);
|
||||
uart_config.uartdiv.address = __cpu_to_le32(UARTDIVADDR);
|
||||
uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr);
|
||||
uart_config.uartdiv.value = __cpu_to_le32(1);
|
||||
uart_config.mcr.address = __cpu_to_le32(UARTMCRADDR);
|
||||
uart_config.mcr.address = __cpu_to_le32(uartmcraddr);
|
||||
uart_config.mcr.value = __cpu_to_le32(MCR);
|
||||
uart_config.re_init.address = __cpu_to_le32(UARTREINITADDR);
|
||||
uart_config.re_init.address = __cpu_to_le32(uartreinitaddr);
|
||||
uart_config.re_init.value = __cpu_to_le32(INIT);
|
||||
uart_config.icr.address = __cpu_to_le32(UARTICRADDR);
|
||||
uart_config.icr.address = __cpu_to_le32(uarticraddr);
|
||||
uart_config.icr.value = __cpu_to_le32(ICR);
|
||||
uart_config.fcr.address = __cpu_to_le32(UARTFCRADDR);
|
||||
uart_config.fcr.address = __cpu_to_le32(uartfcraddr);
|
||||
uart_config.fcr.value = __cpu_to_le32(FCR);
|
||||
/* FW expects swapped CRC bytes */
|
||||
uart_config.crc = __cpu_to_be32(crc32_be(0UL, (char *)&uart_config,
|
||||
|
@ -665,6 +671,9 @@ static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name)
|
|||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
int err = 0;
|
||||
|
||||
if (!fw_name)
|
||||
return -ENOENT;
|
||||
|
||||
if (!strlen(nxpdev->fw_name)) {
|
||||
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "%s", fw_name);
|
||||
|
||||
|
@ -690,7 +699,7 @@ static int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
goto free_skb;
|
||||
|
||||
chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp);
|
||||
if (chip_id == 0xffff) {
|
||||
if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) {
|
||||
nxpdev->fw_dnld_v1_offset = 0;
|
||||
nxpdev->fw_v1_sent_bytes = 0;
|
||||
nxpdev->fw_v1_expected_len = HDR_LEN;
|
||||
|
@ -812,8 +821,10 @@ free_skb:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid)
|
||||
static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
u8 loader_ver)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
char *fw_name = NULL;
|
||||
|
||||
switch (chipid) {
|
||||
|
@ -826,6 +837,24 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid)
|
|||
case CHIP_ID_IW612:
|
||||
fw_name = FIRMWARE_IW612;
|
||||
break;
|
||||
case CHIP_ID_IW624a:
|
||||
case CHIP_ID_IW624c:
|
||||
nxpdev->boot_reg_offset = 1;
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_IW624;
|
||||
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
|
||||
fw_name = FIRMWARE_SECURE_IW624;
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
case CHIP_ID_AW693:
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_AW693;
|
||||
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
|
||||
fw_name = FIRMWARE_SECURE_AW693;
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unknown chip signature %04x", chipid);
|
||||
break;
|
||||
|
@ -838,13 +867,15 @@ static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
struct v3_start_ind *req = skb_pull_data(skb, sizeof(*req));
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
u16 chip_id;
|
||||
u8 loader_ver;
|
||||
|
||||
if (!process_boot_signature(nxpdev))
|
||||
goto free_skb;
|
||||
|
||||
chip_id = le16_to_cpu(req->chip_id);
|
||||
loader_ver = req->loader_ver;
|
||||
if (!nxp_request_firmware(hdev, nxp_get_fw_name_from_chipid(hdev,
|
||||
chip_id)))
|
||||
chip_id, loader_ver)))
|
||||
nxp_send_ack(NXP_ACK_V3, hdev);
|
||||
|
||||
free_skb:
|
||||
|
@ -946,45 +977,13 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct sk_buff *skb;
|
||||
u8 *status;
|
||||
u8 pcmd = 0;
|
||||
int err = 0;
|
||||
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
status = skb_pull_data(skb, 1);
|
||||
if (!status || *status)
|
||||
goto free_skb;
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
err = nxp_download_firmware(hdev);
|
||||
if (err < 0)
|
||||
goto free_skb;
|
||||
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
|
||||
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
|
||||
if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) {
|
||||
nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE;
|
||||
nxp_set_baudrate_cmd(hdev, NULL);
|
||||
}
|
||||
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
|
||||
hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL);
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* NXP protocol */
|
||||
static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
|
||||
{
|
||||
serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
|
||||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
else
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state);
|
||||
|
||||
return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q,
|
||||
|
@ -993,15 +992,29 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
|
|||
msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
|
||||
0x01, BTNXPUART_IR_HW_ERR };
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = bt_skb_alloc(3, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
|
||||
skb_put_data(skb, ir_hw_err, 3);
|
||||
|
||||
/* Inject Hardware Error to upper stack */
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
/* NXP protocol */
|
||||
static int nxp_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
int err = 0;
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
|
||||
init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
|
||||
|
||||
if (nxp_check_boot_sign(nxpdev)) {
|
||||
bt_dev_dbg(hdev, "Need FW Download.");
|
||||
err = nxp_download_firmware(hdev);
|
||||
|
@ -1012,10 +1025,6 @@ static int nxp_setup(struct hci_dev *hdev)
|
|||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
}
|
||||
|
||||
device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
|
||||
&nxpdev->fw_init_baudrate);
|
||||
if (!nxpdev->fw_init_baudrate)
|
||||
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
|
||||
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
|
||||
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
|
||||
|
||||
|
@ -1026,6 +1035,46 @@ static int nxp_setup(struct hci_dev *hdev)
|
|||
|
||||
ps_init(hdev);
|
||||
|
||||
if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
|
||||
hci_dev_clear_flag(hdev, HCI_SETUP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nxp_hw_err(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
|
||||
switch (code) {
|
||||
case BTNXPUART_IR_HW_ERR:
|
||||
set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state);
|
||||
hci_dev_set_flag(hdev, HCI_SETUP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nxp_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct sk_buff *skb;
|
||||
u8 *status;
|
||||
u8 pcmd = 0;
|
||||
|
||||
if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) {
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
status = skb_pull_data(skb, 1);
|
||||
if (status) {
|
||||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1233,7 +1282,8 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
|
|||
nxpdev->rx_skb = NULL;
|
||||
return err;
|
||||
}
|
||||
nxpdev->hdev->stat.byte_rx += count;
|
||||
if (!is_fw_downloading(nxpdev))
|
||||
nxpdev->hdev->stat.byte_rx += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1266,6 +1316,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
|||
INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work);
|
||||
skb_queue_head_init(&nxpdev->txq);
|
||||
|
||||
init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
|
||||
init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
|
||||
|
||||
device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
|
||||
&nxpdev->fw_init_baudrate);
|
||||
if (!nxpdev->fw_init_baudrate)
|
||||
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
|
||||
crc8_populate_msb(crc8_table, POLYNOMIAL8);
|
||||
|
||||
/* Initialize and register HCI device */
|
||||
|
@ -1286,6 +1346,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
|||
hdev->flush = btnxpuart_flush;
|
||||
hdev->setup = nxp_setup;
|
||||
hdev->send = nxp_enqueue;
|
||||
hdev->hw_error = nxp_hw_err;
|
||||
hdev->shutdown = nxp_shutdown;
|
||||
SET_HCIDEV_DEV(hdev, &serdev->dev);
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
|
@ -1294,8 +1356,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ps_init_work(hdev);
|
||||
ps_init_timer(hdev);
|
||||
ps_setup(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -594,30 +594,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|||
/* Firmware files to download are based on ROM version.
|
||||
* ROM version is derived from last two bytes of soc_ver.
|
||||
*/
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
|
||||
if (soc_type == QCA_WCN3988)
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
|
||||
else
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
|
||||
|
||||
if (soc_type == QCA_WCN6750)
|
||||
qca_send_patch_config_cmd(hdev);
|
||||
|
||||
/* Download rampatch file */
|
||||
config.type = TLV_TYPE_PATCH;
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crbtfw%02x.tlv", rom_ver);
|
||||
} else if (soc_type == QCA_QCA6390) {
|
||||
break;
|
||||
case QCA_WCN3988:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htbtfw%02x.tlv", rom_ver);
|
||||
} else if (soc_type == QCA_WCN6750) {
|
||||
break;
|
||||
case QCA_WCN6750:
|
||||
/* Choose mbn file by default.If mbn file is not found
|
||||
* then choose tlv file
|
||||
*/
|
||||
config.type = ELF_TYPE_PATCH;
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/msbtfw%02x.mbn", rom_ver);
|
||||
} else if (soc_type == QCA_WCN6855) {
|
||||
break;
|
||||
case QCA_WCN6855:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpbtfw%02x.tlv", rom_ver);
|
||||
} else {
|
||||
break;
|
||||
case QCA_WCN7850:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hmtbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
default:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/rampatch_%08x.bin", soc_ver);
|
||||
}
|
||||
|
@ -633,30 +651,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|||
|
||||
/* Download NVM configuration */
|
||||
config.type = TLV_TYPE_NVM;
|
||||
if (firmware_name)
|
||||
if (firmware_name) {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/%s", firmware_name);
|
||||
else if (qca_is_wcn399x(soc_type)) {
|
||||
if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
|
||||
} else {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02xu.bin", rom_ver);
|
||||
} else {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02x.bin", rom_ver);
|
||||
}
|
||||
break;
|
||||
case QCA_WCN3988:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02xu.bin", rom_ver);
|
||||
} else {
|
||||
"qca/apnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02x.bin", rom_ver);
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_WCN6750:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/msnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_WCN6855:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_WCN7850:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hmtnv%02x.bin", rom_ver);
|
||||
break;
|
||||
|
||||
default:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/nvm_%08x.bin", soc_ver);
|
||||
}
|
||||
}
|
||||
else if (soc_type == QCA_QCA6390)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
else if (soc_type == QCA_WCN6750)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/msnv%02x.bin", rom_ver);
|
||||
else if (soc_type == QCA_WCN6855)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpnv%02x.bin", rom_ver);
|
||||
else
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/nvm_%08x.bin", soc_ver);
|
||||
|
||||
err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
|
||||
if (err < 0) {
|
||||
|
@ -664,16 +700,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (soc_type >= QCA_WCN3991) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3991:
|
||||
case QCA_QCA6390:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
err = qca_disable_soc_logging(hdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the
|
||||
* VsMsftOpCode.
|
||||
*/
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
|
@ -695,6 +740,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|||
case QCA_WCN3991:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
/* get fw build info */
|
||||
err = qca_read_fw_build_info(hdev);
|
||||
if (err < 0)
|
||||
|
|
|
@ -142,12 +142,14 @@ enum qca_btsoc_type {
|
|||
QCA_INVALID = -1,
|
||||
QCA_AR3002,
|
||||
QCA_ROME,
|
||||
QCA_WCN3988,
|
||||
QCA_WCN3990,
|
||||
QCA_WCN3998,
|
||||
QCA_WCN3991,
|
||||
QCA_QCA6390,
|
||||
QCA_WCN6750,
|
||||
QCA_WCN6855,
|
||||
QCA_WCN7850,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_QCA)
|
||||
|
@ -160,20 +162,6 @@ int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
|
|||
enum qca_btsoc_type);
|
||||
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
|
||||
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return soc_type == QCA_WCN3990 || soc_type == QCA_WCN3991 ||
|
||||
soc_type == QCA_WCN3998;
|
||||
}
|
||||
static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return soc_type == QCA_WCN6750;
|
||||
}
|
||||
static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return soc_type == QCA_WCN6855;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
|
@ -201,21 +189,6 @@ static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#define RTL_ROM_LMP_8851B 0x8851
|
||||
#define RTL_CONFIG_MAGIC 0x8723ab55
|
||||
|
||||
#define RTL_VSC_OP_COREDUMP 0xfcff
|
||||
|
||||
#define IC_MATCH_FL_LMPSUBV (1 << 0)
|
||||
#define IC_MATCH_FL_HCIREV (1 << 1)
|
||||
#define IC_MATCH_FL_HCIVER (1 << 2)
|
||||
|
@ -81,6 +83,7 @@ struct id_table {
|
|||
bool has_msft_ext;
|
||||
char *fw_name;
|
||||
char *cfg_name;
|
||||
char *hw_info;
|
||||
};
|
||||
|
||||
struct btrtl_device_info {
|
||||
|
@ -101,22 +104,25 @@ static const struct id_table ic_id_table[] = {
|
|||
{ IC_INFO(RTL_ROM_LMP_8723A, 0xb, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = false,
|
||||
.fw_name = "rtl_bt/rtl8723a_fw.bin",
|
||||
.cfg_name = NULL },
|
||||
.fw_name = "rtl_bt/rtl8723a_fw",
|
||||
.cfg_name = NULL,
|
||||
.hw_info = "rtl8723au" },
|
||||
|
||||
/* 8723BS */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723bs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723bs_config" },
|
||||
.fw_name = "rtl_bt/rtl8723bs_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723bs_config",
|
||||
.hw_info = "rtl8723bs" },
|
||||
|
||||
/* 8723B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723b_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723b_config" },
|
||||
.fw_name = "rtl_bt/rtl8723b_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723b_config",
|
||||
.hw_info = "rtl8723bu" },
|
||||
|
||||
/* 8723CS-CG */
|
||||
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
|
||||
|
@ -126,8 +132,9 @@ static const struct id_table ic_id_table[] = {
|
|||
.hci_bus = HCI_UART,
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723cs_cg_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723cs_cg_config" },
|
||||
.fw_name = "rtl_bt/rtl8723cs_cg_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723cs_cg_config",
|
||||
.hw_info = "rtl8723cs-cg" },
|
||||
|
||||
/* 8723CS-VF */
|
||||
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
|
||||
|
@ -137,8 +144,9 @@ static const struct id_table ic_id_table[] = {
|
|||
.hci_bus = HCI_UART,
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723cs_vf_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723cs_vf_config" },
|
||||
.fw_name = "rtl_bt/rtl8723cs_vf_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723cs_vf_config",
|
||||
.hw_info = "rtl8723cs-vf" },
|
||||
|
||||
/* 8723CS-XX */
|
||||
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
|
||||
|
@ -148,139 +156,157 @@ static const struct id_table ic_id_table[] = {
|
|||
.hci_bus = HCI_UART,
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723cs_xx_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723cs_xx_config" },
|
||||
.fw_name = "rtl_bt/rtl8723cs_xx_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723cs_xx_config",
|
||||
.hw_info = "rtl8723cs" },
|
||||
|
||||
/* 8723D */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723d_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723d_config" },
|
||||
.fw_name = "rtl_bt/rtl8723d_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723d_config",
|
||||
.hw_info = "rtl8723du" },
|
||||
|
||||
/* 8723DS */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723ds_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723ds_config" },
|
||||
.fw_name = "rtl_bt/rtl8723ds_fw",
|
||||
.cfg_name = "rtl_bt/rtl8723ds_config",
|
||||
.hw_info = "rtl8723ds" },
|
||||
|
||||
/* 8821A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8821a_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8821a_config" },
|
||||
.fw_name = "rtl_bt/rtl8821a_fw",
|
||||
.cfg_name = "rtl_bt/rtl8821a_config",
|
||||
.hw_info = "rtl8821au" },
|
||||
|
||||
/* 8821C */
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8821c_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8821c_config" },
|
||||
.fw_name = "rtl_bt/rtl8821c_fw",
|
||||
.cfg_name = "rtl_bt/rtl8821c_config",
|
||||
.hw_info = "rtl8821cu" },
|
||||
|
||||
/* 8821CS */
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8821cs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8821cs_config" },
|
||||
.fw_name = "rtl_bt/rtl8821cs_fw",
|
||||
.cfg_name = "rtl_bt/rtl8821cs_config",
|
||||
.hw_info = "rtl8821cs" },
|
||||
|
||||
/* 8761A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8761a_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761a_config" },
|
||||
.fw_name = "rtl_bt/rtl8761a_fw",
|
||||
.cfg_name = "rtl_bt/rtl8761a_config",
|
||||
.hw_info = "rtl8761au" },
|
||||
|
||||
/* 8761B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8761b_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761b_config" },
|
||||
.fw_name = "rtl_bt/rtl8761b_fw",
|
||||
.cfg_name = "rtl_bt/rtl8761b_config",
|
||||
.hw_info = "rtl8761btv" },
|
||||
|
||||
/* 8761BU */
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8761bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761bu_config" },
|
||||
.fw_name = "rtl_bt/rtl8761bu_fw",
|
||||
.cfg_name = "rtl_bt/rtl8761bu_config",
|
||||
.hw_info = "rtl8761bu" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config" },
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config",
|
||||
.hw_info = "rtl8822cs" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config" },
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config",
|
||||
.hw_info = "rtl8822cs" },
|
||||
|
||||
/* 8822C with USB interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8822cu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cu_config" },
|
||||
.fw_name = "rtl_bt/rtl8822cu_fw",
|
||||
.cfg_name = "rtl_bt/rtl8822cu_config",
|
||||
.hw_info = "rtl8822cu" },
|
||||
|
||||
/* 8822B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8822b_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822b_config" },
|
||||
.fw_name = "rtl_bt/rtl8822b_fw",
|
||||
.cfg_name = "rtl_bt/rtl8822b_config",
|
||||
.hw_info = "rtl8822bu" },
|
||||
|
||||
/* 8852A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852au_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852au_config" },
|
||||
.fw_name = "rtl_bt/rtl8852au_fw",
|
||||
.cfg_name = "rtl_bt/rtl8852au_config",
|
||||
.hw_info = "rtl8852au" },
|
||||
|
||||
/* 8852B with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852bs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852bs_config" },
|
||||
.fw_name = "rtl_bt/rtl8852bs_fw",
|
||||
.cfg_name = "rtl_bt/rtl8852bs_config",
|
||||
.hw_info = "rtl8852bs" },
|
||||
|
||||
/* 8852B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852bu_config" },
|
||||
.fw_name = "rtl_bt/rtl8852bu_fw",
|
||||
.cfg_name = "rtl_bt/rtl8852bu_config",
|
||||
.hw_info = "rtl8852bu" },
|
||||
|
||||
/* 8852C */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xc, 0xc, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852cu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852cu_config" },
|
||||
.fw_name = "rtl_bt/rtl8852cu_fw",
|
||||
.cfg_name = "rtl_bt/rtl8852cu_config",
|
||||
.hw_info = "rtl8852cu" },
|
||||
|
||||
/* 8851B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8851B, 0xb, 0xc, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = false,
|
||||
.fw_name = "rtl_bt/rtl8851bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8851bu_config" },
|
||||
.fw_name = "rtl_bt/rtl8851bu_fw",
|
||||
.cfg_name = "rtl_bt/rtl8851bu_config",
|
||||
.hw_info = "rtl8851bu" },
|
||||
};
|
||||
|
||||
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
|
||||
|
@ -590,6 +616,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
|||
unsigned char **_buf)
|
||||
{
|
||||
static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
|
||||
struct btrealtek_data *coredump_info = hci_get_priv(hdev);
|
||||
struct rtl_epatch_header *epatch_info;
|
||||
unsigned char *buf;
|
||||
int i, len;
|
||||
|
@ -705,8 +732,10 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
|||
|
||||
epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data;
|
||||
num_patches = le16_to_cpu(epatch_info->num_patches);
|
||||
|
||||
BT_DBG("fw_version=%x, num_patches=%d",
|
||||
le32_to_cpu(epatch_info->fw_version), num_patches);
|
||||
coredump_info->rtl_dump.fw_version = le32_to_cpu(epatch_info->fw_version);
|
||||
|
||||
/* After the rtl_epatch_header there is a funky patch metadata section.
|
||||
* Assuming 2 patches, the layout is:
|
||||
|
@ -903,6 +932,53 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void btrtl_coredump(struct hci_dev *hdev)
|
||||
{
|
||||
static const u8 param[] = { 0x00, 0x00 };
|
||||
|
||||
__hci_cmd_send(hdev, RTL_VSC_OP_COREDUMP, sizeof(param), param);
|
||||
}
|
||||
|
||||
static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btrealtek_data *coredump_info = hci_get_priv(hdev);
|
||||
char buf[80];
|
||||
|
||||
if (coredump_info->rtl_dump.controller)
|
||||
snprintf(buf, sizeof(buf), "Controller Name: %s\n",
|
||||
coredump_info->rtl_dump.controller);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "Controller Name: Unknown\n");
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
|
||||
coredump_info->rtl_dump.fw_version);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info->rtl_dump.driver_name);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Vendor: Realtek\n");
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static int btrtl_register_devcoredump_support(struct hci_dev *hdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
|
||||
{
|
||||
struct btrealtek_data *coredump_info = hci_get_priv(hdev);
|
||||
|
||||
coredump_info->rtl_dump.driver_name = driver_name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btrtl_set_driver_name);
|
||||
|
||||
static bool rtl_has_chip_type(u16 lmp_subver)
|
||||
{
|
||||
switch (lmp_subver) {
|
||||
|
@ -964,15 +1040,16 @@ EXPORT_SYMBOL_GPL(btrtl_free);
|
|||
struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
|
||||
const char *postfix)
|
||||
{
|
||||
struct btrealtek_data *coredump_info = hci_get_priv(hdev);
|
||||
struct btrtl_device_info *btrtl_dev;
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_local_version *resp;
|
||||
struct hci_command_hdr *cmd;
|
||||
char fw_name[40];
|
||||
char cfg_name[40];
|
||||
u16 hci_rev, lmp_subver;
|
||||
u8 hci_ver, lmp_ver, chip_type = 0;
|
||||
int ret;
|
||||
u16 opcode;
|
||||
u8 cmd[2];
|
||||
u8 reg_val[2];
|
||||
|
||||
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
|
||||
|
@ -1041,15 +1118,14 @@ next:
|
|||
btrtl_dev->drop_fw = false;
|
||||
|
||||
if (btrtl_dev->drop_fw) {
|
||||
opcode = hci_opcode_pack(0x3f, 0x66);
|
||||
cmd[0] = opcode & 0xff;
|
||||
cmd[1] = opcode >> 8;
|
||||
|
||||
skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
|
||||
skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto err_free;
|
||||
|
||||
skb_put_data(skb, cmd, sizeof(cmd));
|
||||
cmd = skb_put(skb, HCI_COMMAND_HDR_SIZE);
|
||||
cmd->opcode = cpu_to_le16(0xfc66);
|
||||
cmd->plen = 0;
|
||||
|
||||
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
|
||||
|
||||
ret = hdev->send(hdev, skb);
|
||||
|
@ -1079,8 +1155,26 @@ next:
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
btrtl_dev->fw_len = rtl_load_file(hdev, btrtl_dev->ic_info->fw_name,
|
||||
&btrtl_dev->fw_data);
|
||||
if (!btrtl_dev->ic_info->fw_name) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
btrtl_dev->fw_len = -EIO;
|
||||
if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) {
|
||||
snprintf(fw_name, sizeof(fw_name), "%s_v2.bin",
|
||||
btrtl_dev->ic_info->fw_name);
|
||||
btrtl_dev->fw_len = rtl_load_file(hdev, fw_name,
|
||||
&btrtl_dev->fw_data);
|
||||
}
|
||||
|
||||
if (btrtl_dev->fw_len < 0) {
|
||||
snprintf(fw_name, sizeof(fw_name), "%s.bin",
|
||||
btrtl_dev->ic_info->fw_name);
|
||||
btrtl_dev->fw_len = rtl_load_file(hdev, fw_name,
|
||||
&btrtl_dev->fw_data);
|
||||
}
|
||||
|
||||
if (btrtl_dev->fw_len < 0) {
|
||||
rtl_dev_err(hdev, "firmware file %s not found",
|
||||
btrtl_dev->ic_info->fw_name);
|
||||
|
@ -1113,6 +1207,9 @@ next:
|
|||
if (btrtl_dev->ic_info->has_msft_ext)
|
||||
hci_set_msft_opcode(hdev, 0xFCF0);
|
||||
|
||||
if (btrtl_dev->ic_info)
|
||||
coredump_info->rtl_dump.controller = btrtl_dev->ic_info->hw_info;
|
||||
|
||||
return btrtl_dev;
|
||||
|
||||
err_free:
|
||||
|
@ -1125,6 +1222,8 @@ EXPORT_SYMBOL_GPL(btrtl_initialize);
|
|||
int btrtl_download_firmware(struct hci_dev *hdev,
|
||||
struct btrtl_device_info *btrtl_dev)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* Match a set of subver values that correspond to stock firmware,
|
||||
* which is not compatible with standard btusb.
|
||||
* If matched, upload an alternative firmware that does conform to
|
||||
|
@ -1133,12 +1232,14 @@ int btrtl_download_firmware(struct hci_dev *hdev,
|
|||
*/
|
||||
if (!btrtl_dev->ic_info) {
|
||||
rtl_dev_info(hdev, "assuming no firmware upload needed");
|
||||
return 0;
|
||||
err = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (btrtl_dev->ic_info->lmp_subver) {
|
||||
case RTL_ROM_LMP_8723A:
|
||||
return btrtl_setup_rtl8723a(hdev, btrtl_dev);
|
||||
err = btrtl_setup_rtl8723a(hdev, btrtl_dev);
|
||||
break;
|
||||
case RTL_ROM_LMP_8723B:
|
||||
case RTL_ROM_LMP_8821A:
|
||||
case RTL_ROM_LMP_8761A:
|
||||
|
@ -1146,11 +1247,18 @@ int btrtl_download_firmware(struct hci_dev *hdev,
|
|||
case RTL_ROM_LMP_8852A:
|
||||
case RTL_ROM_LMP_8703B:
|
||||
case RTL_ROM_LMP_8851B:
|
||||
return btrtl_setup_rtl8723b(hdev, btrtl_dev);
|
||||
err = btrtl_setup_rtl8723b(hdev, btrtl_dev);
|
||||
break;
|
||||
default:
|
||||
rtl_dev_info(hdev, "assuming no firmware upload needed");
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (!err)
|
||||
err = btrtl_register_devcoredump_support(hdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btrtl_download_firmware);
|
||||
|
||||
|
@ -1180,6 +1288,10 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
|
|||
if (btrtl_dev->project_id == CHIP_ID_8852C)
|
||||
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
|
||||
|
||||
if (btrtl_dev->project_id == CHIP_ID_8852A ||
|
||||
btrtl_dev->project_id == CHIP_ID_8852C)
|
||||
set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks);
|
||||
|
||||
hci_set_aosp_capable(hdev);
|
||||
break;
|
||||
default:
|
||||
|
@ -1398,4 +1510,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bs_config.bin");
|
|||
MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin");
|
||||
|
|
|
@ -109,8 +109,16 @@ enum {
|
|||
__REALTEK_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct rtl_dump_info {
|
||||
const char *driver_name;
|
||||
char *controller;
|
||||
u32 fw_version;
|
||||
};
|
||||
|
||||
struct btrealtek_data {
|
||||
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
|
||||
|
||||
struct rtl_dump_info rtl_dump;
|
||||
};
|
||||
|
||||
#define btrealtek_set_flag(hdev, nr) \
|
||||
|
@ -139,6 +147,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
|
|||
struct btrtl_device_info *btrtl_dev,
|
||||
unsigned int *controller_baudrate,
|
||||
u32 *device_baudrate, bool *flow_control);
|
||||
void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -182,4 +191,8 @@ static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static inline void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -175,7 +175,7 @@ static const struct usb_device_id btusb_table[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(usb, btusb_table);
|
||||
|
||||
static const struct usb_device_id blacklist_table[] = {
|
||||
static const struct usb_device_id quirks_table[] = {
|
||||
/* CSR BlueCore devices */
|
||||
{ USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },
|
||||
|
||||
|
@ -476,6 +476,7 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
BTUSB_INTEL_NO_WBS_SUPPORT |
|
||||
|
@ -625,9 +626,24 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x0489, 0xe0e4), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x0489, 0xe0f1), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x0489, 0xe0f6), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional Realtek 8723AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
|
||||
|
@ -860,10 +876,26 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
|
|||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct gpio_desc *reset_gpio = data->reset_gpio;
|
||||
struct btintel_data *intel_data = hci_get_priv(hdev);
|
||||
|
||||
if (++data->cmd_timeout_cnt < 5)
|
||||
return;
|
||||
|
||||
if (intel_data->acpi_reset_method) {
|
||||
if (test_and_set_bit(INTEL_ACPI_RESET_ACTIVE, intel_data->flags)) {
|
||||
bt_dev_err(hdev, "acpi: last reset failed ? Not resetting again");
|
||||
return;
|
||||
}
|
||||
|
||||
bt_dev_err(hdev, "Initiating acpi reset method");
|
||||
/* If ACPI reset method fails, lets try with legacy GPIO
|
||||
* toggling
|
||||
*/
|
||||
if (!intel_data->acpi_reset_method(hdev)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!reset_gpio) {
|
||||
btusb_reset(hdev);
|
||||
return;
|
||||
|
@ -887,10 +919,49 @@ static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
|
|||
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||
}
|
||||
|
||||
#define RTK_DEVCOREDUMP_CODE_MEMDUMP 0x01
|
||||
#define RTK_DEVCOREDUMP_CODE_HW_ERR 0x02
|
||||
#define RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT 0x03
|
||||
|
||||
#define RTK_SUB_EVENT_CODE_COREDUMP 0x34
|
||||
|
||||
struct rtk_dev_coredump_hdr {
|
||||
u8 type;
|
||||
u8 code;
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
static inline void btusb_rtl_alloc_devcoredump(struct hci_dev *hdev,
|
||||
struct rtk_dev_coredump_hdr *hdr, u8 *buf, u32 len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = alloc_skb(len + sizeof(*hdr), GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
skb_put_data(skb, hdr, sizeof(*hdr));
|
||||
if (len)
|
||||
skb_put_data(skb, buf, len);
|
||||
|
||||
if (!hci_devcd_init(hdev, skb->len)) {
|
||||
hci_devcd_append(hdev, skb);
|
||||
hci_devcd_complete(hdev);
|
||||
} else {
|
||||
bt_dev_err(hdev, "RTL: Failed to generate devcoredump");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct gpio_desc *reset_gpio = data->reset_gpio;
|
||||
struct rtk_dev_coredump_hdr hdr = {
|
||||
.type = RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT,
|
||||
};
|
||||
|
||||
btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
|
||||
|
||||
if (++data->cmd_timeout_cnt < 5)
|
||||
return;
|
||||
|
@ -917,6 +988,18 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
|
|||
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||
}
|
||||
|
||||
static void btusb_rtl_hw_error(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
struct rtk_dev_coredump_hdr hdr = {
|
||||
.type = RTK_DEVCOREDUMP_CODE_HW_ERR,
|
||||
.code = code,
|
||||
};
|
||||
|
||||
bt_dev_err(hdev, "RTL: hw err, trigger devcoredump (%d)", code);
|
||||
|
||||
btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
|
||||
}
|
||||
|
||||
static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
@ -2079,7 +2162,7 @@ static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts)
|
|||
* alternate setting.
|
||||
*/
|
||||
spin_lock_irqsave(&data->rxlock, flags);
|
||||
kfree_skb(data->sco_skb);
|
||||
dev_kfree_skb_irq(data->sco_skb);
|
||||
data->sco_skb = NULL;
|
||||
spin_unlock_irqrestore(&data->rxlock, flags);
|
||||
|
||||
|
@ -2409,79 +2492,6 @@ static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer,
|
|||
return btusb_recv_bulk(data, buffer, count);
|
||||
}
|
||||
|
||||
static int btusb_intel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct intel_tlv *tlv = (void *)&skb->data[5];
|
||||
|
||||
/* The first event is always an event type TLV */
|
||||
if (tlv->type != INTEL_TLV_TYPE_ID)
|
||||
goto recv_frame;
|
||||
|
||||
switch (tlv->val[0]) {
|
||||
case INTEL_TLV_SYSTEM_EXCEPTION:
|
||||
case INTEL_TLV_FATAL_EXCEPTION:
|
||||
case INTEL_TLV_DEBUG_EXCEPTION:
|
||||
case INTEL_TLV_TEST_EXCEPTION:
|
||||
/* Generate devcoredump from exception */
|
||||
if (!hci_devcd_init(hdev, skb->len)) {
|
||||
hci_devcd_append(hdev, skb);
|
||||
hci_devcd_complete(hdev);
|
||||
} else {
|
||||
bt_dev_err(hdev, "Failed to generate devcoredump");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
|
||||
}
|
||||
|
||||
recv_frame:
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
|
||||
|
||||
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
|
||||
hdr->plen > 0) {
|
||||
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
|
||||
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
|
||||
|
||||
if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
|
||||
switch (skb->data[2]) {
|
||||
case 0x02:
|
||||
/* When switching to the operational firmware
|
||||
* the device sends a vendor specific event
|
||||
* indicating that the bootup completed.
|
||||
*/
|
||||
btintel_bootup(hdev, ptr, len);
|
||||
break;
|
||||
case 0x06:
|
||||
/* When the firmware loading completes the
|
||||
* device sends out a vendor specific event
|
||||
* indicating the result of the firmware
|
||||
* loading.
|
||||
*/
|
||||
btintel_secure_send_result(hdev, ptr, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle all diagnostics events separately. May still call
|
||||
* hci_recv_frame.
|
||||
*/
|
||||
if (len >= sizeof(diagnostics_hdr) &&
|
||||
memcmp(&skb->data[2], diagnostics_hdr,
|
||||
sizeof(diagnostics_hdr)) == 0) {
|
||||
return btusb_intel_diagnostics(hdev, skb);
|
||||
}
|
||||
}
|
||||
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct urb *urb;
|
||||
|
@ -2562,6 +2572,25 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
|
||||
struct rtk_dev_coredump_hdr hdr = {
|
||||
.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
|
||||
};
|
||||
|
||||
bt_dev_dbg(hdev, "RTL: received coredump vendor evt, len %u",
|
||||
skb->len);
|
||||
|
||||
btusb_rtl_alloc_devcoredump(hdev, &hdr, skb->data, skb->len);
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
/* UHW CR mapping */
|
||||
#define MTK_BT_MISC 0x70002510
|
||||
#define MTK_BT_SUBSYS_RST 0x70002610
|
||||
|
@ -2571,8 +2600,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
|
|||
#define MTK_EP_RST_OPT 0x74011890
|
||||
#define MTK_EP_RST_IN_OUT_OPT 0x00010001
|
||||
#define MTK_BT_RST_DONE 0x00000100
|
||||
#define MTK_BT_RESET_WAIT_MS 100
|
||||
#define MTK_BT_RESET_NUM_TRIES 10
|
||||
#define MTK_BT_RESET_REG_CONNV3 0x70028610
|
||||
#define MTK_BT_READ_DEV_ID 0x70010200
|
||||
|
||||
|
||||
static void btusb_mtk_wmt_recv(struct urb *urb)
|
||||
{
|
||||
|
@ -2943,6 +2973,88 @@ static int btusb_mtk_id_get(struct btusb_data *data, u32 reg, u32 *id)
|
|||
return btusb_mtk_reg_read(data, reg, id);
|
||||
}
|
||||
|
||||
static u32 btusb_mtk_reset_done(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u32 val = 0;
|
||||
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val);
|
||||
|
||||
return val & MTK_BT_RST_DONE;
|
||||
}
|
||||
|
||||
static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct btmediatek_data *mediatek;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
/* It's MediaTek specific bluetooth reset mechanism via USB */
|
||||
if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
|
||||
bt_dev_err(hdev, "last reset failed? Not resetting again");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = usb_autopm_get_interface(data->intf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
btusb_stop_traffic(data);
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
mediatek = hci_get_priv(hdev);
|
||||
|
||||
if (mediatek->dev_id == 0x7925) {
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
|
||||
val |= (1 << 5);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
|
||||
val &= 0xFFFF00FF;
|
||||
val |= (1 << 13);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, 0x00010001);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
|
||||
val |= (1 << 0);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
|
||||
msleep(100);
|
||||
} else {
|
||||
/* It's Device EndPoint Reset Option Register */
|
||||
bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
|
||||
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
|
||||
|
||||
/* Reset the bluetooth chip via USB interface. */
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
|
||||
/* MT7921 need to delay 20ms between toggle reset bit */
|
||||
msleep(20);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
|
||||
}
|
||||
|
||||
err = readx_poll_timeout(btusb_mtk_reset_done, hdev, val,
|
||||
val & MTK_BT_RST_DONE, 20000, 1000000);
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Reset timeout");
|
||||
|
||||
btusb_mtk_id_get(data, 0x70010200, &val);
|
||||
if (!val)
|
||||
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
|
||||
|
||||
usb_queue_reset_device(data->intf);
|
||||
|
||||
clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_mtk_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
@ -2953,10 +3065,11 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
|||
struct sk_buff *skb;
|
||||
const char *fwname;
|
||||
int err, status;
|
||||
u32 dev_id;
|
||||
u32 dev_id = 0;
|
||||
char fw_bin_name[64];
|
||||
u32 fw_version = 0;
|
||||
u8 param;
|
||||
struct btmediatek_data *mediatek;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
|
@ -2966,7 +3079,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!dev_id) {
|
||||
if (!dev_id || dev_id != 0x7663) {
|
||||
err = btusb_mtk_id_get(data, 0x70010200, &dev_id);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to get device id (%d)", err);
|
||||
|
@ -2979,6 +3092,14 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
|||
}
|
||||
}
|
||||
|
||||
mediatek = hci_get_priv(hdev);
|
||||
mediatek->dev_id = dev_id;
|
||||
mediatek->reset_sync = btusb_mtk_reset;
|
||||
|
||||
err = btmtk_register_coredump(hdev, btusb_driver.name, fw_version);
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Failed to register coredump (%d)", err);
|
||||
|
||||
switch (dev_id) {
|
||||
case 0x7663:
|
||||
fwname = FIRMWARE_MT7663;
|
||||
|
@ -2988,9 +3109,16 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
|||
break;
|
||||
case 0x7922:
|
||||
case 0x7961:
|
||||
snprintf(fw_bin_name, sizeof(fw_bin_name),
|
||||
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
|
||||
dev_id & 0xffff, (fw_version & 0xff) + 1);
|
||||
case 0x7925:
|
||||
if (dev_id == 0x7925)
|
||||
snprintf(fw_bin_name, sizeof(fw_bin_name),
|
||||
"mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
|
||||
dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1);
|
||||
else
|
||||
snprintf(fw_bin_name, sizeof(fw_bin_name),
|
||||
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
|
||||
dev_id & 0xffff, (fw_version & 0xff) + 1);
|
||||
|
||||
err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
|
||||
btusb_mtk_hci_wmt_sync);
|
||||
if (err < 0) {
|
||||
|
@ -3128,67 +3256,11 @@ static int btusb_mtk_shutdown(struct hci_dev *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void btusb_mtk_cmd_timeout(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u32 val;
|
||||
int err, retry = 0;
|
||||
|
||||
/* It's MediaTek specific bluetooth reset mechanism via USB */
|
||||
if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
|
||||
bt_dev_err(hdev, "last reset failed? Not resetting again");
|
||||
return;
|
||||
}
|
||||
|
||||
err = usb_autopm_get_interface(data->intf);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
btusb_stop_traffic(data);
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
|
||||
/* It's Device EndPoint Reset Option Register */
|
||||
bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
|
||||
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
|
||||
|
||||
/* Reset the bluetooth chip via USB interface. */
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
|
||||
/* MT7921 need to delay 20ms between toggle reset bit */
|
||||
msleep(20);
|
||||
btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
|
||||
|
||||
/* Poll the register until reset is completed */
|
||||
do {
|
||||
btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val);
|
||||
if (val & MTK_BT_RST_DONE) {
|
||||
bt_dev_dbg(hdev, "Bluetooth Reset Successfully");
|
||||
break;
|
||||
}
|
||||
|
||||
bt_dev_dbg(hdev, "Polling Bluetooth Reset CR");
|
||||
retry++;
|
||||
msleep(MTK_BT_RESET_WAIT_MS);
|
||||
} while (retry < MTK_BT_RESET_NUM_TRIES);
|
||||
|
||||
btusb_mtk_id_get(data, 0x70010200, &val);
|
||||
if (!val)
|
||||
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
|
||||
|
||||
usb_queue_reset_device(data->intf);
|
||||
|
||||
clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags);
|
||||
}
|
||||
|
||||
static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
|
||||
struct sk_buff *skb_cd;
|
||||
|
||||
switch (handle) {
|
||||
case 0xfc6f: /* Firmware dump from device */
|
||||
|
@ -3196,6 +3268,15 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
* suspend and thus disable auto-suspend.
|
||||
*/
|
||||
usb_disable_autosuspend(data->udev);
|
||||
|
||||
/* We need to forward the diagnostic packet to userspace daemon
|
||||
* for backward compatibility, so we have to clone the packet
|
||||
* extraly for the in-kernel coredump support.
|
||||
*/
|
||||
skb_cd = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb_cd)
|
||||
btmtk_process_coredump(hdev, skb_cd);
|
||||
|
||||
fallthrough;
|
||||
case 0x05ff: /* Firmware debug logging 1 */
|
||||
case 0x05fe: /* Firmware debug logging 2 */
|
||||
|
@ -4113,7 +4194,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
if (!id->driver_info) {
|
||||
const struct usb_device_id *match;
|
||||
|
||||
match = usb_match_id(intf, blacklist_table);
|
||||
match = usb_match_id(intf, quirks_table);
|
||||
if (match)
|
||||
id = match;
|
||||
}
|
||||
|
@ -4196,11 +4277,16 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
priv_size += sizeof(struct btintel_data);
|
||||
|
||||
/* Override the rx handlers */
|
||||
data->recv_event = btusb_recv_event_intel;
|
||||
data->recv_event = btintel_recv_event;
|
||||
data->recv_bulk = btusb_recv_bulk_intel;
|
||||
} else if (id->driver_info & BTUSB_REALTEK) {
|
||||
/* Allocate extra space for Realtek device */
|
||||
priv_size += sizeof(struct btrealtek_data);
|
||||
|
||||
data->recv_event = btusb_recv_event_realtek;
|
||||
} else if (id->driver_info & BTUSB_MEDIATEK) {
|
||||
/* Allocate extra space for Mediatek device */
|
||||
priv_size += sizeof(struct btmediatek_data);
|
||||
}
|
||||
|
||||
data->recv_acl = hci_recv_frame;
|
||||
|
@ -4307,7 +4393,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
hdev->setup = btusb_mtk_setup;
|
||||
hdev->shutdown = btusb_mtk_shutdown;
|
||||
hdev->manufacturer = 70;
|
||||
hdev->cmd_timeout = btusb_mtk_cmd_timeout;
|
||||
hdev->cmd_timeout = btmtk_reset_sync;
|
||||
hdev->set_bdaddr = btmtk_set_bdaddr;
|
||||
set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
|
||||
|
@ -4364,9 +4450,11 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
|
||||
(id->driver_info & BTUSB_REALTEK)) {
|
||||
btrtl_set_driver_name(hdev, btusb_driver.name);
|
||||
hdev->setup = btusb_setup_realtek;
|
||||
hdev->shutdown = btrtl_shutdown_realtek;
|
||||
hdev->cmd_timeout = btusb_rtl_cmd_timeout;
|
||||
hdev->hw_error = btusb_rtl_hw_error;
|
||||
|
||||
/* Realtek devices need to set remote wakeup on auto-suspend */
|
||||
set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
|
|
@ -770,7 +770,8 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
|
|||
break;
|
||||
|
||||
case HCIUARTGETPROTO:
|
||||
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
|
||||
if (test_bit(HCI_UART_PROTO_SET, &hu->flags) &&
|
||||
test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
err = hu->proto->id;
|
||||
else
|
||||
err = -EUNATCH;
|
||||
|
|
|
@ -734,7 +734,11 @@ static int nokia_bluetooth_serdev_probe(struct serdev_device *serdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
clk_prepare_enable(sysclk);
|
||||
err = clk_prepare_enable(sysclk);
|
||||
if (err) {
|
||||
dev_err(dev, "could not enable sysclk: %d", err);
|
||||
return err;
|
||||
}
|
||||
btdev->sysclk_speed = clk_get_rate(sysclk);
|
||||
clk_disable_unprepare(sysclk);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
@ -117,9 +117,7 @@ enum qca_memdump_states {
|
|||
QCA_MEMDUMP_TIMEOUT,
|
||||
};
|
||||
|
||||
struct qca_memdump_data {
|
||||
char *memdump_buf_head;
|
||||
char *memdump_buf_tail;
|
||||
struct qca_memdump_info {
|
||||
u32 current_seq_no;
|
||||
u32 received_dump;
|
||||
u32 ram_dump_size;
|
||||
|
@ -160,13 +158,15 @@ struct qca_data {
|
|||
struct work_struct ws_tx_vote_off;
|
||||
struct work_struct ctrl_memdump_evt;
|
||||
struct delayed_work ctrl_memdump_timeout;
|
||||
struct qca_memdump_data *qca_memdump;
|
||||
struct qca_memdump_info *qca_memdump;
|
||||
unsigned long flags;
|
||||
struct completion drop_ev_comp;
|
||||
wait_queue_head_t suspend_wait_q;
|
||||
enum qca_memdump_states memdump_state;
|
||||
struct mutex hci_memdump_lock;
|
||||
|
||||
u16 fw_version;
|
||||
u16 controller_id;
|
||||
/* For debugging purpose */
|
||||
u64 ibs_sent_wacks;
|
||||
u64 ibs_sent_slps;
|
||||
|
@ -233,6 +233,7 @@ static void qca_regulator_disable(struct qca_serdev *qcadev);
|
|||
static void qca_power_shutdown(struct hci_uart *hu);
|
||||
static int qca_power_off(struct hci_dev *hdev);
|
||||
static void qca_controller_memdump(struct work_struct *work);
|
||||
static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
||||
static enum qca_btsoc_type qca_soc_type(struct hci_uart *hu)
|
||||
{
|
||||
|
@ -606,9 +607,18 @@ static int qca_open(struct hci_uart *hu)
|
|||
if (hu->serdev) {
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
|
||||
if (qca_is_wcn399x(qcadev->btsoc_type) ||
|
||||
qca_is_wcn6750(qcadev->btsoc_type))
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
hu->init_speed = qcadev->init_speed;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (qcadev->oper_speed)
|
||||
hu->oper_speed = qcadev->oper_speed;
|
||||
|
@ -980,6 +990,28 @@ static int qca_recv_acl_data(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct qca_data *qca = hu->priv;
|
||||
char buf[80];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n",
|
||||
qca->controller_id);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n",
|
||||
qca->fw_version);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Vendor:Qualcomm\n");
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Driver: %s\n",
|
||||
hu->serdev->dev.driver->name);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static void qca_controller_memdump(struct work_struct *work)
|
||||
{
|
||||
struct qca_data *qca = container_of(work, struct qca_data,
|
||||
|
@ -987,13 +1019,11 @@ static void qca_controller_memdump(struct work_struct *work)
|
|||
struct hci_uart *hu = qca->hu;
|
||||
struct sk_buff *skb;
|
||||
struct qca_memdump_event_hdr *cmd_hdr;
|
||||
struct qca_memdump_data *qca_memdump = qca->qca_memdump;
|
||||
struct qca_memdump_info *qca_memdump = qca->qca_memdump;
|
||||
struct qca_dump_size *dump;
|
||||
char *memdump_buf;
|
||||
char nullBuff[QCA_DUMP_PACKET_SIZE] = { 0 };
|
||||
u16 seq_no;
|
||||
u32 dump_size;
|
||||
u32 rx_size;
|
||||
int ret = 0;
|
||||
enum qca_btsoc_type soc_type = qca_soc_type(hu);
|
||||
|
||||
while ((skb = skb_dequeue(&qca->rx_memdump_q))) {
|
||||
|
@ -1009,7 +1039,7 @@ static void qca_controller_memdump(struct work_struct *work)
|
|||
}
|
||||
|
||||
if (!qca_memdump) {
|
||||
qca_memdump = kzalloc(sizeof(struct qca_memdump_data),
|
||||
qca_memdump = kzalloc(sizeof(struct qca_memdump_info),
|
||||
GFP_ATOMIC);
|
||||
if (!qca_memdump) {
|
||||
mutex_unlock(&qca->hci_memdump_lock);
|
||||
|
@ -1035,44 +1065,49 @@ static void qca_controller_memdump(struct work_struct *work)
|
|||
set_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
|
||||
dump = (void *) skb->data;
|
||||
dump_size = __le32_to_cpu(dump->dump_size);
|
||||
if (!(dump_size)) {
|
||||
qca_memdump->ram_dump_size = __le32_to_cpu(dump->dump_size);
|
||||
if (!(qca_memdump->ram_dump_size)) {
|
||||
bt_dev_err(hu->hdev, "Rx invalid memdump size");
|
||||
kfree(qca_memdump);
|
||||
kfree_skb(skb);
|
||||
mutex_unlock(&qca->hci_memdump_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
queue_delayed_work(qca->workqueue,
|
||||
&qca->ctrl_memdump_timeout,
|
||||
msecs_to_jiffies(MEMDUMP_TIMEOUT_MS));
|
||||
skb_pull(skb, sizeof(qca_memdump->ram_dump_size));
|
||||
qca_memdump->current_seq_no = 0;
|
||||
qca_memdump->received_dump = 0;
|
||||
ret = hci_devcd_init(hu->hdev, qca_memdump->ram_dump_size);
|
||||
bt_dev_info(hu->hdev, "hci_devcd_init Return:%d",
|
||||
ret);
|
||||
if (ret < 0) {
|
||||
kfree(qca->qca_memdump);
|
||||
qca->qca_memdump = NULL;
|
||||
qca->memdump_state = QCA_MEMDUMP_COLLECTED;
|
||||
cancel_delayed_work(&qca->ctrl_memdump_timeout);
|
||||
clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
|
||||
mutex_unlock(&qca->hci_memdump_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
bt_dev_info(hu->hdev, "QCA collecting dump of size:%u",
|
||||
dump_size);
|
||||
queue_delayed_work(qca->workqueue,
|
||||
&qca->ctrl_memdump_timeout,
|
||||
msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)
|
||||
);
|
||||
qca_memdump->ram_dump_size);
|
||||
|
||||
skb_pull(skb, sizeof(dump_size));
|
||||
memdump_buf = vmalloc(dump_size);
|
||||
qca_memdump->ram_dump_size = dump_size;
|
||||
qca_memdump->memdump_buf_head = memdump_buf;
|
||||
qca_memdump->memdump_buf_tail = memdump_buf;
|
||||
}
|
||||
|
||||
memdump_buf = qca_memdump->memdump_buf_tail;
|
||||
|
||||
/* If sequence no 0 is missed then there is no point in
|
||||
* accepting the other sequences.
|
||||
*/
|
||||
if (!memdump_buf) {
|
||||
if (!test_bit(QCA_MEMDUMP_COLLECTION, &qca->flags)) {
|
||||
bt_dev_err(hu->hdev, "QCA: Discarding other packets");
|
||||
kfree(qca_memdump);
|
||||
kfree_skb(skb);
|
||||
qca->qca_memdump = NULL;
|
||||
mutex_unlock(&qca->hci_memdump_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* There could be chance of missing some packets from
|
||||
* the controller. In such cases let us store the dummy
|
||||
* packets in the buffer.
|
||||
|
@ -1082,8 +1117,8 @@ static void qca_controller_memdump(struct work_struct *work)
|
|||
* bits, so skip this checking for missing packet.
|
||||
*/
|
||||
while ((seq_no > qca_memdump->current_seq_no + 1) &&
|
||||
(soc_type != QCA_QCA6390) &&
|
||||
seq_no != QCA_LAST_SEQUENCE_NUM) {
|
||||
(soc_type != QCA_QCA6390) &&
|
||||
seq_no != QCA_LAST_SEQUENCE_NUM) {
|
||||
bt_dev_err(hu->hdev, "QCA controller missed packet:%d",
|
||||
qca_memdump->current_seq_no);
|
||||
rx_size = qca_memdump->received_dump;
|
||||
|
@ -1094,43 +1129,38 @@ static void qca_controller_memdump(struct work_struct *work)
|
|||
qca_memdump->received_dump);
|
||||
break;
|
||||
}
|
||||
memcpy(memdump_buf, nullBuff, QCA_DUMP_PACKET_SIZE);
|
||||
memdump_buf = memdump_buf + QCA_DUMP_PACKET_SIZE;
|
||||
hci_devcd_append_pattern(hu->hdev, 0x00,
|
||||
QCA_DUMP_PACKET_SIZE);
|
||||
qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE;
|
||||
qca_memdump->current_seq_no++;
|
||||
}
|
||||
|
||||
rx_size = qca_memdump->received_dump + skb->len;
|
||||
rx_size = qca_memdump->received_dump + skb->len;
|
||||
if (rx_size <= qca_memdump->ram_dump_size) {
|
||||
if ((seq_no != QCA_LAST_SEQUENCE_NUM) &&
|
||||
(seq_no != qca_memdump->current_seq_no))
|
||||
(seq_no != qca_memdump->current_seq_no)) {
|
||||
bt_dev_err(hu->hdev,
|
||||
"QCA memdump unexpected packet %d",
|
||||
seq_no);
|
||||
}
|
||||
bt_dev_dbg(hu->hdev,
|
||||
"QCA memdump packet %d with length %d",
|
||||
seq_no, skb->len);
|
||||
memcpy(memdump_buf, (unsigned char *)skb->data,
|
||||
skb->len);
|
||||
memdump_buf = memdump_buf + skb->len;
|
||||
qca_memdump->memdump_buf_tail = memdump_buf;
|
||||
qca_memdump->current_seq_no = seq_no + 1;
|
||||
qca_memdump->received_dump += skb->len;
|
||||
hci_devcd_append(hu->hdev, skb);
|
||||
qca_memdump->current_seq_no += 1;
|
||||
qca_memdump->received_dump = rx_size;
|
||||
} else {
|
||||
bt_dev_err(hu->hdev,
|
||||
"QCA memdump received %d, no space for packet %d",
|
||||
qca_memdump->received_dump, seq_no);
|
||||
"QCA memdump received no space for packet %d",
|
||||
qca_memdump->current_seq_no);
|
||||
}
|
||||
qca->qca_memdump = qca_memdump;
|
||||
kfree_skb(skb);
|
||||
|
||||
if (seq_no == QCA_LAST_SEQUENCE_NUM) {
|
||||
bt_dev_info(hu->hdev,
|
||||
"QCA memdump Done, received %d, total %d",
|
||||
qca_memdump->received_dump,
|
||||
qca_memdump->ram_dump_size);
|
||||
memdump_buf = qca_memdump->memdump_buf_head;
|
||||
dev_coredumpv(&hu->serdev->dev, memdump_buf,
|
||||
qca_memdump->received_dump, GFP_KERNEL);
|
||||
"QCA memdump Done, received %d, total %d",
|
||||
qca_memdump->received_dump,
|
||||
qca_memdump->ram_dump_size);
|
||||
hci_devcd_complete(hu->hdev);
|
||||
cancel_delayed_work(&qca->ctrl_memdump_timeout);
|
||||
kfree(qca->qca_memdump);
|
||||
qca->qca_memdump = NULL;
|
||||
|
@ -1320,12 +1350,20 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
|||
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
|
||||
|
||||
/* Give the controller time to process the request */
|
||||
if (qca_is_wcn399x(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6750(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6855(qca_soc_type(hu)))
|
||||
switch (qca_soc_type(hu)) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
usleep_range(1000, 10000);
|
||||
else
|
||||
break;
|
||||
|
||||
default:
|
||||
msleep(300);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1398,13 +1436,20 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
|
|||
|
||||
static int qca_check_speeds(struct hci_uart *hu)
|
||||
{
|
||||
if (qca_is_wcn399x(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6750(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6855(qca_soc_type(hu))) {
|
||||
switch (qca_soc_type(hu)) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
|
||||
!qca_get_speed(hu, QCA_OPER_SPEED))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!qca_get_speed(hu, QCA_INIT_SPEED) ||
|
||||
!qca_get_speed(hu, QCA_OPER_SPEED))
|
||||
return -EINVAL;
|
||||
|
@ -1433,14 +1478,29 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
|||
/* Disable flow control for wcn3990 to deassert RTS while
|
||||
* changing the baudrate of chip and host.
|
||||
*/
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type))
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
hci_uart_set_flow_control(hu, true);
|
||||
break;
|
||||
|
||||
if (soc_type == QCA_WCN3990) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
reinit_completion(&qca->drop_ev_comp);
|
||||
set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
qca_baudrate = qca_get_baudrate_value(speed);
|
||||
|
@ -1452,12 +1512,23 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
|||
host_set_baudrate(hu, speed);
|
||||
|
||||
error:
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type))
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
hci_uart_set_flow_control(hu, false);
|
||||
break;
|
||||
|
||||
if (soc_type == QCA_WCN3990) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
/* Wait for the controller to send the vendor event
|
||||
* for the baudrate change command.
|
||||
*/
|
||||
|
@ -1469,6 +1540,10 @@ error:
|
|||
}
|
||||
|
||||
clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1541,8 +1616,8 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
|
|||
mutex_lock(&qca->hci_memdump_lock);
|
||||
if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
|
||||
bt_dev_err(hu->hdev, "clearing allocated memory due to memdump timeout");
|
||||
hci_devcd_abort(hu->hdev);
|
||||
if (qca->qca_memdump) {
|
||||
vfree(qca->qca_memdump->memdump_buf_head);
|
||||
kfree(qca->qca_memdump);
|
||||
qca->qca_memdump = NULL;
|
||||
}
|
||||
|
@ -1630,12 +1705,20 @@ static int qca_regulator_init(struct hci_uart *hu)
|
|||
}
|
||||
}
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
/* Forcefully enable wcn399x to enter in to boot mode. */
|
||||
host_set_baudrate(hu, 2400);
|
||||
ret = qca_send_power_pulse(hu, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* For wcn6750 need to enable gpio bt_en */
|
||||
|
@ -1652,10 +1735,18 @@ static int qca_regulator_init(struct hci_uart *hu)
|
|||
|
||||
qca_set_speed(hu, QCA_INIT_SPEED);
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
ret = qca_send_power_pulse(hu, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now the device is in ready state to communicate with host.
|
||||
|
@ -1689,11 +1780,18 @@ static int qca_power_on(struct hci_dev *hdev)
|
|||
if (!hu->serdev)
|
||||
return 0;
|
||||
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
ret = qca_regulator_init(hu);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (qcadev->bt_en) {
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 1);
|
||||
|
@ -1706,6 +1804,17 @@ static int qca_power_on(struct hci_dev *hdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void hci_coredump_qca(struct hci_dev *hdev)
|
||||
{
|
||||
static const u8 param[] = { 0x26 };
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc0c, 1, param, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
bt_dev_err(hdev, "%s: trigger crash failed (%ld)", __func__, PTR_ERR(skb));
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static int qca_setup(struct hci_uart *hu)
|
||||
{
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
@ -1716,6 +1825,7 @@ static int qca_setup(struct hci_uart *hu)
|
|||
const char *firmware_name = qca_get_firmware_name(hu);
|
||||
int ret;
|
||||
struct qca_btsoc_version ver;
|
||||
const char *soc_name;
|
||||
|
||||
ret = qca_check_speeds(hu);
|
||||
if (ret)
|
||||
|
@ -1730,10 +1840,30 @@ static int qca_setup(struct hci_uart *hu)
|
|||
*/
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
|
||||
bt_dev_info(hdev, "setting up %s",
|
||||
qca_is_wcn399x(soc_type) ? "wcn399x" :
|
||||
(soc_type == QCA_WCN6750) ? "wcn6750" :
|
||||
(soc_type == QCA_WCN6855) ? "wcn6855" : "ROME/QCA6390");
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
soc_name = "wcn399x";
|
||||
break;
|
||||
|
||||
case QCA_WCN6750:
|
||||
soc_name = "wcn6750";
|
||||
break;
|
||||
|
||||
case QCA_WCN6855:
|
||||
soc_name = "wcn6855";
|
||||
break;
|
||||
|
||||
case QCA_WCN7850:
|
||||
soc_name = "wcn7850";
|
||||
break;
|
||||
|
||||
default:
|
||||
soc_name = "ROME/QCA6390";
|
||||
}
|
||||
bt_dev_info(hdev, "setting up %s", soc_name);
|
||||
|
||||
qca->memdump_state = QCA_MEMDUMP_IDLE;
|
||||
|
||||
|
@ -1744,16 +1874,23 @@ retry:
|
|||
|
||||
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
|
||||
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
|
||||
hci_set_aosp_capable(hdev);
|
||||
|
||||
ret = qca_read_soc_version(hdev, &ver, soc_type);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
qca_set_speed(hu, QCA_INIT_SPEED);
|
||||
}
|
||||
|
||||
|
@ -1767,9 +1904,17 @@ retry:
|
|||
qca_baudrate = qca_get_baudrate_value(speed);
|
||||
}
|
||||
|
||||
if (!(qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type))) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Get QCA version information */
|
||||
ret = qca_read_soc_version(hdev, &ver, soc_type);
|
||||
if (ret)
|
||||
|
@ -1820,6 +1965,9 @@ out:
|
|||
hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
|
||||
else
|
||||
hu->hdev->set_bdaddr = qca_set_bdaddr;
|
||||
qca->fw_version = le16_to_cpu(ver.patch_ver);
|
||||
qca->controller_id = le16_to_cpu(ver.rom_ver);
|
||||
hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1839,6 +1987,17 @@ static const struct hci_uart_proto qca_proto = {
|
|||
.dequeue = qca_dequeue,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_wcn3988 __maybe_unused = {
|
||||
.soc_type = QCA_WCN3988,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
{ "vddio", 15000 },
|
||||
{ "vddxo", 80000 },
|
||||
{ "vddrf", 300000 },
|
||||
{ "vddch0", 450000 },
|
||||
},
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_wcn3990 __maybe_unused = {
|
||||
.soc_type = QCA_WCN3990,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
|
@ -1909,6 +2068,20 @@ static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = {
|
|||
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = {
|
||||
.soc_type = QCA_WCN7850,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
{ "vddio", 5000 },
|
||||
{ "vddaon", 26000 },
|
||||
{ "vdddig", 126000 },
|
||||
{ "vddrfa0p8", 102000 },
|
||||
{ "vddrfa1p2", 257000 },
|
||||
{ "vddrfa1p9", 302000 },
|
||||
},
|
||||
.num_vregs = 6,
|
||||
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
|
||||
};
|
||||
|
||||
static void qca_power_shutdown(struct hci_uart *hu)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
|
@ -1934,11 +2107,18 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
|||
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
qca_regulator_disable(qcadev);
|
||||
} else if (soc_type == QCA_WCN6750 || soc_type == QCA_WCN6855) {
|
||||
break;
|
||||
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
msleep(100);
|
||||
qca_regulator_disable(qcadev);
|
||||
|
@ -1946,7 +2126,9 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
|||
sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
|
||||
bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
|
||||
}
|
||||
} else if (qcadev->bt_en) {
|
||||
break;
|
||||
|
||||
default:
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
}
|
||||
|
||||
|
@ -2071,11 +2253,19 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
|||
if (!qcadev->oper_speed)
|
||||
BT_DBG("UART will pick default operating speed");
|
||||
|
||||
if (data &&
|
||||
(qca_is_wcn399x(data->soc_type) ||
|
||||
qca_is_wcn6750(data->soc_type) ||
|
||||
qca_is_wcn6855(data->soc_type))) {
|
||||
if (data)
|
||||
qcadev->btsoc_type = data->soc_type;
|
||||
else
|
||||
qcadev->btsoc_type = QCA_ROME;
|
||||
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
qcadev->bt_power = devm_kzalloc(&serdev->dev,
|
||||
sizeof(struct qca_power),
|
||||
GFP_KERNEL);
|
||||
|
@ -2105,7 +2295,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
|||
GPIOD_IN);
|
||||
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) &&
|
||||
(data->soc_type == QCA_WCN6750 ||
|
||||
data->soc_type == QCA_WCN6855))
|
||||
data->soc_type == QCA_WCN6855 ||
|
||||
data->soc_type == QCA_WCN7850))
|
||||
dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
|
||||
|
||||
qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
|
||||
|
@ -2119,12 +2310,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
|||
BT_ERR("wcn3990 serdev registration failed");
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
qcadev->btsoc_type = data->soc_type;
|
||||
else
|
||||
qcadev->btsoc_type = QCA_ROME;
|
||||
break;
|
||||
|
||||
default:
|
||||
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR_OR_NULL(qcadev->bt_en)) {
|
||||
|
@ -2180,13 +2368,24 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
|||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||
struct qca_power *power = qcadev->bt_power;
|
||||
|
||||
if ((qca_is_wcn399x(qcadev->btsoc_type) ||
|
||||
qca_is_wcn6750(qcadev->btsoc_type) ||
|
||||
qca_is_wcn6855(qcadev->btsoc_type)) &&
|
||||
power->vregs_on)
|
||||
qca_power_shutdown(&qcadev->serdev_hu);
|
||||
else if (qcadev->susclk)
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
if (power->vregs_on) {
|
||||
qca_power_shutdown(&qcadev->serdev_hu);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
if (qcadev->susclk)
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
}
|
||||
|
||||
hci_uart_unregister_device(&qcadev->serdev_hu);
|
||||
}
|
||||
|
@ -2363,11 +2562,13 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
|
|||
{ .compatible = "qcom,qca6174-bt" },
|
||||
{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
|
||||
{ .compatible = "qcom,qca9377-bt" },
|
||||
{ .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988},
|
||||
{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
|
||||
{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
|
||||
{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
|
||||
{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
|
||||
{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
|
||||
{ .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
|
||||
|
@ -2384,6 +2585,18 @@ static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
|
|||
MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
static void hciqca_coredump(struct device *dev)
|
||||
{
|
||||
struct serdev_device *serdev = to_serdev_device(dev);
|
||||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||
struct hci_uart *hu = &qcadev->serdev_hu;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
||||
if (hdev->dump.coredump)
|
||||
hdev->dump.coredump(hdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct serdev_device_driver qca_serdev_driver = {
|
||||
.probe = qca_serdev_probe,
|
||||
|
@ -2394,6 +2607,9 @@ static struct serdev_device_driver qca_serdev_driver = {
|
|||
.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
|
||||
.shutdown = qca_serdev_shutdown,
|
||||
.pm = &qca_pm_ops,
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
.coredump = hciqca_coredump,
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -48,8 +48,47 @@ static DEFINE_PER_CPU(struct local_event, local_event) = {
|
|||
.lock = INIT_LOCAL_LOCK(lock),
|
||||
};
|
||||
|
||||
static int cn_filter(struct sock *dsk, struct sk_buff *skb, void *data)
|
||||
{
|
||||
__u32 what, exit_code, *ptr;
|
||||
enum proc_cn_mcast_op mc_op;
|
||||
uintptr_t val;
|
||||
|
||||
if (!dsk || !data)
|
||||
return 0;
|
||||
|
||||
ptr = (__u32 *)data;
|
||||
what = *ptr++;
|
||||
exit_code = *ptr;
|
||||
val = ((struct proc_input *)(dsk->sk_user_data))->event_type;
|
||||
mc_op = ((struct proc_input *)(dsk->sk_user_data))->mcast_op;
|
||||
|
||||
if (mc_op == PROC_CN_MCAST_IGNORE)
|
||||
return 1;
|
||||
|
||||
if ((__u32)val == PROC_EVENT_ALL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Drop packet if we have to report only non-zero exit status
|
||||
* (PROC_EVENT_NONZERO_EXIT) and exit status is 0
|
||||
*/
|
||||
if (((__u32)val & PROC_EVENT_NONZERO_EXIT) &&
|
||||
(what == PROC_EVENT_EXIT)) {
|
||||
if (exit_code)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((__u32)val & what)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void send_msg(struct cn_msg *msg)
|
||||
{
|
||||
__u32 filter_data[2];
|
||||
|
||||
local_lock(&local_event.lock);
|
||||
|
||||
msg->seq = __this_cpu_inc_return(local_event.count) - 1;
|
||||
|
@ -61,7 +100,16 @@ static inline void send_msg(struct cn_msg *msg)
|
|||
*
|
||||
* If cn_netlink_send() fails, the data is not sent.
|
||||
*/
|
||||
cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_NOWAIT);
|
||||
filter_data[0] = ((struct proc_event *)msg->data)->what;
|
||||
if (filter_data[0] == PROC_EVENT_EXIT) {
|
||||
filter_data[1] =
|
||||
((struct proc_event *)msg->data)->event_data.exit.exit_code;
|
||||
} else {
|
||||
filter_data[1] = 0;
|
||||
}
|
||||
|
||||
cn_netlink_send_mult(msg, msg->len, 0, CN_IDX_PROC, GFP_NOWAIT,
|
||||
cn_filter, (void *)filter_data);
|
||||
|
||||
local_unlock(&local_event.lock);
|
||||
}
|
||||
|
@ -341,16 +389,17 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
|
|||
|
||||
/**
|
||||
* cn_proc_mcast_ctl
|
||||
* @data: message sent from userspace via the connector
|
||||
* @msg: message sent from userspace via the connector
|
||||
* @nsp: NETLINK_CB of the client's socket buffer
|
||||
*/
|
||||
static void cn_proc_mcast_ctl(struct cn_msg *msg,
|
||||
struct netlink_skb_parms *nsp)
|
||||
{
|
||||
enum proc_cn_mcast_op *mc_op = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (msg->len != sizeof(*mc_op))
|
||||
return;
|
||||
enum proc_cn_mcast_op mc_op = 0, prev_mc_op = 0;
|
||||
struct proc_input *pinput = NULL;
|
||||
enum proc_cn_event ev_type = 0;
|
||||
int err = 0, initial = 0;
|
||||
struct sock *sk = NULL;
|
||||
|
||||
/*
|
||||
* Events are reported with respect to the initial pid
|
||||
|
@ -361,19 +410,51 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
|
|||
!task_is_in_init_pid_ns(current))
|
||||
return;
|
||||
|
||||
/* Can only change if privileged. */
|
||||
if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
|
||||
err = EPERM;
|
||||
goto out;
|
||||
if (msg->len == sizeof(*pinput)) {
|
||||
pinput = (struct proc_input *)msg->data;
|
||||
mc_op = pinput->mcast_op;
|
||||
ev_type = pinput->event_type;
|
||||
} else if (msg->len == sizeof(mc_op)) {
|
||||
mc_op = *((enum proc_cn_mcast_op *)msg->data);
|
||||
ev_type = PROC_EVENT_ALL;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
mc_op = (enum proc_cn_mcast_op *)msg->data;
|
||||
switch (*mc_op) {
|
||||
ev_type = valid_event((enum proc_cn_event)ev_type);
|
||||
|
||||
if (ev_type == PROC_EVENT_NONE)
|
||||
ev_type = PROC_EVENT_ALL;
|
||||
|
||||
if (nsp->sk) {
|
||||
sk = nsp->sk;
|
||||
if (sk->sk_user_data == NULL) {
|
||||
sk->sk_user_data = kzalloc(sizeof(struct proc_input),
|
||||
GFP_KERNEL);
|
||||
if (sk->sk_user_data == NULL) {
|
||||
err = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
initial = 1;
|
||||
} else {
|
||||
prev_mc_op =
|
||||
((struct proc_input *)(sk->sk_user_data))->mcast_op;
|
||||
}
|
||||
((struct proc_input *)(sk->sk_user_data))->event_type =
|
||||
ev_type;
|
||||
((struct proc_input *)(sk->sk_user_data))->mcast_op = mc_op;
|
||||
}
|
||||
|
||||
switch (mc_op) {
|
||||
case PROC_CN_MCAST_LISTEN:
|
||||
atomic_inc(&proc_event_num_listeners);
|
||||
if (initial || (prev_mc_op != PROC_CN_MCAST_LISTEN))
|
||||
atomic_inc(&proc_event_num_listeners);
|
||||
break;
|
||||
case PROC_CN_MCAST_IGNORE:
|
||||
atomic_dec(&proc_event_num_listeners);
|
||||
if (!initial && (prev_mc_op != PROC_CN_MCAST_IGNORE))
|
||||
atomic_dec(&proc_event_num_listeners);
|
||||
((struct proc_input *)(sk->sk_user_data))->event_type =
|
||||
PROC_EVENT_NONE;
|
||||
break;
|
||||
default:
|
||||
err = EINVAL;
|
||||
|
|
|
@ -59,7 +59,9 @@ static int cn_already_initialized;
|
|||
* both, or if both are zero then the group is looked up and sent there.
|
||||
*/
|
||||
int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group,
|
||||
gfp_t gfp_mask)
|
||||
gfp_t gfp_mask,
|
||||
int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),
|
||||
void *filter_data)
|
||||
{
|
||||
struct cn_callback_entry *__cbq;
|
||||
unsigned int size;
|
||||
|
@ -110,8 +112,9 @@ int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group,
|
|||
NETLINK_CB(skb).dst_group = group;
|
||||
|
||||
if (group)
|
||||
return netlink_broadcast(dev->nls, skb, portid, group,
|
||||
gfp_mask);
|
||||
return netlink_broadcast_filtered(dev->nls, skb, portid, group,
|
||||
gfp_mask, filter,
|
||||
(void *)filter_data);
|
||||
return netlink_unicast(dev->nls, skb, portid,
|
||||
!gfpflags_allow_blocking(gfp_mask));
|
||||
}
|
||||
|
@ -121,7 +124,8 @@ EXPORT_SYMBOL_GPL(cn_netlink_send_mult);
|
|||
int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
return cn_netlink_send_mult(msg, msg->len, portid, __group, gfp_mask);
|
||||
return cn_netlink_send_mult(msg, msg->len, portid, __group, gfp_mask,
|
||||
NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cn_netlink_send);
|
||||
|
||||
|
@ -162,6 +166,31 @@ static int cn_call_callback(struct sk_buff *skb)
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow non-root access for NETLINK_CONNECTOR family having CN_IDX_PROC
|
||||
* multicast group.
|
||||
*/
|
||||
static int cn_bind(struct net *net, int group)
|
||||
{
|
||||
unsigned long groups = (unsigned long) group;
|
||||
|
||||
if (ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return 0;
|
||||
|
||||
if (test_bit(CN_IDX_PROC - 1, &groups))
|
||||
return 0;
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static void cn_release(struct sock *sk, unsigned long *groups)
|
||||
{
|
||||
if (groups && test_bit(CN_IDX_PROC - 1, groups)) {
|
||||
kfree(sk->sk_user_data);
|
||||
sk->sk_user_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main netlink receiving function.
|
||||
*
|
||||
|
@ -249,6 +278,9 @@ static int cn_init(void)
|
|||
struct netlink_kernel_cfg cfg = {
|
||||
.groups = CN_NETLINK_USERS + 0xf,
|
||||
.input = cn_rx_skb,
|
||||
.flags = NL_CFG_F_NONROOT_RECV,
|
||||
.bind = cn_bind,
|
||||
.release = cn_release,
|
||||
};
|
||||
|
||||
dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, &cfg);
|
||||
|
|
|
@ -58,7 +58,7 @@ entrypoints.lskel.h: $(OUTPUT)/entrypoints.bpf.o | $(BPFTOOL)
|
|||
|
||||
$(OUTPUT)/entrypoints.bpf.o: entrypoints.bpf.c $(OUTPUT)/vmlinux.h $(BPFOBJ) | $(OUTPUT)
|
||||
$(call msg,BPF,$@)
|
||||
$(Q)$(CLANG) -g -O2 -target bpf $(INCLUDES) \
|
||||
$(Q)$(CLANG) -g -O2 --target=bpf $(INCLUDES) \
|
||||
-c $(filter %.c,$^) -o $@ && \
|
||||
$(LLVM_STRIP) -g $@
|
||||
|
||||
|
|
|
@ -400,6 +400,9 @@ static void del_gid(struct ib_device *ib_dev, u32 port,
|
|||
table->data_vec[ix] = NULL;
|
||||
write_unlock_irq(&table->rwlock);
|
||||
|
||||
if (rdma_cap_roce_gid_table(ib_dev, port))
|
||||
ib_dev->ops.del_gid(&entry->attr, &entry->context);
|
||||
|
||||
ndev_storage = entry->ndev_storage;
|
||||
if (ndev_storage) {
|
||||
entry->ndev_storage = NULL;
|
||||
|
@ -407,9 +410,6 @@ static void del_gid(struct ib_device *ib_dev, u32 port,
|
|||
call_rcu(&ndev_storage->rcu_head, put_gid_ndev);
|
||||
}
|
||||
|
||||
if (rdma_cap_roce_gid_table(ib_dev, port))
|
||||
ib_dev->ops.del_gid(&entry->attr, &entry->context);
|
||||
|
||||
put_gid_entry_locked(entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,8 @@ static const char mlx4_ib_version[] =
|
|||
static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init);
|
||||
static enum rdma_link_layer mlx4_ib_port_link_layer(struct ib_device *device,
|
||||
u32 port_num);
|
||||
static int mlx4_ib_event(struct notifier_block *this, unsigned long event,
|
||||
void *param);
|
||||
|
||||
static struct workqueue_struct *wq;
|
||||
|
||||
|
@ -125,12 +127,14 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
|
|||
u32 port_num)
|
||||
{
|
||||
struct mlx4_ib_dev *ibdev = to_mdev(device);
|
||||
struct net_device *dev;
|
||||
struct net_device *dev, *ret = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
dev = mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port_num);
|
||||
for_each_netdev_rcu(&init_net, dev) {
|
||||
if (dev->dev.parent != ibdev->ib_dev.dev.parent ||
|
||||
dev->dev_port + 1 != port_num)
|
||||
continue;
|
||||
|
||||
if (dev) {
|
||||
if (mlx4_is_bonded(ibdev->dev)) {
|
||||
struct net_device *upper = NULL;
|
||||
|
||||
|
@ -143,11 +147,14 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
|
|||
dev = active;
|
||||
}
|
||||
}
|
||||
|
||||
dev_hold(dev);
|
||||
ret = dev;
|
||||
break;
|
||||
}
|
||||
dev_hold(dev);
|
||||
|
||||
rcu_read_unlock();
|
||||
return dev;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mlx4_ib_update_gids_v1(struct gid_entry *gids,
|
||||
|
@ -2319,61 +2326,53 @@ unlock:
|
|||
mutex_unlock(&ibdev->qp1_proxy_lock[port - 1]);
|
||||
}
|
||||
|
||||
static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev,
|
||||
struct net_device *dev,
|
||||
unsigned long event)
|
||||
static void mlx4_ib_scan_netdev(struct mlx4_ib_dev *ibdev,
|
||||
struct net_device *dev,
|
||||
unsigned long event)
|
||||
|
||||
{
|
||||
struct mlx4_ib_iboe *iboe;
|
||||
int update_qps_port = -1;
|
||||
int port;
|
||||
struct mlx4_ib_iboe *iboe = &ibdev->iboe;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
iboe = &ibdev->iboe;
|
||||
if (dev->dev.parent != ibdev->ib_dev.dev.parent)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&iboe->lock);
|
||||
mlx4_foreach_ib_transport_port(port, ibdev->dev) {
|
||||
|
||||
iboe->netdevs[port - 1] =
|
||||
mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port);
|
||||
iboe->netdevs[dev->dev_port] = event != NETDEV_UNREGISTER ? dev : NULL;
|
||||
|
||||
if (dev == iboe->netdevs[port - 1] &&
|
||||
(event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
|
||||
event == NETDEV_UP || event == NETDEV_CHANGE))
|
||||
update_qps_port = port;
|
||||
if (event == NETDEV_UP || event == NETDEV_DOWN) {
|
||||
enum ib_port_state port_state;
|
||||
struct ib_event ibev = { };
|
||||
|
||||
if (dev == iboe->netdevs[port - 1] &&
|
||||
(event == NETDEV_UP || event == NETDEV_DOWN)) {
|
||||
enum ib_port_state port_state;
|
||||
struct ib_event ibev = { };
|
||||
if (ib_get_cached_port_state(&ibdev->ib_dev, dev->dev_port + 1,
|
||||
&port_state))
|
||||
goto iboe_out;
|
||||
|
||||
if (ib_get_cached_port_state(&ibdev->ib_dev, port,
|
||||
&port_state))
|
||||
continue;
|
||||
|
||||
if (event == NETDEV_UP &&
|
||||
(port_state != IB_PORT_ACTIVE ||
|
||||
iboe->last_port_state[port - 1] != IB_PORT_DOWN))
|
||||
continue;
|
||||
if (event == NETDEV_DOWN &&
|
||||
(port_state != IB_PORT_DOWN ||
|
||||
iboe->last_port_state[port - 1] != IB_PORT_ACTIVE))
|
||||
continue;
|
||||
iboe->last_port_state[port - 1] = port_state;
|
||||
|
||||
ibev.device = &ibdev->ib_dev;
|
||||
ibev.element.port_num = port;
|
||||
ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
|
||||
IB_EVENT_PORT_ERR;
|
||||
ib_dispatch_event(&ibev);
|
||||
}
|
||||
if (event == NETDEV_UP &&
|
||||
(port_state != IB_PORT_ACTIVE ||
|
||||
iboe->last_port_state[dev->dev_port] != IB_PORT_DOWN))
|
||||
goto iboe_out;
|
||||
if (event == NETDEV_DOWN &&
|
||||
(port_state != IB_PORT_DOWN ||
|
||||
iboe->last_port_state[dev->dev_port] != IB_PORT_ACTIVE))
|
||||
goto iboe_out;
|
||||
iboe->last_port_state[dev->dev_port] = port_state;
|
||||
|
||||
ibev.device = &ibdev->ib_dev;
|
||||
ibev.element.port_num = dev->dev_port + 1;
|
||||
ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
|
||||
IB_EVENT_PORT_ERR;
|
||||
ib_dispatch_event(&ibev);
|
||||
}
|
||||
|
||||
iboe_out:
|
||||
spin_unlock_bh(&iboe->lock);
|
||||
|
||||
if (update_qps_port > 0)
|
||||
mlx4_ib_update_qps(ibdev, dev, update_qps_port);
|
||||
if (event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
|
||||
event == NETDEV_UP || event == NETDEV_CHANGE)
|
||||
mlx4_ib_update_qps(ibdev, dev, dev->dev_port + 1);
|
||||
}
|
||||
|
||||
static int mlx4_ib_netdev_event(struct notifier_block *this,
|
||||
|
@ -2386,7 +2385,7 @@ static int mlx4_ib_netdev_event(struct notifier_block *this,
|
|||
return NOTIFY_DONE;
|
||||
|
||||
ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb);
|
||||
mlx4_ib_scan_netdevs(ibdev, dev, event);
|
||||
mlx4_ib_scan_netdev(ibdev, dev, event);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
@ -2610,8 +2609,11 @@ static const struct ib_device_ops mlx4_ib_dev_fs_ops = {
|
|||
.destroy_flow = mlx4_ib_destroy_flow,
|
||||
};
|
||||
|
||||
static void *mlx4_ib_add(struct mlx4_dev *dev)
|
||||
static int mlx4_ib_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
|
||||
struct mlx4_dev *dev = madev->mdev;
|
||||
struct mlx4_ib_dev *ibdev;
|
||||
int num_ports = 0;
|
||||
int i, j;
|
||||
|
@ -2631,27 +2633,31 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
|
||||
/* No point in registering a device with no ports... */
|
||||
if (num_ports == 0)
|
||||
return NULL;
|
||||
return -ENODEV;
|
||||
|
||||
ibdev = ib_alloc_device(mlx4_ib_dev, ib_dev);
|
||||
if (!ibdev) {
|
||||
dev_err(&dev->persist->pdev->dev,
|
||||
"Device struct alloc failed\n");
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
iboe = &ibdev->iboe;
|
||||
|
||||
if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
|
||||
err = mlx4_pd_alloc(dev, &ibdev->priv_pdn);
|
||||
if (err)
|
||||
goto err_dealloc;
|
||||
|
||||
if (mlx4_uar_alloc(dev, &ibdev->priv_uar))
|
||||
err = mlx4_uar_alloc(dev, &ibdev->priv_uar);
|
||||
if (err)
|
||||
goto err_pd;
|
||||
|
||||
ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT,
|
||||
PAGE_SIZE);
|
||||
if (!ibdev->uar_map)
|
||||
if (!ibdev->uar_map) {
|
||||
err = -ENOMEM;
|
||||
goto err_uar;
|
||||
}
|
||||
MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
|
||||
|
||||
ibdev->dev = dev;
|
||||
|
@ -2695,7 +2701,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
|
||||
spin_lock_init(&iboe->lock);
|
||||
|
||||
if (init_node_data(ibdev))
|
||||
err = init_node_data(ibdev);
|
||||
if (err)
|
||||
goto err_map;
|
||||
mlx4_init_sl2vl_tbl(ibdev);
|
||||
|
||||
|
@ -2727,6 +2734,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
new_counter_index = kmalloc(sizeof(*new_counter_index),
|
||||
GFP_KERNEL);
|
||||
if (!new_counter_index) {
|
||||
err = -ENOMEM;
|
||||
if (allocated)
|
||||
mlx4_counter_free(ibdev->dev, counter_index);
|
||||
goto err_counter;
|
||||
|
@ -2744,8 +2752,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
new_counter_index =
|
||||
kmalloc(sizeof(struct counter_index),
|
||||
GFP_KERNEL);
|
||||
if (!new_counter_index)
|
||||
if (!new_counter_index) {
|
||||
err = -ENOMEM;
|
||||
goto err_counter;
|
||||
}
|
||||
new_counter_index->index = counter_index;
|
||||
new_counter_index->allocated = 0;
|
||||
list_add_tail(&new_counter_index->list,
|
||||
|
@ -2774,8 +2784,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
|
||||
ibdev->ib_uc_qpns_bitmap = bitmap_alloc(ibdev->steer_qpn_count,
|
||||
GFP_KERNEL);
|
||||
if (!ibdev->ib_uc_qpns_bitmap)
|
||||
if (!ibdev->ib_uc_qpns_bitmap) {
|
||||
err = -ENOMEM;
|
||||
goto err_steer_qp_release;
|
||||
}
|
||||
|
||||
if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB) {
|
||||
bitmap_zero(ibdev->ib_uc_qpns_bitmap,
|
||||
|
@ -2795,17 +2807,21 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
for (j = 1; j <= ibdev->dev->caps.num_ports; j++)
|
||||
atomic64_set(&iboe->mac[j - 1], ibdev->dev->caps.def_mac[j]);
|
||||
|
||||
if (mlx4_ib_alloc_diag_counters(ibdev))
|
||||
err = mlx4_ib_alloc_diag_counters(ibdev);
|
||||
if (err)
|
||||
goto err_steer_free_bitmap;
|
||||
|
||||
if (ib_register_device(&ibdev->ib_dev, "mlx4_%d",
|
||||
&dev->persist->pdev->dev))
|
||||
err = ib_register_device(&ibdev->ib_dev, "mlx4_%d",
|
||||
&dev->persist->pdev->dev);
|
||||
if (err)
|
||||
goto err_diag_counters;
|
||||
|
||||
if (mlx4_ib_mad_init(ibdev))
|
||||
err = mlx4_ib_mad_init(ibdev);
|
||||
if (err)
|
||||
goto err_reg;
|
||||
|
||||
if (mlx4_ib_init_sriov(ibdev))
|
||||
err = mlx4_ib_init_sriov(ibdev);
|
||||
if (err)
|
||||
goto err_mad;
|
||||
|
||||
if (!iboe->nb.notifier_call) {
|
||||
|
@ -2839,7 +2855,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
|
|||
do_slave_init(ibdev, j, 1);
|
||||
}
|
||||
}
|
||||
return ibdev;
|
||||
|
||||
/* register mlx4 core notifier */
|
||||
ibdev->mlx_nb.notifier_call = mlx4_ib_event;
|
||||
err = mlx4_register_event_notifier(dev, &ibdev->mlx_nb);
|
||||
WARN(err, "failed to register mlx4 event notifier (%d)", err);
|
||||
|
||||
auxiliary_set_drvdata(adev, ibdev);
|
||||
return 0;
|
||||
|
||||
err_notif:
|
||||
if (ibdev->iboe.nb.notifier_call) {
|
||||
|
@ -2883,7 +2906,7 @@ err_pd:
|
|||
err_dealloc:
|
||||
ib_dealloc_device(&ibdev->ib_dev);
|
||||
|
||||
return NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn)
|
||||
|
@ -2950,12 +2973,16 @@ int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
|
||||
static void mlx4_ib_remove(struct auxiliary_device *adev)
|
||||
{
|
||||
struct mlx4_ib_dev *ibdev = ibdev_ptr;
|
||||
struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
|
||||
struct mlx4_dev *dev = madev->mdev;
|
||||
struct mlx4_ib_dev *ibdev = auxiliary_get_drvdata(adev);
|
||||
int p;
|
||||
int i;
|
||||
|
||||
mlx4_unregister_event_notifier(dev, &ibdev->mlx_nb);
|
||||
|
||||
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
|
||||
devlink_port_type_clear(mlx4_get_devlink_port(dev, i));
|
||||
ibdev->ib_active = false;
|
||||
|
@ -3176,11 +3203,13 @@ void mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev,
|
|||
}
|
||||
}
|
||||
|
||||
static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
||||
enum mlx4_dev_event event, unsigned long param)
|
||||
static int mlx4_ib_event(struct notifier_block *this, unsigned long event,
|
||||
void *param)
|
||||
{
|
||||
struct mlx4_ib_dev *ibdev =
|
||||
container_of(this, struct mlx4_ib_dev, mlx_nb);
|
||||
struct mlx4_dev *dev = ibdev->dev;
|
||||
struct ib_event ibev;
|
||||
struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr);
|
||||
struct mlx4_eqe *eqe = NULL;
|
||||
struct ib_event_work *ew;
|
||||
int p = 0;
|
||||
|
@ -3190,22 +3219,28 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
|||
(event == MLX4_DEV_EVENT_PORT_DOWN))) {
|
||||
ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
|
||||
if (!ew)
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
INIT_WORK(&ew->work, handle_bonded_port_state_event);
|
||||
ew->ib_dev = ibdev;
|
||||
queue_work(wq, &ew->work);
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE)
|
||||
switch (event) {
|
||||
case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
|
||||
break;
|
||||
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
|
||||
eqe = (struct mlx4_eqe *)param;
|
||||
else
|
||||
p = (int) param;
|
||||
break;
|
||||
default:
|
||||
p = *(int *)param;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case MLX4_DEV_EVENT_PORT_UP:
|
||||
if (p > ibdev->num_ports)
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
if (!mlx4_is_slave(dev) &&
|
||||
rdma_port_get_link_layer(&ibdev->ib_dev, p) ==
|
||||
IB_LINK_LAYER_INFINIBAND) {
|
||||
|
@ -3220,7 +3255,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
|||
|
||||
case MLX4_DEV_EVENT_PORT_DOWN:
|
||||
if (p > ibdev->num_ports)
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
ibev.event = IB_EVENT_PORT_ERR;
|
||||
break;
|
||||
|
||||
|
@ -3233,7 +3268,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
|||
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
|
||||
ew = kmalloc(sizeof *ew, GFP_ATOMIC);
|
||||
if (!ew)
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
|
||||
INIT_WORK(&ew->work, handle_port_mgmt_change_event);
|
||||
memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
|
||||
|
@ -3243,7 +3278,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
|||
queue_work(wq, &ew->work);
|
||||
else
|
||||
handle_port_mgmt_change_event(&ew->work);
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
|
||||
case MLX4_DEV_EVENT_SLAVE_INIT:
|
||||
/* here, p is the slave id */
|
||||
|
@ -3259,7 +3294,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
|||
1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
|
||||
case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
|
||||
if (mlx4_is_master(dev)) {
|
||||
|
@ -3275,22 +3310,33 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
|
|||
}
|
||||
/* here, p is the slave id */
|
||||
do_slave_init(ibdev, p, 0);
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
|
||||
default:
|
||||
return;
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
ibev.device = ibdev_ptr;
|
||||
ibev.device = &ibdev->ib_dev;
|
||||
ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p;
|
||||
|
||||
ib_dispatch_event(&ibev);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct mlx4_interface mlx4_ib_interface = {
|
||||
.add = mlx4_ib_add,
|
||||
.remove = mlx4_ib_remove,
|
||||
.event = mlx4_ib_event,
|
||||
static const struct auxiliary_device_id mlx4_ib_id_table[] = {
|
||||
{ .name = MLX4_ADEV_NAME ".ib" },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(auxiliary, mlx4_ib_id_table);
|
||||
|
||||
static struct mlx4_adrv mlx4_ib_adrv = {
|
||||
.adrv = {
|
||||
.name = "ib",
|
||||
.probe = mlx4_ib_probe,
|
||||
.remove = mlx4_ib_remove,
|
||||
.id_table = mlx4_ib_id_table,
|
||||
},
|
||||
.protocol = MLX4_PROT_IB_IPV6,
|
||||
.flags = MLX4_INTFF_BONDING
|
||||
};
|
||||
|
@ -3315,7 +3361,7 @@ static int __init mlx4_ib_init(void)
|
|||
if (err)
|
||||
goto clean_cm;
|
||||
|
||||
err = mlx4_register_interface(&mlx4_ib_interface);
|
||||
err = mlx4_register_auxiliary_driver(&mlx4_ib_adrv);
|
||||
if (err)
|
||||
goto clean_mcg;
|
||||
|
||||
|
@ -3337,7 +3383,7 @@ clean_qp_event:
|
|||
|
||||
static void __exit mlx4_ib_cleanup(void)
|
||||
{
|
||||
mlx4_unregister_interface(&mlx4_ib_interface);
|
||||
mlx4_unregister_auxiliary_driver(&mlx4_ib_adrv);
|
||||
mlx4_ib_mcg_destroy();
|
||||
mlx4_ib_cm_destroy();
|
||||
mlx4_ib_qp_event_cleanup();
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <rdma/ib_umem.h>
|
||||
|
@ -644,6 +645,7 @@ struct mlx4_ib_dev {
|
|||
spinlock_t reset_flow_resource_lock;
|
||||
struct list_head qp_list;
|
||||
struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES];
|
||||
struct notifier_block mlx_nb;
|
||||
};
|
||||
|
||||
struct ib_event_work {
|
||||
|
|
|
@ -28,3 +28,4 @@ mlx5_ib-$(CONFIG_INFINIBAND_USER_ACCESS) += devx.o \
|
|||
fs.o \
|
||||
qos.o \
|
||||
std_types.o
|
||||
mlx5_ib-$(CONFIG_MLX5_MACSEC) += macsec.o
|
||||
|
|
|
@ -993,7 +993,7 @@ int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
|
|||
INIT_WORK(&cq->notify_work, notify_soft_wc_handler);
|
||||
}
|
||||
|
||||
err = mlx5_vector2eqn(dev->mdev, vector, &eqn);
|
||||
err = mlx5_comp_eqn_get(dev->mdev, vector, &eqn);
|
||||
if (err)
|
||||
goto err_cqb;
|
||||
|
||||
|
|
|
@ -1002,7 +1002,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_QUERY_EQN)(
|
|||
return PTR_ERR(c);
|
||||
dev = to_mdev(c->ibucontext.device);
|
||||
|
||||
err = mlx5_vector2eqn(dev->mdev, user_vector, &dev_eqn);
|
||||
err = mlx5_comp_eqn_get(dev->mdev, user_vector, &dev_eqn);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
364
drivers/infiniband/hw/mlx5/macsec.c
Normal file
364
drivers/infiniband/hw/mlx5/macsec.c
Normal file
|
@ -0,0 +1,364 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */
|
||||
|
||||
#include "macsec.h"
|
||||
#include <linux/mlx5/macsec.h>
|
||||
|
||||
struct mlx5_reserved_gids {
|
||||
int macsec_index;
|
||||
const struct ib_gid_attr *physical_gid;
|
||||
};
|
||||
|
||||
struct mlx5_roce_gids {
|
||||
struct list_head roce_gid_list_entry;
|
||||
u16 gid_idx;
|
||||
union {
|
||||
struct sockaddr_in sockaddr_in;
|
||||
struct sockaddr_in6 sockaddr_in6;
|
||||
} addr;
|
||||
};
|
||||
|
||||
struct mlx5_macsec_device {
|
||||
struct list_head macsec_devices_list_entry;
|
||||
void *macdev;
|
||||
struct list_head macsec_roce_gids;
|
||||
struct list_head tx_rules_list;
|
||||
struct list_head rx_rules_list;
|
||||
};
|
||||
|
||||
static void cleanup_macsec_device(struct mlx5_macsec_device *macsec_device)
|
||||
{
|
||||
if (!list_empty(&macsec_device->tx_rules_list) ||
|
||||
!list_empty(&macsec_device->rx_rules_list) ||
|
||||
!list_empty(&macsec_device->macsec_roce_gids))
|
||||
return;
|
||||
|
||||
list_del(&macsec_device->macsec_devices_list_entry);
|
||||
kfree(macsec_device);
|
||||
}
|
||||
|
||||
static struct mlx5_macsec_device *get_macsec_device(void *macdev,
|
||||
struct list_head *macsec_devices_list)
|
||||
{
|
||||
struct mlx5_macsec_device *iter, *macsec_device = NULL;
|
||||
|
||||
list_for_each_entry(iter, macsec_devices_list, macsec_devices_list_entry) {
|
||||
if (iter->macdev == macdev) {
|
||||
macsec_device = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (macsec_device)
|
||||
return macsec_device;
|
||||
|
||||
macsec_device = kzalloc(sizeof(*macsec_device), GFP_KERNEL);
|
||||
if (!macsec_device)
|
||||
return NULL;
|
||||
|
||||
macsec_device->macdev = macdev;
|
||||
INIT_LIST_HEAD(&macsec_device->tx_rules_list);
|
||||
INIT_LIST_HEAD(&macsec_device->rx_rules_list);
|
||||
INIT_LIST_HEAD(&macsec_device->macsec_roce_gids);
|
||||
list_add(&macsec_device->macsec_devices_list_entry, macsec_devices_list);
|
||||
|
||||
return macsec_device;
|
||||
}
|
||||
|
||||
static void mlx5_macsec_del_roce_gid(struct mlx5_macsec_device *macsec_device, u16 gid_idx)
|
||||
{
|
||||
struct mlx5_roce_gids *current_gid, *next_gid;
|
||||
|
||||
list_for_each_entry_safe(current_gid, next_gid, &macsec_device->macsec_roce_gids,
|
||||
roce_gid_list_entry)
|
||||
if (current_gid->gid_idx == gid_idx) {
|
||||
list_del(¤t_gid->roce_gid_list_entry);
|
||||
kfree(current_gid);
|
||||
}
|
||||
}
|
||||
|
||||
static void mlx5_macsec_save_roce_gid(struct mlx5_macsec_device *macsec_device,
|
||||
const struct sockaddr *addr, u16 gid_idx)
|
||||
{
|
||||
struct mlx5_roce_gids *roce_gids;
|
||||
|
||||
roce_gids = kzalloc(sizeof(*roce_gids), GFP_KERNEL);
|
||||
if (!roce_gids)
|
||||
return;
|
||||
|
||||
roce_gids->gid_idx = gid_idx;
|
||||
if (addr->sa_family == AF_INET)
|
||||
memcpy(&roce_gids->addr.sockaddr_in, addr, sizeof(roce_gids->addr.sockaddr_in));
|
||||
else
|
||||
memcpy(&roce_gids->addr.sockaddr_in6, addr, sizeof(roce_gids->addr.sockaddr_in6));
|
||||
|
||||
list_add_tail(&roce_gids->roce_gid_list_entry, &macsec_device->macsec_roce_gids);
|
||||
}
|
||||
|
||||
static void handle_macsec_gids(struct list_head *macsec_devices_list,
|
||||
struct mlx5_macsec_event_data *data)
|
||||
{
|
||||
struct mlx5_macsec_device *macsec_device;
|
||||
struct mlx5_roce_gids *gid;
|
||||
|
||||
macsec_device = get_macsec_device(data->macdev, macsec_devices_list);
|
||||
if (!macsec_device)
|
||||
return;
|
||||
|
||||
list_for_each_entry(gid, &macsec_device->macsec_roce_gids, roce_gid_list_entry) {
|
||||
mlx5_macsec_add_roce_sa_rules(data->fs_id, (struct sockaddr *)&gid->addr,
|
||||
gid->gid_idx, &macsec_device->tx_rules_list,
|
||||
&macsec_device->rx_rules_list, data->macsec_fs,
|
||||
data->is_tx);
|
||||
}
|
||||
}
|
||||
|
||||
static void del_sa_roce_rule(struct list_head *macsec_devices_list,
|
||||
struct mlx5_macsec_event_data *data)
|
||||
{
|
||||
struct mlx5_macsec_device *macsec_device;
|
||||
|
||||
macsec_device = get_macsec_device(data->macdev, macsec_devices_list);
|
||||
WARN_ON(!macsec_device);
|
||||
|
||||
mlx5_macsec_del_roce_sa_rules(data->fs_id, data->macsec_fs,
|
||||
&macsec_device->tx_rules_list,
|
||||
&macsec_device->rx_rules_list, data->is_tx);
|
||||
}
|
||||
|
||||
static int macsec_event(struct notifier_block *nb, unsigned long event, void *data)
|
||||
{
|
||||
struct mlx5_macsec *macsec = container_of(nb, struct mlx5_macsec, blocking_events_nb);
|
||||
|
||||
mutex_lock(&macsec->lock);
|
||||
switch (event) {
|
||||
case MLX5_DRIVER_EVENT_MACSEC_SA_ADDED:
|
||||
handle_macsec_gids(&macsec->macsec_devices_list, data);
|
||||
break;
|
||||
case MLX5_DRIVER_EVENT_MACSEC_SA_DELETED:
|
||||
del_sa_roce_rule(&macsec->macsec_devices_list, data);
|
||||
break;
|
||||
default:
|
||||
mutex_unlock(&macsec->lock);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
mutex_unlock(&macsec->lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
void mlx5r_macsec_event_register(struct mlx5_ib_dev *dev)
|
||||
{
|
||||
if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
|
||||
mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->macsec.blocking_events_nb.notifier_call = macsec_event;
|
||||
blocking_notifier_chain_register(&dev->mdev->macsec_nh,
|
||||
&dev->macsec.blocking_events_nb);
|
||||
}
|
||||
|
||||
void mlx5r_macsec_event_unregister(struct mlx5_ib_dev *dev)
|
||||
{
|
||||
if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
|
||||
mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blocking_notifier_chain_unregister(&dev->mdev->macsec_nh,
|
||||
&dev->macsec.blocking_events_nb);
|
||||
}
|
||||
|
||||
int mlx5r_macsec_init_gids_and_devlist(struct mlx5_ib_dev *dev)
|
||||
{
|
||||
int i, j, max_gids;
|
||||
|
||||
if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
|
||||
mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);
|
||||
for (i = 0; i < dev->num_ports; i++) {
|
||||
dev->port[i].reserved_gids = kcalloc(max_gids,
|
||||
sizeof(*dev->port[i].reserved_gids),
|
||||
GFP_KERNEL);
|
||||
if (!dev->port[i].reserved_gids)
|
||||
goto err;
|
||||
|
||||
for (j = 0; j < max_gids; j++)
|
||||
dev->port[i].reserved_gids[j].macsec_index = -1;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dev->macsec.macsec_devices_list);
|
||||
mutex_init(&dev->macsec.lock);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
while (i >= 0) {
|
||||
kfree(dev->port[i].reserved_gids);
|
||||
i--;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void mlx5r_macsec_dealloc_gids(struct mlx5_ib_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mlx5_is_macsec_roce_supported(dev->mdev))
|
||||
mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
|
||||
|
||||
for (i = 0; i < dev->num_ports; i++)
|
||||
kfree(dev->port[i].reserved_gids);
|
||||
|
||||
mutex_destroy(&dev->macsec.lock);
|
||||
}
|
||||
|
||||
int mlx5r_add_gid_macsec_operations(const struct ib_gid_attr *attr)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(attr->device);
|
||||
struct mlx5_macsec_device *macsec_device;
|
||||
const struct ib_gid_attr *physical_gid;
|
||||
struct mlx5_reserved_gids *mgids;
|
||||
struct net_device *ndev;
|
||||
int ret = 0;
|
||||
union {
|
||||
struct sockaddr_in sockaddr_in;
|
||||
struct sockaddr_in6 sockaddr_in6;
|
||||
} addr;
|
||||
|
||||
if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)
|
||||
return 0;
|
||||
|
||||
if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
|
||||
mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ndev = rcu_dereference(attr->ndev);
|
||||
if (!ndev) {
|
||||
rcu_read_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
dev_hold(ndev);
|
||||
rcu_read_unlock();
|
||||
|
||||
mutex_lock(&dev->macsec.lock);
|
||||
macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);
|
||||
if (!macsec_device) {
|
||||
ret = -ENOMEM;
|
||||
goto dev_err;
|
||||
}
|
||||
|
||||
physical_gid = rdma_find_gid(attr->device, &attr->gid,
|
||||
attr->gid_type, NULL);
|
||||
if (!IS_ERR(physical_gid)) {
|
||||
ret = set_roce_addr(to_mdev(physical_gid->device),
|
||||
physical_gid->port_num,
|
||||
physical_gid->index, NULL,
|
||||
physical_gid);
|
||||
if (ret)
|
||||
goto gid_err;
|
||||
|
||||
mgids = &dev->port[attr->port_num - 1].reserved_gids[physical_gid->index];
|
||||
mgids->macsec_index = attr->index;
|
||||
mgids->physical_gid = physical_gid;
|
||||
}
|
||||
|
||||
/* Proceed with adding steering rules, regardless if there was gid ambiguity or not.*/
|
||||
rdma_gid2ip((struct sockaddr *)&addr, &attr->gid);
|
||||
ret = mlx5_macsec_add_roce_rule(ndev, (struct sockaddr *)&addr, attr->index,
|
||||
&macsec_device->tx_rules_list,
|
||||
&macsec_device->rx_rules_list, dev->mdev->macsec_fs);
|
||||
if (ret && !IS_ERR(physical_gid))
|
||||
goto rule_err;
|
||||
|
||||
mlx5_macsec_save_roce_gid(macsec_device, (struct sockaddr *)&addr, attr->index);
|
||||
|
||||
dev_put(ndev);
|
||||
mutex_unlock(&dev->macsec.lock);
|
||||
return ret;
|
||||
|
||||
rule_err:
|
||||
set_roce_addr(to_mdev(physical_gid->device), physical_gid->port_num,
|
||||
physical_gid->index, &physical_gid->gid, physical_gid);
|
||||
mgids->macsec_index = -1;
|
||||
gid_err:
|
||||
rdma_put_gid_attr(physical_gid);
|
||||
cleanup_macsec_device(macsec_device);
|
||||
dev_err:
|
||||
dev_put(ndev);
|
||||
mutex_unlock(&dev->macsec.lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mlx5r_del_gid_macsec_operations(const struct ib_gid_attr *attr)
|
||||
{
|
||||
struct mlx5_ib_dev *dev = to_mdev(attr->device);
|
||||
struct mlx5_macsec_device *macsec_device;
|
||||
struct mlx5_reserved_gids *mgids;
|
||||
struct net_device *ndev;
|
||||
int i, max_gids;
|
||||
|
||||
if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)
|
||||
return;
|
||||
|
||||
if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
|
||||
mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mgids = &dev->port[attr->port_num - 1].reserved_gids[attr->index];
|
||||
if (mgids->macsec_index != -1) { /* Checking if physical gid has ambiguous IP */
|
||||
rdma_put_gid_attr(mgids->physical_gid);
|
||||
mgids->macsec_index = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ndev = rcu_dereference(attr->ndev);
|
||||
if (!ndev) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
dev_hold(ndev);
|
||||
rcu_read_unlock();
|
||||
|
||||
mutex_lock(&dev->macsec.lock);
|
||||
max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);
|
||||
for (i = 0; i < max_gids; i++) { /* Checking if macsec gid has ambiguous IP */
|
||||
mgids = &dev->port[attr->port_num - 1].reserved_gids[i];
|
||||
if (mgids->macsec_index == attr->index) {
|
||||
const struct ib_gid_attr *physical_gid = mgids->physical_gid;
|
||||
|
||||
set_roce_addr(to_mdev(physical_gid->device),
|
||||
physical_gid->port_num,
|
||||
physical_gid->index,
|
||||
&physical_gid->gid, physical_gid);
|
||||
|
||||
rdma_put_gid_attr(physical_gid);
|
||||
mgids->macsec_index = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);
|
||||
mlx5_macsec_del_roce_rule(attr->index, dev->mdev->macsec_fs,
|
||||
&macsec_device->tx_rules_list, &macsec_device->rx_rules_list);
|
||||
mlx5_macsec_del_roce_gid(macsec_device, attr->index);
|
||||
cleanup_macsec_device(macsec_device);
|
||||
|
||||
dev_put(ndev);
|
||||
mutex_unlock(&dev->macsec.lock);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue