Merge tag 'net-next-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Jakub Kicinski: - Add redirect_neigh() BPF packet redirect helper, allowing to limit stack traversal in common container configs and improving TCP back-pressure. Daniel reports ~10Gbps => ~15Gbps single stream TCP performance gain. - Expand netlink policy support and improve policy export to user space. (Ge)netlink core performs request validation according to declared policies. Expand the expressiveness of those policies (min/max length and bitmasks). Allow dumping policies for particular commands. This is used for feature discovery by user space (instead of kernel version parsing or trial and error). - Support IGMPv3/MLDv2 multicast listener discovery protocols in bridge. - Allow more than 255 IPv4 multicast interfaces. - Add support for Type of Service (ToS) reflection in SYN/SYN-ACK packets of TCPv6. - In Multi-patch TCP (MPTCP) support concurrent transmission of data on multiple subflows in a load balancing scenario. Enhance advertising addresses via the RM_ADDR/ADD_ADDR options. - Support SMC-Dv2 version of SMC, which enables multi-subnet deployments. - Allow more calls to same peer in RxRPC. - Support two new Controller Area Network (CAN) protocols - CAN-FD and ISO 15765-2:2016. - Add xfrm/IPsec compat layer, solving the 32bit user space on 64bit kernel problem. - Add TC actions for implementing MPLS L2 VPNs. - Improve nexthop code - e.g. handle various corner cases when nexthop objects are removed from groups better, skip unnecessary notifications and make it easier to offload nexthops into HW by converting to a blocking notifier. - Support adding and consuming TCP header options by BPF programs, opening the doors for easy experimental and deployment-specific TCP option use. - Reorganize TCP congestion control (CC) initialization to simplify life of TCP CC implemented in BPF. - Add support for shipping BPF programs with the kernel and loading them early on boot via the User Mode Driver mechanism, hence reusing all the user space infra we have. - Support sleepable BPF programs, initially targeting LSM and tracing. - Add bpf_d_path() helper for returning full path for given 'struct path'. - Make bpf_tail_call compatible with bpf-to-bpf calls. - Allow BPF programs to call map_update_elem on sockmaps. - Add BPF Type Format (BTF) support for type and enum discovery, as well as support for using BTF within the kernel itself (current use is for pretty printing structures). - Support listing and getting information about bpf_links via the bpf syscall. - Enhance kernel interfaces around NIC firmware update. Allow specifying overwrite mask to control if settings etc. are reset during update; report expected max time operation may take to users; support firmware activation without machine reboot incl. limits of how much impact reset may have (e.g. dropping link or not). - Extend ethtool configuration interface to report IEEE-standard counters, to limit the need for per-vendor logic in user space. - Adopt or extend devlink use for debug, monitoring, fw update in many drivers (dsa loop, ice, ionic, sja1105, qed, mlxsw, mv88e6xxx, dpaa2-eth). - In mlxsw expose critical and emergency SFP module temperature alarms. Refactor port buffer handling to make the defaults more suitable and support setting these values explicitly via the DCBNL interface. - Add XDP support for Intel's igb driver. - Support offloading TC flower classification and filtering rules to mscc_ocelot switches. - Add PTP support for Marvell Octeontx2 and PP2.2 hardware, as well as fixed interval period pulse generator and one-step timestamping in dpaa-eth. - Add support for various auth offloads in WiFi APs, e.g. SAE (WPA3) offload. - Add Lynx PHY/PCS MDIO module, and convert various drivers which have this HW to use it. Convert mvpp2 to split PCS. - Support Marvell Prestera 98DX3255 24-port switch ASICs, as well as 7-port Mediatek MT7531 IP. - Add initial support for QCA6390 and IPQ6018 in ath11k WiFi driver, and wcn3680 support in wcn36xx. - Improve performance for packets which don't require much offloads on recent Mellanox NICs by 20% by making multiple packets share a descriptor entry. - Move chelsio inline crypto drivers (for TLS and IPsec) from the crypto subtree to drivers/net. Move MDIO drivers out of the phy directory. - Clean up a lot of W=1 warnings, reportedly the actively developed subsections of networking drivers should now build W=1 warning free. - Make sure drivers don't use in_interrupt() to dynamically adapt their code. Convert tasklets to use new tasklet_setup API (sadly this conversion is not yet complete). * tag 'net-next-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2583 commits) Revert "bpfilter: Fix build error with CONFIG_BPFILTER_UMH" net, sockmap: Don't call bpf_prog_put() on NULL pointer bpf, selftest: Fix flaky tcp_hdr_options test when adding addr to lo bpf, sockmap: Add locking annotations to iterator netfilter: nftables: allow re-computing sctp CRC-32C in 'payload' statements net: fix pos incrementment in ipv6_route_seq_next net/smc: fix invalid return code in smcd_new_buf_create() net/smc: fix valid DMBE buffer sizes net/smc: fix use-after-free of delayed events bpfilter: Fix build error with CONFIG_BPFILTER_UMH cxgb4/ch_ipsec: Replace the module name to ch_ipsec from chcr net: sched: Fix suspicious RCU usage while accessing tcf_tunnel_info bpf: Fix register equivalence tracking. rxrpc: Fix loss of final ack on shutdown rxrpc: Fix bundle counting for exclusive connections netfilter: restore NF_INET_NUMHOOKS ibmveth: Identify ingress large send packets. ibmveth: Switch order of ibmveth_helper calls. cxgb4: handle 4-tuple PEDIT to NAT mode translation selftests: Add VRF route leaking tests ...
This commit is contained in:
4
CREDITS
4
CREDITS
@@ -191,6 +191,10 @@ N: Krishna Balasubramanian
|
|||||||
E: balasub@cis.ohio-state.edu
|
E: balasub@cis.ohio-state.edu
|
||||||
D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
|
D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
|
||||||
|
|
||||||
|
B: Robert Baldyga
|
||||||
|
E: r.baldyga@hackerion.com
|
||||||
|
D: Samsung S3FWRN5 NCI NFC Controller
|
||||||
|
|
||||||
N: Chris Ball
|
N: Chris Ball
|
||||||
E: chris@printf.net
|
E: chris@printf.net
|
||||||
D: Former maintainer of the MMC/SD/SDIO subsystem.
|
D: Former maintainer of the MMC/SD/SDIO subsystem.
|
||||||
|
@@ -1349,6 +1349,11 @@
|
|||||||
Format: <interval>,<probability>,<space>,<times>
|
Format: <interval>,<probability>,<space>,<times>
|
||||||
See also Documentation/fault-injection/.
|
See also Documentation/fault-injection/.
|
||||||
|
|
||||||
|
fb_tunnels= [NET]
|
||||||
|
Format: { initns | none }
|
||||||
|
See Documentation/admin-guide/sysctl/net.rst for
|
||||||
|
fb_tunnels_only_for_init_ns
|
||||||
|
|
||||||
floppy= [HW]
|
floppy= [HW]
|
||||||
See Documentation/admin-guide/blockdev/floppy.rst.
|
See Documentation/admin-guide/blockdev/floppy.rst.
|
||||||
|
|
||||||
|
@@ -300,7 +300,6 @@ Note:
|
|||||||
0: 0 1 2 3 4 5 6 7
|
0: 0 1 2 3 4 5 6 7
|
||||||
RSS hash key:
|
RSS hash key:
|
||||||
84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89
|
84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89
|
||||||
|
|
||||||
netdev_tstamp_prequeue
|
netdev_tstamp_prequeue
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@@ -321,11 +320,20 @@ fb_tunnels_only_for_init_net
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
Controls if fallback tunnels (like tunl0, gre0, gretap0, erspan0,
|
Controls if fallback tunnels (like tunl0, gre0, gretap0, erspan0,
|
||||||
sit0, ip6tnl0, ip6gre0) are automatically created when a new
|
sit0, ip6tnl0, ip6gre0) are automatically created. There are 3 possibilities
|
||||||
network namespace is created, if corresponding tunnel is present
|
(a) value = 0; respective fallback tunnels are created when module is
|
||||||
in initial network namespace.
|
loaded in every net namespaces (backward compatible behavior).
|
||||||
If set to 1, these devices are not automatically created, and
|
(b) value = 1; [kcmd value: initns] respective fallback tunnels are
|
||||||
user space is responsible for creating them if needed.
|
created only in init net namespace and every other net namespace will
|
||||||
|
not have them.
|
||||||
|
(c) value = 2; [kcmd value: none] fallback tunnels are not created
|
||||||
|
when a module is loaded in any of the net namespace. Setting value to
|
||||||
|
"2" is pointless after boot if these modules are built-in, so there is
|
||||||
|
a kernel command-line option that can change this default. Please refer to
|
||||||
|
Documentation/admin-guide/kernel-parameters.txt for additional details.
|
||||||
|
|
||||||
|
Not creating fallback tunnels gives control to userspace to create
|
||||||
|
whatever is needed only and avoid creating devices which are redundant.
|
||||||
|
|
||||||
Default : 0 (for compatibility reasons)
|
Default : 0 (for compatibility reasons)
|
||||||
|
|
||||||
|
@@ -60,13 +60,13 @@ Q: Where can I find patches currently under discussion for BPF subsystem?
|
|||||||
A: All patches that are Cc'ed to netdev are queued for review under netdev
|
A: All patches that are Cc'ed to netdev are queued for review under netdev
|
||||||
patchwork project:
|
patchwork project:
|
||||||
|
|
||||||
http://patchwork.ozlabs.org/project/netdev/list/
|
https://patchwork.kernel.org/project/netdevbpf/list/
|
||||||
|
|
||||||
Those patches which target BPF, are assigned to a 'bpf' delegate for
|
Those patches which target BPF, are assigned to a 'bpf' delegate for
|
||||||
further processing from BPF maintainers. The current queue with
|
further processing from BPF maintainers. The current queue with
|
||||||
patches under review can be found at:
|
patches under review can be found at:
|
||||||
|
|
||||||
https://patchwork.ozlabs.org/project/netdev/list/?delegate=77147
|
https://patchwork.kernel.org/project/netdevbpf/list/?delegate=121173
|
||||||
|
|
||||||
Once the patches have been reviewed by the BPF community as a whole
|
Once the patches have been reviewed by the BPF community as a whole
|
||||||
and approved by the BPF maintainers, their status in patchwork will be
|
and approved by the BPF maintainers, their status in patchwork will be
|
||||||
@@ -149,7 +149,7 @@ In case the patch or patch series has to be reworked and sent out
|
|||||||
again in a second or later revision, it is also required to add a
|
again in a second or later revision, it is also required to add a
|
||||||
version number (``v2``, ``v3``, ...) into the subject prefix::
|
version number (``v2``, ``v3``, ...) into the subject prefix::
|
||||||
|
|
||||||
git format-patch --subject-prefix='PATCH net-next v2' start..finish
|
git format-patch --subject-prefix='PATCH bpf-next v2' start..finish
|
||||||
|
|
||||||
When changes have been requested to the patch series, always send the
|
When changes have been requested to the patch series, always send the
|
||||||
whole patch series again with the feedback incorporated (never send
|
whole patch series again with the feedback incorporated (never send
|
||||||
@@ -479,12 +479,13 @@ LLVM's static compiler lists the supported targets through
|
|||||||
|
|
||||||
$ llc --version
|
$ llc --version
|
||||||
LLVM (http://llvm.org/):
|
LLVM (http://llvm.org/):
|
||||||
LLVM version 6.0.0svn
|
LLVM version 10.0.0
|
||||||
Optimized build.
|
Optimized build.
|
||||||
Default target: x86_64-unknown-linux-gnu
|
Default target: x86_64-unknown-linux-gnu
|
||||||
Host CPU: skylake
|
Host CPU: skylake
|
||||||
|
|
||||||
Registered Targets:
|
Registered Targets:
|
||||||
|
aarch64 - AArch64 (little endian)
|
||||||
bpf - BPF (host endian)
|
bpf - BPF (host endian)
|
||||||
bpfeb - BPF (big endian)
|
bpfeb - BPF (big endian)
|
||||||
bpfel - BPF (little endian)
|
bpfel - BPF (little endian)
|
||||||
@@ -517,6 +518,10 @@ from the git repositories::
|
|||||||
The built binaries can then be found in the build/bin/ directory, where
|
The built binaries can then be found in the build/bin/ directory, where
|
||||||
you can point the PATH variable to.
|
you can point the PATH variable to.
|
||||||
|
|
||||||
|
Set ``-DLLVM_TARGETS_TO_BUILD`` equal to the target you wish to build, you
|
||||||
|
will find a full list of targets within the llvm-project/llvm/lib/Target
|
||||||
|
directory.
|
||||||
|
|
||||||
Q: Reporting LLVM BPF issues
|
Q: Reporting LLVM BPF issues
|
||||||
----------------------------
|
----------------------------
|
||||||
Q: Should I notify BPF kernel maintainers about issues in LLVM's BPF code
|
Q: Should I notify BPF kernel maintainers about issues in LLVM's BPF code
|
||||||
|
@@ -724,6 +724,31 @@ want to define unused entry in BTF_ID_LIST, like::
|
|||||||
BTF_ID_UNUSED
|
BTF_ID_UNUSED
|
||||||
BTF_ID(struct, task_struct)
|
BTF_ID(struct, task_struct)
|
||||||
|
|
||||||
|
The ``BTF_SET_START/END`` macros pair defines sorted list of BTF ID values
|
||||||
|
and their count, with following syntax::
|
||||||
|
|
||||||
|
BTF_SET_START(set)
|
||||||
|
BTF_ID(type1, name1)
|
||||||
|
BTF_ID(type2, name2)
|
||||||
|
BTF_SET_END(set)
|
||||||
|
|
||||||
|
resulting in following layout in .BTF_ids section::
|
||||||
|
|
||||||
|
__BTF_ID__set__set:
|
||||||
|
.zero 4
|
||||||
|
__BTF_ID__type1__name1__3:
|
||||||
|
.zero 4
|
||||||
|
__BTF_ID__type2__name2__4:
|
||||||
|
.zero 4
|
||||||
|
|
||||||
|
The ``struct btf_id_set set;`` variable is defined to access the list.
|
||||||
|
|
||||||
|
The ``typeX`` name can be one of following::
|
||||||
|
|
||||||
|
struct, union, typedef, func
|
||||||
|
|
||||||
|
and is used as a filter when resolving the BTF ID value.
|
||||||
|
|
||||||
All the BTF ID lists and sets are compiled in the .BTF_ids section and
|
All the BTF ID lists and sets are compiled in the .BTF_ids section and
|
||||||
resolved during the linking phase of kernel build by ``resolve_btfids`` tool.
|
resolved during the linking phase of kernel build by ``resolve_btfids`` tool.
|
||||||
|
|
||||||
|
@@ -52,6 +52,7 @@ Program types
|
|||||||
prog_cgroup_sysctl
|
prog_cgroup_sysctl
|
||||||
prog_flow_dissector
|
prog_flow_dissector
|
||||||
bpf_lsm
|
bpf_lsm
|
||||||
|
prog_sk_lookup
|
||||||
|
|
||||||
|
|
||||||
Map types
|
Map types
|
||||||
|
98
Documentation/bpf/prog_sk_lookup.rst
Normal file
98
Documentation/bpf/prog_sk_lookup.rst
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
.. SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
=====================
|
||||||
|
BPF sk_lookup program
|
||||||
|
=====================
|
||||||
|
|
||||||
|
BPF sk_lookup program type (``BPF_PROG_TYPE_SK_LOOKUP``) introduces programmability
|
||||||
|
into the socket lookup performed by the transport layer when a packet is to be
|
||||||
|
delivered locally.
|
||||||
|
|
||||||
|
When invoked BPF sk_lookup program can select a socket that will receive the
|
||||||
|
incoming packet by calling the ``bpf_sk_assign()`` BPF helper function.
|
||||||
|
|
||||||
|
Hooks for a common attach point (``BPF_SK_LOOKUP``) exist for both TCP and UDP.
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
|
BPF sk_lookup program type was introduced to address setup scenarios where
|
||||||
|
binding sockets to an address with ``bind()`` socket call is impractical, such
|
||||||
|
as:
|
||||||
|
|
||||||
|
1. receiving connections on a range of IP addresses, e.g. 192.0.2.0/24, when
|
||||||
|
binding to a wildcard address ``INADRR_ANY`` is not possible due to a port
|
||||||
|
conflict,
|
||||||
|
2. receiving connections on all or a wide range of ports, i.e. an L7 proxy use
|
||||||
|
case.
|
||||||
|
|
||||||
|
Such setups would require creating and ``bind()``'ing one socket to each of the
|
||||||
|
IP address/port in the range, leading to resource consumption and potential
|
||||||
|
latency spikes during socket lookup.
|
||||||
|
|
||||||
|
Attachment
|
||||||
|
==========
|
||||||
|
|
||||||
|
BPF sk_lookup program can be attached to a network namespace with
|
||||||
|
``bpf(BPF_LINK_CREATE, ...)`` syscall using the ``BPF_SK_LOOKUP`` attach type and a
|
||||||
|
netns FD as attachment ``target_fd``.
|
||||||
|
|
||||||
|
Multiple programs can be attached to one network namespace. Programs will be
|
||||||
|
invoked in the same order as they were attached.
|
||||||
|
|
||||||
|
Hooks
|
||||||
|
=====
|
||||||
|
|
||||||
|
The attached BPF sk_lookup programs run whenever the transport layer needs to
|
||||||
|
find a listening (TCP) or an unconnected (UDP) socket for an incoming packet.
|
||||||
|
|
||||||
|
Incoming traffic to established (TCP) and connected (UDP) sockets is delivered
|
||||||
|
as usual without triggering the BPF sk_lookup hook.
|
||||||
|
|
||||||
|
The attached BPF programs must return with either ``SK_PASS`` or ``SK_DROP``
|
||||||
|
verdict code. As for other BPF program types that are network filters,
|
||||||
|
``SK_PASS`` signifies that the socket lookup should continue on to regular
|
||||||
|
hashtable-based lookup, while ``SK_DROP`` causes the transport layer to drop the
|
||||||
|
packet.
|
||||||
|
|
||||||
|
A BPF sk_lookup program can also select a socket to receive the packet by
|
||||||
|
calling ``bpf_sk_assign()`` BPF helper. Typically, the program looks up a socket
|
||||||
|
in a map holding sockets, such as ``SOCKMAP`` or ``SOCKHASH``, and passes a
|
||||||
|
``struct bpf_sock *`` to ``bpf_sk_assign()`` helper to record the
|
||||||
|
selection. Selecting a socket only takes effect if the program has terminated
|
||||||
|
with ``SK_PASS`` code.
|
||||||
|
|
||||||
|
When multiple programs are attached, the end result is determined from return
|
||||||
|
codes of all the programs according to the following rules:
|
||||||
|
|
||||||
|
1. If any program returned ``SK_PASS`` and selected a valid socket, the socket
|
||||||
|
is used as the result of the socket lookup.
|
||||||
|
2. If more than one program returned ``SK_PASS`` and selected a socket, the last
|
||||||
|
selection takes effect.
|
||||||
|
3. If any program returned ``SK_DROP``, and no program returned ``SK_PASS`` and
|
||||||
|
selected a socket, socket lookup fails.
|
||||||
|
4. If all programs returned ``SK_PASS`` and none of them selected a socket,
|
||||||
|
socket lookup continues on.
|
||||||
|
|
||||||
|
API
|
||||||
|
===
|
||||||
|
|
||||||
|
In its context, an instance of ``struct bpf_sk_lookup``, BPF sk_lookup program
|
||||||
|
receives information about the packet that triggered the socket lookup. Namely:
|
||||||
|
|
||||||
|
* IP version (``AF_INET`` or ``AF_INET6``),
|
||||||
|
* L4 protocol identifier (``IPPROTO_TCP`` or ``IPPROTO_UDP``),
|
||||||
|
* source and destination IP address,
|
||||||
|
* source and destination L4 port,
|
||||||
|
* the socket that has been selected with ``bpf_sk_assign()``.
|
||||||
|
|
||||||
|
Refer to ``struct bpf_sk_lookup`` declaration in ``linux/bpf.h`` user API
|
||||||
|
header, and `bpf-helpers(7)
|
||||||
|
<https://man7.org/linux/man-pages/man7/bpf-helpers.7.html>`_ man-page section
|
||||||
|
for ``bpf_sk_assign()`` for details.
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
See ``tools/testing/selftests/bpf/prog_tests/sk_lookup.c`` for the reference
|
||||||
|
implementation.
|
@@ -50,6 +50,13 @@ Optional properties:
|
|||||||
- reset-names: If the "reset" property is specified, this property should have
|
- reset-names: If the "reset" property is specified, this property should have
|
||||||
the value "switch" to denote the switch reset line.
|
the value "switch" to denote the switch reset line.
|
||||||
|
|
||||||
|
- clocks: when provided, the first phandle is to the switch's main clock and
|
||||||
|
is valid for both BCM7445 and BCM7278. The second phandle is only applicable
|
||||||
|
to BCM7445 and is to support dividing the switch core clock.
|
||||||
|
|
||||||
|
- clock-names: when provided, the first phandle must be "sw_switch", and the
|
||||||
|
second must be named "sw_switch_mdiv".
|
||||||
|
|
||||||
Port subnodes:
|
Port subnodes:
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
@@ -20,6 +20,11 @@ Optional properties:
|
|||||||
- systemport,num-tier1-arb: number of tier 1 arbiters, an integer
|
- systemport,num-tier1-arb: number of tier 1 arbiters, an integer
|
||||||
- systemport,num-txq: number of HW transmit queues, an integer
|
- systemport,num-txq: number of HW transmit queues, an integer
|
||||||
- systemport,num-rxq: number of HW receive queues, an integer
|
- systemport,num-rxq: number of HW receive queues, an integer
|
||||||
|
- clocks: When provided, must be two phandles to the functional clocks nodes of
|
||||||
|
the SYSTEMPORT block. The first phandle is the main SYSTEMPORT clock used
|
||||||
|
during normal operation, while the second phandle is the Wake-on-LAN clock.
|
||||||
|
- clock-names: When provided, names of the functional clock phandles, first
|
||||||
|
name should be "sw_sysport" and second should be "sw_sysportwol".
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
ethernet@f04a0000 {
|
ethernet@f04a0000 {
|
||||||
|
@@ -4,6 +4,12 @@ Required properties:
|
|||||||
|
|
||||||
- compatible : Should be "fsl,<processor>-flexcan"
|
- compatible : Should be "fsl,<processor>-flexcan"
|
||||||
|
|
||||||
|
where <processor> is imx8qm, imx6q, imx28, imx53, imx35, imx25, p1010,
|
||||||
|
vf610, ls1021ar2, lx2160ar1, ls1028ar1.
|
||||||
|
|
||||||
|
The ls1028ar1 must be followed by lx2160ar1, e.g.
|
||||||
|
- "fsl,ls1028ar1-flexcan", "fsl,lx2160ar1-flexcan"
|
||||||
|
|
||||||
An implementation should also claim any of the following compatibles
|
An implementation should also claim any of the following compatibles
|
||||||
that it is fully backwards compatible with:
|
that it is fully backwards compatible with:
|
||||||
|
|
||||||
@@ -25,12 +31,10 @@ Optional properties:
|
|||||||
endian.
|
endian.
|
||||||
|
|
||||||
- fsl,stop-mode: register bits of stop mode control, the format is
|
- fsl,stop-mode: register bits of stop mode control, the format is
|
||||||
<&gpr req_gpr req_bit ack_gpr ack_bit>.
|
<&gpr req_gpr req_bit>.
|
||||||
gpr is the phandle to general purpose register node.
|
gpr is the phandle to general purpose register node.
|
||||||
req_gpr is the gpr register offset of CAN stop request.
|
req_gpr is the gpr register offset of CAN stop request.
|
||||||
req_bit is the bit offset of CAN stop request.
|
req_bit is the bit offset of CAN stop request.
|
||||||
ack_gpr is the gpr register offset of CAN stop acknowledge.
|
|
||||||
ack_bit is the bit offset of CAN stop acknowledge.
|
|
||||||
|
|
||||||
- fsl,clk-source: Select the clock source to the CAN Protocol Engine (PE).
|
- fsl,clk-source: Select the clock source to the CAN Protocol Engine (PE).
|
||||||
It's SoC Implementation dependent. Refer to RM for detailed
|
It's SoC Implementation dependent. Refer to RM for detailed
|
||||||
|
@@ -12,6 +12,9 @@ Required properties:
|
|||||||
Optional properties:
|
Optional properties:
|
||||||
- vdd-supply: Regulator that powers the CAN controller.
|
- vdd-supply: Regulator that powers the CAN controller.
|
||||||
- xceiver-supply: Regulator that powers the CAN transceiver.
|
- xceiver-supply: Regulator that powers the CAN transceiver.
|
||||||
|
- gpio-controller: Indicates this device is a GPIO controller.
|
||||||
|
- #gpio-cells: Should be two. The first cell is the pin number and
|
||||||
|
the second cell is used to specify the gpio polarity.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
can0: can@1 {
|
can0: can@1 {
|
||||||
@@ -19,7 +22,9 @@ Example:
|
|||||||
reg = <1>;
|
reg = <1>;
|
||||||
clocks = <&clk24m>;
|
clocks = <&clk24m>;
|
||||||
interrupt-parent = <&gpio4>;
|
interrupt-parent = <&gpio4>;
|
||||||
interrupts = <13 0x2>;
|
interrupts = <13 IRQ_TYPE_LEVEL_LOW>;
|
||||||
vdd-supply = <®5v0>;
|
vdd-supply = <®5v0>;
|
||||||
xceiver-supply = <®5v0>;
|
xceiver-supply = <®5v0>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
};
|
};
|
||||||
|
@@ -0,0 +1,79 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/net/can/microchip,mcp251xfd.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title:
|
||||||
|
Microchip MCP2517FD and MCP2518FD stand-alone CAN controller device tree
|
||||||
|
bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Marc Kleine-Budde <mkl@pengutronix.de>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- const: microchip,mcp2517fd
|
||||||
|
description: for MCP2517FD
|
||||||
|
- const: microchip,mcp2518fd
|
||||||
|
description: for MCP2518FD
|
||||||
|
- const: microchip,mcp251xfd
|
||||||
|
description: to autodetect chip variant
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
vdd-supply:
|
||||||
|
description: Regulator that powers the CAN controller.
|
||||||
|
|
||||||
|
xceiver-supply:
|
||||||
|
description: Regulator that powers the CAN transceiver.
|
||||||
|
|
||||||
|
microchip,rx-int-gpios:
|
||||||
|
description:
|
||||||
|
GPIO phandle of GPIO connected to to INT1 pin of the MCP251XFD, which
|
||||||
|
signals a pending RX interrupt.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
spi-max-frequency:
|
||||||
|
description:
|
||||||
|
Must be half or less of "clocks" frequency.
|
||||||
|
maximum: 20000000
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
spi0 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
can@0 {
|
||||||
|
compatible = "microchip,mcp251xfd";
|
||||||
|
reg = <0>;
|
||||||
|
clocks = <&can0_osc>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&can0_pins>;
|
||||||
|
spi-max-frequency = <20000000>;
|
||||||
|
interrupts-extended = <&gpio 13 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
microchip,rx-int-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
|
||||||
|
vdd-supply = <®5v0>;
|
||||||
|
xceiver-supply = <®5v0>;
|
||||||
|
};
|
||||||
|
};
|
@@ -2,13 +2,15 @@ Renesas R-Car CAN controller Device Tree Bindings
|
|||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC.
|
- compatible: "renesas,can-r8a7742" if CAN controller is a part of R8A7742 SoC.
|
||||||
|
"renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC.
|
||||||
"renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC.
|
"renesas,can-r8a7744" if CAN controller is a part of R8A7744 SoC.
|
||||||
"renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC.
|
"renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC.
|
||||||
"renesas,can-r8a77470" if CAN controller is a part of R8A77470 SoC.
|
"renesas,can-r8a77470" if CAN controller is a part of R8A77470 SoC.
|
||||||
"renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC.
|
"renesas,can-r8a774a1" if CAN controller is a part of R8A774A1 SoC.
|
||||||
"renesas,can-r8a774b1" if CAN controller is a part of R8A774B1 SoC.
|
"renesas,can-r8a774b1" if CAN controller is a part of R8A774B1 SoC.
|
||||||
"renesas,can-r8a774c0" if CAN controller is a part of R8A774C0 SoC.
|
"renesas,can-r8a774c0" if CAN controller is a part of R8A774C0 SoC.
|
||||||
|
"renesas,can-r8a774e1" if CAN controller is a part of R8A774E1 SoC.
|
||||||
"renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
|
"renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
|
||||||
"renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
|
"renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
|
||||||
"renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
|
"renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
|
||||||
@@ -37,8 +39,8 @@ Required properties:
|
|||||||
- pinctrl-0: pin control group to be used for this controller.
|
- pinctrl-0: pin control group to be used for this controller.
|
||||||
- pinctrl-names: must be "default".
|
- pinctrl-names: must be "default".
|
||||||
|
|
||||||
Required properties for R8A774A1, R8A774B1, R8A774C0, R8A7795, R8A7796,
|
Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795,
|
||||||
R8A77965, R8A77990, and R8A77995:
|
R8A7796, R8A77965, R8A77990, and R8A77995:
|
||||||
For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can
|
For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can
|
||||||
be used by both CAN and CAN FD controller at the same time. It needs to be
|
be used by both CAN and CAN FD controller at the same time. It needs to be
|
||||||
scaled to maximum frequency if any of these controllers use it. This is done
|
scaled to maximum frequency if any of these controllers use it. This is done
|
||||||
|
@@ -7,6 +7,7 @@ Required properties:
|
|||||||
- "renesas,r8a774a1-canfd" for R8A774A1 (RZ/G2M) compatible controller.
|
- "renesas,r8a774a1-canfd" for R8A774A1 (RZ/G2M) compatible controller.
|
||||||
- "renesas,r8a774b1-canfd" for R8A774B1 (RZ/G2N) compatible controller.
|
- "renesas,r8a774b1-canfd" for R8A774B1 (RZ/G2N) compatible controller.
|
||||||
- "renesas,r8a774c0-canfd" for R8A774C0 (RZ/G2E) compatible controller.
|
- "renesas,r8a774c0-canfd" for R8A774C0 (RZ/G2E) compatible controller.
|
||||||
|
- "renesas,r8a774e1-canfd" for R8A774E1 (RZ/G2H) compatible controller.
|
||||||
- "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller.
|
- "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller.
|
||||||
- "renesas,r8a7796-canfd" for R8A7796 (R-Car M3-W) compatible controller.
|
- "renesas,r8a7796-canfd" for R8A7796 (R-Car M3-W) compatible controller.
|
||||||
- "renesas,r8a77965-canfd" for R8A77965 (R-Car M3-N) compatible controller.
|
- "renesas,r8a77965-canfd" for R8A77965 (R-Car M3-N) compatible controller.
|
||||||
@@ -32,8 +33,8 @@ The name of the child nodes are "channel0" and "channel1" respectively. Each
|
|||||||
child node supports the "status" property only, which is used to
|
child node supports the "status" property only, which is used to
|
||||||
enable/disable the respective channel.
|
enable/disable the respective channel.
|
||||||
|
|
||||||
Required properties for R8A774A1, R8A774B1, R8A774C0, R8A7795, R8A7796,
|
Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795,
|
||||||
R8A77965, R8A77990, and R8A77995:
|
R8A7796, R8A77965, R8A77990, and R8A77995:
|
||||||
In the denoted SoCs, canfd clock is a div6 clock and can be used by both CAN
|
In the denoted SoCs, canfd clock is a div6 clock and can be used by both CAN
|
||||||
and CAN FD controller at the same time. It needs to be scaled to maximum
|
and CAN FD controller at the same time. It needs to be scaled to maximum
|
||||||
frequency if any of these controllers use it. This is done using the below
|
frequency if any of these controllers use it. This is done using the below
|
||||||
|
@@ -95,7 +95,7 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
|
|||||||
|
|
||||||
fixed-link {
|
fixed-link {
|
||||||
speed = <1000>;
|
speed = <1000>;
|
||||||
duplex-full;
|
full-duplex;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,8 +104,9 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
|
|||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
switch0: ethernet-switch@30 {
|
switch0: ethernet-switch@1e {
|
||||||
compatible = "brcm,bcm53125";
|
compatible = "brcm,bcm53125";
|
||||||
|
reg = <30>;
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
|
|||||||
label = "cable-modem";
|
label = "cable-modem";
|
||||||
fixed-link {
|
fixed-link {
|
||||||
speed = <1000>;
|
speed = <1000>;
|
||||||
duplex-full;
|
full-duplex;
|
||||||
};
|
};
|
||||||
phy-mode = "rgmii-txid";
|
phy-mode = "rgmii-txid";
|
||||||
};
|
};
|
||||||
@@ -138,7 +139,7 @@ Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
|
|||||||
label = "cpu";
|
label = "cpu";
|
||||||
fixed-link {
|
fixed-link {
|
||||||
speed = <1000>;
|
speed = <1000>;
|
||||||
duplex-full;
|
full-duplex;
|
||||||
};
|
};
|
||||||
phy-mode = "rgmii-txid";
|
phy-mode = "rgmii-txid";
|
||||||
ethernet = <ð0>;
|
ethernet = <ð0>;
|
||||||
|
@@ -5,6 +5,7 @@ Required properties:
|
|||||||
|
|
||||||
- compatible: may be compatible = "mediatek,mt7530"
|
- compatible: may be compatible = "mediatek,mt7530"
|
||||||
or compatible = "mediatek,mt7621"
|
or compatible = "mediatek,mt7621"
|
||||||
|
or compatible = "mediatek,mt7531"
|
||||||
- #address-cells: Must be 1.
|
- #address-cells: Must be 1.
|
||||||
- #size-cells: Must be 0.
|
- #size-cells: Must be 0.
|
||||||
- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
|
- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
|
||||||
@@ -32,10 +33,14 @@ Required properties for the child nodes within ports container:
|
|||||||
|
|
||||||
- reg: Port address described must be 6 for CPU port and from 0 to 5 for
|
- reg: Port address described must be 6 for CPU port and from 0 to 5 for
|
||||||
user ports.
|
user ports.
|
||||||
- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
|
- phy-mode: String, the following values are acceptable for port labeled
|
||||||
"cpu".
|
"cpu":
|
||||||
|
If compatible mediatek,mt7530 or mediatek,mt7621 is set,
|
||||||
|
must be either "trgmii" or "rgmii"
|
||||||
|
If compatible mediatek,mt7531 is set,
|
||||||
|
must be either "sgmii", "1000base-x" or "2500base-x"
|
||||||
|
|
||||||
Port 5 of the switch is muxed between:
|
Port 5 of mt7530 and mt7621 switch is muxed between:
|
||||||
1. GMAC5: GMAC5 can interface with another external MAC or PHY.
|
1. GMAC5: GMAC5 can interface with another external MAC or PHY.
|
||||||
2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC
|
2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC
|
||||||
of the SOC. Used in many setups where port 0/4 becomes the WAN port.
|
of the SOC. Used in many setups where port 0/4 becomes the WAN port.
|
||||||
|
@@ -120,6 +120,13 @@ properties:
|
|||||||
and is useful for determining certain configuration settings
|
and is useful for determining certain configuration settings
|
||||||
such as flow control thresholds.
|
such as flow control thresholds.
|
||||||
|
|
||||||
|
rx-internal-delay-ps:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: |
|
||||||
|
RGMII Receive Clock Delay defined in pico seconds.
|
||||||
|
This is used for controllers that have configurable RX internal delays.
|
||||||
|
If this property is present then the MAC applies the RX delay.
|
||||||
|
|
||||||
sfp:
|
sfp:
|
||||||
$ref: /schemas/types.yaml#definitions/phandle
|
$ref: /schemas/types.yaml#definitions/phandle
|
||||||
description:
|
description:
|
||||||
@@ -131,6 +138,13 @@ properties:
|
|||||||
The size of the controller\'s transmit fifo in bytes. This
|
The size of the controller\'s transmit fifo in bytes. This
|
||||||
is used for components that can have configurable fifo sizes.
|
is used for components that can have configurable fifo sizes.
|
||||||
|
|
||||||
|
tx-internal-delay-ps:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: |
|
||||||
|
RGMII Transmit Clock Delay defined in pico seconds.
|
||||||
|
This is used for controllers that have configurable TX internal delays.
|
||||||
|
If this property is present then the MAC applies the TX delay.
|
||||||
|
|
||||||
managed:
|
managed:
|
||||||
description:
|
description:
|
||||||
Specifies the PHY management type. If auto is set and fixed-link
|
Specifies the PHY management type. If auto is set and fixed-link
|
||||||
|
130
Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml
Normal file
130
Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/net/intel,dwmac-plat.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Intel DWMAC glue layer Device Tree Bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Vineetha G. Jaya Kumaran <vineetha.g.jaya.kumaran@intel.com>
|
||||||
|
|
||||||
|
select:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- intel,keembay-dwmac
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: "snps,dwmac.yaml#"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- intel,keembay-dwmac
|
||||||
|
- const: snps,dwmac-4.10a
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
items:
|
||||||
|
- description: GMAC main clock
|
||||||
|
- description: PTP reference clock
|
||||||
|
- description: Tx clock
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: stmmaceth
|
||||||
|
- const: ptp_ref
|
||||||
|
- const: tx_clk
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
examples:
|
||||||
|
# FIXME: Remove defines and include the correct header file
|
||||||
|
# once it is available in mainline.
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#define MOVISOC_KMB_PSS_GBE
|
||||||
|
#define MOVISOC_KMB_PSS_AUX_GBE_PTP
|
||||||
|
#define MOVISOC_KMB_PSS_AUX_GBE_TX
|
||||||
|
|
||||||
|
stmmac_axi_setup: stmmac-axi-config {
|
||||||
|
snps,lpi_en;
|
||||||
|
snps,wr_osr_lmt = <0x0>;
|
||||||
|
snps,rd_osr_lmt = <0x2>;
|
||||||
|
snps,blen = <0 0 0 0 16 8 4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
mtl_rx_setup: rx-queues-config {
|
||||||
|
snps,rx-queues-to-use = <2>;
|
||||||
|
snps,rx-sched-sp;
|
||||||
|
queue0 {
|
||||||
|
snps,dcb-algorithm;
|
||||||
|
snps,map-to-dma-channel = <0x0>;
|
||||||
|
snps,priority = <0x0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
queue1 {
|
||||||
|
snps,dcb-algorithm;
|
||||||
|
snps,map-to-dma-channel = <0x1>;
|
||||||
|
snps,priority = <0x1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mtl_tx_setup: tx-queues-config {
|
||||||
|
snps,tx-queues-to-use = <2>;
|
||||||
|
snps,tx-sched-wrr;
|
||||||
|
queue0 {
|
||||||
|
snps,weight = <0x10>;
|
||||||
|
snps,dcb-algorithm;
|
||||||
|
snps,priority = <0x0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
queue1 {
|
||||||
|
snps,weight = <0x10>;
|
||||||
|
snps,dcb-algorithm;
|
||||||
|
snps,priority = <0x1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
gmac0: ethernet@3a000000 {
|
||||||
|
compatible = "intel,keembay-dwmac", "snps,dwmac-4.10a";
|
||||||
|
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
interrupt-names = "macirq";
|
||||||
|
reg = <0x3a000000 0x8000>;
|
||||||
|
snps,perfect-filter-entries = <128>;
|
||||||
|
phy-handle = <ð_phy0>;
|
||||||
|
phy-mode = "rgmii";
|
||||||
|
rx-fifo-depth = <4096>;
|
||||||
|
tx-fifo-depth = <4096>;
|
||||||
|
clock-names = "stmmaceth", "ptp_ref", "tx_clk";
|
||||||
|
clocks = <&scmi_clk MOVISOC_KMB_PSS_GBE>,
|
||||||
|
<&scmi_clk MOVISOC_KMB_PSS_AUX_GBE_PTP>,
|
||||||
|
<&scmi_clk MOVISOC_KMB_PSS_AUX_GBE_TX>;
|
||||||
|
snps,pbl = <0x4>;
|
||||||
|
snps,axi-config = <&stmmac_axi_setup>;
|
||||||
|
snps,mtl-rx-config = <&mtl_rx_setup>;
|
||||||
|
snps,mtl-tx-config = <&mtl_tx_setup>;
|
||||||
|
snps,tso;
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
mdio0 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "snps,dwmac-mdio";
|
||||||
|
|
||||||
|
ethernet-phy@0 {
|
||||||
|
reg = <0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@@ -45,3 +45,37 @@ dfx-server {
|
|||||||
ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>;
|
ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>;
|
||||||
reg = <MBUS_ID(0x08, 0x00) 0 0x100000>;
|
reg = <MBUS_ID(0x08, 0x00) 0 0x100000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Marvell Prestera SwitchDev bindings
|
||||||
|
-----------------------------------
|
||||||
|
Optional properties:
|
||||||
|
- compatible: must be "marvell,prestera"
|
||||||
|
- base-mac-provider: describes handle to node which provides base mac address,
|
||||||
|
might be a static base mac address or nvme cell provider.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
eeprom_mac_addr: eeprom-mac-addr {
|
||||||
|
compatible = "eeprom,mac-addr-cell";
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
nvmem = <&eeprom_at24>;
|
||||||
|
};
|
||||||
|
|
||||||
|
prestera {
|
||||||
|
compatible = "marvell,prestera";
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
base-mac-provider = <&eeprom_mac_addr>;
|
||||||
|
};
|
||||||
|
|
||||||
|
The current implementation of Prestera Switchdev PCI interface driver requires
|
||||||
|
that BAR2 is assigned to 0xf6000000 as base address from the PCI IO range:
|
||||||
|
|
||||||
|
&cp0_pcie0 {
|
||||||
|
ranges = <0x81000000 0x0 0xfb000000 0x0 0xfb000000 0x0 0xf0000
|
||||||
|
0x82000000 0x0 0xf6000000 0x0 0xf6000000 0x0 0x2000000
|
||||||
|
0x82000000 0x0 0xf9000000 0x0 0xf9000000 0x0 0x100000>;
|
||||||
|
phys = <&cp0_comphy0 0>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
* Samsung S3FWRN5 NCI NFC Controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Should be "samsung,s3fwrn5-i2c".
|
|
||||||
- reg: address on the bus
|
|
||||||
- interrupts: GPIO interrupt to which the chip is connected
|
|
||||||
- s3fwrn5,en-gpios: Output GPIO pin used for enabling/disabling the chip
|
|
||||||
- s3fwrn5,fw-gpios: Output GPIO pin used to enter firmware mode and
|
|
||||||
sleep/wakeup control
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
&hsi2c_4 {
|
|
||||||
s3fwrn5@27 {
|
|
||||||
compatible = "samsung,s3fwrn5-i2c";
|
|
||||||
|
|
||||||
reg = <0x27>;
|
|
||||||
|
|
||||||
interrupt-parent = <&gpa1>;
|
|
||||||
interrupts = <3 0 0>;
|
|
||||||
|
|
||||||
s3fwrn5,en-gpios = <&gpf1 4 0>;
|
|
||||||
s3fwrn5,fw-gpios = <&gpj0 2 0>;
|
|
||||||
};
|
|
||||||
};
|
|
@@ -0,0 +1,73 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/net/nfc/samsung,s3fwrn5.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Samsung S3FWRN5 NCI NFC Controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Krzysztof Kozlowski <krzk@kernel.org>
|
||||||
|
- Krzysztof Opasiak <k.opasiak@samsung.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: samsung,s3fwrn5-i2c
|
||||||
|
|
||||||
|
en-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
Output GPIO pin used for enabling/disabling the chip
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
wake-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
Output GPIO pin used to enter firmware mode and sleep/wakeup control
|
||||||
|
|
||||||
|
s3fwrn5,en-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
deprecated: true
|
||||||
|
description:
|
||||||
|
Use en-gpios
|
||||||
|
|
||||||
|
s3fwrn5,fw-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
deprecated: true
|
||||||
|
description:
|
||||||
|
Use wake-gpios
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- en-gpios
|
||||||
|
- interrupts
|
||||||
|
- reg
|
||||||
|
- wake-gpios
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c4 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
s3fwrn5@27 {
|
||||||
|
compatible = "samsung,s3fwrn5-i2c";
|
||||||
|
reg = <0x27>;
|
||||||
|
|
||||||
|
interrupt-parent = <&gpa1>;
|
||||||
|
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
|
||||||
|
en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>;
|
||||||
|
wake-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
};
|
262
Documentation/devicetree/bindings/net/renesas,etheravb.yaml
Normal file
262
Documentation/devicetree/bindings/net/renesas,etheravb.yaml
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/net/renesas,etheravb.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Renesas Ethernet AVB
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Sergei Shtylyov <sergei.shtylyov@gmail.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- renesas,etheravb-r8a7742 # RZ/G1H
|
||||||
|
- renesas,etheravb-r8a7743 # RZ/G1M
|
||||||
|
- renesas,etheravb-r8a7744 # RZ/G1N
|
||||||
|
- renesas,etheravb-r8a7745 # RZ/G1E
|
||||||
|
- renesas,etheravb-r8a77470 # RZ/G1C
|
||||||
|
- renesas,etheravb-r8a7790 # R-Car H2
|
||||||
|
- renesas,etheravb-r8a7791 # R-Car M2-W
|
||||||
|
- renesas,etheravb-r8a7792 # R-Car V2H
|
||||||
|
- renesas,etheravb-r8a7793 # R-Car M2-N
|
||||||
|
- renesas,etheravb-r8a7794 # R-Car E2
|
||||||
|
- const: renesas,etheravb-rcar-gen2 # R-Car Gen2 and RZ/G1
|
||||||
|
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- renesas,etheravb-r8a774a1 # RZ/G2M
|
||||||
|
- renesas,etheravb-r8a774b1 # RZ/G2N
|
||||||
|
- renesas,etheravb-r8a774c0 # RZ/G2E
|
||||||
|
- renesas,etheravb-r8a774e1 # RZ/G2H
|
||||||
|
- renesas,etheravb-r8a7795 # R-Car H3
|
||||||
|
- renesas,etheravb-r8a7796 # R-Car M3-W
|
||||||
|
- renesas,etheravb-r8a77961 # R-Car M3-W+
|
||||||
|
- renesas,etheravb-r8a77965 # R-Car M3-N
|
||||||
|
- renesas,etheravb-r8a77970 # R-Car V3M
|
||||||
|
- renesas,etheravb-r8a77980 # R-Car V3H
|
||||||
|
- renesas,etheravb-r8a77990 # R-Car E3
|
||||||
|
- renesas,etheravb-r8a77995 # R-Car D3
|
||||||
|
- const: renesas,etheravb-rcar-gen3 # R-Car Gen3 and RZ/G2
|
||||||
|
|
||||||
|
reg: true
|
||||||
|
|
||||||
|
interrupts: true
|
||||||
|
|
||||||
|
interrupt-names: true
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
iommus:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
resets:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
phy-mode: true
|
||||||
|
|
||||||
|
phy-handle: true
|
||||||
|
|
||||||
|
'#address-cells':
|
||||||
|
description: Number of address cells for the MDIO bus.
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
'#size-cells':
|
||||||
|
description: Number of size cells on the MDIO bus.
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
renesas,no-ether-link:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Specify when a board does not provide a proper AVB_LINK signal.
|
||||||
|
|
||||||
|
renesas,ether-link-active-low:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Specify when the AVB_LINK signal is active-low instead of normal
|
||||||
|
active-high.
|
||||||
|
|
||||||
|
rx-internal-delay-ps:
|
||||||
|
enum: [0, 1800]
|
||||||
|
|
||||||
|
tx-internal-delay-ps:
|
||||||
|
enum: [0, 2000]
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^ethernet-phy@[0-9a-f]$":
|
||||||
|
type: object
|
||||||
|
$ref: ethernet-phy.yaml#
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- power-domains
|
||||||
|
- resets
|
||||||
|
- phy-mode
|
||||||
|
- phy-handle
|
||||||
|
- '#address-cells'
|
||||||
|
- '#size-cells'
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: ethernet-controller.yaml#
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- renesas,etheravb-rcar-gen2
|
||||||
|
- renesas,etheravb-r8a7795
|
||||||
|
- renesas,etheravb-r8a7796
|
||||||
|
- renesas,etheravb-r8a77961
|
||||||
|
- renesas,etheravb-r8a77965
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- description: MAC register block
|
||||||
|
- description: Stream buffer
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- description: MAC register block
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: renesas,etheravb-rcar-gen2
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
interrupt-names:
|
||||||
|
items:
|
||||||
|
- const: mux
|
||||||
|
rx-internal-delay-ps: false
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
interrupts:
|
||||||
|
minItems: 25
|
||||||
|
maxItems: 25
|
||||||
|
interrupt-names:
|
||||||
|
items:
|
||||||
|
pattern: '^ch[0-9]+$'
|
||||||
|
required:
|
||||||
|
- interrupt-names
|
||||||
|
- rx-internal-delay-ps
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- renesas,etheravb-r8a774a1
|
||||||
|
- renesas,etheravb-r8a774b1
|
||||||
|
- renesas,etheravb-r8a7795
|
||||||
|
- renesas,etheravb-r8a7796
|
||||||
|
- renesas,etheravb-r8a77961
|
||||||
|
- renesas,etheravb-r8a77965
|
||||||
|
- renesas,etheravb-r8a77970
|
||||||
|
- renesas,etheravb-r8a77980
|
||||||
|
then:
|
||||||
|
required:
|
||||||
|
- tx-internal-delay-ps
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
tx-internal-delay-ps: false
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: renesas,etheravb-r8a77995
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
rx-internal-delay-ps:
|
||||||
|
const: 1800
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: renesas,etheravb-r8a77980
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
tx-internal-delay-ps:
|
||||||
|
const: 2000
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
#include <dt-bindings/power/r8a7795-sysc.h>
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
aliases {
|
||||||
|
ethernet0 = &avb;
|
||||||
|
};
|
||||||
|
|
||||||
|
avb: ethernet@e6800000 {
|
||||||
|
compatible = "renesas,etheravb-r8a7795",
|
||||||
|
"renesas,etheravb-rcar-gen3";
|
||||||
|
reg = <0xe6800000 0x800>, <0xe6a00000 0x10000>;
|
||||||
|
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
interrupt-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6",
|
||||||
|
"ch7", "ch8", "ch9", "ch10", "ch11", "ch12",
|
||||||
|
"ch13", "ch14", "ch15", "ch16", "ch17", "ch18",
|
||||||
|
"ch19", "ch20", "ch21", "ch22", "ch23", "ch24";
|
||||||
|
clocks = <&cpg CPG_MOD 812>;
|
||||||
|
iommus = <&ipmmu_ds0 16>;
|
||||||
|
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||||
|
resets = <&cpg 812>;
|
||||||
|
phy-mode = "rgmii";
|
||||||
|
phy-handle = <&phy0>;
|
||||||
|
rx-internal-delay-ps = <0>;
|
||||||
|
tx-internal-delay-ps = <2000>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
phy0: ethernet-phy@0 {
|
||||||
|
rxc-skew-ps = <1500>;
|
||||||
|
reg = <0>;
|
||||||
|
interrupt-parent = <&gpio2>;
|
||||||
|
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
|
||||||
|
};
|
||||||
|
};
|
@@ -1,135 +0,0 @@
|
|||||||
* Renesas Electronics Ethernet AVB
|
|
||||||
|
|
||||||
This file provides information on what the device node for the Ethernet AVB
|
|
||||||
interface contains.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: Must contain one or more of the following:
|
|
||||||
- "renesas,etheravb-r8a7742" for the R8A7742 SoC.
|
|
||||||
- "renesas,etheravb-r8a7743" for the R8A7743 SoC.
|
|
||||||
- "renesas,etheravb-r8a7744" for the R8A7744 SoC.
|
|
||||||
- "renesas,etheravb-r8a7745" for the R8A7745 SoC.
|
|
||||||
- "renesas,etheravb-r8a77470" for the R8A77470 SoC.
|
|
||||||
- "renesas,etheravb-r8a7790" for the R8A7790 SoC.
|
|
||||||
- "renesas,etheravb-r8a7791" for the R8A7791 SoC.
|
|
||||||
- "renesas,etheravb-r8a7792" for the R8A7792 SoC.
|
|
||||||
- "renesas,etheravb-r8a7793" for the R8A7793 SoC.
|
|
||||||
- "renesas,etheravb-r8a7794" for the R8A7794 SoC.
|
|
||||||
- "renesas,etheravb-rcar-gen2" as a fallback for the above
|
|
||||||
R-Car Gen2 and RZ/G1 devices.
|
|
||||||
|
|
||||||
- "renesas,etheravb-r8a774a1" for the R8A774A1 SoC.
|
|
||||||
- "renesas,etheravb-r8a774b1" for the R8A774B1 SoC.
|
|
||||||
- "renesas,etheravb-r8a774c0" for the R8A774C0 SoC.
|
|
||||||
- "renesas,etheravb-r8a774e1" for the R8A774E1 SoC.
|
|
||||||
- "renesas,etheravb-r8a7795" for the R8A7795 SoC.
|
|
||||||
- "renesas,etheravb-r8a7796" for the R8A77960 SoC.
|
|
||||||
- "renesas,etheravb-r8a77961" for the R8A77961 SoC.
|
|
||||||
- "renesas,etheravb-r8a77965" for the R8A77965 SoC.
|
|
||||||
- "renesas,etheravb-r8a77970" for the R8A77970 SoC.
|
|
||||||
- "renesas,etheravb-r8a77980" for the R8A77980 SoC.
|
|
||||||
- "renesas,etheravb-r8a77990" for the R8A77990 SoC.
|
|
||||||
- "renesas,etheravb-r8a77995" for the R8A77995 SoC.
|
|
||||||
- "renesas,etheravb-rcar-gen3" as a fallback for the above
|
|
||||||
R-Car Gen3 and RZ/G2 devices.
|
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
|
||||||
SoC-specific version corresponding to the platform first followed by
|
|
||||||
the generic version.
|
|
||||||
|
|
||||||
- reg: Offset and length of (1) the register block and (2) the stream buffer.
|
|
||||||
The region for the register block is mandatory.
|
|
||||||
The region for the stream buffer is optional, as it is only present on
|
|
||||||
R-Car Gen2 and RZ/G1 SoCs, and on R-Car H3 (R8A7795), M3-W (R8A77960),
|
|
||||||
M3-W+ (R8A77961), and M3-N (R8A77965).
|
|
||||||
- interrupts: A list of interrupt-specifiers, one for each entry in
|
|
||||||
interrupt-names.
|
|
||||||
If interrupt-names is not present, an interrupt specifier
|
|
||||||
for a single muxed interrupt.
|
|
||||||
- phy-mode: see ethernet.txt file in the same directory.
|
|
||||||
- phy-handle: see ethernet.txt file in the same directory.
|
|
||||||
- #address-cells: number of address cells for the MDIO bus, must be equal to 1.
|
|
||||||
- #size-cells: number of size cells on the MDIO bus, must be equal to 0.
|
|
||||||
- clocks: clock phandle and specifier pair.
|
|
||||||
- pinctrl-0: phandle, referring to a default pin configuration node.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- interrupt-names: A list of interrupt names.
|
|
||||||
For the R-Car Gen 3 SoCs this property is mandatory;
|
|
||||||
it should include one entry per channel, named "ch%u",
|
|
||||||
where %u is the channel number ranging from 0 to 24.
|
|
||||||
For other SoCs this property is optional; if present
|
|
||||||
it should contain "mux" for a single muxed interrupt.
|
|
||||||
- pinctrl-names: pin configuration state name ("default").
|
|
||||||
- renesas,no-ether-link: boolean, specify when a board does not provide a proper
|
|
||||||
AVB_LINK signal.
|
|
||||||
- renesas,ether-link-active-low: boolean, specify when the AVB_LINK signal is
|
|
||||||
active-low instead of normal active-high.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
ethernet@e6800000 {
|
|
||||||
compatible = "renesas,etheravb-r8a7795", "renesas,etheravb-rcar-gen3";
|
|
||||||
reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>;
|
|
||||||
interrupt-parent = <&gic>;
|
|
||||||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
<GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
interrupt-names = "ch0", "ch1", "ch2", "ch3",
|
|
||||||
"ch4", "ch5", "ch6", "ch7",
|
|
||||||
"ch8", "ch9", "ch10", "ch11",
|
|
||||||
"ch12", "ch13", "ch14", "ch15",
|
|
||||||
"ch16", "ch17", "ch18", "ch19",
|
|
||||||
"ch20", "ch21", "ch22", "ch23",
|
|
||||||
"ch24";
|
|
||||||
clocks = <&cpg CPG_MOD 812>;
|
|
||||||
power-domains = <&cpg>;
|
|
||||||
phy-mode = "rgmii-id";
|
|
||||||
phy-handle = <&phy0>;
|
|
||||||
|
|
||||||
pinctrl-0 = <ðer_pins>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
renesas,no-ether-link;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
|
|
||||||
phy0: ethernet-phy@0 {
|
|
||||||
rxc-skew-ps = <900>;
|
|
||||||
rxdv-skew-ps = <0>;
|
|
||||||
rxd0-skew-ps = <0>;
|
|
||||||
rxd1-skew-ps = <0>;
|
|
||||||
rxd2-skew-ps = <0>;
|
|
||||||
rxd3-skew-ps = <0>;
|
|
||||||
txc-skew-ps = <900>;
|
|
||||||
txen-skew-ps = <0>;
|
|
||||||
txd0-skew-ps = <0>;
|
|
||||||
txd1-skew-ps = <0>;
|
|
||||||
txd2-skew-ps = <0>;
|
|
||||||
txd3-skew-ps = <0>;
|
|
||||||
reg = <0>;
|
|
||||||
interrupt-parent = <&gpio2>;
|
|
||||||
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
|
|
||||||
};
|
|
||||||
};
|
|
@@ -5,6 +5,10 @@ through an Ethernet OF device node.
|
|||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|
||||||
|
- clocks:
|
||||||
|
The clock used as phy reference clock and is connected to phy
|
||||||
|
pin XTAL1/CLKIN.
|
||||||
|
|
||||||
- smsc,disable-energy-detect:
|
- smsc,disable-energy-detect:
|
||||||
If set, do not enable energy detect mode for the SMSC phy.
|
If set, do not enable energy detect mode for the SMSC phy.
|
||||||
default: enable energy detect mode
|
default: enable energy detect mode
|
||||||
|
80
Documentation/devicetree/bindings/net/ti,dp83822.yaml
Normal file
80
Documentation/devicetree/bindings/net/ti,dp83822.yaml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
|
||||||
|
# Copyright (C) 2020 Texas Instruments Incorporated
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/net/ti,dp83822.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: TI DP83822 ethernet PHY
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Dan Murphy <dmurphy@ti.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The DP83822 is a low-power, single-port, 10/100 Mbps Ethernet PHY. It
|
||||||
|
provides all of the physical layer functions needed to transmit and receive
|
||||||
|
data over standard, twisted-pair cables or to connect to an external,
|
||||||
|
fiber-optic transceiver. Additionally, the DP83822 provides flexibility to
|
||||||
|
connect to a MAC through a standard MII, RMII, or RGMII interface
|
||||||
|
|
||||||
|
Specifications about the Ethernet PHY can be found at:
|
||||||
|
http://www.ti.com/lit/ds/symlink/dp83822i.pdf
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: "ethernet-phy.yaml#"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
ti,link-loss-low:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
DP83822 PHY in Fiber mode only.
|
||||||
|
Sets the DP83822 to detect a link drop condition when the signal goes
|
||||||
|
high. If not set then link drop will occur when the signal goes low.
|
||||||
|
This property is only applicable if the fiber mode support is strapped
|
||||||
|
to on.
|
||||||
|
|
||||||
|
ti,fiber-mode:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
DP83822 PHY only.
|
||||||
|
If present the DP83822 PHY is configured to operate in fiber mode
|
||||||
|
Fiber mode support can also be strapped. If the strap pin is not set
|
||||||
|
correctly or not set at all then this boolean can be used to enable it.
|
||||||
|
If the fiber mode is not strapped then signal detection for the PHY
|
||||||
|
is disabled.
|
||||||
|
In fiber mode, auto-negotiation is disabled and the PHY can only work in
|
||||||
|
100base-fx (full and half duplex) modes.
|
||||||
|
|
||||||
|
rx-internal-delay-ps:
|
||||||
|
description: |
|
||||||
|
DP83822 PHY only.
|
||||||
|
Setting this property to a non-zero number sets the RX internal delay
|
||||||
|
for the PHY. The internal delay for the PHY is fixed to 3.5ns relative
|
||||||
|
to receive data.
|
||||||
|
|
||||||
|
tx-internal-delay-ps:
|
||||||
|
description: |
|
||||||
|
DP83822 PHY only.
|
||||||
|
Setting this property to a non-zero number sets the TX internal delay
|
||||||
|
for the PHY. The internal delay for the PHY is fixed to 3.5ns relative
|
||||||
|
to transmit data.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
mdio0 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
ethphy0: ethernet-phy@0 {
|
||||||
|
reg = <0>;
|
||||||
|
rx-internal-delay-ps = <1>;
|
||||||
|
tx-internal-delay-ps = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@@ -65,7 +65,8 @@ Optional properties:
|
|||||||
the length can vary between hw versions.
|
the length can vary between hw versions.
|
||||||
- <supply-name>-supply: handle to the regulator device tree node
|
- <supply-name>-supply: handle to the regulator device tree node
|
||||||
optional "supply-name" are "vdd-0.8-cx-mx",
|
optional "supply-name" are "vdd-0.8-cx-mx",
|
||||||
"vdd-1.8-xo", "vdd-1.3-rfa" and "vdd-3.3-ch0".
|
"vdd-1.8-xo", "vdd-1.3-rfa", "vdd-3.3-ch0",
|
||||||
|
and "vdd-3.3-ch1".
|
||||||
- memory-region:
|
- memory-region:
|
||||||
Usage: optional
|
Usage: optional
|
||||||
Value type: <phandle>
|
Value type: <phandle>
|
||||||
@@ -204,6 +205,7 @@ wifi@18000000 {
|
|||||||
vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
|
vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
|
||||||
vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
|
vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
|
||||||
vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
|
vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
|
||||||
|
vdd-3.3-ch1-supply = <&vreg_l26a_3p3>;
|
||||||
memory-region = <&wifi_msa_mem>;
|
memory-region = <&wifi_msa_mem>;
|
||||||
iommus = <&apps_smmu 0x0040 0x1>;
|
iommus = <&apps_smmu 0x0040 0x1>;
|
||||||
qcom,msa-fixed-perm;
|
qcom,msa-fixed-perm;
|
||||||
|
@@ -17,7 +17,9 @@ description: |
|
|||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
const: qcom,ipq8074-wifi
|
enum:
|
||||||
|
- qcom,ipq8074-wifi
|
||||||
|
- qcom,ipq6018-wifi
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@@ -18,6 +18,8 @@ Clock Properties:
|
|||||||
- fsl,tmr-add Frequency compensation value.
|
- fsl,tmr-add Frequency compensation value.
|
||||||
- fsl,tmr-fiper1 Fixed interval period pulse generator.
|
- fsl,tmr-fiper1 Fixed interval period pulse generator.
|
||||||
- fsl,tmr-fiper2 Fixed interval period pulse generator.
|
- fsl,tmr-fiper2 Fixed interval period pulse generator.
|
||||||
|
- fsl,tmr-fiper3 Fixed interval period pulse generator.
|
||||||
|
Supported only on DPAA2 and ENETC hardware.
|
||||||
- fsl,max-adj Maximum frequency adjustment in parts per billion.
|
- fsl,max-adj Maximum frequency adjustment in parts per billion.
|
||||||
- fsl,extts-fifo The presence of this property indicates hardware
|
- fsl,extts-fifo The presence of this property indicates hardware
|
||||||
support for the external trigger stamp FIFO.
|
support for the external trigger stamp FIFO.
|
||||||
|
@@ -12,79 +12,32 @@ Device registration
|
|||||||
:doc: Device registration
|
:doc: Device registration
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: ieee80211_channel_flags
|
:functions:
|
||||||
|
ieee80211_channel_flags
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
ieee80211_channel
|
||||||
:functions: ieee80211_channel
|
ieee80211_rate_flags
|
||||||
|
ieee80211_rate
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
ieee80211_sta_ht_cap
|
||||||
:functions: ieee80211_rate_flags
|
ieee80211_supported_band
|
||||||
|
cfg80211_signal_type
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
wiphy_params_flags
|
||||||
:functions: ieee80211_rate
|
wiphy_flags
|
||||||
|
wiphy
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
wireless_dev
|
||||||
:functions: ieee80211_sta_ht_cap
|
wiphy_new
|
||||||
|
wiphy_read_of_freq_limits
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
wiphy_register
|
||||||
:functions: ieee80211_supported_band
|
wiphy_unregister
|
||||||
|
wiphy_free
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
wiphy_name
|
||||||
:functions: cfg80211_signal_type
|
wiphy_dev
|
||||||
|
wiphy_priv
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
priv_to_wiphy
|
||||||
:functions: wiphy_params_flags
|
set_wiphy_dev
|
||||||
|
wdev_priv
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
ieee80211_iface_limit
|
||||||
:functions: wiphy_flags
|
ieee80211_iface_combination
|
||||||
|
cfg80211_check_combinations
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wireless_dev
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_new
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_read_of_freq_limits
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_register
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_unregister
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_free
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_name
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_dev
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_priv
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: priv_to_wiphy
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: set_wiphy_dev
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wdev_priv
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_iface_limit
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_iface_combination
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_check_combinations
|
|
||||||
|
|
||||||
Actions and configuration
|
Actions and configuration
|
||||||
=========================
|
=========================
|
||||||
@@ -93,139 +46,52 @@ Actions and configuration
|
|||||||
:doc: Actions and configuration
|
:doc: Actions and configuration
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: cfg80211_ops
|
:functions:
|
||||||
|
cfg80211_ops
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
vif_params
|
||||||
:functions: vif_params
|
key_params
|
||||||
|
survey_info_flags
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
survey_info
|
||||||
:functions: key_params
|
cfg80211_beacon_data
|
||||||
|
cfg80211_ap_settings
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
station_parameters
|
||||||
:functions: survey_info_flags
|
rate_info_flags
|
||||||
|
rate_info
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
station_info
|
||||||
:functions: survey_info
|
monitor_flags
|
||||||
|
mpath_info_flags
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
mpath_info
|
||||||
:functions: cfg80211_beacon_data
|
bss_parameters
|
||||||
|
ieee80211_txq_params
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_crypto_settings
|
||||||
:functions: cfg80211_ap_settings
|
cfg80211_auth_request
|
||||||
|
cfg80211_assoc_request
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_deauth_request
|
||||||
:functions: station_parameters
|
cfg80211_disassoc_request
|
||||||
|
cfg80211_ibss_params
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_connect_params
|
||||||
:functions: rate_info_flags
|
cfg80211_pmksa
|
||||||
|
cfg80211_rx_mlme_mgmt
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_auth_timeout
|
||||||
:functions: rate_info
|
cfg80211_rx_assoc_resp
|
||||||
|
cfg80211_assoc_timeout
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_tx_mlme_mgmt
|
||||||
:functions: station_info
|
cfg80211_ibss_joined
|
||||||
|
cfg80211_connect_resp_params
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_connect_done
|
||||||
:functions: monitor_flags
|
cfg80211_connect_result
|
||||||
|
cfg80211_connect_bss
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_connect_timeout
|
||||||
:functions: mpath_info_flags
|
cfg80211_roamed
|
||||||
|
cfg80211_disconnected
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_ready_on_channel
|
||||||
:functions: mpath_info
|
cfg80211_remain_on_channel_expired
|
||||||
|
cfg80211_new_sta
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_rx_mgmt
|
||||||
:functions: bss_parameters
|
cfg80211_mgmt_tx_status
|
||||||
|
cfg80211_cqm_rssi_notify
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_cqm_pktloss_notify
|
||||||
:functions: ieee80211_txq_params
|
cfg80211_michael_mic_failure
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_crypto_settings
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_auth_request
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_assoc_request
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_deauth_request
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_disassoc_request
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_ibss_params
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_connect_params
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_pmksa
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_rx_mlme_mgmt
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_auth_timeout
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_rx_assoc_resp
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_assoc_timeout
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_tx_mlme_mgmt
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_ibss_joined
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_connect_resp_params
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_connect_done
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_connect_result
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_connect_bss
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_connect_timeout
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_roamed
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_disconnected
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_ready_on_channel
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_remain_on_channel_expired
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_new_sta
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_rx_mgmt
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_mgmt_tx_status
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_cqm_rssi_notify
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_cqm_pktloss_notify
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_michael_mic_failure
|
|
||||||
|
|
||||||
Scanning and BSS list handling
|
Scanning and BSS list handling
|
||||||
==============================
|
==============================
|
||||||
@@ -234,34 +100,17 @@ Scanning and BSS list handling
|
|||||||
:doc: Scanning and BSS list handling
|
:doc: Scanning and BSS list handling
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: cfg80211_ssid
|
:functions:
|
||||||
|
cfg80211_ssid
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_scan_request
|
||||||
:functions: cfg80211_scan_request
|
cfg80211_scan_done
|
||||||
|
cfg80211_bss
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_inform_bss
|
||||||
:functions: cfg80211_scan_done
|
cfg80211_inform_bss_frame_data
|
||||||
|
cfg80211_inform_bss_data
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_unlink_bss
|
||||||
:functions: cfg80211_bss
|
cfg80211_find_ie
|
||||||
|
ieee80211_bss_get_ie
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_inform_bss
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_inform_bss_frame_data
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_inform_bss_data
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_unlink_bss
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_find_ie
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_bss_get_ie
|
|
||||||
|
|
||||||
Utility functions
|
Utility functions
|
||||||
=================
|
=================
|
||||||
@@ -270,25 +119,14 @@ Utility functions
|
|||||||
:doc: Utility functions
|
:doc: Utility functions
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: ieee80211_channel_to_frequency
|
:functions:
|
||||||
|
ieee80211_channel_to_frequency
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
ieee80211_frequency_to_channel
|
||||||
:functions: ieee80211_frequency_to_channel
|
ieee80211_get_channel
|
||||||
|
ieee80211_get_response_rate
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
ieee80211_hdrlen
|
||||||
:functions: ieee80211_get_channel
|
ieee80211_get_hdrlen_from_skb
|
||||||
|
ieee80211_radiotap_iterator
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_get_response_rate
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_hdrlen
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_get_hdrlen_from_skb
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: ieee80211_radiotap_iterator
|
|
||||||
|
|
||||||
Data path helpers
|
Data path helpers
|
||||||
=================
|
=================
|
||||||
@@ -297,13 +135,10 @@ Data path helpers
|
|||||||
:doc: Data path helpers
|
:doc: Data path helpers
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: ieee80211_data_to_8023
|
:functions:
|
||||||
|
ieee80211_data_to_8023
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
ieee80211_amsdu_to_8023s
|
||||||
:functions: ieee80211_amsdu_to_8023s
|
cfg80211_classify8021d
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_classify8021d
|
|
||||||
|
|
||||||
Regulatory enforcement infrastructure
|
Regulatory enforcement infrastructure
|
||||||
=====================================
|
=====================================
|
||||||
@@ -312,13 +147,10 @@ Regulatory enforcement infrastructure
|
|||||||
:doc: Regulatory enforcement infrastructure
|
:doc: Regulatory enforcement infrastructure
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: regulatory_hint
|
:functions:
|
||||||
|
regulatory_hint
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
wiphy_apply_custom_regulatory
|
||||||
:functions: wiphy_apply_custom_regulatory
|
freq_reg_info
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: freq_reg_info
|
|
||||||
|
|
||||||
RFkill integration
|
RFkill integration
|
||||||
==================
|
==================
|
||||||
@@ -327,13 +159,10 @@ RFkill integration
|
|||||||
:doc: RFkill integration
|
:doc: RFkill integration
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: wiphy_rfkill_set_hw_state
|
:functions:
|
||||||
|
wiphy_rfkill_set_hw_state
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
wiphy_rfkill_start_polling
|
||||||
:functions: wiphy_rfkill_start_polling
|
wiphy_rfkill_stop_polling
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: wiphy_rfkill_stop_polling
|
|
||||||
|
|
||||||
Test mode
|
Test mode
|
||||||
=========
|
=========
|
||||||
@@ -342,13 +171,8 @@ Test mode
|
|||||||
:doc: Test mode
|
:doc: Test mode
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
.. kernel-doc:: include/net/cfg80211.h
|
||||||
:functions: cfg80211_testmode_alloc_reply_skb
|
:functions:
|
||||||
|
cfg80211_testmode_alloc_reply_skb
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
cfg80211_testmode_reply
|
||||||
:functions: cfg80211_testmode_reply
|
cfg80211_testmode_alloc_event_skb
|
||||||
|
cfg80211_testmode_event
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_testmode_alloc_event_skb
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/cfg80211.h
|
|
||||||
:functions: cfg80211_testmode_event
|
|
||||||
|
@@ -15,25 +15,14 @@ appropriate trigger, which will then be triggered appropriately by
|
|||||||
mac80211.
|
mac80211.
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_get_tx_led_name
|
:functions:
|
||||||
|
ieee80211_get_tx_led_name
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_get_rx_led_name
|
||||||
:functions: ieee80211_get_rx_led_name
|
ieee80211_get_assoc_led_name
|
||||||
|
ieee80211_get_radio_led_name
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_tpt_blink
|
||||||
:functions: ieee80211_get_assoc_led_name
|
ieee80211_tpt_led_trigger_flags
|
||||||
|
ieee80211_create_tpt_led_trigger
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_get_radio_led_name
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_tpt_blink
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_tpt_led_trigger_flags
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_create_tpt_led_trigger
|
|
||||||
|
|
||||||
Hardware crypto acceleration
|
Hardware crypto acceleration
|
||||||
============================
|
============================
|
||||||
@@ -42,22 +31,13 @@ Hardware crypto acceleration
|
|||||||
:doc: Hardware crypto acceleration
|
:doc: Hardware crypto acceleration
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: set_key_cmd
|
:functions:
|
||||||
|
set_key_cmd
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_key_conf
|
||||||
:functions: ieee80211_key_conf
|
ieee80211_key_flags
|
||||||
|
ieee80211_get_tkip_p1k
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_get_tkip_p1k_iv
|
||||||
:functions: ieee80211_key_flags
|
ieee80211_get_tkip_p2k
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_get_tkip_p1k
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_get_tkip_p1k_iv
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_get_tkip_p2k
|
|
||||||
|
|
||||||
Powersave support
|
Powersave support
|
||||||
=================
|
=================
|
||||||
@@ -99,28 +79,15 @@ support for powersaving clients
|
|||||||
:doc: AP support for powersaving clients
|
:doc: AP support for powersaving clients
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_get_buffered_bc
|
:functions:
|
||||||
|
ieee80211_get_buffered_bc
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_beacon_get
|
||||||
:functions: ieee80211_beacon_get
|
ieee80211_sta_eosp
|
||||||
|
ieee80211_frame_release_type
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_sta_ps_transition
|
||||||
:functions: ieee80211_sta_eosp
|
ieee80211_sta_ps_transition_ni
|
||||||
|
ieee80211_sta_set_buffered
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_sta_block_awake
|
||||||
:functions: ieee80211_frame_release_type
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_sta_ps_transition
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_sta_ps_transition_ni
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_sta_set_buffered
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_sta_block_awake
|
|
||||||
|
|
||||||
Supporting multiple virtual interfaces
|
Supporting multiple virtual interfaces
|
||||||
======================================
|
======================================
|
||||||
@@ -134,10 +101,9 @@ addresses here, note which configurations are supported by mac80211, add
|
|||||||
notes about supporting hw crypto with it.
|
notes about supporting hw crypto with it.
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_iterate_active_interfaces
|
:functions:
|
||||||
|
ieee80211_iterate_active_interfaces
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_iterate_active_interfaces_atomic
|
||||||
:functions: ieee80211_iterate_active_interfaces_atomic
|
|
||||||
|
|
||||||
Station handling
|
Station handling
|
||||||
================
|
================
|
||||||
@@ -145,16 +111,11 @@ Station handling
|
|||||||
TODO
|
TODO
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_sta
|
:functions:
|
||||||
|
ieee80211_sta
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
sta_notify_cmd
|
||||||
:functions: sta_notify_cmd
|
ieee80211_find_sta
|
||||||
|
ieee80211_find_sta_by_ifaddr
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_find_sta
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_find_sta_by_ifaddr
|
|
||||||
|
|
||||||
Hardware scan offload
|
Hardware scan offload
|
||||||
=====================
|
=====================
|
||||||
@@ -193,10 +154,9 @@ Spatial Multiplexing Powersave (SMPS)
|
|||||||
:doc: Spatial multiplexing power save
|
:doc: Spatial multiplexing power save
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_request_smps
|
:functions:
|
||||||
|
ieee80211_request_smps
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_smps_mode
|
||||||
:functions: ieee80211_smps_mode
|
|
||||||
|
|
||||||
TBD
|
TBD
|
||||||
|
|
||||||
@@ -209,22 +169,13 @@ Rate Control API
|
|||||||
TBD
|
TBD
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_start_tx_ba_session
|
:functions:
|
||||||
|
ieee80211_start_tx_ba_session
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_start_tx_ba_cb_irqsafe
|
||||||
:functions: ieee80211_start_tx_ba_cb_irqsafe
|
ieee80211_stop_tx_ba_session
|
||||||
|
ieee80211_stop_tx_ba_cb_irqsafe
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_rate_control_changed
|
||||||
:functions: ieee80211_stop_tx_ba_session
|
ieee80211_tx_rate_control
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_stop_tx_ba_cb_irqsafe
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_rate_control_changed
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_tx_rate_control
|
|
||||||
|
|
||||||
TBD
|
TBD
|
||||||
|
|
||||||
@@ -261,10 +212,9 @@ Programming information
|
|||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
.. kernel-doc:: net/mac80211/sta_info.h
|
.. kernel-doc:: net/mac80211/sta_info.h
|
||||||
:functions: sta_info
|
:functions:
|
||||||
|
sta_info
|
||||||
.. kernel-doc:: net/mac80211/sta_info.h
|
ieee80211_sta_info_flags
|
||||||
:functions: ieee80211_sta_info_flags
|
|
||||||
|
|
||||||
STA information lifetime rules
|
STA information lifetime rules
|
||||||
------------------------------
|
------------------------------
|
||||||
@@ -276,13 +226,10 @@ Aggregation Functions
|
|||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. kernel-doc:: net/mac80211/sta_info.h
|
.. kernel-doc:: net/mac80211/sta_info.h
|
||||||
:functions: sta_ampdu_mlme
|
:functions:
|
||||||
|
sta_ampdu_mlme
|
||||||
.. kernel-doc:: net/mac80211/sta_info.h
|
tid_ampdu_tx
|
||||||
:functions: tid_ampdu_tx
|
tid_ampdu_rx
|
||||||
|
|
||||||
.. kernel-doc:: net/mac80211/sta_info.h
|
|
||||||
:functions: tid_ampdu_rx
|
|
||||||
|
|
||||||
Synchronisation Functions
|
Synchronisation Functions
|
||||||
=========================
|
=========================
|
||||||
|
@@ -30,31 +30,16 @@ Finally, a discussion of hardware capabilities should be done with
|
|||||||
references to other parts of the book.
|
references to other parts of the book.
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_hw
|
:functions:
|
||||||
|
ieee80211_hw
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_hw_flags
|
||||||
:functions: ieee80211_hw_flags
|
SET_IEEE80211_DEV
|
||||||
|
SET_IEEE80211_PERM_ADDR
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_ops
|
||||||
:functions: SET_IEEE80211_DEV
|
ieee80211_alloc_hw
|
||||||
|
ieee80211_register_hw
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_unregister_hw
|
||||||
:functions: SET_IEEE80211_PERM_ADDR
|
ieee80211_free_hw
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_ops
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_alloc_hw
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_register_hw
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_unregister_hw
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_free_hw
|
|
||||||
|
|
||||||
PHY configuration
|
PHY configuration
|
||||||
=================
|
=================
|
||||||
@@ -65,10 +50,9 @@ This chapter should describe PHY handling including start/stop callbacks
|
|||||||
and the various structures used.
|
and the various structures used.
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_conf
|
:functions:
|
||||||
|
ieee80211_conf
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_conf_flags
|
||||||
:functions: ieee80211_conf_flags
|
|
||||||
|
|
||||||
Virtual interfaces
|
Virtual interfaces
|
||||||
==================
|
==================
|
||||||
@@ -123,79 +107,32 @@ functions/definitions
|
|||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_rx_status
|
:functions:
|
||||||
|
ieee80211_rx_status
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
mac80211_rx_encoding_flags
|
||||||
:functions: mac80211_rx_encoding_flags
|
mac80211_rx_flags
|
||||||
|
mac80211_tx_info_flags
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
mac80211_tx_control_flags
|
||||||
:functions: mac80211_rx_flags
|
mac80211_rate_control_flags
|
||||||
|
ieee80211_tx_rate
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_tx_info
|
||||||
:functions: mac80211_tx_info_flags
|
ieee80211_tx_info_clear_status
|
||||||
|
ieee80211_rx
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_rx_ni
|
||||||
:functions: mac80211_tx_control_flags
|
ieee80211_rx_irqsafe
|
||||||
|
ieee80211_tx_status
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_tx_status_ni
|
||||||
:functions: mac80211_rate_control_flags
|
ieee80211_tx_status_irqsafe
|
||||||
|
ieee80211_rts_get
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_rts_duration
|
||||||
:functions: ieee80211_tx_rate
|
ieee80211_ctstoself_get
|
||||||
|
ieee80211_ctstoself_duration
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_generic_frame_duration
|
||||||
:functions: ieee80211_tx_info
|
ieee80211_wake_queue
|
||||||
|
ieee80211_stop_queue
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_wake_queues
|
||||||
:functions: ieee80211_tx_info_clear_status
|
ieee80211_stop_queues
|
||||||
|
ieee80211_queue_stopped
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_rx
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_rx_ni
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_rx_irqsafe
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_tx_status
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_tx_status_ni
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_tx_status_irqsafe
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_rts_get
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_rts_duration
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_ctstoself_get
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_ctstoself_duration
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_generic_frame_duration
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_wake_queue
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_stop_queue
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_wake_queues
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_stop_queues
|
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
|
||||||
:functions: ieee80211_queue_stopped
|
|
||||||
|
|
||||||
Frame filtering
|
Frame filtering
|
||||||
===============
|
===============
|
||||||
@@ -213,7 +150,6 @@ The mac80211 workqueue
|
|||||||
:doc: mac80211 workqueue
|
:doc: mac80211 workqueue
|
||||||
|
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
.. kernel-doc:: include/net/mac80211.h
|
||||||
:functions: ieee80211_queue_work
|
:functions:
|
||||||
|
ieee80211_queue_work
|
||||||
.. kernel-doc:: include/net/mac80211.h
|
ieee80211_queue_delayed_work
|
||||||
:functions: ieee80211_queue_delayed_work
|
|
||||||
|
@@ -258,14 +258,21 @@ socket into zero-copy mode or fail.
|
|||||||
XDP_SHARED_UMEM bind flag
|
XDP_SHARED_UMEM bind flag
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
This flag enables you to bind multiple sockets to the same UMEM, but
|
This flag enables you to bind multiple sockets to the same UMEM. It
|
||||||
only if they share the same queue id. In this mode, each socket has
|
works on the same queue id, between queue ids and between
|
||||||
their own RX and TX rings, but the UMEM (tied to the fist socket
|
netdevs/devices. In this mode, each socket has their own RX and TX
|
||||||
created) only has a single FILL ring and a single COMPLETION
|
rings as usual, but you are going to have one or more FILL and
|
||||||
ring. To use this mode, create the first socket and bind it in the normal
|
COMPLETION ring pairs. You have to create one of these pairs per
|
||||||
way. Create a second socket and create an RX and a TX ring, or at
|
unique netdev and queue id tuple that you bind to.
|
||||||
least one of them, but no FILL or COMPLETION rings as the ones from
|
|
||||||
the first socket will be used. In the bind call, set he
|
Starting with the case were we would like to share a UMEM between
|
||||||
|
sockets bound to the same netdev and queue id. The UMEM (tied to the
|
||||||
|
fist socket created) will only have a single FILL ring and a single
|
||||||
|
COMPLETION ring as there is only on unique netdev,queue_id tuple that
|
||||||
|
we have bound to. To use this mode, create the first socket and bind
|
||||||
|
it in the normal way. Create a second socket and create an RX and a TX
|
||||||
|
ring, or at least one of them, but no FILL or COMPLETION rings as the
|
||||||
|
ones from the first socket will be used. In the bind call, set he
|
||||||
XDP_SHARED_UMEM option and provide the initial socket's fd in the
|
XDP_SHARED_UMEM option and provide the initial socket's fd in the
|
||||||
sxdp_shared_umem_fd field. You can attach an arbitrary number of extra
|
sxdp_shared_umem_fd field. You can attach an arbitrary number of extra
|
||||||
sockets this way.
|
sockets this way.
|
||||||
@@ -305,11 +312,41 @@ concurrently. There are no synchronization primitives in the
|
|||||||
libbpf code that protects multiple users at this point in time.
|
libbpf code that protects multiple users at this point in time.
|
||||||
|
|
||||||
Libbpf uses this mode if you create more than one socket tied to the
|
Libbpf uses this mode if you create more than one socket tied to the
|
||||||
same umem. However, note that you need to supply the
|
same UMEM. However, note that you need to supply the
|
||||||
XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD libbpf_flag with the
|
XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD libbpf_flag with the
|
||||||
xsk_socket__create calls and load your own XDP program as there is no
|
xsk_socket__create calls and load your own XDP program as there is no
|
||||||
built in one in libbpf that will route the traffic for you.
|
built in one in libbpf that will route the traffic for you.
|
||||||
|
|
||||||
|
The second case is when you share a UMEM between sockets that are
|
||||||
|
bound to different queue ids and/or netdevs. In this case you have to
|
||||||
|
create one FILL ring and one COMPLETION ring for each unique
|
||||||
|
netdev,queue_id pair. Let us say you want to create two sockets bound
|
||||||
|
to two different queue ids on the same netdev. Create the first socket
|
||||||
|
and bind it in the normal way. Create a second socket and create an RX
|
||||||
|
and a TX ring, or at least one of them, and then one FILL and
|
||||||
|
COMPLETION ring for this socket. Then in the bind call, set he
|
||||||
|
XDP_SHARED_UMEM option and provide the initial socket's fd in the
|
||||||
|
sxdp_shared_umem_fd field as you registered the UMEM on that
|
||||||
|
socket. These two sockets will now share one and the same UMEM.
|
||||||
|
|
||||||
|
There is no need to supply an XDP program like the one in the previous
|
||||||
|
case where sockets were bound to the same queue id and
|
||||||
|
device. Instead, use the NIC's packet steering capabilities to steer
|
||||||
|
the packets to the right queue. In the previous example, there is only
|
||||||
|
one queue shared among sockets, so the NIC cannot do this steering. It
|
||||||
|
can only steer between queues.
|
||||||
|
|
||||||
|
In libbpf, you need to use the xsk_socket__create_shared() API as it
|
||||||
|
takes a reference to a FILL ring and a COMPLETION ring that will be
|
||||||
|
created for you and bound to the shared UMEM. You can use this
|
||||||
|
function for all the sockets you create, or you can use it for the
|
||||||
|
second and following ones and use xsk_socket__create() for the first
|
||||||
|
one. Both methods yield the same result.
|
||||||
|
|
||||||
|
Note that a UMEM can be shared between sockets on the same queue id
|
||||||
|
and device, as well as between queues on the same device and between
|
||||||
|
devices at the same time.
|
||||||
|
|
||||||
XDP_USE_NEED_WAKEUP bind flag
|
XDP_USE_NEED_WAKEUP bind flag
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
@@ -364,7 +401,7 @@ resources by only setting up one of them. Both the FILL ring and the
|
|||||||
COMPLETION ring are mandatory as you need to have a UMEM tied to your
|
COMPLETION ring are mandatory as you need to have a UMEM tied to your
|
||||||
socket. But if the XDP_SHARED_UMEM flag is used, any socket after the
|
socket. But if the XDP_SHARED_UMEM flag is used, any socket after the
|
||||||
first one does not have a UMEM and should in that case not have any
|
first one does not have a UMEM and should in that case not have any
|
||||||
FILL or COMPLETION rings created as the ones from the shared umem will
|
FILL or COMPLETION rings created as the ones from the shared UMEM will
|
||||||
be used. Note, that the rings are single-producer single-consumer, so
|
be used. Note, that the rings are single-producer single-consumer, so
|
||||||
do not try to access them from multiple processes at the same
|
do not try to access them from multiple processes at the same
|
||||||
time. See the XDP_SHARED_UMEM section.
|
time. See the XDP_SHARED_UMEM section.
|
||||||
@@ -567,6 +604,17 @@ A: The short answer is no, that is not supported at the moment. The
|
|||||||
switch, or other distribution mechanism, in your NIC to direct
|
switch, or other distribution mechanism, in your NIC to direct
|
||||||
traffic to the correct queue id and socket.
|
traffic to the correct queue id and socket.
|
||||||
|
|
||||||
|
Q: My packets are sometimes corrupted. What is wrong?
|
||||||
|
|
||||||
|
A: Care has to be taken not to feed the same buffer in the UMEM into
|
||||||
|
more than one ring at the same time. If you for example feed the
|
||||||
|
same buffer into the FILL ring and the TX ring at the same time, the
|
||||||
|
NIC might receive data into the buffer at the same time it is
|
||||||
|
sending it. This will cause some packets to become corrupted. Same
|
||||||
|
thing goes for feeding the same buffer into the FILL rings
|
||||||
|
belonging to different queue ids or netdevs bound with the
|
||||||
|
XDP_SHARED_UMEM flag.
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
@@ -10,4 +10,3 @@ Contents:
|
|||||||
|
|
||||||
linux_caif
|
linux_caif
|
||||||
caif
|
caif
|
||||||
spi_porting
|
|
||||||
|
@@ -1,229 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
|
||||||
|
|
||||||
================
|
|
||||||
CAIF SPI porting
|
|
||||||
================
|
|
||||||
|
|
||||||
CAIF SPI basics
|
|
||||||
===============
|
|
||||||
|
|
||||||
Running CAIF over SPI needs some extra setup, owing to the nature of SPI.
|
|
||||||
Two extra GPIOs have been added in order to negotiate the transfers
|
|
||||||
between the master and the slave. The minimum requirement for running
|
|
||||||
CAIF over SPI is a SPI slave chip and two GPIOs (more details below).
|
|
||||||
Please note that running as a slave implies that you need to keep up
|
|
||||||
with the master clock. An overrun or underrun event is fatal.
|
|
||||||
|
|
||||||
CAIF SPI framework
|
|
||||||
==================
|
|
||||||
|
|
||||||
To make porting as easy as possible, the CAIF SPI has been divided in
|
|
||||||
two parts. The first part (called the interface part) deals with all
|
|
||||||
generic functionality such as length framing, SPI frame negotiation
|
|
||||||
and SPI frame delivery and transmission. The other part is the CAIF
|
|
||||||
SPI slave device part, which is the module that you have to write if
|
|
||||||
you want to run SPI CAIF on a new hardware. This part takes care of
|
|
||||||
the physical hardware, both with regard to SPI and to GPIOs.
|
|
||||||
|
|
||||||
- Implementing a CAIF SPI device:
|
|
||||||
|
|
||||||
- Functionality provided by the CAIF SPI slave device:
|
|
||||||
|
|
||||||
In order to implement a SPI device you will, as a minimum,
|
|
||||||
need to implement the following
|
|
||||||
functions:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
int (*init_xfer) (struct cfspi_xfer * xfer, struct cfspi_dev *dev):
|
|
||||||
|
|
||||||
This function is called by the CAIF SPI interface to give
|
|
||||||
you a chance to set up your hardware to be ready to receive
|
|
||||||
a stream of data from the master. The xfer structure contains
|
|
||||||
both physical and logical addresses, as well as the total length
|
|
||||||
of the transfer in both directions.The dev parameter can be used
|
|
||||||
to map to different CAIF SPI slave devices.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
void (*sig_xfer) (bool xfer, struct cfspi_dev *dev):
|
|
||||||
|
|
||||||
This function is called by the CAIF SPI interface when the output
|
|
||||||
(SPI_INT) GPIO needs to change state. The boolean value of the xfer
|
|
||||||
variable indicates whether the GPIO should be asserted (HIGH) or
|
|
||||||
deasserted (LOW). The dev parameter can be used to map to different CAIF
|
|
||||||
SPI slave devices.
|
|
||||||
|
|
||||||
- Functionality provided by the CAIF SPI interface:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
void (*ss_cb) (bool assert, struct cfspi_ifc *ifc);
|
|
||||||
|
|
||||||
This function is called by the CAIF SPI slave device in order to
|
|
||||||
signal a change of state of the input GPIO (SS) to the interface.
|
|
||||||
Only active edges are mandatory to be reported.
|
|
||||||
This function can be called from IRQ context (recommended in order
|
|
||||||
not to introduce latency). The ifc parameter should be the pointer
|
|
||||||
returned from the platform probe function in the SPI device structure.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
void (*xfer_done_cb) (struct cfspi_ifc *ifc);
|
|
||||||
|
|
||||||
This function is called by the CAIF SPI slave device in order to
|
|
||||||
report that a transfer is completed. This function should only be
|
|
||||||
called once both the transmission and the reception are completed.
|
|
||||||
This function can be called from IRQ context (recommended in order
|
|
||||||
not to introduce latency). The ifc parameter should be the pointer
|
|
||||||
returned from the platform probe function in the SPI device structure.
|
|
||||||
|
|
||||||
- Connecting the bits and pieces:
|
|
||||||
|
|
||||||
- Filling in the SPI slave device structure:
|
|
||||||
|
|
||||||
Connect the necessary callback functions.
|
|
||||||
|
|
||||||
Indicate clock speed (used to calculate toggle delays).
|
|
||||||
|
|
||||||
Chose a suitable name (helps debugging if you use several CAIF
|
|
||||||
SPI slave devices).
|
|
||||||
|
|
||||||
Assign your private data (can be used to map to your
|
|
||||||
structure).
|
|
||||||
|
|
||||||
- Filling in the SPI slave platform device structure:
|
|
||||||
|
|
||||||
Add name of driver to connect to ("cfspi_sspi").
|
|
||||||
|
|
||||||
Assign the SPI slave device structure as platform data.
|
|
||||||
|
|
||||||
Padding
|
|
||||||
=======
|
|
||||||
|
|
||||||
In order to optimize throughput, a number of SPI padding options are provided.
|
|
||||||
Padding can be enabled independently for uplink and downlink transfers.
|
|
||||||
Padding can be enabled for the head, the tail and for the total frame size.
|
|
||||||
The padding needs to be correctly configured on both sides of the link.
|
|
||||||
The padding can be changed via module parameters in cfspi_sspi.c or via
|
|
||||||
the sysfs directory of the cfspi_sspi driver (before device registration).
|
|
||||||
|
|
||||||
- CAIF SPI device template::
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) ST-Ericsson AB 2010
|
|
||||||
* Author: Daniel Martensson / Daniel.Martensson@stericsson.com
|
|
||||||
* License terms: GNU General Public License (GPL), version 2.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/wait.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
|
||||||
#include <net/caif/caif_spi.h>
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
||||||
struct sspi_struct {
|
|
||||||
struct cfspi_dev sdev;
|
|
||||||
struct cfspi_xfer *xfer;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct sspi_struct slave;
|
|
||||||
static struct platform_device slave_device;
|
|
||||||
|
|
||||||
static irqreturn_t sspi_irq(int irq, void *arg)
|
|
||||||
{
|
|
||||||
/* You only need to trigger on an edge to the active state of the
|
|
||||||
* SS signal. Once a edge is detected, the ss_cb() function should be
|
|
||||||
* called with the parameter assert set to true. It is OK
|
|
||||||
* (and even advised) to call the ss_cb() function in IRQ context in
|
|
||||||
* order not to add any delay. */
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sspi_complete(void *context)
|
|
||||||
{
|
|
||||||
/* Normally the DMA or the SPI framework will call you back
|
|
||||||
* in something similar to this. The only thing you need to
|
|
||||||
* do is to call the xfer_done_cb() function, providing the pointer
|
|
||||||
* to the CAIF SPI interface. It is OK to call this function
|
|
||||||
* from IRQ context. */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sspi_init_xfer(struct cfspi_xfer *xfer, struct cfspi_dev *dev)
|
|
||||||
{
|
|
||||||
/* Store transfer info. For a normal implementation you should
|
|
||||||
* set up your DMA here and make sure that you are ready to
|
|
||||||
* receive the data from the master SPI. */
|
|
||||||
|
|
||||||
struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
|
|
||||||
|
|
||||||
sspi->xfer = xfer;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sspi_sig_xfer(bool xfer, struct cfspi_dev *dev)
|
|
||||||
{
|
|
||||||
/* If xfer is true then you should assert the SPI_INT to indicate to
|
|
||||||
* the master that you are ready to receive the data from the master
|
|
||||||
* SPI. If xfer is false then you should de-assert SPI_INT to indicate
|
|
||||||
* that the transfer is done.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct sspi_struct *sspi = (struct sspi_struct *)dev->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sspi_release(struct device *dev)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Here you should release your SPI device resources.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init sspi_init(void)
|
|
||||||
{
|
|
||||||
/* Here you should initialize your SPI device by providing the
|
|
||||||
* necessary functions, clock speed, name and private data. Once
|
|
||||||
* done, you can register your device with the
|
|
||||||
* platform_device_register() function. This function will return
|
|
||||||
* with the CAIF SPI interface initialized. This is probably also
|
|
||||||
* the place where you should set up your GPIOs, interrupts and SPI
|
|
||||||
* resources. */
|
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
/* Initialize slave device. */
|
|
||||||
slave.sdev.init_xfer = sspi_init_xfer;
|
|
||||||
slave.sdev.sig_xfer = sspi_sig_xfer;
|
|
||||||
slave.sdev.clk_mhz = 13;
|
|
||||||
slave.sdev.priv = &slave;
|
|
||||||
slave.sdev.name = "spi_sspi";
|
|
||||||
slave_device.dev.release = sspi_release;
|
|
||||||
|
|
||||||
/* Initialize platform device. */
|
|
||||||
slave_device.name = "cfspi_sspi";
|
|
||||||
slave_device.dev.platform_data = &slave.sdev;
|
|
||||||
|
|
||||||
/* Register platform device. */
|
|
||||||
res = platform_device_register(&slave_device);
|
|
||||||
if (res) {
|
|
||||||
printk(KERN_WARNING "sspi_init: failed to register dev.\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit sspi_exit(void)
|
|
||||||
{
|
|
||||||
platform_device_del(&slave_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(sspi_init);
|
|
||||||
module_exit(sspi_exit);
|
|
@@ -39,16 +39,6 @@ debug logs.
|
|||||||
Some of the ENA devices support a working mode called Low-latency
|
Some of the ENA devices support a working mode called Low-latency
|
||||||
Queue (LLQ), which saves several more microseconds.
|
Queue (LLQ), which saves several more microseconds.
|
||||||
|
|
||||||
Supported PCI vendor ID/device IDs
|
|
||||||
==================================
|
|
||||||
|
|
||||||
========= =======================
|
|
||||||
1d0f:0ec2 ENA PF
|
|
||||||
1d0f:1ec2 ENA PF with LLQ support
|
|
||||||
1d0f:ec20 ENA VF
|
|
||||||
1d0f:ec21 ENA VF with LLQ support
|
|
||||||
========= =======================
|
|
||||||
|
|
||||||
ENA Source Code Directory Structure
|
ENA Source Code Directory Structure
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
@@ -212,20 +202,11 @@ In adaptive interrupt moderation mode the interrupt delay value is
|
|||||||
updated by the driver dynamically and adjusted every NAPI cycle
|
updated by the driver dynamically and adjusted every NAPI cycle
|
||||||
according to the traffic nature.
|
according to the traffic nature.
|
||||||
|
|
||||||
By default ENA driver applies adaptive coalescing on Rx traffic and
|
|
||||||
conventional coalescing on Tx traffic.
|
|
||||||
|
|
||||||
Adaptive coalescing can be switched on/off through ethtool(8)
|
Adaptive coalescing can be switched on/off through ethtool(8)
|
||||||
adaptive_rx on|off parameter.
|
adaptive_rx on|off parameter.
|
||||||
|
|
||||||
The driver chooses interrupt delay value according to the number of
|
More information about Adaptive Interrupt Moderation (DIM) can be found in
|
||||||
bytes and packets received between interrupt unmasking and interrupt
|
Documentation/networking/net_dim.rst
|
||||||
posting. The driver uses interrupt delay table that subdivides the
|
|
||||||
range of received bytes/packets into 5 levels and assigns interrupt
|
|
||||||
delay value to each level.
|
|
||||||
|
|
||||||
The user can enable/disable adaptive moderation, modify the interrupt
|
|
||||||
delay table and restore its default values through sysfs.
|
|
||||||
|
|
||||||
RX copybreak
|
RX copybreak
|
||||||
============
|
============
|
||||||
@@ -274,7 +255,7 @@ RSS
|
|||||||
inputs for hash functions.
|
inputs for hash functions.
|
||||||
- The driver configures RSS settings using the AQ SetFeature command
|
- The driver configures RSS settings using the AQ SetFeature command
|
||||||
(ENA_ADMIN_RSS_HASH_FUNCTION, ENA_ADMIN_RSS_HASH_INPUT and
|
(ENA_ADMIN_RSS_HASH_FUNCTION, ENA_ADMIN_RSS_HASH_INPUT and
|
||||||
ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG properties).
|
ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG properties).
|
||||||
- If the NETIF_F_RXHASH flag is set, the 32-bit result of the hash
|
- If the NETIF_F_RXHASH flag is set, the 32-bit result of the hash
|
||||||
function delivered in the Rx CQ descriptor is set in the received
|
function delivered in the Rx CQ descriptor is set in the received
|
||||||
SKB.
|
SKB.
|
||||||
|
@@ -16,6 +16,34 @@ Note that the file name is a path relative to the firmware loading path
|
|||||||
(usually ``/lib/firmware/``). Drivers may send status updates to inform
|
(usually ``/lib/firmware/``). Drivers may send status updates to inform
|
||||||
user space about the progress of the update operation.
|
user space about the progress of the update operation.
|
||||||
|
|
||||||
|
Overwrite Mask
|
||||||
|
==============
|
||||||
|
|
||||||
|
The ``devlink-flash`` command allows optionally specifying a mask indicating
|
||||||
|
how the device should handle subsections of flash components when updating.
|
||||||
|
This mask indicates the set of sections which are allowed to be overwritten.
|
||||||
|
|
||||||
|
.. list-table:: List of overwrite mask bits
|
||||||
|
:widths: 5 95
|
||||||
|
|
||||||
|
* - Name
|
||||||
|
- Description
|
||||||
|
* - ``DEVLINK_FLASH_OVERWRITE_SETTINGS``
|
||||||
|
- Indicates that the device should overwrite settings in the components
|
||||||
|
being updated with the settings found in the provided image.
|
||||||
|
* - ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS``
|
||||||
|
- Indicates that the device should overwrite identifiers in the
|
||||||
|
components being updated with the identifiers found in the provided
|
||||||
|
image. This includes MAC addresses, serial IDs, and similar device
|
||||||
|
identifiers.
|
||||||
|
|
||||||
|
Multiple overwrite bits may be combined and requested together. If no bits
|
||||||
|
are provided, it is expected that the device only update firmware binaries
|
||||||
|
in the components being updated. Settings and identifiers are expected to be
|
||||||
|
preserved across the update. A device may not support every combination and
|
||||||
|
the driver for such a device must reject any combination which cannot be
|
||||||
|
faithfully implemented.
|
||||||
|
|
||||||
Firmware Loading
|
Firmware Loading
|
||||||
================
|
================
|
||||||
|
|
||||||
|
@@ -108,3 +108,9 @@ own name.
|
|||||||
* - ``region_snapshot_enable``
|
* - ``region_snapshot_enable``
|
||||||
- Boolean
|
- Boolean
|
||||||
- Enable capture of ``devlink-region`` snapshots.
|
- Enable capture of ``devlink-region`` snapshots.
|
||||||
|
* - ``enable_remote_dev_reset``
|
||||||
|
- Boolean
|
||||||
|
- Enable device reset by remote host. When cleared, the device driver
|
||||||
|
will NACK any attempt of other host to reset the device. This parameter
|
||||||
|
is useful for setups where a device is shared by different hosts, such
|
||||||
|
as multi-host setup.
|
||||||
|
81
Documentation/networking/devlink/devlink-reload.rst
Normal file
81
Documentation/networking/devlink/devlink-reload.rst
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
==============
|
||||||
|
Devlink Reload
|
||||||
|
==============
|
||||||
|
|
||||||
|
``devlink-reload`` provides mechanism to reinit driver entities, applying
|
||||||
|
``devlink-params`` and ``devlink-resources`` new values. It also provides
|
||||||
|
mechanism to activate firmware.
|
||||||
|
|
||||||
|
Reload Actions
|
||||||
|
==============
|
||||||
|
|
||||||
|
User may select a reload action.
|
||||||
|
By default ``driver_reinit`` action is selected.
|
||||||
|
|
||||||
|
.. list-table:: Possible reload actions
|
||||||
|
:widths: 5 90
|
||||||
|
|
||||||
|
* - Name
|
||||||
|
- Description
|
||||||
|
* - ``driver-reinit``
|
||||||
|
- Devlink driver entities re-initialization, including applying
|
||||||
|
new values to devlink entities which are used during driver
|
||||||
|
load such as ``devlink-params`` in configuration mode
|
||||||
|
``driverinit`` or ``devlink-resources``
|
||||||
|
* - ``fw_activate``
|
||||||
|
- Firmware activate. Activates new firmware if such image is stored and
|
||||||
|
pending activation. If no limitation specified this action may involve
|
||||||
|
firmware reset. If no new image pending this action will reload current
|
||||||
|
firmware image.
|
||||||
|
|
||||||
|
Note that even though user asks for a specific action, the driver
|
||||||
|
implementation might require to perform another action alongside with
|
||||||
|
it. For example, some driver do not support driver reinitialization
|
||||||
|
being performed without fw activation. Therefore, the devlink reload
|
||||||
|
command returns the list of actions which were actrually performed.
|
||||||
|
|
||||||
|
Reload Limits
|
||||||
|
=============
|
||||||
|
|
||||||
|
By default reload actions are not limited and driver implementation may
|
||||||
|
include reset or downtime as needed to perform the actions.
|
||||||
|
|
||||||
|
However, some drivers support action limits, which limit the action
|
||||||
|
implementation to specific constraints.
|
||||||
|
|
||||||
|
.. list-table:: Possible reload limits
|
||||||
|
:widths: 5 90
|
||||||
|
|
||||||
|
* - Name
|
||||||
|
- Description
|
||||||
|
* - ``no_reset``
|
||||||
|
- No reset allowed, no down time allowed, no link flap and no
|
||||||
|
configuration is lost.
|
||||||
|
|
||||||
|
Change Namespace
|
||||||
|
================
|
||||||
|
|
||||||
|
The netns option allows user to be able to move devlink instances into
|
||||||
|
namespaces during devlink reload operation.
|
||||||
|
By default all devlink instances are created in init_net and stay there.
|
||||||
|
|
||||||
|
example usage
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
$ devlink dev reload help
|
||||||
|
$ devlink dev reload DEV [ netns { PID | NAME | ID } ] [ action { driver_reinit | fw_activate } ] [ limit no_reset ]
|
||||||
|
|
||||||
|
# Run reload command for devlink driver entities re-initialization:
|
||||||
|
$ devlink dev reload pci/0000:82:00.0 action driver_reinit
|
||||||
|
reload_actions_performed:
|
||||||
|
driver_reinit
|
||||||
|
|
||||||
|
# Run reload command to activate firmware:
|
||||||
|
# Note that mlx5 driver reloads the driver while activating firmware
|
||||||
|
$ devlink dev reload pci/0000:82:00.0 action fw_activate
|
||||||
|
reload_actions_performed:
|
||||||
|
driver_reinit fw_activate
|
@@ -409,6 +409,73 @@ be added to the following table:
|
|||||||
- ``drop``
|
- ``drop``
|
||||||
- Traps packets dropped due to the RED (Random Early Detection) algorithm
|
- Traps packets dropped due to the RED (Random Early Detection) algorithm
|
||||||
(i.e., early drops)
|
(i.e., early drops)
|
||||||
|
* - ``vxlan_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the VXLAN header parsing which
|
||||||
|
might be because of packet truncation or the I flag is not set.
|
||||||
|
* - ``llc_snap_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the LLC+SNAP header parsing
|
||||||
|
* - ``vlan_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the VLAN header parsing. Could
|
||||||
|
include unexpected packet truncation.
|
||||||
|
* - ``pppoe_ppp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the PPPoE+PPP header parsing.
|
||||||
|
This could include finding a session ID of 0xFFFF (which is reserved and
|
||||||
|
not for use), a PPPoE length which is larger than the frame received or
|
||||||
|
any common error on this type of header
|
||||||
|
* - ``mpls_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the MPLS header parsing which
|
||||||
|
could include unexpected header truncation
|
||||||
|
* - ``arp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the ARP header parsing
|
||||||
|
* - ``ip_1_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the first IP header parsing.
|
||||||
|
This packet trap could include packets which do not pass an IP checksum
|
||||||
|
check, a header length check (a minimum of 20 bytes), which might suffer
|
||||||
|
from packet truncation thus the total length field exceeds the received
|
||||||
|
packet length etc
|
||||||
|
* - ``ip_n_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the parsing of the last IP
|
||||||
|
header (the inner one in case of an IP over IP tunnel). The same common
|
||||||
|
error checking is performed here as for the ip_1_parsing trap
|
||||||
|
* - ``gre_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the GRE header parsing
|
||||||
|
* - ``udp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the UDP header parsing.
|
||||||
|
This packet trap could include checksum errorrs, an improper UDP
|
||||||
|
length detected (smaller than 8 bytes) or detection of header
|
||||||
|
truncation.
|
||||||
|
* - ``tcp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the TCP header parsing.
|
||||||
|
This could include TCP checksum errors, improper combination of SYN, FIN
|
||||||
|
and/or RESET etc.
|
||||||
|
* - ``ipsec_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the IPSEC header parsing
|
||||||
|
* - ``sctp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the SCTP header parsing.
|
||||||
|
This would mean that port number 0 was used or that the header is
|
||||||
|
truncated.
|
||||||
|
* - ``dccp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the DCCP header parsing
|
||||||
|
* - ``gtp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the GTP header parsing
|
||||||
|
* - ``esp_parsing``
|
||||||
|
- ``drop``
|
||||||
|
- Traps packets dropped due to an error in the ESP header parsing
|
||||||
|
|
||||||
Driver-specific Packet Traps
|
Driver-specific Packet Traps
|
||||||
============================
|
============================
|
||||||
@@ -509,6 +576,9 @@ narrow. The description of these groups must be added to the following table:
|
|||||||
* - ``acl_trap``
|
* - ``acl_trap``
|
||||||
- Contains packet traps for packets that were trapped (logged) by the
|
- Contains packet traps for packets that were trapped (logged) by the
|
||||||
device during ACL processing
|
device during ACL processing
|
||||||
|
* - ``parser_error_drops``
|
||||||
|
- Contains packet traps for packets that were marked by the device during
|
||||||
|
parsing as erroneous
|
||||||
|
|
||||||
Packet Trap Policers
|
Packet Trap Policers
|
||||||
====================
|
====================
|
||||||
|
@@ -69,6 +69,11 @@ The ``ice`` driver reports the following versions
|
|||||||
- The version of the DDP package that is active in the device. Note
|
- The version of the DDP package that is active in the device. Note
|
||||||
that both the name (as reported by ``fw.app.name``) and version are
|
that both the name (as reported by ``fw.app.name``) and version are
|
||||||
required to uniquely identify the package.
|
required to uniquely identify the package.
|
||||||
|
* - ``fw.app.bundle_id``
|
||||||
|
- 0xc0000001
|
||||||
|
- Unique identifier for the DDP package loaded in the device. Also
|
||||||
|
referred to as the DDP Track ID. Can be used to uniquely identify
|
||||||
|
the specific DDP package.
|
||||||
* - ``fw.netlist``
|
* - ``fw.netlist``
|
||||||
- running
|
- running
|
||||||
- 1.1.2000-6.7.0
|
- 1.1.2000-6.7.0
|
||||||
@@ -81,6 +86,37 @@ The ``ice`` driver reports the following versions
|
|||||||
- 0xee16ced7
|
- 0xee16ced7
|
||||||
- The first 4 bytes of the hash of the netlist module contents.
|
- The first 4 bytes of the hash of the netlist module contents.
|
||||||
|
|
||||||
|
Flash Update
|
||||||
|
============
|
||||||
|
|
||||||
|
The ``ice`` driver implements support for flash update using the
|
||||||
|
``devlink-flash`` interface. It supports updating the device flash using a
|
||||||
|
combined flash image that contains the ``fw.mgmt``, ``fw.undi``, and
|
||||||
|
``fw.netlist`` components.
|
||||||
|
|
||||||
|
.. list-table:: List of supported overwrite modes
|
||||||
|
:widths: 5 95
|
||||||
|
|
||||||
|
* - Bits
|
||||||
|
- Behavior
|
||||||
|
* - ``DEVLINK_FLASH_OVERWRITE_SETTINGS``
|
||||||
|
- Do not preserve settings stored in the flash components being
|
||||||
|
updated. This includes overwriting the port configuration that
|
||||||
|
determines the number of physical functions the device will
|
||||||
|
initialize with.
|
||||||
|
* - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` and ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS``
|
||||||
|
- Do not preserve either settings or identifiers. Overwrite everything
|
||||||
|
in the flash with the contents from the provided image, without
|
||||||
|
performing any preservation. This includes overwriting device
|
||||||
|
identifying fields such as the MAC address, VPD area, and device
|
||||||
|
serial number. It is expected that this combination be used with an
|
||||||
|
image customized for the specific device.
|
||||||
|
|
||||||
|
The ice hardware does not support overwriting only identifiers while
|
||||||
|
preserving settings, and thus ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` on its
|
||||||
|
own will be rejected. If no overwrite mask is provided, the firmware will be
|
||||||
|
instructed to preserve all settings and identifying fields when updating.
|
||||||
|
|
||||||
Regions
|
Regions
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@ general.
|
|||||||
devlink-params
|
devlink-params
|
||||||
devlink-region
|
devlink-region
|
||||||
devlink-resource
|
devlink-resource
|
||||||
|
devlink-reload
|
||||||
devlink-trap
|
devlink-trap
|
||||||
|
|
||||||
Driver-specific documentation
|
Driver-specific documentation
|
||||||
|
@@ -68,6 +68,7 @@ the flags may not apply to requests. Recognized flags are:
|
|||||||
================================= ===================================
|
================================= ===================================
|
||||||
``ETHTOOL_FLAG_COMPACT_BITSETS`` use compact format bitsets in reply
|
``ETHTOOL_FLAG_COMPACT_BITSETS`` use compact format bitsets in reply
|
||||||
``ETHTOOL_FLAG_OMIT_REPLY`` omit optional reply (_SET and _ACT)
|
``ETHTOOL_FLAG_OMIT_REPLY`` omit optional reply (_SET and _ACT)
|
||||||
|
``ETHTOOL_FLAG_STATS`` include optional device statistics
|
||||||
================================= ===================================
|
================================= ===================================
|
||||||
|
|
||||||
New request flags should follow the general idea that if the flag is not set,
|
New request flags should follow the general idea that if the flag is not set,
|
||||||
@@ -991,8 +992,18 @@ Kernel response contents:
|
|||||||
``ETHTOOL_A_PAUSE_AUTONEG`` bool pause autonegotiation
|
``ETHTOOL_A_PAUSE_AUTONEG`` bool pause autonegotiation
|
||||||
``ETHTOOL_A_PAUSE_RX`` bool receive pause frames
|
``ETHTOOL_A_PAUSE_RX`` bool receive pause frames
|
||||||
``ETHTOOL_A_PAUSE_TX`` bool transmit pause frames
|
``ETHTOOL_A_PAUSE_TX`` bool transmit pause frames
|
||||||
|
``ETHTOOL_A_PAUSE_STATS`` nested pause statistics
|
||||||
===================================== ====== ==========================
|
===================================== ====== ==========================
|
||||||
|
|
||||||
|
``ETHTOOL_A_PAUSE_STATS`` are reported if ``ETHTOOL_FLAG_STATS`` was set
|
||||||
|
in ``ETHTOOL_A_HEADER_FLAGS``.
|
||||||
|
It will be empty if driver did not report any statistics. Drivers fill in
|
||||||
|
the statistics in the following structure:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/ethtool.h
|
||||||
|
:identifiers: ethtool_pause_stats
|
||||||
|
|
||||||
|
Each member has a corresponding attribute defined.
|
||||||
|
|
||||||
PAUSE_SET
|
PAUSE_SET
|
||||||
============
|
============
|
||||||
|
@@ -93,6 +93,7 @@ Contents:
|
|||||||
sctp
|
sctp
|
||||||
secid
|
secid
|
||||||
seg6-sysctl
|
seg6-sysctl
|
||||||
|
statistics
|
||||||
strparser
|
strparser
|
||||||
switchdev
|
switchdev
|
||||||
sysfs-tagging
|
sysfs-tagging
|
||||||
|
@@ -134,6 +134,15 @@ PHY Support
|
|||||||
.. kernel-doc:: drivers/net/phy/phy.c
|
.. kernel-doc:: drivers/net/phy/phy.c
|
||||||
:internal:
|
:internal:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/net/phy/phy-core.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/net/phy/phy-c45.c
|
||||||
|
:export:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/phy.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
.. kernel-doc:: drivers/net/phy/phy_device.c
|
.. kernel-doc:: drivers/net/phy/phy_device.c
|
||||||
:export:
|
:export:
|
||||||
|
|
||||||
|
@@ -4,124 +4,364 @@
|
|||||||
L2TP
|
L2TP
|
||||||
====
|
====
|
||||||
|
|
||||||
This document describes how to use the kernel's L2TP drivers to
|
Layer 2 Tunneling Protocol (L2TP) allows L2 frames to be tunneled over
|
||||||
provide L2TP functionality. L2TP is a protocol that tunnels one or
|
an IP network.
|
||||||
more sessions over an IP tunnel. It is commonly used for VPNs
|
|
||||||
(L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP
|
|
||||||
network infrastructure. With L2TPv3, it is also useful as a Layer-2
|
|
||||||
tunneling infrastructure.
|
|
||||||
|
|
||||||
Features
|
This document covers the kernel's L2TP subsystem. It documents kernel
|
||||||
|
APIs for application developers who want to use the L2TP subsystem and
|
||||||
|
it provides some technical details about the internal implementation
|
||||||
|
which may be useful to kernel developers and maintainers.
|
||||||
|
|
||||||
|
Overview
|
||||||
========
|
========
|
||||||
|
|
||||||
L2TPv2 (PPP over L2TP (UDP tunnels)).
|
The kernel's L2TP subsystem implements the datapath for L2TPv2 and
|
||||||
L2TPv3 ethernet pseudowires.
|
L2TPv3. L2TPv2 is carried over UDP. L2TPv3 is carried over UDP or
|
||||||
L2TPv3 PPP pseudowires.
|
directly over IP (protocol 115).
|
||||||
L2TPv3 IP encapsulation.
|
|
||||||
Netlink sockets for L2TPv3 configuration management.
|
|
||||||
|
|
||||||
History
|
The L2TP RFCs define two basic kinds of L2TP packets: control packets
|
||||||
=======
|
(the "control plane"), and data packets (the "data plane"). The kernel
|
||||||
|
deals only with data packets. The more complex control packets are
|
||||||
|
handled by user space.
|
||||||
|
|
||||||
The original pppol2tp driver was introduced in 2.6.23 and provided
|
An L2TP tunnel carries one or more L2TP sessions. Each tunnel is
|
||||||
L2TPv2 functionality (rfc2661). L2TPv2 is used to tunnel one or more PPP
|
associated with a socket. Each session is associated with a virtual
|
||||||
sessions over a UDP tunnel.
|
netdevice, e.g. ``pppN``, ``l2tpethN``, through which data frames pass
|
||||||
|
to/from L2TP. Fields in the L2TP header identify the tunnel or session
|
||||||
|
and whether it is a control or data packet. When tunnels and sessions
|
||||||
|
are set up using the Linux kernel API, we're just setting up the L2TP
|
||||||
|
data path. All aspects of the control protocol are to be handled by
|
||||||
|
user space.
|
||||||
|
|
||||||
L2TPv3 (rfc3931) changes the protocol to allow different frame types
|
This split in responsibilities leads to a natural sequence of
|
||||||
to be passed over an L2TP tunnel by moving the PPP-specific parts of
|
operations when establishing tunnels and sessions. The procedure looks
|
||||||
the protocol out of the core L2TP packet headers. Each frame type is
|
like this:
|
||||||
known as a pseudowire type. Ethernet, PPP, HDLC, Frame Relay and ATM
|
|
||||||
pseudowires for L2TP are defined in separate RFC standards. Another
|
|
||||||
change for L2TPv3 is that it can be carried directly over IP with no
|
|
||||||
UDP header (UDP is optional). It is also possible to create static
|
|
||||||
unmanaged L2TPv3 tunnels manually without a control protocol
|
|
||||||
(userspace daemon) to manage them.
|
|
||||||
|
|
||||||
To support L2TPv3, the original pppol2tp driver was split up to
|
1) Create a tunnel socket. Exchange L2TP control protocol messages
|
||||||
separate the L2TP and PPP functionality. Existing L2TPv2 userspace
|
with the peer over that socket in order to establish a tunnel.
|
||||||
apps should be unaffected as the original pppol2tp sockets API is
|
|
||||||
retained. L2TPv3, however, uses netlink to manage L2TPv3 tunnels and
|
|
||||||
sessions.
|
|
||||||
|
|
||||||
Design
|
2) Create a tunnel context in the kernel, using information
|
||||||
======
|
obtained from the peer using the control protocol messages.
|
||||||
|
|
||||||
The L2TP protocol separates control and data frames. The L2TP kernel
|
3) Exchange L2TP control protocol messages with the peer over the
|
||||||
drivers handle only L2TP data frames; control frames are always
|
tunnel socket in order to establish a session.
|
||||||
handled by userspace. L2TP control frames carry messages between L2TP
|
|
||||||
clients/servers and are used to setup / teardown tunnels and
|
|
||||||
sessions. An L2TP client or server is implemented in userspace.
|
|
||||||
|
|
||||||
Each L2TP tunnel is implemented using a UDP or L2TPIP socket; L2TPIP
|
4) Create a session context in the kernel using information
|
||||||
provides L2TPv3 IP encapsulation (no UDP) and is implemented using a
|
obtained from the peer using the control protocol messages.
|
||||||
new l2tpip socket family. The tunnel socket is typically created by
|
|
||||||
userspace, though for unmanaged L2TPv3 tunnels, the socket can also be
|
|
||||||
created by the kernel. Each L2TP session (pseudowire) gets a network
|
|
||||||
interface instance. In the case of PPP, these interfaces are created
|
|
||||||
indirectly by pppd using a pppol2tp socket. In the case of ethernet,
|
|
||||||
the netdevice is created upon a netlink request to create an L2TPv3
|
|
||||||
ethernet pseudowire.
|
|
||||||
|
|
||||||
For PPP, the PPPoL2TP driver, net/l2tp/l2tp_ppp.c, provides a
|
L2TP APIs
|
||||||
mechanism by which PPP frames carried through an L2TP session are
|
=========
|
||||||
passed through the kernel's PPP subsystem. The standard PPP daemon,
|
|
||||||
pppd, handles all PPP interaction with the peer. PPP network
|
|
||||||
interfaces are created for each local PPP endpoint. The kernel's PPP
|
|
||||||
subsystem arranges for PPP control frames to be delivered to pppd,
|
|
||||||
while data frames are forwarded as usual.
|
|
||||||
|
|
||||||
For ethernet, the L2TPETH driver, net/l2tp/l2tp_eth.c, implements a
|
This section documents each userspace API of the L2TP subsystem.
|
||||||
netdevice driver, managing virtual ethernet devices, one per
|
|
||||||
pseudowire. These interfaces can be managed using standard Linux tools
|
|
||||||
such as "ip" and "ifconfig". If only IP frames are passed over the
|
|
||||||
tunnel, the interface can be given an IP addresses of itself and its
|
|
||||||
peer. If non-IP frames are to be passed over the tunnel, the interface
|
|
||||||
can be added to a bridge using brctl. All L2TP datapath protocol
|
|
||||||
functions are handled by the L2TP core driver.
|
|
||||||
|
|
||||||
Each tunnel and session within a tunnel is assigned a unique tunnel_id
|
Tunnel Sockets
|
||||||
and session_id. These ids are carried in the L2TP header of every
|
--------------
|
||||||
control and data packet. (Actually, in L2TPv3, the tunnel_id isn't
|
|
||||||
present in data frames - it is inferred from the IP connection on
|
|
||||||
which the packet was received.) The L2TP driver uses the ids to lookup
|
|
||||||
internal tunnel and/or session contexts to determine how to handle the
|
|
||||||
packet. Zero tunnel / session ids are treated specially - zero ids are
|
|
||||||
never assigned to tunnels or sessions in the network. In the driver,
|
|
||||||
the tunnel context keeps a reference to the tunnel UDP or L2TPIP
|
|
||||||
socket. The session context holds data that lets the driver interface
|
|
||||||
to the kernel's network frame type subsystems, i.e. PPP, ethernet.
|
|
||||||
|
|
||||||
Userspace Programming
|
L2TPv2 always uses UDP. L2TPv3 may use UDP or IP encapsulation.
|
||||||
=====================
|
|
||||||
|
|
||||||
For L2TPv2, there are a number of requirements on the userspace L2TP
|
To create a tunnel socket for use by L2TP, the standard POSIX
|
||||||
daemon in order to use the pppol2tp driver.
|
socket API is used.
|
||||||
|
|
||||||
1. Use a UDP socket per tunnel.
|
For example, for a tunnel using IPv4 addresses and UDP encapsulation::
|
||||||
|
|
||||||
2. Create a single PPPoL2TP socket per tunnel bound to a special null
|
int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
session id. This is used only for communicating with the driver but
|
|
||||||
must remain open while the tunnel is active. Opening this tunnel
|
|
||||||
management socket causes the driver to mark the tunnel socket as an
|
|
||||||
L2TP UDP encapsulation socket and flags it for use by the
|
|
||||||
referenced tunnel id. This hooks up the UDP receive path via
|
|
||||||
udp_encap_rcv() in net/ipv4/udp.c. PPP data frames are never passed
|
|
||||||
in this special PPPoX socket.
|
|
||||||
|
|
||||||
3. Create a PPPoL2TP socket per L2TP session. This is typically done
|
Or for a tunnel using IPv6 addresses and IP encapsulation::
|
||||||
by starting pppd with the pppol2tp plugin and appropriate
|
|
||||||
arguments. A PPPoL2TP tunnel management socket (Step 2) must be
|
int sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_L2TP);
|
||||||
created before the first PPPoL2TP session socket is created.
|
|
||||||
|
UDP socket programming doesn't need to be covered here.
|
||||||
|
|
||||||
|
IPPROTO_L2TP is an IP protocol type implemented by the kernel's L2TP
|
||||||
|
subsystem. The L2TPIP socket address is defined in struct
|
||||||
|
sockaddr_l2tpip and struct sockaddr_l2tpip6 at
|
||||||
|
`include/uapi/linux/l2tp.h`_. The address includes the L2TP tunnel
|
||||||
|
(connection) id. To use L2TP IP encapsulation, an L2TPv3 application
|
||||||
|
should bind the L2TPIP socket using the locally assigned
|
||||||
|
tunnel id. When the peer's tunnel id and IP address is known, a
|
||||||
|
connect must be done.
|
||||||
|
|
||||||
|
If the L2TP application needs to handle L2TPv3 tunnel setup requests
|
||||||
|
from peers using L2TPIP, it must open a dedicated L2TPIP
|
||||||
|
socket to listen for those requests and bind the socket using tunnel
|
||||||
|
id 0 since tunnel setup requests are addressed to tunnel id 0.
|
||||||
|
|
||||||
|
An L2TP tunnel and all of its sessions are automatically closed when
|
||||||
|
its tunnel socket is closed.
|
||||||
|
|
||||||
|
Netlink API
|
||||||
|
-----------
|
||||||
|
|
||||||
|
L2TP applications use netlink to manage L2TP tunnel and session
|
||||||
|
instances in the kernel. The L2TP netlink API is defined in
|
||||||
|
`include/uapi/linux/l2tp.h`_.
|
||||||
|
|
||||||
|
L2TP uses `Generic Netlink`_ (GENL). Several commands are defined:
|
||||||
|
Create, Delete, Modify and Get for tunnel and session
|
||||||
|
instances, e.g. ``L2TP_CMD_TUNNEL_CREATE``. The API header lists the
|
||||||
|
netlink attribute types that can be used with each command.
|
||||||
|
|
||||||
|
Tunnel and session instances are identified by a locally unique
|
||||||
|
32-bit id. L2TP tunnel ids are given by ``L2TP_ATTR_CONN_ID`` and
|
||||||
|
``L2TP_ATTR_PEER_CONN_ID`` attributes and L2TP session ids are given
|
||||||
|
by ``L2TP_ATTR_SESSION_ID`` and ``L2TP_ATTR_PEER_SESSION_ID``
|
||||||
|
attributes. If netlink is used to manage L2TPv2 tunnel and session
|
||||||
|
instances, the L2TPv2 16-bit tunnel/session id is cast to a 32-bit
|
||||||
|
value in these attributes.
|
||||||
|
|
||||||
|
In the ``L2TP_CMD_TUNNEL_CREATE`` command, ``L2TP_ATTR_FD`` tells the
|
||||||
|
kernel the tunnel socket fd being used. If not specified, the kernel
|
||||||
|
creates a kernel socket for the tunnel, using IP parameters set in
|
||||||
|
``L2TP_ATTR_IP[6]_SADDR``, ``L2TP_ATTR_IP[6]_DADDR``,
|
||||||
|
``L2TP_ATTR_UDP_SPORT``, ``L2TP_ATTR_UDP_DPORT`` attributes. Kernel
|
||||||
|
sockets are used to implement unmanaged L2TPv3 tunnels (iproute2's "ip
|
||||||
|
l2tp" commands). If ``L2TP_ATTR_FD`` is given, it must be a socket fd
|
||||||
|
that is already bound and connected. There is more information about
|
||||||
|
unmanaged tunnels later in this document.
|
||||||
|
|
||||||
|
``L2TP_CMD_TUNNEL_CREATE`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID Y Sets the tunnel (connection) id.
|
||||||
|
PEER_CONN_ID Y Sets the peer tunnel (connection) id.
|
||||||
|
PROTO_VERSION Y Protocol version. 2 or 3.
|
||||||
|
ENCAP_TYPE Y Encapsulation type: UDP or IP.
|
||||||
|
FD N Tunnel socket file descriptor.
|
||||||
|
UDP_CSUM N Enable IPv4 UDP checksums. Used only if FD is
|
||||||
|
not set.
|
||||||
|
UDP_ZERO_CSUM6_TX N Zero IPv6 UDP checksum on transmit. Used only
|
||||||
|
if FD is not set.
|
||||||
|
UDP_ZERO_CSUM6_RX N Zero IPv6 UDP checksum on receive. Used only if
|
||||||
|
FD is not set.
|
||||||
|
IP_SADDR N IPv4 source address. Used only if FD is not
|
||||||
|
set.
|
||||||
|
IP_DADDR N IPv4 destination address. Used only if FD is
|
||||||
|
not set.
|
||||||
|
UDP_SPORT N UDP source port. Used only if FD is not set.
|
||||||
|
UDP_DPORT N UDP destination port. Used only if FD is not
|
||||||
|
set.
|
||||||
|
IP6_SADDR N IPv6 source address. Used only if FD is not
|
||||||
|
set.
|
||||||
|
IP6_DADDR N IPv6 destination address. Used only if FD is
|
||||||
|
not set.
|
||||||
|
DEBUG N Debug flags.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
``L2TP_CMD_TUNNEL_DESTROY`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID Y Identifies the tunnel id to be destroyed.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
``L2TP_CMD_TUNNEL_MODIFY`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID Y Identifies the tunnel id to be modified.
|
||||||
|
DEBUG N Debug flags.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
``L2TP_CMD_TUNNEL_GET`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID N Identifies the tunnel id to be queried.
|
||||||
|
Ignored in DUMP requests.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
``L2TP_CMD_SESSION_CREATE`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID Y The parent tunnel id.
|
||||||
|
SESSION_ID Y Sets the session id.
|
||||||
|
PEER_SESSION_ID Y Sets the parent session id.
|
||||||
|
PW_TYPE Y Sets the pseudowire type.
|
||||||
|
DEBUG N Debug flags.
|
||||||
|
RECV_SEQ N Enable rx data sequence numbers.
|
||||||
|
SEND_SEQ N Enable tx data sequence numbers.
|
||||||
|
LNS_MODE N Enable LNS mode (auto-enable data sequence
|
||||||
|
numbers).
|
||||||
|
RECV_TIMEOUT N Timeout to wait when reordering received
|
||||||
|
packets.
|
||||||
|
L2SPEC_TYPE N Sets layer2-specific-sublayer type (L2TPv3
|
||||||
|
only).
|
||||||
|
COOKIE N Sets optional cookie (L2TPv3 only).
|
||||||
|
PEER_COOKIE N Sets optional peer cookie (L2TPv3 only).
|
||||||
|
IFNAME N Sets interface name (L2TPv3 only).
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
For Ethernet session types, this will create an l2tpeth virtual
|
||||||
|
interface which can then be configured as required. For PPP session
|
||||||
|
types, a PPPoL2TP socket must also be opened and connected, mapping it
|
||||||
|
onto the new session. This is covered in "PPPoL2TP Sockets" later.
|
||||||
|
|
||||||
|
``L2TP_CMD_SESSION_DESTROY`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID Y Identifies the parent tunnel id of the session
|
||||||
|
to be destroyed.
|
||||||
|
SESSION_ID Y Identifies the session id to be destroyed.
|
||||||
|
IFNAME N Identifies the session by interface name. If
|
||||||
|
set, this overrides any CONN_ID and SESSION_ID
|
||||||
|
attributes. Currently supported for L2TPv3
|
||||||
|
Ethernet sessions only.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
``L2TP_CMD_SESSION_MODIFY`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID Y Identifies the parent tunnel id of the session
|
||||||
|
to be modified.
|
||||||
|
SESSION_ID Y Identifies the session id to be modified.
|
||||||
|
IFNAME N Identifies the session by interface name. If
|
||||||
|
set, this overrides any CONN_ID and SESSION_ID
|
||||||
|
attributes. Currently supported for L2TPv3
|
||||||
|
Ethernet sessions only.
|
||||||
|
DEBUG N Debug flags.
|
||||||
|
RECV_SEQ N Enable rx data sequence numbers.
|
||||||
|
SEND_SEQ N Enable tx data sequence numbers.
|
||||||
|
LNS_MODE N Enable LNS mode (auto-enable data sequence
|
||||||
|
numbers).
|
||||||
|
RECV_TIMEOUT N Timeout to wait when reordering received
|
||||||
|
packets.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
``L2TP_CMD_SESSION_GET`` attributes:-
|
||||||
|
|
||||||
|
================== ======== ===
|
||||||
|
Attribute Required Use
|
||||||
|
================== ======== ===
|
||||||
|
CONN_ID N Identifies the tunnel id to be queried.
|
||||||
|
Ignored for DUMP requests.
|
||||||
|
SESSION_ID N Identifies the session id to be queried.
|
||||||
|
Ignored for DUMP requests.
|
||||||
|
IFNAME N Identifies the session by interface name.
|
||||||
|
If set, this overrides any CONN_ID and
|
||||||
|
SESSION_ID attributes. Ignored for DUMP
|
||||||
|
requests. Currently supported for L2TPv3
|
||||||
|
Ethernet sessions only.
|
||||||
|
================== ======== ===
|
||||||
|
|
||||||
|
Application developers should refer to `include/uapi/linux/l2tp.h`_ for
|
||||||
|
netlink command and attribute definitions.
|
||||||
|
|
||||||
|
Sample userspace code using libmnl_:
|
||||||
|
|
||||||
|
- Open L2TP netlink socket::
|
||||||
|
|
||||||
|
struct nl_sock *nl_sock;
|
||||||
|
int l2tp_nl_family_id;
|
||||||
|
|
||||||
|
nl_sock = nl_socket_alloc();
|
||||||
|
genl_connect(nl_sock);
|
||||||
|
genl_id = genl_ctrl_resolve(nl_sock, L2TP_GENL_NAME);
|
||||||
|
|
||||||
|
- Create a tunnel::
|
||||||
|
|
||||||
|
struct nlmsghdr *nlh;
|
||||||
|
struct genlmsghdr *gnlh;
|
||||||
|
|
||||||
|
nlh = mnl_nlmsg_put_header(buf);
|
||||||
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
||||||
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||||
|
nlh->nlmsg_seq = seq;
|
||||||
|
|
||||||
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
||||||
|
gnlh->cmd = L2TP_CMD_TUNNEL_CREATE;
|
||||||
|
gnlh->version = L2TP_GENL_VERSION;
|
||||||
|
gnlh->reserved = 0;
|
||||||
|
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_FD, tunl_sock_fd);
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_CONN_ID, peer_tid);
|
||||||
|
mnl_attr_put_u8(nlh, L2TP_ATTR_PROTO_VERSION, protocol_version);
|
||||||
|
mnl_attr_put_u16(nlh, L2TP_ATTR_ENCAP_TYPE, encap);
|
||||||
|
|
||||||
|
- Create a session::
|
||||||
|
|
||||||
|
struct nlmsghdr *nlh;
|
||||||
|
struct genlmsghdr *gnlh;
|
||||||
|
|
||||||
|
nlh = mnl_nlmsg_put_header(buf);
|
||||||
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
||||||
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||||
|
nlh->nlmsg_seq = seq;
|
||||||
|
|
||||||
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
||||||
|
gnlh->cmd = L2TP_CMD_SESSION_CREATE;
|
||||||
|
gnlh->version = L2TP_GENL_VERSION;
|
||||||
|
gnlh->reserved = 0;
|
||||||
|
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_CONN_ID, peer_tid);
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_SESSION_ID, sid);
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_PEER_SESSION_ID, peer_sid);
|
||||||
|
mnl_attr_put_u16(nlh, L2TP_ATTR_PW_TYPE, pwtype);
|
||||||
|
/* there are other session options which can be set using netlink
|
||||||
|
* attributes during session creation -- see l2tp.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
- Delete a session::
|
||||||
|
|
||||||
|
struct nlmsghdr *nlh;
|
||||||
|
struct genlmsghdr *gnlh;
|
||||||
|
|
||||||
|
nlh = mnl_nlmsg_put_header(buf);
|
||||||
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
||||||
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||||
|
nlh->nlmsg_seq = seq;
|
||||||
|
|
||||||
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
||||||
|
gnlh->cmd = L2TP_CMD_SESSION_DELETE;
|
||||||
|
gnlh->version = L2TP_GENL_VERSION;
|
||||||
|
gnlh->reserved = 0;
|
||||||
|
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_SESSION_ID, sid);
|
||||||
|
|
||||||
|
- Delete a tunnel and all of its sessions (if any)::
|
||||||
|
|
||||||
|
struct nlmsghdr *nlh;
|
||||||
|
struct genlmsghdr *gnlh;
|
||||||
|
|
||||||
|
nlh = mnl_nlmsg_put_header(buf);
|
||||||
|
nlh->nlmsg_type = genl_id; /* assigned to genl socket */
|
||||||
|
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||||
|
nlh->nlmsg_seq = seq;
|
||||||
|
|
||||||
|
gnlh = mnl_nlmsg_put_extra_header(nlh, sizeof(*gnlh));
|
||||||
|
gnlh->cmd = L2TP_CMD_TUNNEL_DELETE;
|
||||||
|
gnlh->version = L2TP_GENL_VERSION;
|
||||||
|
gnlh->reserved = 0;
|
||||||
|
|
||||||
|
mnl_attr_put_u32(nlh, L2TP_ATTR_CONN_ID, tid);
|
||||||
|
|
||||||
|
PPPoL2TP Session Socket API
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
For PPP session types, a PPPoL2TP socket must be opened and connected
|
||||||
|
to the L2TP session.
|
||||||
|
|
||||||
When creating PPPoL2TP sockets, the application provides information
|
When creating PPPoL2TP sockets, the application provides information
|
||||||
to the driver about the socket in a socket connect() call. Source and
|
to the kernel about the tunnel and session in a socket connect()
|
||||||
destination tunnel and session ids are provided, as well as the file
|
call. Source and destination tunnel and session ids are provided, as
|
||||||
descriptor of a UDP socket. See struct pppol2tp_addr in
|
well as the file descriptor of a UDP or L2TPIP socket. See struct
|
||||||
include/linux/if_pppol2tp.h. Note that zero tunnel / session ids are
|
pppol2tp_addr in `include/linux/if_pppol2tp.h`_. For historical reasons,
|
||||||
treated specially. When creating the per-tunnel PPPoL2TP management
|
there are unfortunately slightly different address structures for
|
||||||
socket in Step 2 above, zero source and destination session ids are
|
L2TPv2/L2TPv3 IPv4/IPv6 tunnels and userspace must use the appropriate
|
||||||
specified, which tells the driver to prepare the supplied UDP file
|
structure that matches the tunnel socket type.
|
||||||
descriptor for use as an L2TP tunnel socket.
|
|
||||||
|
|
||||||
Userspace may control behavior of the tunnel or session using
|
Userspace may control behavior of the tunnel or session using
|
||||||
setsockopt and ioctl on the PPPoX socket. The following socket
|
setsockopt and ioctl on the PPPoX socket. The following socket
|
||||||
@@ -138,159 +378,20 @@ LNSMODE - 0 => act as LAC.
|
|||||||
REORDERTO reorder timeout (in millisecs). If 0, don't try to reorder.
|
REORDERTO reorder timeout (in millisecs). If 0, don't try to reorder.
|
||||||
========= ===========================================================
|
========= ===========================================================
|
||||||
|
|
||||||
Only the DEBUG option is supported by the special tunnel management
|
|
||||||
PPPoX socket.
|
|
||||||
|
|
||||||
In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided
|
In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided
|
||||||
to retrieve tunnel and session statistics from the kernel using the
|
to retrieve tunnel and session statistics from the kernel using the
|
||||||
PPPoX socket of the appropriate tunnel or session.
|
PPPoX socket of the appropriate tunnel or session.
|
||||||
|
|
||||||
For L2TPv3, userspace must use the netlink API defined in
|
Sample userspace code:
|
||||||
include/linux/l2tp.h to manage tunnel and session contexts. The
|
|
||||||
general procedure to create a new L2TP tunnel with one session is:-
|
|
||||||
|
|
||||||
1. Open a GENL socket using L2TP_GENL_NAME for configuring the kernel
|
- Create session PPPoX data socket::
|
||||||
using netlink.
|
|
||||||
|
|
||||||
2. Create a UDP or L2TPIP socket for the tunnel.
|
|
||||||
|
|
||||||
3. Create a new L2TP tunnel using a L2TP_CMD_TUNNEL_CREATE
|
|
||||||
request. Set attributes according to desired tunnel parameters,
|
|
||||||
referencing the UDP or L2TPIP socket created in the previous step.
|
|
||||||
|
|
||||||
4. Create a new L2TP session in the tunnel using a
|
|
||||||
L2TP_CMD_SESSION_CREATE request.
|
|
||||||
|
|
||||||
The tunnel and all of its sessions are closed when the tunnel socket
|
|
||||||
is closed. The netlink API may also be used to delete sessions and
|
|
||||||
tunnels. Configuration and status info may be set or read using netlink.
|
|
||||||
|
|
||||||
The L2TP driver also supports static (unmanaged) L2TPv3 tunnels. These
|
|
||||||
are where there is no L2TP control message exchange with the peer to
|
|
||||||
setup the tunnel; the tunnel is configured manually at each end of the
|
|
||||||
tunnel. There is no need for an L2TP userspace application in this
|
|
||||||
case -- the tunnel socket is created by the kernel and configured
|
|
||||||
using parameters sent in the L2TP_CMD_TUNNEL_CREATE netlink
|
|
||||||
request. The "ip" utility of iproute2 has commands for managing static
|
|
||||||
L2TPv3 tunnels; do "ip l2tp help" for more information.
|
|
||||||
|
|
||||||
Debugging
|
|
||||||
=========
|
|
||||||
|
|
||||||
The driver supports a flexible debug scheme where kernel trace
|
|
||||||
messages may be optionally enabled per tunnel and per session. Care is
|
|
||||||
needed when debugging a live system since the messages are not
|
|
||||||
rate-limited and a busy system could be swamped. Userspace uses
|
|
||||||
setsockopt on the PPPoX socket to set a debug mask.
|
|
||||||
|
|
||||||
The following debug mask bits are available:
|
|
||||||
|
|
||||||
================ ==============================
|
|
||||||
L2TP_MSG_DEBUG verbose debug (if compiled in)
|
|
||||||
L2TP_MSG_CONTROL userspace - kernel interface
|
|
||||||
L2TP_MSG_SEQ sequence numbers handling
|
|
||||||
L2TP_MSG_DATA data packets
|
|
||||||
================ ==============================
|
|
||||||
|
|
||||||
If enabled, files under a l2tp debugfs directory can be used to dump
|
|
||||||
kernel state about L2TP tunnels and sessions. To access it, the
|
|
||||||
debugfs filesystem must first be mounted::
|
|
||||||
|
|
||||||
# mount -t debugfs debugfs /debug
|
|
||||||
|
|
||||||
Files under the l2tp directory can then be accessed::
|
|
||||||
|
|
||||||
# cat /debug/l2tp/tunnels
|
|
||||||
|
|
||||||
The debugfs files should not be used by applications to obtain L2TP
|
|
||||||
state information because the file format is subject to change. It is
|
|
||||||
implemented to provide extra debug information to help diagnose
|
|
||||||
problems.) Users should use the netlink API.
|
|
||||||
|
|
||||||
/proc/net/pppol2tp is also provided for backwards compatibility with
|
|
||||||
the original pppol2tp driver. It lists information about L2TPv2
|
|
||||||
tunnels and sessions only. Its use is discouraged.
|
|
||||||
|
|
||||||
Unmanaged L2TPv3 Tunnels
|
|
||||||
========================
|
|
||||||
|
|
||||||
Some commercial L2TP products support unmanaged L2TPv3 ethernet
|
|
||||||
tunnels, where there is no L2TP control protocol; tunnels are
|
|
||||||
configured at each side manually. New commands are available in
|
|
||||||
iproute2's ip utility to support this.
|
|
||||||
|
|
||||||
To create an L2TPv3 ethernet pseudowire between local host 192.168.1.1
|
|
||||||
and peer 192.168.1.2, using IP addresses 10.5.1.1 and 10.5.1.2 for the
|
|
||||||
tunnel endpoints::
|
|
||||||
|
|
||||||
# ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 udp_sport 5000 \
|
|
||||||
udp_dport 5000 encap udp local 192.168.1.1 remote 192.168.1.2
|
|
||||||
# ip l2tp add session tunnel_id 1 session_id 1 peer_session_id 1
|
|
||||||
# ip -s -d show dev l2tpeth0
|
|
||||||
# ip addr add 10.5.1.2/32 peer 10.5.1.1/32 dev l2tpeth0
|
|
||||||
# ip li set dev l2tpeth0 up
|
|
||||||
|
|
||||||
Choose IP addresses to be the address of a local IP interface and that
|
|
||||||
of the remote system. The IP addresses of the l2tpeth0 interface can be
|
|
||||||
anything suitable.
|
|
||||||
|
|
||||||
Repeat the above at the peer, with ports, tunnel/session ids and IP
|
|
||||||
addresses reversed. The tunnel and session IDs can be any non-zero
|
|
||||||
32-bit number, but the values must be reversed at the peer.
|
|
||||||
|
|
||||||
======================== ===================
|
|
||||||
Host 1 Host2
|
|
||||||
======================== ===================
|
|
||||||
udp_sport=5000 udp_sport=5001
|
|
||||||
udp_dport=5001 udp_dport=5000
|
|
||||||
tunnel_id=42 tunnel_id=45
|
|
||||||
peer_tunnel_id=45 peer_tunnel_id=42
|
|
||||||
session_id=128 session_id=5196755
|
|
||||||
peer_session_id=5196755 peer_session_id=128
|
|
||||||
======================== ===================
|
|
||||||
|
|
||||||
When done at both ends of the tunnel, it should be possible to send
|
|
||||||
data over the network. e.g.::
|
|
||||||
|
|
||||||
# ping 10.5.1.1
|
|
||||||
|
|
||||||
|
|
||||||
Sample Userspace Code
|
|
||||||
=====================
|
|
||||||
|
|
||||||
1. Create tunnel management PPPoX socket::
|
|
||||||
|
|
||||||
kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
|
|
||||||
if (kernel_fd >= 0) {
|
|
||||||
struct sockaddr_pppol2tp sax;
|
|
||||||
struct sockaddr_in const *peer_addr;
|
|
||||||
|
|
||||||
peer_addr = l2tp_tunnel_get_peer_addr(tunnel);
|
|
||||||
memset(&sax, 0, sizeof(sax));
|
|
||||||
sax.sa_family = AF_PPPOX;
|
|
||||||
sax.sa_protocol = PX_PROTO_OL2TP;
|
|
||||||
sax.pppol2tp.fd = udp_fd; /* fd of tunnel UDP socket */
|
|
||||||
sax.pppol2tp.addr.sin_addr.s_addr = peer_addr->sin_addr.s_addr;
|
|
||||||
sax.pppol2tp.addr.sin_port = peer_addr->sin_port;
|
|
||||||
sax.pppol2tp.addr.sin_family = AF_INET;
|
|
||||||
sax.pppol2tp.s_tunnel = tunnel_id;
|
|
||||||
sax.pppol2tp.s_session = 0; /* special case: mgmt socket */
|
|
||||||
sax.pppol2tp.d_tunnel = 0;
|
|
||||||
sax.pppol2tp.d_session = 0; /* special case: mgmt socket */
|
|
||||||
|
|
||||||
if(connect(kernel_fd, (struct sockaddr *)&sax, sizeof(sax) ) < 0 ) {
|
|
||||||
perror("connect failed");
|
|
||||||
result = -errno;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
2. Create session PPPoX data socket::
|
|
||||||
|
|
||||||
struct sockaddr_pppol2tp sax;
|
struct sockaddr_pppol2tp sax;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/* Note, the target socket must be bound already, else it will not be ready */
|
/* Note, the tunnel socket must be bound already, else it
|
||||||
|
* will not be ready
|
||||||
|
*/
|
||||||
sax.sa_family = AF_PPPOX;
|
sax.sa_family = AF_PPPOX;
|
||||||
sax.sa_protocol = PX_PROTO_OL2TP;
|
sax.sa_protocol = PX_PROTO_OL2TP;
|
||||||
sax.pppol2tp.fd = tunnel_fd;
|
sax.pppol2tp.fd = tunnel_fd;
|
||||||
@@ -303,7 +404,7 @@ Sample Userspace Code
|
|||||||
sax.pppol2tp.d_session = peer_session_id;
|
sax.pppol2tp.d_session = peer_session_id;
|
||||||
|
|
||||||
/* session_fd is the fd of the session's PPPoL2TP socket.
|
/* session_fd is the fd of the session's PPPoL2TP socket.
|
||||||
* tunnel_fd is the fd of the tunnel UDP socket.
|
* tunnel_fd is the fd of the tunnel UDP / L2TPIP socket.
|
||||||
*/
|
*/
|
||||||
fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax));
|
fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax));
|
||||||
if (fd < 0 ) {
|
if (fd < 0 ) {
|
||||||
@@ -311,48 +412,266 @@ Sample Userspace Code
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
Old L2TPv2-only API
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
When L2TP was first added to the Linux kernel in 2.6.23, it
|
||||||
|
implemented only L2TPv2 and did not include a netlink API. Instead,
|
||||||
|
tunnel and session instances in the kernel were managed directly using
|
||||||
|
only PPPoL2TP sockets. The PPPoL2TP socket is used as described in
|
||||||
|
section "PPPoL2TP Session Socket API" but tunnel and session instances
|
||||||
|
are automatically created on a connect() of the socket instead of
|
||||||
|
being created by a separate netlink request:
|
||||||
|
|
||||||
|
- Tunnels are managed using a tunnel management socket which is a
|
||||||
|
dedicated PPPoL2TP socket, connected to (invalid) session
|
||||||
|
id 0. The L2TP tunnel instance is created when the PPPoL2TP
|
||||||
|
tunnel management socket is connected and is destroyed when the
|
||||||
|
socket is closed.
|
||||||
|
|
||||||
|
- Session instances are created in the kernel when a PPPoL2TP
|
||||||
|
socket is connected to a non-zero session id. Session parameters
|
||||||
|
are set using setsockopt. The L2TP session instance is destroyed
|
||||||
|
when the socket is closed.
|
||||||
|
|
||||||
|
This API is still supported but its use is discouraged. Instead, new
|
||||||
|
L2TPv2 applications should use netlink to first create the tunnel and
|
||||||
|
session, then create a PPPoL2TP socket for the session.
|
||||||
|
|
||||||
|
Unmanaged L2TPv3 tunnels
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The kernel L2TP subsystem also supports static (unmanaged) L2TPv3
|
||||||
|
tunnels. Unmanaged tunnels have no userspace tunnel socket, and
|
||||||
|
exchange no control messages with the peer to set up the tunnel; the
|
||||||
|
tunnel is configured manually at each end of the tunnel. All
|
||||||
|
configuration is done using netlink. There is no need for an L2TP
|
||||||
|
userspace application in this case -- the tunnel socket is created by
|
||||||
|
the kernel and configured using parameters sent in the
|
||||||
|
``L2TP_CMD_TUNNEL_CREATE`` netlink request. The ``ip`` utility of
|
||||||
|
``iproute2`` has commands for managing static L2TPv3 tunnels; do ``ip
|
||||||
|
l2tp help`` for more information.
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
---------
|
||||||
|
|
||||||
|
The L2TP subsystem offers a range of debugging interfaces through the
|
||||||
|
debugfs filesystem.
|
||||||
|
|
||||||
|
To access these interfaces, the debugfs filesystem must first be mounted::
|
||||||
|
|
||||||
|
# mount -t debugfs debugfs /debug
|
||||||
|
|
||||||
|
Files under the l2tp directory can then be accessed, providing a summary
|
||||||
|
of the current population of tunnel and session contexts existing in the
|
||||||
|
kernel::
|
||||||
|
|
||||||
|
# cat /debug/l2tp/tunnels
|
||||||
|
|
||||||
|
The debugfs files should not be used by applications to obtain L2TP
|
||||||
|
state information because the file format is subject to change. It is
|
||||||
|
implemented to provide extra debug information to help diagnose
|
||||||
|
problems. Applications should instead use the netlink API.
|
||||||
|
|
||||||
|
In addition the L2TP subsystem implements tracepoints using the standard
|
||||||
|
kernel event tracing API. The available L2TP events can be reviewed as
|
||||||
|
follows::
|
||||||
|
|
||||||
|
# find /debug/tracing/events/l2tp
|
||||||
|
|
||||||
|
Finally, /proc/net/pppol2tp is also provided for backwards compatibility
|
||||||
|
with the original pppol2tp code. It lists information about L2TPv2
|
||||||
|
tunnels and sessions only. Its use is discouraged.
|
||||||
|
|
||||||
Internal Implementation
|
Internal Implementation
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
The driver keeps a struct l2tp_tunnel context per L2TP tunnel and a
|
This section is for kernel developers and maintainers.
|
||||||
struct l2tp_session context for each session. The l2tp_tunnel is
|
|
||||||
always associated with a UDP or L2TP/IP socket and keeps a list of
|
|
||||||
sessions in the tunnel. The l2tp_session context keeps kernel state
|
|
||||||
about the session. It has private data which is used for data specific
|
|
||||||
to the session type. With L2TPv2, the session always carried PPP
|
|
||||||
traffic. With L2TPv3, the session can also carry ethernet frames
|
|
||||||
(ethernet pseudowire) or other data types such as ATM, HDLC or Frame
|
|
||||||
Relay.
|
|
||||||
|
|
||||||
When a tunnel is first opened, the reference count on the socket is
|
Sockets
|
||||||
increased using sock_hold(). This ensures that the kernel socket
|
-------
|
||||||
cannot be removed while L2TP's data structures reference it.
|
|
||||||
|
|
||||||
Some L2TP sessions also have a socket (PPP pseudowires) while others
|
UDP sockets are implemented by the networking core. When an L2TP
|
||||||
do not (ethernet pseudowires). We can't use the socket reference count
|
tunnel is created using a UDP socket, the socket is set up as an
|
||||||
as the reference count for session contexts. The L2TP implementation
|
encapsulated UDP socket by setting encap_rcv and encap_destroy
|
||||||
therefore has its own internal reference counts on the session
|
callbacks on the UDP socket. l2tp_udp_encap_recv is called when
|
||||||
contexts.
|
packets are received on the socket. l2tp_udp_encap_destroy is called
|
||||||
|
when userspace closes the socket.
|
||||||
|
|
||||||
To Do
|
L2TPIP sockets are implemented in `net/l2tp/l2tp_ip.c`_ and
|
||||||
=====
|
`net/l2tp/l2tp_ip6.c`_.
|
||||||
|
|
||||||
Add L2TP tunnel switching support. This would route tunneled traffic
|
Tunnels
|
||||||
from one L2TP tunnel into another. Specified in
|
-------
|
||||||
http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08
|
|
||||||
|
|
||||||
Add L2TPv3 VLAN pseudowire support.
|
The kernel keeps a struct l2tp_tunnel context per L2TP tunnel. The
|
||||||
|
l2tp_tunnel is always associated with a UDP or L2TP/IP socket and
|
||||||
|
keeps a list of sessions in the tunnel. When a tunnel is first
|
||||||
|
registered with L2TP core, the reference count on the socket is
|
||||||
|
increased. This ensures that the socket cannot be removed while L2TP's
|
||||||
|
data structures reference it.
|
||||||
|
|
||||||
Add L2TPv3 IP pseudowire support.
|
Tunnels are identified by a unique tunnel id. The id is 16-bit for
|
||||||
|
L2TPv2 and 32-bit for L2TPv3. Internally, the id is stored as a 32-bit
|
||||||
|
value.
|
||||||
|
|
||||||
Add L2TPv3 ATM pseudowire support.
|
Tunnels are kept in a per-net list, indexed by tunnel id. The tunnel
|
||||||
|
id namespace is shared by L2TPv2 and L2TPv3. The tunnel context can be
|
||||||
|
derived from the socket's sk_user_data.
|
||||||
|
|
||||||
|
Handling tunnel socket close is perhaps the most tricky part of the
|
||||||
|
L2TP implementation. If userspace closes a tunnel socket, the L2TP
|
||||||
|
tunnel and all of its sessions must be closed and destroyed. Since the
|
||||||
|
tunnel context holds a ref on the tunnel socket, the socket's
|
||||||
|
sk_destruct won't be called until the tunnel sock_put's its
|
||||||
|
socket. For UDP sockets, when userspace closes the tunnel socket, the
|
||||||
|
socket's encap_destroy handler is invoked, which L2TP uses to initiate
|
||||||
|
its tunnel close actions. For L2TPIP sockets, the socket's close
|
||||||
|
handler initiates the same tunnel close actions. All sessions are
|
||||||
|
first closed. Each session drops its tunnel ref. When the tunnel ref
|
||||||
|
reaches zero, the tunnel puts its socket ref. When the socket is
|
||||||
|
eventually destroyed, it's sk_destruct finally frees the L2TP tunnel
|
||||||
|
context.
|
||||||
|
|
||||||
|
Sessions
|
||||||
|
--------
|
||||||
|
|
||||||
|
The kernel keeps a struct l2tp_session context for each session. Each
|
||||||
|
session has private data which is used for data specific to the
|
||||||
|
session type. With L2TPv2, the session always carries PPP
|
||||||
|
traffic. With L2TPv3, the session can carry Ethernet frames (Ethernet
|
||||||
|
pseudowire) or other data types such as PPP, ATM, HDLC or Frame
|
||||||
|
Relay. Linux currently implements only Ethernet and PPP session types.
|
||||||
|
|
||||||
|
Some L2TP session types also have a socket (PPP pseudowires) while
|
||||||
|
others do not (Ethernet pseudowires). We can't therefore use the
|
||||||
|
socket reference count as the reference count for session
|
||||||
|
contexts. The L2TP implementation therefore has its own internal
|
||||||
|
reference counts on the session contexts.
|
||||||
|
|
||||||
|
Like tunnels, L2TP sessions are identified by a unique
|
||||||
|
session id. Just as with tunnel ids, the session id is 16-bit for
|
||||||
|
L2TPv2 and 32-bit for L2TPv3. Internally, the id is stored as a 32-bit
|
||||||
|
value.
|
||||||
|
|
||||||
|
Sessions hold a ref on their parent tunnel to ensure that the tunnel
|
||||||
|
stays extant while one or more sessions references it.
|
||||||
|
|
||||||
|
Sessions are kept in a per-tunnel list, indexed by session id. L2TPv3
|
||||||
|
sessions are also kept in a per-net list indexed by session id,
|
||||||
|
because L2TPv3 session ids are unique across all tunnels and L2TPv3
|
||||||
|
data packets do not contain a tunnel id in the header. This list is
|
||||||
|
therefore needed to find the session context associated with a
|
||||||
|
received data packet when the tunnel context cannot be derived from
|
||||||
|
the tunnel socket.
|
||||||
|
|
||||||
|
Although the L2TPv3 RFC specifies that L2TPv3 session ids are not
|
||||||
|
scoped by the tunnel, the kernel does not police this for L2TPv3 UDP
|
||||||
|
tunnels and does not add sessions of L2TPv3 UDP tunnels into the
|
||||||
|
per-net session list. In the UDP receive code, we must trust that the
|
||||||
|
tunnel can be identified using the tunnel socket's sk_user_data and
|
||||||
|
lookup the session in the tunnel's session list instead of the per-net
|
||||||
|
session list.
|
||||||
|
|
||||||
|
PPP
|
||||||
|
---
|
||||||
|
|
||||||
|
`net/l2tp/l2tp_ppp.c`_ implements the PPPoL2TP socket family. Each PPP
|
||||||
|
session has a PPPoL2TP socket.
|
||||||
|
|
||||||
|
The PPPoL2TP socket's sk_user_data references the l2tp_session.
|
||||||
|
|
||||||
|
Userspace sends and receives PPP packets over L2TP using a PPPoL2TP
|
||||||
|
socket. Only PPP control frames pass over this socket: PPP data
|
||||||
|
packets are handled entirely by the kernel, passing between the L2TP
|
||||||
|
session and its associated ``pppN`` netdev through the PPP channel
|
||||||
|
interface of the kernel PPP subsystem.
|
||||||
|
|
||||||
|
The L2TP PPP implementation handles the closing of a PPPoL2TP socket
|
||||||
|
by closing its corresponding L2TP session. This is complicated because
|
||||||
|
it must consider racing with netlink session create/destroy requests
|
||||||
|
and pppol2tp_connect trying to reconnect with a session that is in the
|
||||||
|
process of being closed. Unlike tunnels, PPP sessions do not hold a
|
||||||
|
ref on their associated socket, so code must be careful to sock_hold
|
||||||
|
the socket where necessary. For all the details, see commit
|
||||||
|
3d609342cc04129ff7568e19316ce3d7451a27e8.
|
||||||
|
|
||||||
|
Ethernet
|
||||||
|
--------
|
||||||
|
|
||||||
|
`net/l2tp/l2tp_eth.c`_ implements L2TPv3 Ethernet pseudowires. It
|
||||||
|
manages a netdev for each session.
|
||||||
|
|
||||||
|
L2TP Ethernet sessions are created and destroyed by netlink request,
|
||||||
|
or are destroyed when the tunnel is destroyed. Unlike PPP sessions,
|
||||||
|
Ethernet sessions do not have an associated socket.
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
=============
|
=============
|
||||||
|
|
||||||
The L2TP drivers were developed as part of the OpenL2TP project by
|
RFCs
|
||||||
Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server,
|
----
|
||||||
designed from the ground up to have the L2TP datapath in the
|
|
||||||
kernel. The project also implemented the pppol2tp plugin for pppd
|
The kernel code implements the datapath features specified in the
|
||||||
which allows pppd to use the kernel driver. Details can be found at
|
following RFCs:
|
||||||
http://www.openl2tp.org.
|
|
||||||
|
======= =============== ===================================
|
||||||
|
RFC2661 L2TPv2 https://tools.ietf.org/html/rfc2661
|
||||||
|
RFC3931 L2TPv3 https://tools.ietf.org/html/rfc3931
|
||||||
|
RFC4719 L2TPv3 Ethernet https://tools.ietf.org/html/rfc4719
|
||||||
|
======= =============== ===================================
|
||||||
|
|
||||||
|
Implementations
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A number of open source applications use the L2TP kernel subsystem:
|
||||||
|
|
||||||
|
============ ==============================================
|
||||||
|
iproute2 https://github.com/shemminger/iproute2
|
||||||
|
go-l2tp https://github.com/katalix/go-l2tp
|
||||||
|
tunneldigger https://github.com/wlanslovenija/tunneldigger
|
||||||
|
xl2tpd https://github.com/xelerance/xl2tpd
|
||||||
|
============ ==============================================
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The current implementation has a number of limitations:
|
||||||
|
|
||||||
|
1) Multiple UDP sockets with the same 5-tuple address cannot be
|
||||||
|
used. The kernel's tunnel context is identified using private
|
||||||
|
data associated with the socket so it is important that each
|
||||||
|
socket is uniquely identified by its address.
|
||||||
|
|
||||||
|
2) Interfacing with openvswitch is not yet implemented. It may be
|
||||||
|
useful to map OVS Ethernet and VLAN ports into L2TPv3 tunnels.
|
||||||
|
|
||||||
|
3) VLAN pseudowires are implemented using an ``l2tpethN`` interface
|
||||||
|
configured with a VLAN sub-interface. Since L2TPv3 VLAN
|
||||||
|
pseudowires carry one and only one VLAN, it may be better to use
|
||||||
|
a single netdevice rather than an ``l2tpethN`` and ``l2tpethN``:M
|
||||||
|
pair per VLAN session. The netlink attribute
|
||||||
|
``L2TP_ATTR_VLAN_ID`` was added for this, but it was never
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
Testing
|
||||||
|
-------
|
||||||
|
|
||||||
|
Unmanaged L2TPv3 Ethernet features are tested by the kernel's built-in
|
||||||
|
selftests. See `tools/testing/selftests/net/l2tp.sh`_.
|
||||||
|
|
||||||
|
Another test suite, l2tp-ktest_, covers all
|
||||||
|
of the L2TP APIs and tunnel/session types. This may be integrated into
|
||||||
|
the kernel's built-in L2TP selftests in the future.
|
||||||
|
|
||||||
|
.. Links
|
||||||
|
.. _Generic Netlink: generic_netlink.html
|
||||||
|
.. _libmnl: https://www.netfilter.org/projects/libmnl
|
||||||
|
.. _include/uapi/linux/l2tp.h: ../../../include/uapi/linux/l2tp.h
|
||||||
|
.. _include/linux/if_pppol2tp.h: ../../../include/linux/if_pppol2tp.h
|
||||||
|
.. _net/l2tp/l2tp_ip.c: ../../../net/l2tp/l2tp_ip.c
|
||||||
|
.. _net/l2tp/l2tp_ip6.c: ../../../net/l2tp/l2tp_ip6.c
|
||||||
|
.. _net/l2tp/l2tp_ppp.c: ../../../net/l2tp/l2tp_ppp.c
|
||||||
|
.. _net/l2tp/l2tp_eth.c: ../../../net/l2tp/l2tp_eth.c
|
||||||
|
.. _tools/testing/selftests/net/l2tp.sh: ../../../tools/testing/selftests/net/l2tp.sh
|
||||||
|
.. _l2tp-ktest: https://github.com/katalix/l2tp-ktest
|
||||||
|
@@ -465,9 +465,9 @@ XPS Configuration
|
|||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
XPS is only available if the kconfig symbol CONFIG_XPS is enabled (on by
|
XPS is only available if the kconfig symbol CONFIG_XPS is enabled (on by
|
||||||
default for SMP). The functionality remains disabled until explicitly
|
default for SMP). If compiled in, it is driver dependent whether, and
|
||||||
configured. To enable XPS, the bitmap of CPUs/receive-queues that may
|
how, XPS is configured at device init. The mapping of CPUs/receive-queues
|
||||||
use a transmit queue is configured using the sysfs file entry:
|
to transmit queue can be inspected and configured using sysfs:
|
||||||
|
|
||||||
For selection based on CPUs map::
|
For selection based on CPUs map::
|
||||||
|
|
||||||
|
179
Documentation/networking/statistics.rst
Normal file
179
Documentation/networking/statistics.rst
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
====================
|
||||||
|
Interface statistics
|
||||||
|
====================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
This document is a guide to Linux network interface statistics.
|
||||||
|
|
||||||
|
There are three main sources of interface statistics in Linux:
|
||||||
|
|
||||||
|
- standard interface statistics based on
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`;
|
||||||
|
- protocol-specific statistics; and
|
||||||
|
- driver-defined statistics available via ethtool.
|
||||||
|
|
||||||
|
Standard interface statistics
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
There are multiple interfaces to reach the standard statistics.
|
||||||
|
Most commonly used is the `ip` command from `iproute2`::
|
||||||
|
|
||||||
|
$ ip -s -s link show dev ens4u1u1
|
||||||
|
6: ens4u1u1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
|
||||||
|
link/ether 48:2a:e3:4c:b1:d1 brd ff:ff:ff:ff:ff:ff
|
||||||
|
RX: bytes packets errors dropped overrun mcast
|
||||||
|
74327665117 69016965 0 0 0 0
|
||||||
|
RX errors: length crc frame fifo missed
|
||||||
|
0 0 0 0 0
|
||||||
|
TX: bytes packets errors dropped carrier collsns
|
||||||
|
21405556176 44608960 0 0 0 0
|
||||||
|
TX errors: aborted fifo window heartbeat transns
|
||||||
|
0 0 0 0 128
|
||||||
|
altname enp58s0u1u1
|
||||||
|
|
||||||
|
Note that `-s` has been specified twice to see all members of
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`.
|
||||||
|
If `-s` is specified once the detailed errors won't be shown.
|
||||||
|
|
||||||
|
`ip` supports JSON formatting via the `-j` option.
|
||||||
|
|
||||||
|
Protocol-specific statistics
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Some of the interfaces used for configuring devices are also able
|
||||||
|
to report related statistics. For example ethtool interface used
|
||||||
|
to configure pause frames can report corresponding hardware counters::
|
||||||
|
|
||||||
|
$ ethtool --include-statistics -a eth0
|
||||||
|
Pause parameters for eth0:
|
||||||
|
Autonegotiate: on
|
||||||
|
RX: on
|
||||||
|
TX: on
|
||||||
|
Statistics:
|
||||||
|
tx_pause_frames: 1
|
||||||
|
rx_pause_frames: 1
|
||||||
|
|
||||||
|
Driver-defined statistics
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Driver-defined ethtool statistics can be dumped using `ethtool -S $ifc`, e.g.::
|
||||||
|
|
||||||
|
$ ethtool -S ens4u1u1
|
||||||
|
NIC statistics:
|
||||||
|
tx_single_collisions: 0
|
||||||
|
tx_multi_collisions: 0
|
||||||
|
|
||||||
|
uAPIs
|
||||||
|
=====
|
||||||
|
|
||||||
|
procfs
|
||||||
|
------
|
||||||
|
|
||||||
|
The historical `/proc/net/dev` text interface gives access to the list
|
||||||
|
of interfaces as well as their statistics.
|
||||||
|
|
||||||
|
Note that even though this interface is using
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`
|
||||||
|
internally it combines some of the fields.
|
||||||
|
|
||||||
|
sysfs
|
||||||
|
-----
|
||||||
|
|
||||||
|
Each device directory in sysfs contains a `statistics` directory (e.g.
|
||||||
|
`/sys/class/net/lo/statistics/`) with files corresponding to
|
||||||
|
members of :c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`.
|
||||||
|
|
||||||
|
This simple interface is convenient especially in constrained/embedded
|
||||||
|
environments without access to tools. However, it's inefficient when
|
||||||
|
reading multiple stats as it internally performs a full dump of
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`
|
||||||
|
and reports only the stat corresponding to the accessed file.
|
||||||
|
|
||||||
|
Sysfs files are documented in
|
||||||
|
`Documentation/ABI/testing/sysfs-class-net-statistics`.
|
||||||
|
|
||||||
|
|
||||||
|
netlink
|
||||||
|
-------
|
||||||
|
|
||||||
|
`rtnetlink` (`NETLINK_ROUTE`) is the preferred method of accessing
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` stats.
|
||||||
|
|
||||||
|
Statistics are reported both in the responses to link information
|
||||||
|
requests (`RTM_GETLINK`) and statistic requests (`RTM_GETSTATS`,
|
||||||
|
when `IFLA_STATS_LINK_64` bit is set in the `.filter_mask` of the request).
|
||||||
|
|
||||||
|
ethtool
|
||||||
|
-------
|
||||||
|
|
||||||
|
Ethtool IOCTL interface allows drivers to report implementation
|
||||||
|
specific statistics. Historically it has also been used to report
|
||||||
|
statistics for which other APIs did not exist, like per-device-queue
|
||||||
|
statistics, or standard-based statistics (e.g. RFC 2863).
|
||||||
|
|
||||||
|
Statistics and their string identifiers are retrieved separately.
|
||||||
|
Identifiers via `ETHTOOL_GSTRINGS` with `string_set` set to `ETH_SS_STATS`,
|
||||||
|
and values via `ETHTOOL_GSTATS`. User space should use `ETHTOOL_GDRVINFO`
|
||||||
|
to retrieve the number of statistics (`.n_stats`).
|
||||||
|
|
||||||
|
ethtool-netlink
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Ethtool netlink is a replacement for the older IOCTL interface.
|
||||||
|
|
||||||
|
Protocol-related statistics can be requested in get commands by setting
|
||||||
|
the `ETHTOOL_FLAG_STATS` flag in `ETHTOOL_A_HEADER_FLAGS`. Currently
|
||||||
|
statistics are supported in the following commands:
|
||||||
|
|
||||||
|
- `ETHTOOL_MSG_PAUSE_GET`
|
||||||
|
|
||||||
|
debugfs
|
||||||
|
-------
|
||||||
|
|
||||||
|
Some drivers expose extra statistics via `debugfs`.
|
||||||
|
|
||||||
|
struct rtnl_link_stats64
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. kernel-doc:: include/uapi/linux/if_link.h
|
||||||
|
:identifiers: rtnl_link_stats64
|
||||||
|
|
||||||
|
Notes for driver authors
|
||||||
|
========================
|
||||||
|
|
||||||
|
Drivers should report all statistics which have a matching member in
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>` exclusively
|
||||||
|
via `.ndo_get_stats64`. Reporting such standard stats via ethtool
|
||||||
|
or debugfs will not be accepted.
|
||||||
|
|
||||||
|
Drivers must ensure best possible compliance with
|
||||||
|
:c:type:`struct rtnl_link_stats64 <rtnl_link_stats64>`.
|
||||||
|
Please note for example that detailed error statistics must be
|
||||||
|
added into the general `rx_error` / `tx_error` counters.
|
||||||
|
|
||||||
|
The `.ndo_get_stats64` callback can not sleep because of accesses
|
||||||
|
via `/proc/net/dev`. If driver may sleep when retrieving the statistics
|
||||||
|
from the device it should do so periodically asynchronously and only return
|
||||||
|
a recent copy from `.ndo_get_stats64`. Ethtool interrupt coalescing interface
|
||||||
|
allows setting the frequency of refreshing statistics, if needed.
|
||||||
|
|
||||||
|
Retrieving ethtool statistics is a multi-syscall process, drivers are advised
|
||||||
|
to keep the number of statistics constant to avoid race conditions with
|
||||||
|
user space trying to read them.
|
||||||
|
|
||||||
|
Statistics must persist across routine operations like bringing the interface
|
||||||
|
down and up.
|
||||||
|
|
||||||
|
Kernel-internal data structures
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The following structures are internal to the kernel, their members are
|
||||||
|
translated to netlink attributes when dumped. Drivers must not overwrite
|
||||||
|
the statistics they don't report with 0.
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/ethtool.h
|
||||||
|
:identifiers: ethtool_pause_stats
|
@@ -58,3 +58,31 @@ forwarding table using the new bridge command.
|
|||||||
3. Show forwarding table::
|
3. Show forwarding table::
|
||||||
|
|
||||||
# bridge fdb show dev vxlan0
|
# bridge fdb show dev vxlan0
|
||||||
|
|
||||||
|
The following NIC features may indicate support for UDP tunnel-related
|
||||||
|
offloads (most commonly VXLAN features, but support for a particular
|
||||||
|
encapsulation protocol is NIC specific):
|
||||||
|
|
||||||
|
- `tx-udp_tnl-segmentation`
|
||||||
|
- `tx-udp_tnl-csum-segmentation`
|
||||||
|
ability to perform TCP segmentation offload of UDP encapsulated frames
|
||||||
|
|
||||||
|
- `rx-udp_tunnel-port-offload`
|
||||||
|
receive side parsing of UDP encapsulated frames which allows NICs to
|
||||||
|
perform protocol-aware offloads, like checksum validation offload of
|
||||||
|
inner frames (only needed by NICs without protocol-agnostic offloads)
|
||||||
|
|
||||||
|
For devices supporting `rx-udp_tunnel-port-offload` the list of currently
|
||||||
|
offloaded ports can be interrogated with `ethtool`::
|
||||||
|
|
||||||
|
$ ethtool --show-tunnels eth0
|
||||||
|
Tunnel information for eth0:
|
||||||
|
UDP port table 0:
|
||||||
|
Size: 4
|
||||||
|
Types: vxlan
|
||||||
|
No entries
|
||||||
|
UDP port table 1:
|
||||||
|
Size: 4
|
||||||
|
Types: geneve, vxlan-gpe
|
||||||
|
Entries (1):
|
||||||
|
port 1230, vxlan-gpe
|
||||||
|
50
MAINTAINERS
50
MAINTAINERS
@@ -1259,7 +1259,7 @@ S: Supported
|
|||||||
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
|
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
|
||||||
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
|
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
|
||||||
F: drivers/net/ethernet/apm/xgene/
|
F: drivers/net/ethernet/apm/xgene/
|
||||||
F: drivers/net/phy/mdio-xgene.c
|
F: drivers/net/mdio/mdio-xgene.c
|
||||||
|
|
||||||
APPLIED MICRO (APM) X-GENE SOC PMU
|
APPLIED MICRO (APM) X-GENE SOC PMU
|
||||||
M: Khuong Dinh <khuong@os.amperecomputing.com>
|
M: Khuong Dinh <khuong@os.amperecomputing.com>
|
||||||
@@ -3238,7 +3238,7 @@ M: Daniel Borkmann <daniel@iogearbox.net>
|
|||||||
R: Martin KaFai Lau <kafai@fb.com>
|
R: Martin KaFai Lau <kafai@fb.com>
|
||||||
R: Song Liu <songliubraving@fb.com>
|
R: Song Liu <songliubraving@fb.com>
|
||||||
R: Yonghong Song <yhs@fb.com>
|
R: Yonghong Song <yhs@fb.com>
|
||||||
R: Andrii Nakryiko <andriin@fb.com>
|
R: Andrii Nakryiko <andrii@kernel.org>
|
||||||
R: John Fastabend <john.fastabend@gmail.com>
|
R: John Fastabend <john.fastabend@gmail.com>
|
||||||
R: KP Singh <kpsingh@chromium.org>
|
R: KP Singh <kpsingh@chromium.org>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
@@ -3914,6 +3914,7 @@ F: include/net/netns/can.h
|
|||||||
F: include/uapi/linux/can.h
|
F: include/uapi/linux/can.h
|
||||||
F: include/uapi/linux/can/bcm.h
|
F: include/uapi/linux/can/bcm.h
|
||||||
F: include/uapi/linux/can/gw.h
|
F: include/uapi/linux/can/gw.h
|
||||||
|
F: include/uapi/linux/can/isotp.h
|
||||||
F: include/uapi/linux/can/raw.h
|
F: include/uapi/linux/can/raw.h
|
||||||
F: net/can/
|
F: net/can/
|
||||||
|
|
||||||
@@ -4713,6 +4714,15 @@ S: Supported
|
|||||||
W: http://www.chelsio.com
|
W: http://www.chelsio.com
|
||||||
F: drivers/crypto/chelsio
|
F: drivers/crypto/chelsio
|
||||||
|
|
||||||
|
CXGB4 INLINE CRYPTO DRIVER
|
||||||
|
M: Ayush Sawal <ayush.sawal@chelsio.com>
|
||||||
|
M: Vinay Kumar Yadav <vinay.yadav@chelsio.com>
|
||||||
|
M: Rohit Maheshwari <rohitm@chelsio.com>
|
||||||
|
L: netdev@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
W: http://www.chelsio.com
|
||||||
|
F: drivers/net/ethernet/chelsio/inline_crypto/
|
||||||
|
|
||||||
CXGB4 ETHERNET DRIVER (CXGB4)
|
CXGB4 ETHERNET DRIVER (CXGB4)
|
||||||
M: Vishal Kulkarni <vishal@chelsio.com>
|
M: Vishal Kulkarni <vishal@chelsio.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
@@ -6546,11 +6556,14 @@ F: Documentation/devicetree/bindings/net/ethernet-phy.yaml
|
|||||||
F: Documentation/devicetree/bindings/net/mdio*
|
F: Documentation/devicetree/bindings/net/mdio*
|
||||||
F: Documentation/devicetree/bindings/net/qca,ar803x.yaml
|
F: Documentation/devicetree/bindings/net/qca,ar803x.yaml
|
||||||
F: Documentation/networking/phy.rst
|
F: Documentation/networking/phy.rst
|
||||||
|
F: drivers/net/mdio/
|
||||||
|
F: drivers/net/mdio/of_mdio.c
|
||||||
|
F: drivers/net/pcs/
|
||||||
F: drivers/net/phy/
|
F: drivers/net/phy/
|
||||||
F: drivers/of/of_mdio.c
|
|
||||||
F: drivers/of/of_net.c
|
F: drivers/of/of_net.c
|
||||||
F: include/dt-bindings/net/qca-ar803x.h
|
F: include/dt-bindings/net/qca-ar803x.h
|
||||||
F: include/linux/*mdio*.h
|
F: include/linux/*mdio*.h
|
||||||
|
F: include/linux/mdio/*.h
|
||||||
F: include/linux/of_net.h
|
F: include/linux/of_net.h
|
||||||
F: include/linux/phy.h
|
F: include/linux/phy.h
|
||||||
F: include/linux/phy_fixed.h
|
F: include/linux/phy_fixed.h
|
||||||
@@ -10347,6 +10360,13 @@ S: Maintained
|
|||||||
W: http://linux-test-project.github.io/
|
W: http://linux-test-project.github.io/
|
||||||
T: git git://github.com/linux-test-project/ltp.git
|
T: git git://github.com/linux-test-project/ltp.git
|
||||||
|
|
||||||
|
LYNX PCS MODULE
|
||||||
|
M: Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||||
|
L: netdev@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
F: drivers/net/pcs/pcs-lynx.c
|
||||||
|
F: include/linux/pcs-lynx.h
|
||||||
|
|
||||||
M68K ARCHITECTURE
|
M68K ARCHITECTURE
|
||||||
M: Geert Uytterhoeven <geert@linux-m68k.org>
|
M: Geert Uytterhoeven <geert@linux-m68k.org>
|
||||||
L: linux-m68k@lists.linux-m68k.org
|
L: linux-m68k@lists.linux-m68k.org
|
||||||
@@ -10554,7 +10574,7 @@ M: Tobias Waldekranz <tobias@waldekranz.com>
|
|||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/net/marvell,mvusb.yaml
|
F: Documentation/devicetree/bindings/net/marvell,mvusb.yaml
|
||||||
F: drivers/net/phy/mdio-mvusb.c
|
F: drivers/net/mdio/mdio-mvusb.c
|
||||||
|
|
||||||
MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
|
MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
|
||||||
M: Hu Ziji <huziji@marvell.com>
|
M: Hu Ziji <huziji@marvell.com>
|
||||||
@@ -10701,6 +10721,15 @@ L: linux-input@vger.kernel.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/hid/hid-mcp2221.c
|
F: drivers/hid/hid-mcp2221.c
|
||||||
|
|
||||||
|
MCP251XFD SPI-CAN NETWORK DRIVER
|
||||||
|
M: Marc Kleine-Budde <mkl@pengutronix.de>
|
||||||
|
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||||
|
R: Thomas Kopp <thomas.kopp@microchip.com>
|
||||||
|
L: linux-can@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/net/can/microchip,mcp251xfd.yaml
|
||||||
|
F: drivers/net/can/spi/mcp251xfd/
|
||||||
|
|
||||||
MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS
|
MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS
|
||||||
M: Peter Rosin <peda@axentia.se>
|
M: Peter Rosin <peda@axentia.se>
|
||||||
L: linux-iio@vger.kernel.org
|
L: linux-iio@vger.kernel.org
|
||||||
@@ -12090,7 +12119,6 @@ M: Neil Horman <nhorman@tuxdriver.com>
|
|||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: https://fedorahosted.org/dropwatch/
|
W: https://fedorahosted.org/dropwatch/
|
||||||
F: include/net/drop_monitor.h
|
|
||||||
F: include/uapi/linux/net_dropmon.h
|
F: include/uapi/linux/net_dropmon.h
|
||||||
F: net/core/drop_monitor.c
|
F: net/core/drop_monitor.c
|
||||||
|
|
||||||
@@ -12185,6 +12213,7 @@ F: net/ipv6/ipcomp6.c
|
|||||||
F: net/ipv6/xfrm*
|
F: net/ipv6/xfrm*
|
||||||
F: net/key/
|
F: net/key/
|
||||||
F: net/xfrm/
|
F: net/xfrm/
|
||||||
|
F: tools/testing/selftests/net/ipsec.c
|
||||||
|
|
||||||
NETWORKING [IPv4/IPv6]
|
NETWORKING [IPv4/IPv6]
|
||||||
M: "David S. Miller" <davem@davemloft.net>
|
M: "David S. Miller" <davem@davemloft.net>
|
||||||
@@ -12597,6 +12626,7 @@ F: drivers/net/dsa/ocelot/*
|
|||||||
F: drivers/net/ethernet/mscc/
|
F: drivers/net/ethernet/mscc/
|
||||||
F: include/soc/mscc/ocelot*
|
F: include/soc/mscc/ocelot*
|
||||||
F: net/dsa/tag_ocelot.c
|
F: net/dsa/tag_ocelot.c
|
||||||
|
F: tools/testing/selftests/drivers/net/ocelot/*
|
||||||
|
|
||||||
OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER
|
OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER
|
||||||
M: Frederic Barrat <fbarrat@linux.ibm.com>
|
M: Frederic Barrat <fbarrat@linux.ibm.com>
|
||||||
@@ -15372,10 +15402,11 @@ F: drivers/media/platform/s3c-camif/
|
|||||||
F: include/media/drv-intf/s3c_camif.h
|
F: include/media/drv-intf/s3c_camif.h
|
||||||
|
|
||||||
SAMSUNG S3FWRN5 NFC DRIVER
|
SAMSUNG S3FWRN5 NFC DRIVER
|
||||||
M: Robert Baldyga <r.baldyga@samsung.com>
|
M: Krzysztof Kozlowski <krzk@kernel.org>
|
||||||
M: Krzysztof Opasiak <k.opasiak@samsung.com>
|
M: Krzysztof Opasiak <k.opasiak@samsung.com>
|
||||||
L: linux-nfc@lists.01.org (moderated for non-subscribers)
|
L: linux-nfc@lists.01.org (moderated for non-subscribers)
|
||||||
S: Supported
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
|
||||||
F: drivers/nfc/s3fwrn5
|
F: drivers/nfc/s3fwrn5
|
||||||
|
|
||||||
SAMSUNG S5C73M3 CAMERA DRIVER
|
SAMSUNG S5C73M3 CAMERA DRIVER
|
||||||
@@ -15762,6 +15793,7 @@ L: netdev@vger.kernel.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/net/phy/phylink.c
|
F: drivers/net/phy/phylink.c
|
||||||
F: drivers/net/phy/sfp*
|
F: drivers/net/phy/sfp*
|
||||||
|
F: include/linux/mdio/mdio-i2c.h
|
||||||
F: include/linux/phylink.h
|
F: include/linux/phylink.h
|
||||||
F: include/linux/sfp.h
|
F: include/linux/sfp.h
|
||||||
K: phylink\.h|struct\s+phylink|\.phylink|>phylink_|phylink_(autoneg|clear|connect|create|destroy|disconnect|ethtool|helper|mac|mii|of|set|start|stop|test|validate)
|
K: phylink\.h|struct\s+phylink|\.phylink|>phylink_|phylink_(autoneg|clear|connect|create|destroy|disconnect|ethtool|helper|mac|mii|of|set|start|stop|test|validate)
|
||||||
@@ -16851,8 +16883,8 @@ SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
|
|||||||
M: Jose Abreu <Jose.Abreu@synopsys.com>
|
M: Jose Abreu <Jose.Abreu@synopsys.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/net/phy/mdio-xpcs.c
|
F: drivers/net/pcs/pcs-xpcs.c
|
||||||
F: include/linux/mdio-xpcs.h
|
F: include/linux/pcs/pcs-xpcs.h
|
||||||
|
|
||||||
SYNOPSYS DESIGNWARE I2C DRIVER
|
SYNOPSYS DESIGNWARE I2C DRIVER
|
||||||
M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||||
|
4
Makefile
4
Makefile
@@ -1071,13 +1071,15 @@ ifdef CONFIG_STACK_VALIDATION
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_BPF
|
||||||
ifdef CONFIG_DEBUG_INFO_BTF
|
ifdef CONFIG_DEBUG_INFO_BTF
|
||||||
ifeq ($(has_libelf),1)
|
ifeq ($(has_libelf),1)
|
||||||
resolve_btfids_target := tools/bpf/resolve_btfids FORCE
|
resolve_btfids_target := tools/bpf/resolve_btfids FORCE
|
||||||
else
|
else
|
||||||
ERROR_RESOLVE_BTFIDS := 1
|
ERROR_RESOLVE_BTFIDS := 1
|
||||||
endif
|
endif
|
||||||
endif
|
endif # CONFIG_DEBUG_INFO_BTF
|
||||||
|
endif # CONFIG_BPF
|
||||||
|
|
||||||
PHONY += prepare0
|
PHONY += prepare0
|
||||||
|
|
||||||
|
@@ -795,8 +795,8 @@
|
|||||||
reg = <0x27>;
|
reg = <0x27>;
|
||||||
interrupt-parent = <&gpa1>;
|
interrupt-parent = <&gpa1>;
|
||||||
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
s3fwrn5,en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>;
|
en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>;
|
||||||
s3fwrn5,fw-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>;
|
wake-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -199,6 +199,7 @@
|
|||||||
&enetc_port0 {
|
&enetc_port0 {
|
||||||
phy-handle = <&sgmii_phy0>;
|
phy-handle = <&sgmii_phy0>;
|
||||||
phy-connection-type = "sgmii";
|
phy-connection-type = "sgmii";
|
||||||
|
managed = "in-band-status";
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
mdio {
|
mdio {
|
||||||
|
@@ -143,6 +143,56 @@
|
|||||||
mdio: mdio-bus {
|
mdio: mdio-bus {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
switch@0 {
|
||||||
|
compatible = "mediatek,mt7531";
|
||||||
|
reg = <0>;
|
||||||
|
reset-gpios = <&pio 54 0>;
|
||||||
|
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
label = "wan";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
label = "lan0";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@2 {
|
||||||
|
reg = <2>;
|
||||||
|
label = "lan1";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@3 {
|
||||||
|
reg = <3>;
|
||||||
|
label = "lan2";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@4 {
|
||||||
|
reg = <4>;
|
||||||
|
label = "lan3";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@6 {
|
||||||
|
reg = <6>;
|
||||||
|
label = "cpu";
|
||||||
|
ethernet = <&gmac0>;
|
||||||
|
phy-mode = "2500base-x";
|
||||||
|
|
||||||
|
fixed-link {
|
||||||
|
speed = <2500>;
|
||||||
|
full-duplex;
|
||||||
|
pause;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -105,20 +105,71 @@
|
|||||||
pinctrl-0 = <ð_pins>;
|
pinctrl-0 = <ð_pins>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
gmac1: mac@1 {
|
gmac0: mac@0 {
|
||||||
compatible = "mediatek,eth-mac";
|
compatible = "mediatek,eth-mac";
|
||||||
reg = <1>;
|
reg = <0>;
|
||||||
phy-handle = <&phy5>;
|
phy-mode = "2500base-x";
|
||||||
|
|
||||||
|
fixed-link {
|
||||||
|
speed = <2500>;
|
||||||
|
full-duplex;
|
||||||
|
pause;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
mdio-bus {
|
mdio-bus {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
phy5: ethernet-phy@5 {
|
switch@0 {
|
||||||
reg = <5>;
|
compatible = "mediatek,mt7531";
|
||||||
phy-mode = "sgmii";
|
reg = <0>;
|
||||||
|
reset-gpios = <&pio 54 0>;
|
||||||
|
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
label = "lan0";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
label = "lan1";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@2 {
|
||||||
|
reg = <2>;
|
||||||
|
label = "lan2";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@3 {
|
||||||
|
reg = <3>;
|
||||||
|
label = "lan3";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@4 {
|
||||||
|
reg = <4>;
|
||||||
|
label = "wan";
|
||||||
|
};
|
||||||
|
|
||||||
|
port@6 {
|
||||||
|
reg = <6>;
|
||||||
|
label = "cpu";
|
||||||
|
ethernet = <&gmac0>;
|
||||||
|
phy-mode = "2500base-x";
|
||||||
|
|
||||||
|
fixed-link {
|
||||||
|
speed = <2500>;
|
||||||
|
full-duplex;
|
||||||
|
pause;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -134,11 +134,13 @@
|
|||||||
<0x1280000 0x100>,
|
<0x1280000 0x100>,
|
||||||
<0x1800000 0x80000>,
|
<0x1800000 0x80000>,
|
||||||
<0x1880000 0x10000>,
|
<0x1880000 0x10000>,
|
||||||
|
<0x1040000 0x10000>,
|
||||||
|
<0x1050000 0x10000>,
|
||||||
<0x1060000 0x10000>;
|
<0x1060000 0x10000>;
|
||||||
reg-names = "sys", "rew", "qs", "ptp", "port0", "port1",
|
reg-names = "sys", "rew", "qs", "ptp", "port0", "port1",
|
||||||
"port2", "port3", "port4", "port5", "port6",
|
"port2", "port3", "port4", "port5", "port6",
|
||||||
"port7", "port8", "port9", "port10", "qsys",
|
"port7", "port8", "port9", "port10", "qsys",
|
||||||
"ana", "s2";
|
"ana", "s0", "s1", "s2";
|
||||||
interrupts = <18 21 22>;
|
interrupts = <18 21 22>;
|
||||||
interrupt-names = "ptp_rdy", "xtr", "inj";
|
interrupt-names = "ptp_rdy", "xtr", "inj";
|
||||||
|
|
||||||
|
@@ -64,6 +64,40 @@
|
|||||||
phy_sgmii_2: ethernet-phy@3 {
|
phy_sgmii_2: ethernet-phy@3 {
|
||||||
reg = <0x03>;
|
reg = <0x03>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* VSC8514 QSGMII PHY */
|
||||||
|
phy_qsgmii_0: ethernet-phy@4 {
|
||||||
|
reg = <0x4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_qsgmii_1: ethernet-phy@5 {
|
||||||
|
reg = <0x5>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_qsgmii_2: ethernet-phy@6 {
|
||||||
|
reg = <0x6>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_qsgmii_3: ethernet-phy@7 {
|
||||||
|
reg = <0x7>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* VSC8514 QSGMII PHY */
|
||||||
|
phy_qsgmii_4: ethernet-phy@8 {
|
||||||
|
reg = <0x8>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_qsgmii_5: ethernet-phy@9 {
|
||||||
|
reg = <0x9>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_qsgmii_6: ethernet-phy@a {
|
||||||
|
reg = <0xa>;
|
||||||
|
};
|
||||||
|
|
||||||
|
phy_qsgmii_7: ethernet-phy@b {
|
||||||
|
reg = <0xb>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -76,3 +110,76 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
#include "t1040si-post.dtsi"
|
#include "t1040si-post.dtsi"
|
||||||
|
|
||||||
|
&seville_switch {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port0 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_0>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH5";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port1 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_1>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH4";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port2 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_2>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH7";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port3 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_3>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH6";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port4 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_4>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH9";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port5 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_5>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH8";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port6 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_6>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH11";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port7 {
|
||||||
|
managed = "in-band-status";
|
||||||
|
phy-handle = <&phy_qsgmii_7>;
|
||||||
|
phy-mode = "qsgmii";
|
||||||
|
label = "ETH10";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&seville_port8 {
|
||||||
|
ethernet = <&enet0>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
@@ -628,6 +628,84 @@
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
seville_switch: ethernet-switch@800000 {
|
||||||
|
compatible = "mscc,vsc9953-switch";
|
||||||
|
reg = <0x800000 0x290000>;
|
||||||
|
interrupts = <26 2 0 0>;
|
||||||
|
interrupt-names = "xtr";
|
||||||
|
little-endian;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
seville_port0: port@0 {
|
||||||
|
reg = <0>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port1: port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port2: port@2 {
|
||||||
|
reg = <2>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port3: port@3 {
|
||||||
|
reg = <3>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port4: port@4 {
|
||||||
|
reg = <4>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port5: port@5 {
|
||||||
|
reg = <5>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port6: port@6 {
|
||||||
|
reg = <6>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port7: port@7 {
|
||||||
|
reg = <7>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port8: port@8 {
|
||||||
|
reg = <8>;
|
||||||
|
phy-mode = "internal";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
fixed-link {
|
||||||
|
speed = <2500>;
|
||||||
|
full-duplex;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
seville_port9: port@9 {
|
||||||
|
reg = <9>;
|
||||||
|
phy-mode = "internal";
|
||||||
|
status = "disabled";
|
||||||
|
|
||||||
|
fixed-link {
|
||||||
|
speed = <2500>;
|
||||||
|
full-duplex;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
&qe {
|
&qe {
|
||||||
|
@@ -238,7 +238,10 @@ extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *);
|
|||||||
struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *, int);
|
struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *, int);
|
||||||
u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx);
|
u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx);
|
||||||
int ccw_device_pnso(struct ccw_device *cdev,
|
int ccw_device_pnso(struct ccw_device *cdev,
|
||||||
struct chsc_pnso_area *pnso_area,
|
struct chsc_pnso_area *pnso_area, u8 oc,
|
||||||
struct chsc_pnso_resume_token resume_token,
|
struct chsc_pnso_resume_token resume_token, int cnc);
|
||||||
int cnc);
|
int ccw_device_get_cssid(struct ccw_device *cdev, u8 *cssid);
|
||||||
|
int ccw_device_get_iid(struct ccw_device *cdev, u8 *iid);
|
||||||
|
int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid);
|
||||||
|
int ccw_device_get_chid(struct ccw_device *cdev, int chp_idx, u16 *chid);
|
||||||
#endif /* _S390_CCWDEV_H_ */
|
#endif /* _S390_CCWDEV_H_ */
|
||||||
|
@@ -11,6 +11,13 @@
|
|||||||
|
|
||||||
#include <uapi/asm/chsc.h>
|
#include <uapi/asm/chsc.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation codes for CHSC PNSO:
|
||||||
|
* PNSO_OC_NET_BRIDGE_INFO - only addresses that are visible to a bridgeport
|
||||||
|
* PNSO_OC_NET_ADDR_INFO - all addresses
|
||||||
|
*/
|
||||||
|
#define PNSO_OC_NET_BRIDGE_INFO 0
|
||||||
|
#define PNSO_OC_NET_ADDR_INFO 3
|
||||||
/**
|
/**
|
||||||
* struct chsc_pnso_naid_l2 - network address information descriptor
|
* struct chsc_pnso_naid_l2 - network address information descriptor
|
||||||
* @nit: Network interface token
|
* @nit: Network interface token
|
||||||
|
@@ -36,7 +36,9 @@ struct css_general_char {
|
|||||||
u64 alt_ssi : 1; /* bit 108 */
|
u64 alt_ssi : 1; /* bit 108 */
|
||||||
u64 : 1;
|
u64 : 1;
|
||||||
u64 narf : 1; /* bit 110 */
|
u64 narf : 1; /* bit 110 */
|
||||||
u64 : 12;
|
u64 : 5;
|
||||||
|
u64 enarf: 1; /* bit 116 */
|
||||||
|
u64 : 6;
|
||||||
u64 util_str : 1;/* bit 123 */
|
u64 util_str : 1;/* bit 123 */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
@@ -50,7 +50,6 @@ struct bpf_jit {
|
|||||||
int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */
|
int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */
|
||||||
int tail_call_start; /* Tail call start offset */
|
int tail_call_start; /* Tail call start offset */
|
||||||
int excnt; /* Number of exception table entries */
|
int excnt; /* Number of exception table entries */
|
||||||
int labels[1]; /* Labels for local jumps */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SEEN_MEM BIT(0) /* use mem[] for temporary storage */
|
#define SEEN_MEM BIT(0) /* use mem[] for temporary storage */
|
||||||
@@ -229,18 +228,18 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
|
|||||||
REG_SET_SEEN(b3); \
|
REG_SET_SEEN(b3); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define EMIT6_PCREL_LABEL(op1, op2, b1, b2, label, mask) \
|
#define EMIT6_PCREL_RIEB(op1, op2, b1, b2, mask, target) \
|
||||||
({ \
|
({ \
|
||||||
int rel = (jit->labels[label] - jit->prg) >> 1; \
|
unsigned int rel = (int)((target) - jit->prg) / 2; \
|
||||||
_EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), \
|
_EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), \
|
||||||
(op2) | (mask) << 12); \
|
(op2) | (mask) << 12); \
|
||||||
REG_SET_SEEN(b1); \
|
REG_SET_SEEN(b1); \
|
||||||
REG_SET_SEEN(b2); \
|
REG_SET_SEEN(b2); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define EMIT6_PCREL_IMM_LABEL(op1, op2, b1, imm, label, mask) \
|
#define EMIT6_PCREL_RIEC(op1, op2, b1, imm, mask, target) \
|
||||||
({ \
|
({ \
|
||||||
int rel = (jit->labels[label] - jit->prg) >> 1; \
|
unsigned int rel = (int)((target) - jit->prg) / 2; \
|
||||||
_EMIT6((op1) | (reg_high(b1) | (mask)) << 16 | \
|
_EMIT6((op1) | (reg_high(b1) | (mask)) << 16 | \
|
||||||
(rel & 0xffff), (op2) | ((imm) & 0xff) << 8); \
|
(rel & 0xffff), (op2) | ((imm) & 0xff) << 8); \
|
||||||
REG_SET_SEEN(b1); \
|
REG_SET_SEEN(b1); \
|
||||||
@@ -1282,7 +1281,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
|||||||
EMIT4(0xb9040000, BPF_REG_0, REG_2);
|
EMIT4(0xb9040000, BPF_REG_0, REG_2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BPF_JMP | BPF_TAIL_CALL:
|
case BPF_JMP | BPF_TAIL_CALL: {
|
||||||
|
int patch_1_clrj, patch_2_clij, patch_3_brc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implicit input:
|
* Implicit input:
|
||||||
* B1: pointer to ctx
|
* B1: pointer to ctx
|
||||||
@@ -1300,16 +1301,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
|||||||
EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
|
EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
|
||||||
offsetof(struct bpf_array, map.max_entries));
|
offsetof(struct bpf_array, map.max_entries));
|
||||||
/* if ((u32)%b3 >= (u32)%w1) goto out; */
|
/* if ((u32)%b3 >= (u32)%w1) goto out; */
|
||||||
if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
|
/* clrj %b3,%w1,0xa,out */
|
||||||
/* clrj %b3,%w1,0xa,label0 */
|
patch_1_clrj = jit->prg;
|
||||||
EMIT6_PCREL_LABEL(0xec000000, 0x0077, BPF_REG_3,
|
EMIT6_PCREL_RIEB(0xec000000, 0x0077, BPF_REG_3, REG_W1, 0xa,
|
||||||
REG_W1, 0, 0xa);
|
jit->prg);
|
||||||
} else {
|
|
||||||
/* clr %b3,%w1 */
|
|
||||||
EMIT2(0x1500, BPF_REG_3, REG_W1);
|
|
||||||
/* brcl 0xa,label0 */
|
|
||||||
EMIT6_PCREL_RILC(0xc0040000, 0xa, jit->labels[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if (tail_call_cnt++ > MAX_TAIL_CALL_CNT)
|
* if (tail_call_cnt++ > MAX_TAIL_CALL_CNT)
|
||||||
@@ -1324,16 +1319,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
|||||||
EMIT4_IMM(0xa7080000, REG_W0, 1);
|
EMIT4_IMM(0xa7080000, REG_W0, 1);
|
||||||
/* laal %w1,%w0,off(%r15) */
|
/* laal %w1,%w0,off(%r15) */
|
||||||
EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off);
|
EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off);
|
||||||
if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
|
/* clij %w1,MAX_TAIL_CALL_CNT,0x2,out */
|
||||||
/* clij %w1,MAX_TAIL_CALL_CNT,0x2,label0 */
|
patch_2_clij = jit->prg;
|
||||||
EMIT6_PCREL_IMM_LABEL(0xec000000, 0x007f, REG_W1,
|
EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT,
|
||||||
MAX_TAIL_CALL_CNT, 0, 0x2);
|
2, jit->prg);
|
||||||
} else {
|
|
||||||
/* clfi %w1,MAX_TAIL_CALL_CNT */
|
|
||||||
EMIT6_IMM(0xc20f0000, REG_W1, MAX_TAIL_CALL_CNT);
|
|
||||||
/* brcl 0x2,label0 */
|
|
||||||
EMIT6_PCREL_RILC(0xc0040000, 0x2, jit->labels[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prog = array->ptrs[index];
|
* prog = array->ptrs[index];
|
||||||
@@ -1348,13 +1337,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
|||||||
/* ltg %r1,prog(%b2,%r1) */
|
/* ltg %r1,prog(%b2,%r1) */
|
||||||
EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2,
|
EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2,
|
||||||
REG_1, offsetof(struct bpf_array, ptrs));
|
REG_1, offsetof(struct bpf_array, ptrs));
|
||||||
if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
|
/* brc 0x8,out */
|
||||||
/* brc 0x8,label0 */
|
patch_3_brc = jit->prg;
|
||||||
EMIT4_PCREL_RIC(0xa7040000, 0x8, jit->labels[0]);
|
EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg);
|
||||||
} else {
|
|
||||||
/* brcl 0x8,label0 */
|
|
||||||
EMIT6_PCREL_RILC(0xc0040000, 0x8, jit->labels[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore registers before calling function
|
* Restore registers before calling function
|
||||||
@@ -1371,8 +1356,16 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
|||||||
/* bc 0xf,tail_call_start(%r1) */
|
/* bc 0xf,tail_call_start(%r1) */
|
||||||
_EMIT4(0x47f01000 + jit->tail_call_start);
|
_EMIT4(0x47f01000 + jit->tail_call_start);
|
||||||
/* out: */
|
/* out: */
|
||||||
jit->labels[0] = jit->prg;
|
if (jit->prg_buf) {
|
||||||
|
*(u16 *)(jit->prg_buf + patch_1_clrj + 2) =
|
||||||
|
(jit->prg - patch_1_clrj) >> 1;
|
||||||
|
*(u16 *)(jit->prg_buf + patch_2_clij + 2) =
|
||||||
|
(jit->prg - patch_2_clij) >> 1;
|
||||||
|
*(u16 *)(jit->prg_buf + patch_3_brc + 2) =
|
||||||
|
(jit->prg - patch_3_brc) >> 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case BPF_JMP | BPF_EXIT: /* return b0 */
|
case BPF_JMP | BPF_EXIT: /* return b0 */
|
||||||
last = (i == fp->len - 1) ? 1 : 0;
|
last = (i == fp->len - 1) ? 1 : 0;
|
||||||
if (last)
|
if (last)
|
||||||
|
@@ -314,19 +314,19 @@ static inline void mds_idle_clear_cpu_buffers(void)
|
|||||||
* lfence
|
* lfence
|
||||||
* jmp spec_trap
|
* jmp spec_trap
|
||||||
* do_rop:
|
* do_rop:
|
||||||
* mov %rax,(%rsp) for x86_64
|
* mov %rcx,(%rsp) for x86_64
|
||||||
* mov %edx,(%esp) for x86_32
|
* mov %edx,(%esp) for x86_32
|
||||||
* retq
|
* retq
|
||||||
*
|
*
|
||||||
* Without retpolines configured:
|
* Without retpolines configured:
|
||||||
*
|
*
|
||||||
* jmp *%rax for x86_64
|
* jmp *%rcx for x86_64
|
||||||
* jmp *%edx for x86_32
|
* jmp *%edx for x86_32
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_RETPOLINE
|
#ifdef CONFIG_RETPOLINE
|
||||||
# ifdef CONFIG_X86_64
|
# ifdef CONFIG_X86_64
|
||||||
# define RETPOLINE_RAX_BPF_JIT_SIZE 17
|
# define RETPOLINE_RCX_BPF_JIT_SIZE 17
|
||||||
# define RETPOLINE_RAX_BPF_JIT() \
|
# define RETPOLINE_RCX_BPF_JIT() \
|
||||||
do { \
|
do { \
|
||||||
EMIT1_off32(0xE8, 7); /* callq do_rop */ \
|
EMIT1_off32(0xE8, 7); /* callq do_rop */ \
|
||||||
/* spec_trap: */ \
|
/* spec_trap: */ \
|
||||||
@@ -334,7 +334,7 @@ do { \
|
|||||||
EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \
|
EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \
|
||||||
EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \
|
EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \
|
||||||
/* do_rop: */ \
|
/* do_rop: */ \
|
||||||
EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \
|
EMIT4(0x48, 0x89, 0x0C, 0x24); /* mov %rcx,(%rsp) */ \
|
||||||
EMIT1(0xC3); /* retq */ \
|
EMIT1(0xC3); /* retq */ \
|
||||||
} while (0)
|
} while (0)
|
||||||
# else /* !CONFIG_X86_64 */
|
# else /* !CONFIG_X86_64 */
|
||||||
@@ -352,9 +352,9 @@ do { \
|
|||||||
# endif
|
# endif
|
||||||
#else /* !CONFIG_RETPOLINE */
|
#else /* !CONFIG_RETPOLINE */
|
||||||
# ifdef CONFIG_X86_64
|
# ifdef CONFIG_X86_64
|
||||||
# define RETPOLINE_RAX_BPF_JIT_SIZE 2
|
# define RETPOLINE_RCX_BPF_JIT_SIZE 2
|
||||||
# define RETPOLINE_RAX_BPF_JIT() \
|
# define RETPOLINE_RCX_BPF_JIT() \
|
||||||
EMIT2(0xFF, 0xE0); /* jmp *%rax */
|
EMIT2(0xFF, 0xE1); /* jmp *%rcx */
|
||||||
# else /* !CONFIG_X86_64 */
|
# else /* !CONFIG_X86_64 */
|
||||||
# define RETPOLINE_EDX_BPF_JIT() \
|
# define RETPOLINE_EDX_BPF_JIT() \
|
||||||
EMIT2(0xFF, 0xE2) /* jmp *%edx */
|
EMIT2(0xFF, 0xE2) /* jmp *%edx */
|
||||||
|
@@ -221,14 +221,48 @@ struct jit_context {
|
|||||||
|
|
||||||
/* Number of bytes emit_patch() needs to generate instructions */
|
/* Number of bytes emit_patch() needs to generate instructions */
|
||||||
#define X86_PATCH_SIZE 5
|
#define X86_PATCH_SIZE 5
|
||||||
|
/* Number of bytes that will be skipped on tailcall */
|
||||||
|
#define X86_TAIL_CALL_OFFSET 11
|
||||||
|
|
||||||
#define PROLOGUE_SIZE 25
|
static void push_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||||
|
{
|
||||||
|
u8 *prog = *pprog;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
if (callee_regs_used[0])
|
||||||
|
EMIT1(0x53); /* push rbx */
|
||||||
|
if (callee_regs_used[1])
|
||||||
|
EMIT2(0x41, 0x55); /* push r13 */
|
||||||
|
if (callee_regs_used[2])
|
||||||
|
EMIT2(0x41, 0x56); /* push r14 */
|
||||||
|
if (callee_regs_used[3])
|
||||||
|
EMIT2(0x41, 0x57); /* push r15 */
|
||||||
|
*pprog = prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pop_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||||
|
{
|
||||||
|
u8 *prog = *pprog;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
if (callee_regs_used[3])
|
||||||
|
EMIT2(0x41, 0x5F); /* pop r15 */
|
||||||
|
if (callee_regs_used[2])
|
||||||
|
EMIT2(0x41, 0x5E); /* pop r14 */
|
||||||
|
if (callee_regs_used[1])
|
||||||
|
EMIT2(0x41, 0x5D); /* pop r13 */
|
||||||
|
if (callee_regs_used[0])
|
||||||
|
EMIT1(0x5B); /* pop rbx */
|
||||||
|
*pprog = prog;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit x86-64 prologue code for BPF program and check its size.
|
* Emit x86-64 prologue code for BPF program.
|
||||||
* bpf_tail_call helper will skip it while jumping into another program
|
* bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes
|
||||||
|
* while jumping to another program
|
||||||
*/
|
*/
|
||||||
static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf)
|
static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
|
||||||
|
bool tail_call_reachable, bool is_subprog)
|
||||||
{
|
{
|
||||||
u8 *prog = *pprog;
|
u8 *prog = *pprog;
|
||||||
int cnt = X86_PATCH_SIZE;
|
int cnt = X86_PATCH_SIZE;
|
||||||
@@ -238,19 +272,19 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf)
|
|||||||
*/
|
*/
|
||||||
memcpy(prog, ideal_nops[NOP_ATOMIC5], cnt);
|
memcpy(prog, ideal_nops[NOP_ATOMIC5], cnt);
|
||||||
prog += cnt;
|
prog += cnt;
|
||||||
|
if (!ebpf_from_cbpf) {
|
||||||
|
if (tail_call_reachable && !is_subprog)
|
||||||
|
EMIT2(0x31, 0xC0); /* xor eax, eax */
|
||||||
|
else
|
||||||
|
EMIT2(0x66, 0x90); /* nop2 */
|
||||||
|
}
|
||||||
EMIT1(0x55); /* push rbp */
|
EMIT1(0x55); /* push rbp */
|
||||||
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
||||||
/* sub rsp, rounded_stack_depth */
|
/* sub rsp, rounded_stack_depth */
|
||||||
|
if (stack_depth)
|
||||||
EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8));
|
EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8));
|
||||||
EMIT1(0x53); /* push rbx */
|
if (tail_call_reachable)
|
||||||
EMIT2(0x41, 0x55); /* push r13 */
|
EMIT1(0x50); /* push rax */
|
||||||
EMIT2(0x41, 0x56); /* push r14 */
|
|
||||||
EMIT2(0x41, 0x57); /* push r15 */
|
|
||||||
if (!ebpf_from_cbpf) {
|
|
||||||
/* zero init tail_call_cnt */
|
|
||||||
EMIT2(0x6a, 0x00);
|
|
||||||
BUILD_BUG_ON(cnt != PROLOGUE_SIZE);
|
|
||||||
}
|
|
||||||
*pprog = prog;
|
*pprog = prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,13 +348,14 @@ static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
|
|||||||
mutex_lock(&text_mutex);
|
mutex_lock(&text_mutex);
|
||||||
if (memcmp(ip, old_insn, X86_PATCH_SIZE))
|
if (memcmp(ip, old_insn, X86_PATCH_SIZE))
|
||||||
goto out;
|
goto out;
|
||||||
|
ret = 1;
|
||||||
if (memcmp(ip, new_insn, X86_PATCH_SIZE)) {
|
if (memcmp(ip, new_insn, X86_PATCH_SIZE)) {
|
||||||
if (text_live)
|
if (text_live)
|
||||||
text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
|
text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
|
||||||
else
|
else
|
||||||
memcpy(ip, new_insn, X86_PATCH_SIZE);
|
memcpy(ip, new_insn, X86_PATCH_SIZE);
|
||||||
}
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&text_mutex);
|
mutex_unlock(&text_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -337,6 +372,22 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
|
|||||||
return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true);
|
return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_pop_bytes(bool *callee_regs_used)
|
||||||
|
{
|
||||||
|
int bytes = 0;
|
||||||
|
|
||||||
|
if (callee_regs_used[3])
|
||||||
|
bytes += 2;
|
||||||
|
if (callee_regs_used[2])
|
||||||
|
bytes += 2;
|
||||||
|
if (callee_regs_used[1])
|
||||||
|
bytes += 2;
|
||||||
|
if (callee_regs_used[0])
|
||||||
|
bytes += 1;
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate the following code:
|
* Generate the following code:
|
||||||
*
|
*
|
||||||
@@ -351,12 +402,32 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
|
|||||||
* goto *(prog->bpf_func + prologue_size);
|
* goto *(prog->bpf_func + prologue_size);
|
||||||
* out:
|
* out:
|
||||||
*/
|
*/
|
||||||
static void emit_bpf_tail_call_indirect(u8 **pprog)
|
static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||||
|
u32 stack_depth)
|
||||||
{
|
{
|
||||||
|
int tcc_off = -4 - round_up(stack_depth, 8);
|
||||||
u8 *prog = *pprog;
|
u8 *prog = *pprog;
|
||||||
int label1, label2, label3;
|
int pop_bytes = 0;
|
||||||
|
int off1 = 42;
|
||||||
|
int off2 = 31;
|
||||||
|
int off3 = 9;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
|
/* count the additional bytes used for popping callee regs from stack
|
||||||
|
* that need to be taken into account for each of the offsets that
|
||||||
|
* are used for bailing out of the tail call
|
||||||
|
*/
|
||||||
|
pop_bytes = get_pop_bytes(callee_regs_used);
|
||||||
|
off1 += pop_bytes;
|
||||||
|
off2 += pop_bytes;
|
||||||
|
off3 += pop_bytes;
|
||||||
|
|
||||||
|
if (stack_depth) {
|
||||||
|
off1 += 7;
|
||||||
|
off2 += 7;
|
||||||
|
off3 += 7;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rdi - pointer to ctx
|
* rdi - pointer to ctx
|
||||||
* rsi - pointer to bpf_array
|
* rsi - pointer to bpf_array
|
||||||
@@ -370,72 +441,112 @@ static void emit_bpf_tail_call_indirect(u8 **pprog)
|
|||||||
EMIT2(0x89, 0xD2); /* mov edx, edx */
|
EMIT2(0x89, 0xD2); /* mov edx, edx */
|
||||||
EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */
|
EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */
|
||||||
offsetof(struct bpf_array, map.max_entries));
|
offsetof(struct bpf_array, map.max_entries));
|
||||||
#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* Number of bytes to jump */
|
#define OFFSET1 (off1 + RETPOLINE_RCX_BPF_JIT_SIZE) /* Number of bytes to jump */
|
||||||
EMIT2(X86_JBE, OFFSET1); /* jbe out */
|
EMIT2(X86_JBE, OFFSET1); /* jbe out */
|
||||||
label1 = cnt;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
|
* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
|
||||||
* goto out;
|
* goto out;
|
||||||
*/
|
*/
|
||||||
EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */
|
EMIT2_off32(0x8B, 0x85, tcc_off); /* mov eax, dword ptr [rbp - tcc_off] */
|
||||||
EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
|
EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
|
||||||
#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE)
|
#define OFFSET2 (off2 + RETPOLINE_RCX_BPF_JIT_SIZE)
|
||||||
EMIT2(X86_JA, OFFSET2); /* ja out */
|
EMIT2(X86_JA, OFFSET2); /* ja out */
|
||||||
label2 = cnt;
|
|
||||||
EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
|
EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
|
||||||
EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */
|
EMIT2_off32(0x89, 0x85, tcc_off); /* mov dword ptr [rbp - tcc_off], eax */
|
||||||
|
|
||||||
/* prog = array->ptrs[index]; */
|
/* prog = array->ptrs[index]; */
|
||||||
EMIT4_off32(0x48, 0x8B, 0x84, 0xD6, /* mov rax, [rsi + rdx * 8 + offsetof(...)] */
|
EMIT4_off32(0x48, 0x8B, 0x8C, 0xD6, /* mov rcx, [rsi + rdx * 8 + offsetof(...)] */
|
||||||
offsetof(struct bpf_array, ptrs));
|
offsetof(struct bpf_array, ptrs));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if (prog == NULL)
|
* if (prog == NULL)
|
||||||
* goto out;
|
* goto out;
|
||||||
*/
|
*/
|
||||||
EMIT3(0x48, 0x85, 0xC0); /* test rax,rax */
|
EMIT3(0x48, 0x85, 0xC9); /* test rcx,rcx */
|
||||||
#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE)
|
#define OFFSET3 (off3 + RETPOLINE_RCX_BPF_JIT_SIZE)
|
||||||
EMIT2(X86_JE, OFFSET3); /* je out */
|
EMIT2(X86_JE, OFFSET3); /* je out */
|
||||||
label3 = cnt;
|
|
||||||
|
|
||||||
/* goto *(prog->bpf_func + prologue_size); */
|
*pprog = prog;
|
||||||
EMIT4(0x48, 0x8B, 0x40, /* mov rax, qword ptr [rax + 32] */
|
pop_callee_regs(pprog, callee_regs_used);
|
||||||
|
prog = *pprog;
|
||||||
|
|
||||||
|
EMIT1(0x58); /* pop rax */
|
||||||
|
if (stack_depth)
|
||||||
|
EMIT3_off32(0x48, 0x81, 0xC4, /* add rsp, sd */
|
||||||
|
round_up(stack_depth, 8));
|
||||||
|
|
||||||
|
/* goto *(prog->bpf_func + X86_TAIL_CALL_OFFSET); */
|
||||||
|
EMIT4(0x48, 0x8B, 0x49, /* mov rcx, qword ptr [rcx + 32] */
|
||||||
offsetof(struct bpf_prog, bpf_func));
|
offsetof(struct bpf_prog, bpf_func));
|
||||||
EMIT4(0x48, 0x83, 0xC0, PROLOGUE_SIZE); /* add rax, prologue_size */
|
EMIT4(0x48, 0x83, 0xC1, /* add rcx, X86_TAIL_CALL_OFFSET */
|
||||||
|
X86_TAIL_CALL_OFFSET);
|
||||||
/*
|
/*
|
||||||
* Wow we're ready to jump into next BPF program
|
* Now we're ready to jump into next BPF program
|
||||||
* rdi == ctx (1st arg)
|
* rdi == ctx (1st arg)
|
||||||
* rax == prog->bpf_func + prologue_size
|
* rcx == prog->bpf_func + X86_TAIL_CALL_OFFSET
|
||||||
*/
|
*/
|
||||||
RETPOLINE_RAX_BPF_JIT();
|
RETPOLINE_RCX_BPF_JIT();
|
||||||
|
|
||||||
/* out: */
|
/* out: */
|
||||||
BUILD_BUG_ON(cnt - label1 != OFFSET1);
|
|
||||||
BUILD_BUG_ON(cnt - label2 != OFFSET2);
|
|
||||||
BUILD_BUG_ON(cnt - label3 != OFFSET3);
|
|
||||||
*pprog = prog;
|
*pprog = prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke,
|
static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke,
|
||||||
u8 **pprog, int addr, u8 *image)
|
u8 **pprog, int addr, u8 *image,
|
||||||
|
bool *callee_regs_used, u32 stack_depth)
|
||||||
{
|
{
|
||||||
|
int tcc_off = -4 - round_up(stack_depth, 8);
|
||||||
u8 *prog = *pprog;
|
u8 *prog = *pprog;
|
||||||
|
int pop_bytes = 0;
|
||||||
|
int off1 = 20;
|
||||||
|
int poke_off;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
|
/* count the additional bytes used for popping callee regs to stack
|
||||||
|
* that need to be taken into account for jump offset that is used for
|
||||||
|
* bailing out from of the tail call when limit is reached
|
||||||
|
*/
|
||||||
|
pop_bytes = get_pop_bytes(callee_regs_used);
|
||||||
|
off1 += pop_bytes;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* total bytes for:
|
||||||
|
* - nop5/ jmpq $off
|
||||||
|
* - pop callee regs
|
||||||
|
* - sub rsp, $val if depth > 0
|
||||||
|
* - pop rax
|
||||||
|
*/
|
||||||
|
poke_off = X86_PATCH_SIZE + pop_bytes + 1;
|
||||||
|
if (stack_depth) {
|
||||||
|
poke_off += 7;
|
||||||
|
off1 += 7;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
|
* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
|
||||||
* goto out;
|
* goto out;
|
||||||
*/
|
*/
|
||||||
EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */
|
EMIT2_off32(0x8B, 0x85, tcc_off); /* mov eax, dword ptr [rbp - tcc_off] */
|
||||||
EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
|
EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
|
||||||
EMIT2(X86_JA, 14); /* ja out */
|
EMIT2(X86_JA, off1); /* ja out */
|
||||||
EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
|
EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
|
||||||
EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */
|
EMIT2_off32(0x89, 0x85, tcc_off); /* mov dword ptr [rbp - tcc_off], eax */
|
||||||
|
|
||||||
poke->ip = image + (addr - X86_PATCH_SIZE);
|
poke->tailcall_bypass = image + (addr - poke_off - X86_PATCH_SIZE);
|
||||||
poke->adj_off = PROLOGUE_SIZE;
|
poke->adj_off = X86_TAIL_CALL_OFFSET;
|
||||||
|
poke->tailcall_target = image + (addr - X86_PATCH_SIZE);
|
||||||
|
poke->bypass_addr = (u8 *)poke->tailcall_target + X86_PATCH_SIZE;
|
||||||
|
|
||||||
|
emit_jump(&prog, (u8 *)poke->tailcall_target + X86_PATCH_SIZE,
|
||||||
|
poke->tailcall_bypass);
|
||||||
|
|
||||||
|
*pprog = prog;
|
||||||
|
pop_callee_regs(pprog, callee_regs_used);
|
||||||
|
prog = *pprog;
|
||||||
|
EMIT1(0x58); /* pop rax */
|
||||||
|
if (stack_depth)
|
||||||
|
EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8));
|
||||||
|
|
||||||
memcpy(prog, ideal_nops[NOP_ATOMIC5], X86_PATCH_SIZE);
|
memcpy(prog, ideal_nops[NOP_ATOMIC5], X86_PATCH_SIZE);
|
||||||
prog += X86_PATCH_SIZE;
|
prog += X86_PATCH_SIZE;
|
||||||
@@ -453,7 +564,7 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog)
|
|||||||
|
|
||||||
for (i = 0; i < prog->aux->size_poke_tab; i++) {
|
for (i = 0; i < prog->aux->size_poke_tab; i++) {
|
||||||
poke = &prog->aux->poke_tab[i];
|
poke = &prog->aux->poke_tab[i];
|
||||||
WARN_ON_ONCE(READ_ONCE(poke->ip_stable));
|
WARN_ON_ONCE(READ_ONCE(poke->tailcall_target_stable));
|
||||||
|
|
||||||
if (poke->reason != BPF_POKE_REASON_TAIL_CALL)
|
if (poke->reason != BPF_POKE_REASON_TAIL_CALL)
|
||||||
continue;
|
continue;
|
||||||
@@ -464,18 +575,25 @@ static void bpf_tail_call_direct_fixup(struct bpf_prog *prog)
|
|||||||
if (target) {
|
if (target) {
|
||||||
/* Plain memcpy is used when image is not live yet
|
/* Plain memcpy is used when image is not live yet
|
||||||
* and still not locked as read-only. Once poke
|
* and still not locked as read-only. Once poke
|
||||||
* location is active (poke->ip_stable), any parallel
|
* location is active (poke->tailcall_target_stable),
|
||||||
* bpf_arch_text_poke() might occur still on the
|
* any parallel bpf_arch_text_poke() might occur
|
||||||
* read-write image until we finally locked it as
|
* still on the read-write image until we finally
|
||||||
* read-only. Both modifications on the given image
|
* locked it as read-only. Both modifications on
|
||||||
* are under text_mutex to avoid interference.
|
* the given image are under text_mutex to avoid
|
||||||
|
* interference.
|
||||||
*/
|
*/
|
||||||
ret = __bpf_arch_text_poke(poke->ip, BPF_MOD_JUMP, NULL,
|
ret = __bpf_arch_text_poke(poke->tailcall_target,
|
||||||
|
BPF_MOD_JUMP, NULL,
|
||||||
(u8 *)target->bpf_func +
|
(u8 *)target->bpf_func +
|
||||||
poke->adj_off, false);
|
poke->adj_off, false);
|
||||||
BUG_ON(ret < 0);
|
BUG_ON(ret < 0);
|
||||||
|
ret = __bpf_arch_text_poke(poke->tailcall_bypass,
|
||||||
|
BPF_MOD_JUMP,
|
||||||
|
(u8 *)poke->tailcall_target +
|
||||||
|
X86_PATCH_SIZE, NULL, false);
|
||||||
|
BUG_ON(ret < 0);
|
||||||
}
|
}
|
||||||
WRITE_ONCE(poke->ip_stable, true);
|
WRITE_ONCE(poke->tailcall_target_stable, true);
|
||||||
mutex_unlock(&array->aux->poke_mutex);
|
mutex_unlock(&array->aux->poke_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -652,19 +770,49 @@ static bool ex_handler_bpf(const struct exception_table_entry *x,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void detect_reg_usage(struct bpf_insn *insn, int insn_cnt,
|
||||||
|
bool *regs_used, bool *tail_call_seen)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i <= insn_cnt; i++, insn++) {
|
||||||
|
if (insn->code == (BPF_JMP | BPF_TAIL_CALL))
|
||||||
|
*tail_call_seen = true;
|
||||||
|
if (insn->dst_reg == BPF_REG_6 || insn->src_reg == BPF_REG_6)
|
||||||
|
regs_used[0] = true;
|
||||||
|
if (insn->dst_reg == BPF_REG_7 || insn->src_reg == BPF_REG_7)
|
||||||
|
regs_used[1] = true;
|
||||||
|
if (insn->dst_reg == BPF_REG_8 || insn->src_reg == BPF_REG_8)
|
||||||
|
regs_used[2] = true;
|
||||||
|
if (insn->dst_reg == BPF_REG_9 || insn->src_reg == BPF_REG_9)
|
||||||
|
regs_used[3] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||||
int oldproglen, struct jit_context *ctx)
|
int oldproglen, struct jit_context *ctx)
|
||||||
{
|
{
|
||||||
|
bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
|
||||||
struct bpf_insn *insn = bpf_prog->insnsi;
|
struct bpf_insn *insn = bpf_prog->insnsi;
|
||||||
|
bool callee_regs_used[4] = {};
|
||||||
int insn_cnt = bpf_prog->len;
|
int insn_cnt = bpf_prog->len;
|
||||||
|
bool tail_call_seen = false;
|
||||||
bool seen_exit = false;
|
bool seen_exit = false;
|
||||||
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
|
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
|
||||||
int i, cnt = 0, excnt = 0;
|
int i, cnt = 0, excnt = 0;
|
||||||
int proglen = 0;
|
int proglen = 0;
|
||||||
u8 *prog = temp;
|
u8 *prog = temp;
|
||||||
|
|
||||||
|
detect_reg_usage(insn, insn_cnt, callee_regs_used,
|
||||||
|
&tail_call_seen);
|
||||||
|
|
||||||
|
/* tail call's presence in current prog implies it is reachable */
|
||||||
|
tail_call_reachable |= tail_call_seen;
|
||||||
|
|
||||||
emit_prologue(&prog, bpf_prog->aux->stack_depth,
|
emit_prologue(&prog, bpf_prog->aux->stack_depth,
|
||||||
bpf_prog_was_classic(bpf_prog));
|
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
|
||||||
|
bpf_prog->aux->func_idx != 0);
|
||||||
|
push_callee_regs(&prog, callee_regs_used);
|
||||||
addrs[0] = prog - temp;
|
addrs[0] = prog - temp;
|
||||||
|
|
||||||
for (i = 1; i <= insn_cnt; i++, insn++) {
|
for (i = 1; i <= insn_cnt; i++, insn++) {
|
||||||
@@ -1102,16 +1250,27 @@ xadd: if (is_imm8(insn->off))
|
|||||||
/* call */
|
/* call */
|
||||||
case BPF_JMP | BPF_CALL:
|
case BPF_JMP | BPF_CALL:
|
||||||
func = (u8 *) __bpf_call_base + imm32;
|
func = (u8 *) __bpf_call_base + imm32;
|
||||||
|
if (tail_call_reachable) {
|
||||||
|
EMIT3_off32(0x48, 0x8B, 0x85,
|
||||||
|
-(bpf_prog->aux->stack_depth + 8));
|
||||||
|
if (!imm32 || emit_call(&prog, func, image + addrs[i - 1] + 7))
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
if (!imm32 || emit_call(&prog, func, image + addrs[i - 1]))
|
if (!imm32 || emit_call(&prog, func, image + addrs[i - 1]))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BPF_JMP | BPF_TAIL_CALL:
|
case BPF_JMP | BPF_TAIL_CALL:
|
||||||
if (imm32)
|
if (imm32)
|
||||||
emit_bpf_tail_call_direct(&bpf_prog->aux->poke_tab[imm32 - 1],
|
emit_bpf_tail_call_direct(&bpf_prog->aux->poke_tab[imm32 - 1],
|
||||||
&prog, addrs[i], image);
|
&prog, addrs[i], image,
|
||||||
|
callee_regs_used,
|
||||||
|
bpf_prog->aux->stack_depth);
|
||||||
else
|
else
|
||||||
emit_bpf_tail_call_indirect(&prog);
|
emit_bpf_tail_call_indirect(&prog,
|
||||||
|
callee_regs_used,
|
||||||
|
bpf_prog->aux->stack_depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* cond jump */
|
/* cond jump */
|
||||||
@@ -1294,12 +1453,7 @@ emit_jmp:
|
|||||||
seen_exit = true;
|
seen_exit = true;
|
||||||
/* Update cleanup_addr */
|
/* Update cleanup_addr */
|
||||||
ctx->cleanup_addr = proglen;
|
ctx->cleanup_addr = proglen;
|
||||||
if (!bpf_prog_was_classic(bpf_prog))
|
pop_callee_regs(&prog, callee_regs_used);
|
||||||
EMIT1(0x5B); /* get rid of tail_call_cnt */
|
|
||||||
EMIT2(0x41, 0x5F); /* pop r15 */
|
|
||||||
EMIT2(0x41, 0x5E); /* pop r14 */
|
|
||||||
EMIT2(0x41, 0x5D); /* pop r13 */
|
|
||||||
EMIT1(0x5B); /* pop rbx */
|
|
||||||
EMIT1(0xC9); /* leave */
|
EMIT1(0xC9); /* leave */
|
||||||
EMIT1(0xC3); /* ret */
|
EMIT1(0xC3); /* ret */
|
||||||
break;
|
break;
|
||||||
@@ -1379,10 +1533,15 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
|
|||||||
u8 *prog = *pprog;
|
u8 *prog = *pprog;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
|
if (p->aux->sleepable) {
|
||||||
|
if (emit_call(&prog, __bpf_prog_enter_sleepable, prog))
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
if (emit_call(&prog, __bpf_prog_enter, prog))
|
if (emit_call(&prog, __bpf_prog_enter, prog))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
/* remember prog start time returned by __bpf_prog_enter */
|
/* remember prog start time returned by __bpf_prog_enter */
|
||||||
emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0);
|
emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0);
|
||||||
|
}
|
||||||
|
|
||||||
/* arg1: lea rdi, [rbp - stack_size] */
|
/* arg1: lea rdi, [rbp - stack_size] */
|
||||||
EMIT4(0x48, 0x8D, 0x7D, -stack_size);
|
EMIT4(0x48, 0x8D, 0x7D, -stack_size);
|
||||||
@@ -1402,6 +1561,10 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
|
|||||||
if (mod_ret)
|
if (mod_ret)
|
||||||
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8);
|
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8);
|
||||||
|
|
||||||
|
if (p->aux->sleepable) {
|
||||||
|
if (emit_call(&prog, __bpf_prog_exit_sleepable, prog))
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
/* arg1: mov rdi, progs[i] */
|
/* arg1: mov rdi, progs[i] */
|
||||||
emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32,
|
emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32,
|
||||||
(u32) (long) p);
|
(u32) (long) p);
|
||||||
@@ -1409,6 +1572,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
|
|||||||
emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6);
|
emit_mov_reg(&prog, true, BPF_REG_2, BPF_REG_6);
|
||||||
if (emit_call(&prog, __bpf_prog_exit, prog))
|
if (emit_call(&prog, __bpf_prog_exit, prog))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
*pprog = prog;
|
*pprog = prog;
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -327,7 +327,7 @@ done:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static struct atmdev_ops atmtcp_v_dev_ops = {
|
static const struct atmdev_ops atmtcp_v_dev_ops = {
|
||||||
.dev_close = atmtcp_v_dev_close,
|
.dev_close = atmtcp_v_dev_close,
|
||||||
.open = atmtcp_v_open,
|
.open = atmtcp_v_open,
|
||||||
.close = atmtcp_v_close,
|
.close = atmtcp_v_close,
|
||||||
|
@@ -419,12 +419,12 @@ void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
|
|||||||
pc_host->pci_ops.read = bcma_core_pci_hostmode_read_config;
|
pc_host->pci_ops.read = bcma_core_pci_hostmode_read_config;
|
||||||
pc_host->pci_ops.write = bcma_core_pci_hostmode_write_config;
|
pc_host->pci_ops.write = bcma_core_pci_hostmode_write_config;
|
||||||
|
|
||||||
pc_host->mem_resource.name = "BCMA PCIcore external memory",
|
pc_host->mem_resource.name = "BCMA PCIcore external memory";
|
||||||
pc_host->mem_resource.start = BCMA_SOC_PCI_DMA;
|
pc_host->mem_resource.start = BCMA_SOC_PCI_DMA;
|
||||||
pc_host->mem_resource.end = BCMA_SOC_PCI_DMA + BCMA_SOC_PCI_DMA_SZ - 1;
|
pc_host->mem_resource.end = BCMA_SOC_PCI_DMA + BCMA_SOC_PCI_DMA_SZ - 1;
|
||||||
pc_host->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
|
pc_host->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
|
||||||
|
|
||||||
pc_host->io_resource.name = "BCMA PCIcore external I/O",
|
pc_host->io_resource.name = "BCMA PCIcore external I/O";
|
||||||
pc_host->io_resource.start = 0x100;
|
pc_host->io_resource.start = 0x100;
|
||||||
pc_host->io_resource.end = 0x7FF;
|
pc_host->io_resource.end = 0x7FF;
|
||||||
pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
|
pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
|
||||||
|
@@ -2184,7 +2184,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct genl_ops nbd_connect_genl_ops[] = {
|
static const struct genl_small_ops nbd_connect_genl_ops[] = {
|
||||||
{
|
{
|
||||||
.cmd = NBD_CMD_CONNECT,
|
.cmd = NBD_CMD_CONNECT,
|
||||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||||
@@ -2216,8 +2216,8 @@ static struct genl_family nbd_genl_family __ro_after_init = {
|
|||||||
.name = NBD_GENL_FAMILY_NAME,
|
.name = NBD_GENL_FAMILY_NAME,
|
||||||
.version = NBD_GENL_VERSION,
|
.version = NBD_GENL_VERSION,
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.ops = nbd_connect_genl_ops,
|
.small_ops = nbd_connect_genl_ops,
|
||||||
.n_ops = ARRAY_SIZE(nbd_connect_genl_ops),
|
.n_small_ops = ARRAY_SIZE(nbd_connect_genl_ops),
|
||||||
.maxattr = NBD_ATTR_MAX,
|
.maxattr = NBD_ATTR_MAX,
|
||||||
.policy = nbd_attr_policy,
|
.policy = nbd_attr_policy,
|
||||||
.mcgrps = nbd_mcast_grps,
|
.mcgrps = nbd_mcast_grps,
|
||||||
|
@@ -19,6 +19,10 @@
|
|||||||
#define VERSION "0.1"
|
#define VERSION "0.1"
|
||||||
|
|
||||||
#define BDADDR_INTEL (&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
|
#define BDADDR_INTEL (&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
|
||||||
|
#define RSA_HEADER_LEN 644
|
||||||
|
#define CSS_HEADER_OFFSET 8
|
||||||
|
#define ECDSA_OFFSET 644
|
||||||
|
#define ECDSA_HEADER_LEN 320
|
||||||
|
|
||||||
int btintel_check_bdaddr(struct hci_dev *hdev)
|
int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
@@ -360,6 +364,144 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(btintel_read_version);
|
EXPORT_SYMBOL_GPL(btintel_read_version);
|
||||||
|
|
||||||
|
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
|
||||||
|
{
|
||||||
|
const char *variant;
|
||||||
|
|
||||||
|
switch (version->img_type) {
|
||||||
|
case 0x01:
|
||||||
|
variant = "Bootloader";
|
||||||
|
bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id);
|
||||||
|
bt_dev_info(hdev, "Secure boot is %s",
|
||||||
|
version->secure_boot ? "enabled" : "disabled");
|
||||||
|
bt_dev_info(hdev, "OTP lock is %s",
|
||||||
|
version->otp_lock ? "enabled" : "disabled");
|
||||||
|
bt_dev_info(hdev, "API lock is %s",
|
||||||
|
version->api_lock ? "enabled" : "disabled");
|
||||||
|
bt_dev_info(hdev, "Debug lock is %s",
|
||||||
|
version->debug_lock ? "enabled" : "disabled");
|
||||||
|
bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
|
||||||
|
version->min_fw_build_nn, version->min_fw_build_cw,
|
||||||
|
2000 + version->min_fw_build_yy);
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
variant = "Firmware";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
|
||||||
|
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
|
||||||
|
version->build_type, version->build_num);
|
||||||
|
|
||||||
|
done:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(btintel_version_info_tlv);
|
||||||
|
|
||||||
|
int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
const u8 param[1] = { 0xFF };
|
||||||
|
|
||||||
|
if (!version)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
|
||||||
|
PTR_ERR(skb));
|
||||||
|
return PTR_ERR(skb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skb->data[0]) {
|
||||||
|
bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
|
||||||
|
skb->data[0]);
|
||||||
|
kfree_skb(skb);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume Command Complete Status field */
|
||||||
|
skb_pull(skb, 1);
|
||||||
|
|
||||||
|
/* Event parameters contatin multiple TLVs. Read each of them
|
||||||
|
* and only keep the required data. Also, it use existing legacy
|
||||||
|
* version field like hw_platform, hw_variant, and fw_variant
|
||||||
|
* to keep the existing setup flow
|
||||||
|
*/
|
||||||
|
while (skb->len) {
|
||||||
|
struct intel_tlv *tlv;
|
||||||
|
|
||||||
|
tlv = (struct intel_tlv *)skb->data;
|
||||||
|
switch (tlv->type) {
|
||||||
|
case INTEL_TLV_CNVI_TOP:
|
||||||
|
version->cnvi_top = get_unaligned_le32(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_CNVR_TOP:
|
||||||
|
version->cnvr_top = get_unaligned_le32(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_CNVI_BT:
|
||||||
|
version->cnvi_bt = get_unaligned_le32(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_CNVR_BT:
|
||||||
|
version->cnvr_bt = get_unaligned_le32(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_DEV_REV_ID:
|
||||||
|
version->dev_rev_id = get_unaligned_le16(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_IMAGE_TYPE:
|
||||||
|
version->img_type = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_TIME_STAMP:
|
||||||
|
version->timestamp = get_unaligned_le16(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_BUILD_TYPE:
|
||||||
|
version->build_type = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_BUILD_NUM:
|
||||||
|
version->build_num = get_unaligned_le32(tlv->val);
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_SECURE_BOOT:
|
||||||
|
version->secure_boot = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_OTP_LOCK:
|
||||||
|
version->otp_lock = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_API_LOCK:
|
||||||
|
version->api_lock = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_DEBUG_LOCK:
|
||||||
|
version->debug_lock = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_MIN_FW:
|
||||||
|
version->min_fw_build_nn = tlv->val[0];
|
||||||
|
version->min_fw_build_cw = tlv->val[1];
|
||||||
|
version->min_fw_build_yy = tlv->val[2];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_LIMITED_CCE:
|
||||||
|
version->limited_cce = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_SBE_TYPE:
|
||||||
|
version->sbe_type = tlv->val[0];
|
||||||
|
break;
|
||||||
|
case INTEL_TLV_OTP_BDADDR:
|
||||||
|
memcpy(&version->otp_bd_addr, tlv->val, tlv->len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore rest of information */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* consume the current tlv and move to next*/
|
||||||
|
skb_pull(skb, tlv->len + sizeof(*tlv));
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree_skb(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(btintel_read_version_tlv);
|
||||||
|
|
||||||
/* ------- REGMAP IBT SUPPORT ------- */
|
/* ------- REGMAP IBT SUPPORT ------- */
|
||||||
|
|
||||||
#define IBT_REG_MODE_8BIT 0x00
|
#define IBT_REG_MODE_8BIT 0x00
|
||||||
@@ -626,12 +768,10 @@ int btintel_read_boot_params(struct hci_dev *hdev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(btintel_read_boot_params);
|
EXPORT_SYMBOL_GPL(btintel_read_boot_params);
|
||||||
|
|
||||||
int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
|
static int btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev,
|
||||||
u32 *boot_param)
|
const struct firmware *fw)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
const u8 *fw_ptr;
|
|
||||||
u32 frag_len;
|
|
||||||
|
|
||||||
/* Start the firmware download transaction with the Init fragment
|
/* Start the firmware download transaction with the Init fragment
|
||||||
* represented by the 128 bytes of CSS header.
|
* represented by the 128 bytes of CSS header.
|
||||||
@@ -660,8 +800,56 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
fw_ptr = fw->data + 644;
|
done:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
|
||||||
|
const struct firmware *fw)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* Start the firmware download transaction with the Init fragment
|
||||||
|
* represented by the 128 bytes of CSS header.
|
||||||
|
*/
|
||||||
|
err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644);
|
||||||
|
if (err < 0) {
|
||||||
|
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the 96 bytes of public key information from the firmware
|
||||||
|
* as the PKey fragment.
|
||||||
|
*/
|
||||||
|
err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128);
|
||||||
|
if (err < 0) {
|
||||||
|
bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the 96 bytes of signature information from the firmware
|
||||||
|
* as the Sign fragment
|
||||||
|
*/
|
||||||
|
err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224);
|
||||||
|
if (err < 0) {
|
||||||
|
bt_dev_err(hdev, "Failed to send firmware signature (%d)",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btintel_download_firmware_payload(struct hci_dev *hdev,
|
||||||
|
const struct firmware *fw,
|
||||||
|
u32 *boot_param, size_t offset)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const u8 *fw_ptr;
|
||||||
|
u32 frag_len;
|
||||||
|
|
||||||
|
fw_ptr = fw->data + offset;
|
||||||
frag_len = 0;
|
frag_len = 0;
|
||||||
|
err = -EINVAL;
|
||||||
|
|
||||||
while (fw_ptr - fw->data < fw->size) {
|
while (fw_ptr - fw->data < fw->size) {
|
||||||
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||||
@@ -707,8 +895,99 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
|
|||||||
done:
|
done:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btintel_download_firmware(struct hci_dev *hdev,
|
||||||
|
const struct firmware *fw,
|
||||||
|
u32 *boot_param)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return btintel_download_firmware_payload(hdev, fw, boot_param,
|
||||||
|
RSA_HEADER_LEN);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(btintel_download_firmware);
|
EXPORT_SYMBOL_GPL(btintel_download_firmware);
|
||||||
|
|
||||||
|
int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||||
|
const struct firmware *fw, u32 *boot_param,
|
||||||
|
u8 hw_variant, u8 sbe_type)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
u32 css_header_ver;
|
||||||
|
|
||||||
|
/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
|
||||||
|
* only RSA secure boot engine. Hence, the corresponding sfi file will
|
||||||
|
* have RSA header of 644 bytes followed by Command Buffer.
|
||||||
|
*
|
||||||
|
* iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA
|
||||||
|
* secure boot engine. As a result, the corresponding sfi file will
|
||||||
|
* have RSA header of 644, ECDSA header of 320 bytes followed by
|
||||||
|
* Command Buffer.
|
||||||
|
*
|
||||||
|
* CSS Header byte positions 0x08 to 0x0B represent the CSS Header
|
||||||
|
* version: RSA(0x00010000) , ECDSA (0x00020000)
|
||||||
|
*/
|
||||||
|
css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET);
|
||||||
|
if (css_header_ver != 0x00010000) {
|
||||||
|
bt_dev_err(hdev, "Invalid CSS Header version");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hw_variant <= 0x14) {
|
||||||
|
if (sbe_type != 0x00) {
|
||||||
|
bt_dev_err(hdev, "Invalid SBE type for hardware variant (%d)",
|
||||||
|
hw_variant);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
} else if (hw_variant >= 0x17) {
|
||||||
|
/* Check if CSS header for ECDSA follows the RSA header */
|
||||||
|
if (fw->data[ECDSA_OFFSET] != 0x06)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Check if the CSS Header version is ECDSA(0x00020000) */
|
||||||
|
css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET);
|
||||||
|
if (css_header_ver != 0x00020000) {
|
||||||
|
bt_dev_err(hdev, "Invalid CSS Header version");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbe_type == 0x00) {
|
||||||
|
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = btintel_download_firmware_payload(hdev, fw,
|
||||||
|
boot_param,
|
||||||
|
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
} else if (sbe_type == 0x01) {
|
||||||
|
err = btintel_sfi_ecdsa_header_secure_send(hdev, fw);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = btintel_download_firmware_payload(hdev, fw,
|
||||||
|
boot_param,
|
||||||
|
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(btintel_download_firmware_newgen);
|
||||||
|
|
||||||
void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct intel_reset params;
|
struct intel_reset params;
|
||||||
|
@@ -6,6 +6,72 @@
|
|||||||
* Copyright (C) 2015 Intel Corporation
|
* Copyright (C) 2015 Intel Corporation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* List of tlv type */
|
||||||
|
enum {
|
||||||
|
INTEL_TLV_CNVI_TOP = 0x10,
|
||||||
|
INTEL_TLV_CNVR_TOP,
|
||||||
|
INTEL_TLV_CNVI_BT,
|
||||||
|
INTEL_TLV_CNVR_BT,
|
||||||
|
INTEL_TLV_CNVI_OTP,
|
||||||
|
INTEL_TLV_CNVR_OTP,
|
||||||
|
INTEL_TLV_DEV_REV_ID,
|
||||||
|
INTEL_TLV_USB_VENDOR_ID,
|
||||||
|
INTEL_TLV_USB_PRODUCT_ID,
|
||||||
|
INTEL_TLV_PCIE_VENDOR_ID,
|
||||||
|
INTEL_TLV_PCIE_DEVICE_ID,
|
||||||
|
INTEL_TLV_PCIE_SUBSYSTEM_ID,
|
||||||
|
INTEL_TLV_IMAGE_TYPE,
|
||||||
|
INTEL_TLV_TIME_STAMP,
|
||||||
|
INTEL_TLV_BUILD_TYPE,
|
||||||
|
INTEL_TLV_BUILD_NUM,
|
||||||
|
INTEL_TLV_FW_BUILD_PRODUCT,
|
||||||
|
INTEL_TLV_FW_BUILD_HW,
|
||||||
|
INTEL_TLV_FW_STEP,
|
||||||
|
INTEL_TLV_BT_SPEC,
|
||||||
|
INTEL_TLV_MFG_NAME,
|
||||||
|
INTEL_TLV_HCI_REV,
|
||||||
|
INTEL_TLV_LMP_SUBVER,
|
||||||
|
INTEL_TLV_OTP_PATCH_VER,
|
||||||
|
INTEL_TLV_SECURE_BOOT,
|
||||||
|
INTEL_TLV_KEY_FROM_HDR,
|
||||||
|
INTEL_TLV_OTP_LOCK,
|
||||||
|
INTEL_TLV_API_LOCK,
|
||||||
|
INTEL_TLV_DEBUG_LOCK,
|
||||||
|
INTEL_TLV_MIN_FW,
|
||||||
|
INTEL_TLV_LIMITED_CCE,
|
||||||
|
INTEL_TLV_SBE_TYPE,
|
||||||
|
INTEL_TLV_OTP_BDADDR,
|
||||||
|
INTEL_TLV_UNLOCKED_STATE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct intel_tlv {
|
||||||
|
u8 type;
|
||||||
|
u8 len;
|
||||||
|
u8 val[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct intel_version_tlv {
|
||||||
|
u32 cnvi_top;
|
||||||
|
u32 cnvr_top;
|
||||||
|
u32 cnvi_bt;
|
||||||
|
u32 cnvr_bt;
|
||||||
|
u16 dev_rev_id;
|
||||||
|
u8 img_type;
|
||||||
|
u16 timestamp;
|
||||||
|
u8 build_type;
|
||||||
|
u32 build_num;
|
||||||
|
u8 secure_boot;
|
||||||
|
u8 otp_lock;
|
||||||
|
u8 api_lock;
|
||||||
|
u8 debug_lock;
|
||||||
|
u8 min_fw_build_nn;
|
||||||
|
u8 min_fw_build_cw;
|
||||||
|
u8 min_fw_build_yy;
|
||||||
|
u8 limited_cce;
|
||||||
|
u8 sbe_type;
|
||||||
|
bdaddr_t otp_bd_addr;
|
||||||
|
};
|
||||||
|
|
||||||
struct intel_version {
|
struct intel_version {
|
||||||
u8 status;
|
u8 status;
|
||||||
u8 hw_platform;
|
u8 hw_platform;
|
||||||
@@ -77,12 +143,14 @@ int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
|
|||||||
void btintel_hw_error(struct hci_dev *hdev, u8 code);
|
void btintel_hw_error(struct hci_dev *hdev, u8 code);
|
||||||
|
|
||||||
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
|
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
|
||||||
|
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version);
|
||||||
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
|
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
|
||||||
const void *param);
|
const void *param);
|
||||||
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
|
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
|
||||||
int btintel_set_event_mask(struct hci_dev *hdev, bool debug);
|
int btintel_set_event_mask(struct hci_dev *hdev, bool debug);
|
||||||
int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug);
|
int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug);
|
||||||
int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver);
|
int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver);
|
||||||
|
int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver);
|
||||||
|
|
||||||
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
|
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
|
||||||
u16 opcode_write);
|
u16 opcode_write);
|
||||||
@@ -91,6 +159,10 @@ int btintel_read_boot_params(struct hci_dev *hdev,
|
|||||||
struct intel_boot_params *params);
|
struct intel_boot_params *params);
|
||||||
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
|
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
|
||||||
u32 *boot_param);
|
u32 *boot_param);
|
||||||
|
int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||||
|
const struct firmware *fw,
|
||||||
|
u32 *boot_param, u8 hw_variant,
|
||||||
|
u8 sbe_type);
|
||||||
void btintel_reset_to_bootloader(struct hci_dev *hdev);
|
void btintel_reset_to_bootloader(struct hci_dev *hdev);
|
||||||
int btintel_read_debug_features(struct hci_dev *hdev,
|
int btintel_read_debug_features(struct hci_dev *hdev,
|
||||||
struct intel_debug_features *features);
|
struct intel_debug_features *features);
|
||||||
@@ -137,6 +209,11 @@ static inline void btintel_version_info(struct hci_dev *hdev,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void btintel_version_info_tlv(struct hci_dev *hdev,
|
||||||
|
struct intel_version_tlv *version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
|
static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
|
||||||
u32 plen, const void *param)
|
u32 plen, const void *param)
|
||||||
{
|
{
|
||||||
@@ -165,6 +242,12 @@ static inline int btintel_read_version(struct hci_dev *hdev,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int btintel_read_version_tlv(struct hci_dev *hdev,
|
||||||
|
struct intel_version_tlv *ver)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
|
static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
|
||||||
u16 opcode_read,
|
u16 opcode_read,
|
||||||
u16 opcode_write)
|
u16 opcode_write)
|
||||||
@@ -191,6 +274,14 @@ static inline int btintel_download_firmware(struct hci_dev *dev,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||||
|
const struct firmware *fw,
|
||||||
|
u32 *boot_param,
|
||||||
|
u8 hw_variant, u8 sbe_type)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
static inline void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -215,30 +215,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
|
|||||||
.fw_dump_end = 0xea,
|
.fw_dump_end = 0xea,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8977 = {
|
static const struct btmrvl_sdio_card_reg btmrvl_reg_89xx = {
|
||||||
.cfg = 0x00,
|
|
||||||
.host_int_mask = 0x08,
|
|
||||||
.host_intstatus = 0x0c,
|
|
||||||
.card_status = 0x5c,
|
|
||||||
.sq_read_base_addr_a0 = 0xf8,
|
|
||||||
.sq_read_base_addr_a1 = 0xf9,
|
|
||||||
.card_revision = 0xc8,
|
|
||||||
.card_fw_status0 = 0xe8,
|
|
||||||
.card_fw_status1 = 0xe9,
|
|
||||||
.card_rx_len = 0xea,
|
|
||||||
.card_rx_unit = 0xeb,
|
|
||||||
.io_port_0 = 0xe4,
|
|
||||||
.io_port_1 = 0xe5,
|
|
||||||
.io_port_2 = 0xe6,
|
|
||||||
.int_read_to_clear = true,
|
|
||||||
.host_int_rsr = 0x04,
|
|
||||||
.card_misc_cfg = 0xD8,
|
|
||||||
.fw_dump_ctrl = 0xf0,
|
|
||||||
.fw_dump_start = 0xf1,
|
|
||||||
.fw_dump_end = 0xf8,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8987 = {
|
|
||||||
.cfg = 0x00,
|
.cfg = 0x00,
|
||||||
.host_int_mask = 0x08,
|
.host_int_mask = 0x08,
|
||||||
.host_intstatus = 0x0c,
|
.host_intstatus = 0x0c,
|
||||||
@@ -261,29 +238,6 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8987 = {
|
|||||||
.fw_dump_end = 0xf8,
|
.fw_dump_end = 0xf8,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = {
|
|
||||||
.cfg = 0x00,
|
|
||||||
.host_int_mask = 0x08,
|
|
||||||
.host_intstatus = 0x0c,
|
|
||||||
.card_status = 0x5c,
|
|
||||||
.sq_read_base_addr_a0 = 0xf8,
|
|
||||||
.sq_read_base_addr_a1 = 0xf9,
|
|
||||||
.card_revision = 0xc8,
|
|
||||||
.card_fw_status0 = 0xe8,
|
|
||||||
.card_fw_status1 = 0xe9,
|
|
||||||
.card_rx_len = 0xea,
|
|
||||||
.card_rx_unit = 0xeb,
|
|
||||||
.io_port_0 = 0xe4,
|
|
||||||
.io_port_1 = 0xe5,
|
|
||||||
.io_port_2 = 0xe6,
|
|
||||||
.int_read_to_clear = true,
|
|
||||||
.host_int_rsr = 0x04,
|
|
||||||
.card_misc_cfg = 0xD8,
|
|
||||||
.fw_dump_ctrl = 0xf0,
|
|
||||||
.fw_dump_start = 0xf1,
|
|
||||||
.fw_dump_end = 0xf8,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
||||||
.helper = "mrvl/sd8688_helper.bin",
|
.helper = "mrvl/sd8688_helper.bin",
|
||||||
.firmware = "mrvl/sd8688.bin",
|
.firmware = "mrvl/sd8688.bin",
|
||||||
@@ -332,7 +286,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
|||||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
|
||||||
.helper = NULL,
|
.helper = NULL,
|
||||||
.firmware = "mrvl/sdsd8977_combo_v2.bin",
|
.firmware = "mrvl/sdsd8977_combo_v2.bin",
|
||||||
.reg = &btmrvl_reg_8977,
|
.reg = &btmrvl_reg_89xx,
|
||||||
.support_pscan_win_report = true,
|
.support_pscan_win_report = true,
|
||||||
.sd_blksz_fw_dl = 256,
|
.sd_blksz_fw_dl = 256,
|
||||||
.supports_fw_dump = true,
|
.supports_fw_dump = true,
|
||||||
@@ -341,7 +295,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
|
|||||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = {
|
||||||
.helper = NULL,
|
.helper = NULL,
|
||||||
.firmware = "mrvl/sd8987_uapsta.bin",
|
.firmware = "mrvl/sd8987_uapsta.bin",
|
||||||
.reg = &btmrvl_reg_8987,
|
.reg = &btmrvl_reg_89xx,
|
||||||
.support_pscan_win_report = true,
|
.support_pscan_win_report = true,
|
||||||
.sd_blksz_fw_dl = 256,
|
.sd_blksz_fw_dl = 256,
|
||||||
.supports_fw_dump = true,
|
.supports_fw_dump = true,
|
||||||
@@ -350,7 +304,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = {
|
|||||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
|
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
|
||||||
.helper = NULL,
|
.helper = NULL,
|
||||||
.firmware = "mrvl/sdsd8997_combo_v4.bin",
|
.firmware = "mrvl/sdsd8997_combo_v4.bin",
|
||||||
.reg = &btmrvl_reg_8997,
|
.reg = &btmrvl_reg_89xx,
|
||||||
.support_pscan_win_report = true,
|
.support_pscan_win_report = true,
|
||||||
.sd_blksz_fw_dl = 256,
|
.sd_blksz_fw_dl = 256,
|
||||||
.supports_fw_dump = true,
|
.supports_fw_dump = true,
|
||||||
|
@@ -496,7 +496,7 @@ static void btmtksdio_interrupt(struct sdio_func *func)
|
|||||||
sdio_claim_host(bdev->func);
|
sdio_claim_host(bdev->func);
|
||||||
|
|
||||||
/* Disable interrupt */
|
/* Disable interrupt */
|
||||||
sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
|
sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
|
||||||
|
|
||||||
int_status = sdio_readl(func, MTK_REG_CHISR, NULL);
|
int_status = sdio_readl(func, MTK_REG_CHISR, NULL);
|
||||||
|
|
||||||
@@ -530,7 +530,7 @@ static void btmtksdio_interrupt(struct sdio_func *func)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable interrupt */
|
/* Enable interrupt */
|
||||||
sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, 0);
|
sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
|
||||||
|
|
||||||
pm_runtime_mark_last_busy(bdev->dev);
|
pm_runtime_mark_last_busy(bdev->dev);
|
||||||
pm_runtime_put_autosuspend(bdev->dev);
|
pm_runtime_put_autosuspend(bdev->dev);
|
||||||
|
@@ -59,6 +59,7 @@ static struct usb_driver btusb_driver;
|
|||||||
#define BTUSB_MEDIATEK 0x200000
|
#define BTUSB_MEDIATEK 0x200000
|
||||||
#define BTUSB_WIDEBAND_SPEECH 0x400000
|
#define BTUSB_WIDEBAND_SPEECH 0x400000
|
||||||
#define BTUSB_VALID_LE_STATES 0x800000
|
#define BTUSB_VALID_LE_STATES 0x800000
|
||||||
|
#define BTUSB_QCA_WCN6855 0x1000000
|
||||||
|
|
||||||
static const struct usb_device_id btusb_table[] = {
|
static const struct usb_device_id btusb_table[] = {
|
||||||
/* Generic Bluetooth USB device */
|
/* Generic Bluetooth USB device */
|
||||||
@@ -254,24 +255,46 @@ static const struct usb_device_id blacklist_table[] = {
|
|||||||
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
|
||||||
|
|
||||||
/* QCA ROME chipset */
|
/* QCA ROME chipset */
|
||||||
{ USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME },
|
{ USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME |
|
||||||
{ USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME },
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
{ USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
|
||||||
|
/* QCA WCN6855 chipset */
|
||||||
|
{ USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
|
||||||
|
BTUSB_WIDEBAND_SPEECH },
|
||||||
|
|
||||||
/* Broadcom BCM2035 */
|
/* Broadcom BCM2035 */
|
||||||
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
|
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
|
||||||
@@ -2338,10 +2361,10 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
|||||||
|
|
||||||
static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||||
struct intel_version *ver,
|
struct intel_version *ver,
|
||||||
struct intel_boot_params *params)
|
struct intel_boot_params *params,
|
||||||
|
u32 *boot_param)
|
||||||
{
|
{
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
u32 boot_param;
|
|
||||||
char fwname[64];
|
char fwname[64];
|
||||||
int err;
|
int err;
|
||||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||||
@@ -2479,7 +2502,7 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
|||||||
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
||||||
|
|
||||||
/* Start firmware downloading and get boot parameter */
|
/* Start firmware downloading and get boot parameter */
|
||||||
err = btintel_download_firmware(hdev, fw, &boot_param);
|
err = btintel_download_firmware(hdev, fw, boot_param);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
/* When FW download fails, send Intel Reset to retry
|
/* When FW download fails, send Intel Reset to retry
|
||||||
* FW download.
|
* FW download.
|
||||||
@@ -2561,7 +2584,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = btusb_intel_download_firmware(hdev, &ver, ¶ms);
|
err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -2896,6 +2919,7 @@ static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev)
|
|||||||
buf = kmalloc(size, GFP_KERNEL);
|
buf = kmalloc(size, GFP_KERNEL);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
kfree(dr);
|
kfree(dr);
|
||||||
|
usb_free_urb(urb);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3390,6 +3414,27 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
|
||||||
|
const bdaddr_t *bdaddr)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
u8 buf[6];
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
memcpy(buf, bdaddr, sizeof(bdaddr_t));
|
||||||
|
|
||||||
|
skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(buf), buf,
|
||||||
|
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
|
||||||
|
if (IS_ERR(skb)) {
|
||||||
|
ret = PTR_ERR(skb);
|
||||||
|
bt_dev_err(hdev, "Change address command failed (%ld)", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
kfree_skb(skb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define QCA_DFU_PACKET_LEN 4096
|
#define QCA_DFU_PACKET_LEN 4096
|
||||||
|
|
||||||
#define QCA_GET_TARGET_VERSION 0x09
|
#define QCA_GET_TARGET_VERSION 0x09
|
||||||
@@ -3409,7 +3454,8 @@ struct qca_version {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct qca_rampatch_version {
|
struct qca_rampatch_version {
|
||||||
__le16 rom_version;
|
__le16 rom_version_high;
|
||||||
|
__le16 rom_version_low;
|
||||||
__le16 patch_version;
|
__le16 patch_version;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
@@ -3421,12 +3467,14 @@ struct qca_device_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct qca_device_info qca_devices_table[] = {
|
static const struct qca_device_info qca_devices_table[] = {
|
||||||
{ 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
|
{ 0x00000100, 20, 4, 8 }, /* Rome 1.0 */
|
||||||
{ 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
|
{ 0x00000101, 20, 4, 8 }, /* Rome 1.1 */
|
||||||
{ 0x00000200, 28, 4, 18 }, /* Rome 2.0 */
|
{ 0x00000200, 28, 4, 16 }, /* Rome 2.0 */
|
||||||
{ 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
|
{ 0x00000201, 28, 4, 16 }, /* Rome 2.1 */
|
||||||
{ 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
|
{ 0x00000300, 28, 4, 16 }, /* Rome 3.0 */
|
||||||
{ 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
|
{ 0x00000302, 28, 4, 16 }, /* Rome 3.2 */
|
||||||
|
{ 0x00130100, 40, 4, 16 }, /* WCN6855 1.0 */
|
||||||
|
{ 0x00130200, 40, 4, 16 }, /* WCN6855 2.0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
|
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
|
||||||
@@ -3528,8 +3576,8 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
|
|||||||
{
|
{
|
||||||
struct qca_rampatch_version *rver;
|
struct qca_rampatch_version *rver;
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
u32 ver_rom, ver_patch;
|
u32 ver_rom, ver_patch, rver_rom;
|
||||||
u16 rver_rom, rver_patch;
|
u16 rver_rom_low, rver_rom_high, rver_patch;
|
||||||
char fwname[64];
|
char fwname[64];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -3548,9 +3596,16 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
|
|||||||
bt_dev_info(hdev, "using rampatch file: %s", fwname);
|
bt_dev_info(hdev, "using rampatch file: %s", fwname);
|
||||||
|
|
||||||
rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset);
|
rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset);
|
||||||
rver_rom = le16_to_cpu(rver->rom_version);
|
rver_rom_low = le16_to_cpu(rver->rom_version_low);
|
||||||
rver_patch = le16_to_cpu(rver->patch_version);
|
rver_patch = le16_to_cpu(rver->patch_version);
|
||||||
|
|
||||||
|
if (ver_rom & ~0xffffU) {
|
||||||
|
rver_rom_high = le16_to_cpu(rver->rom_version_high);
|
||||||
|
rver_rom = le32_to_cpu(rver_rom_high << 16 | rver_rom_low);
|
||||||
|
} else {
|
||||||
|
rver_rom = rver_rom_low;
|
||||||
|
}
|
||||||
|
|
||||||
bt_dev_info(hdev, "QCA: patch rome 0x%x build 0x%x, "
|
bt_dev_info(hdev, "QCA: patch rome 0x%x build 0x%x, "
|
||||||
"firmware rome 0x%x build 0x%x",
|
"firmware rome 0x%x build 0x%x",
|
||||||
rver_rom, rver_patch, ver_rom, ver_patch);
|
rver_rom, rver_patch, ver_rom, ver_patch);
|
||||||
@@ -3624,9 +3679,6 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
ver_rom = le32_to_cpu(ver.rom_version);
|
ver_rom = le32_to_cpu(ver.rom_version);
|
||||||
/* Don't care about high ROM versions */
|
|
||||||
if (ver_rom & ~0xffffU)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) {
|
for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) {
|
||||||
if (ver_rom == qca_devices_table[i].rom_version)
|
if (ver_rom == qca_devices_table[i].rom_version)
|
||||||
@@ -4062,6 +4114,13 @@ static int btusb_probe(struct usb_interface *intf,
|
|||||||
btusb_check_needs_reset_resume(intf);
|
btusb_check_needs_reset_resume(intf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (id->driver_info & BTUSB_QCA_WCN6855) {
|
||||||
|
data->setup_on_usb = btusb_setup_qca;
|
||||||
|
hdev->set_bdaddr = btusb_set_bdaddr_wcn6855;
|
||||||
|
hdev->cmd_timeout = btusb_qca_cmd_timeout;
|
||||||
|
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||||
|
}
|
||||||
|
|
||||||
if (id->driver_info & BTUSB_AMP) {
|
if (id->driver_info & BTUSB_AMP) {
|
||||||
/* AMP controllers do not support SCO packets */
|
/* AMP controllers do not support SCO packets */
|
||||||
data->isoc = NULL;
|
data->isoc = NULL;
|
||||||
|
@@ -793,8 +793,6 @@ static int h5_serdev_probe(struct serdev_device *serdev)
|
|||||||
if (!h5)
|
if (!h5)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.hdev_flags);
|
|
||||||
|
|
||||||
h5->hu = &h5->serdev_hu;
|
h5->hu = &h5->serdev_hu;
|
||||||
h5->serdev_hu.serdev = serdev;
|
h5->serdev_hu.serdev = serdev;
|
||||||
serdev_device_set_drvdata(serdev, h5);
|
serdev_device_set_drvdata(serdev, h5);
|
||||||
|
@@ -288,7 +288,7 @@ static irqreturn_t intel_irq(int irq, void *dev_id)
|
|||||||
|
|
||||||
static int intel_set_power(struct hci_uart *hu, bool powered)
|
static int intel_set_power(struct hci_uart *hu, bool powered)
|
||||||
{
|
{
|
||||||
struct list_head *p;
|
struct intel_device *idev;
|
||||||
int err = -ENODEV;
|
int err = -ENODEV;
|
||||||
|
|
||||||
if (!hu->tty->dev)
|
if (!hu->tty->dev)
|
||||||
@@ -296,10 +296,7 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
|
|||||||
|
|
||||||
mutex_lock(&intel_device_list_lock);
|
mutex_lock(&intel_device_list_lock);
|
||||||
|
|
||||||
list_for_each(p, &intel_device_list) {
|
list_for_each_entry(idev, &intel_device_list, list) {
|
||||||
struct intel_device *idev = list_entry(p, struct intel_device,
|
|
||||||
list);
|
|
||||||
|
|
||||||
/* tty device and pdev device should share the same parent
|
/* tty device and pdev device should share the same parent
|
||||||
* which is the UART port.
|
* which is the UART port.
|
||||||
*/
|
*/
|
||||||
@@ -362,19 +359,16 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
|
|||||||
|
|
||||||
static void intel_busy_work(struct work_struct *work)
|
static void intel_busy_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct list_head *p;
|
|
||||||
struct intel_data *intel = container_of(work, struct intel_data,
|
struct intel_data *intel = container_of(work, struct intel_data,
|
||||||
busy_work);
|
busy_work);
|
||||||
|
struct intel_device *idev;
|
||||||
|
|
||||||
if (!intel->hu->tty->dev)
|
if (!intel->hu->tty->dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Link is busy, delay the suspend */
|
/* Link is busy, delay the suspend */
|
||||||
mutex_lock(&intel_device_list_lock);
|
mutex_lock(&intel_device_list_lock);
|
||||||
list_for_each(p, &intel_device_list) {
|
list_for_each_entry(idev, &intel_device_list, list) {
|
||||||
struct intel_device *idev = list_entry(p, struct intel_device,
|
|
||||||
list);
|
|
||||||
|
|
||||||
if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) {
|
if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) {
|
||||||
pm_runtime_get(&idev->pdev->dev);
|
pm_runtime_get(&idev->pdev->dev);
|
||||||
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
||||||
@@ -533,7 +527,7 @@ static int intel_setup(struct hci_uart *hu)
|
|||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct intel_version ver;
|
struct intel_version ver;
|
||||||
struct intel_boot_params params;
|
struct intel_boot_params params;
|
||||||
struct list_head *p;
|
struct intel_device *idev;
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
char fwname[64];
|
char fwname[64];
|
||||||
u32 boot_param;
|
u32 boot_param;
|
||||||
@@ -693,14 +687,11 @@ static int intel_setup(struct hci_uart *hu)
|
|||||||
case 0x0b: /* SfP */
|
case 0x0b: /* SfP */
|
||||||
case 0x0c: /* WsP */
|
case 0x0c: /* WsP */
|
||||||
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
|
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
|
||||||
le16_to_cpu(ver.hw_variant),
|
ver.hw_variant, le16_to_cpu(params.dev_revid));
|
||||||
le16_to_cpu(params.dev_revid));
|
|
||||||
break;
|
break;
|
||||||
case 0x12: /* ThP */
|
case 0x12: /* ThP */
|
||||||
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi",
|
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi",
|
||||||
le16_to_cpu(ver.hw_variant),
|
ver.hw_variant, ver.hw_revision, ver.fw_revision);
|
||||||
le16_to_cpu(ver.hw_revision),
|
|
||||||
le16_to_cpu(ver.fw_revision));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||||
@@ -722,14 +713,11 @@ static int intel_setup(struct hci_uart *hu)
|
|||||||
case 0x0b: /* SfP */
|
case 0x0b: /* SfP */
|
||||||
case 0x0c: /* WsP */
|
case 0x0c: /* WsP */
|
||||||
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
|
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
|
||||||
le16_to_cpu(ver.hw_variant),
|
ver.hw_variant, le16_to_cpu(params.dev_revid));
|
||||||
le16_to_cpu(params.dev_revid));
|
|
||||||
break;
|
break;
|
||||||
case 0x12: /* ThP */
|
case 0x12: /* ThP */
|
||||||
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc",
|
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc",
|
||||||
le16_to_cpu(ver.hw_variant),
|
ver.hw_variant, ver.hw_revision, ver.fw_revision);
|
||||||
le16_to_cpu(ver.hw_revision),
|
|
||||||
le16_to_cpu(ver.fw_revision));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||||
@@ -839,13 +827,11 @@ done:
|
|||||||
* until further LPM TX notification.
|
* until further LPM TX notification.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&intel_device_list_lock);
|
mutex_lock(&intel_device_list_lock);
|
||||||
list_for_each(p, &intel_device_list) {
|
list_for_each_entry(idev, &intel_device_list, list) {
|
||||||
struct intel_device *dev = list_entry(p, struct intel_device,
|
|
||||||
list);
|
|
||||||
if (!hu->tty->dev)
|
if (!hu->tty->dev)
|
||||||
break;
|
break;
|
||||||
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
|
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
|
||||||
if (device_may_wakeup(&dev->pdev->dev)) {
|
if (device_may_wakeup(&idev->pdev->dev)) {
|
||||||
set_bit(STATE_LPM_ENABLED, &intel->flags);
|
set_bit(STATE_LPM_ENABLED, &intel->flags);
|
||||||
set_bit(STATE_TX_ACTIVE, &intel->flags);
|
set_bit(STATE_TX_ACTIVE, &intel->flags);
|
||||||
}
|
}
|
||||||
@@ -999,7 +985,7 @@ static int intel_recv(struct hci_uart *hu, const void *data, int count)
|
|||||||
static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct intel_data *intel = hu->priv;
|
struct intel_data *intel = hu->priv;
|
||||||
struct list_head *p;
|
struct intel_device *idev;
|
||||||
|
|
||||||
BT_DBG("hu %p skb %p", hu, skb);
|
BT_DBG("hu %p skb %p", hu, skb);
|
||||||
|
|
||||||
@@ -1010,10 +996,7 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||||||
* completed before enqueuing any packet.
|
* completed before enqueuing any packet.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&intel_device_list_lock);
|
mutex_lock(&intel_device_list_lock);
|
||||||
list_for_each(p, &intel_device_list) {
|
list_for_each_entry(idev, &intel_device_list, list) {
|
||||||
struct intel_device *idev = list_entry(p, struct intel_device,
|
|
||||||
list);
|
|
||||||
|
|
||||||
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
|
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
|
||||||
pm_runtime_get_sync(&idev->pdev->dev);
|
pm_runtime_get_sync(&idev->pdev->dev);
|
||||||
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
||||||
@@ -1076,7 +1059,8 @@ static const struct hci_uart_proto intel_proto = {
|
|||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static const struct acpi_device_id intel_acpi_match[] = {
|
static const struct acpi_device_id intel_acpi_match[] = {
|
||||||
{ "INT33E1", 0 },
|
{ "INT33E1", 0 },
|
||||||
{ },
|
{ "INT33E3", 0 },
|
||||||
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
|
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
|
||||||
#endif
|
#endif
|
||||||
@@ -1138,9 +1122,9 @@ static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
|
|||||||
static const struct acpi_gpio_params host_wake_gpios = { 1, 0, false };
|
static const struct acpi_gpio_params host_wake_gpios = { 1, 0, false };
|
||||||
|
|
||||||
static const struct acpi_gpio_mapping acpi_hci_intel_gpios[] = {
|
static const struct acpi_gpio_mapping acpi_hci_intel_gpios[] = {
|
||||||
{ "reset-gpios", &reset_gpios, 1 },
|
{ "reset-gpios", &reset_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
|
||||||
{ "host-wake-gpios", &host_wake_gpios, 1 },
|
{ "host-wake-gpios", &host_wake_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
|
||||||
{ },
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int intel_probe(struct platform_device *pdev)
|
static int intel_probe(struct platform_device *pdev)
|
||||||
|
@@ -538,6 +538,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
|||||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
percpu_up_write(&hu->proto_lock);
|
percpu_up_write(&hu->proto_lock);
|
||||||
|
|
||||||
|
cancel_work_sync(&hu->init_ready);
|
||||||
cancel_work_sync(&hu->write_work);
|
cancel_work_sync(&hu->write_work);
|
||||||
|
|
||||||
if (hdev) {
|
if (hdev) {
|
||||||
|
@@ -693,8 +693,6 @@ static int qca_close(struct hci_uart *hu)
|
|||||||
destroy_workqueue(qca->workqueue);
|
destroy_workqueue(qca->workqueue);
|
||||||
qca->hu = NULL;
|
qca->hu = NULL;
|
||||||
|
|
||||||
qca_power_shutdown(hu);
|
|
||||||
|
|
||||||
kfree_skb(qca->rx_skb);
|
kfree_skb(qca->rx_skb);
|
||||||
|
|
||||||
hu->priv = NULL;
|
hu->priv = NULL;
|
||||||
@@ -2007,7 +2005,6 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
|||||||
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
|
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
|
||||||
if (err) {
|
if (err) {
|
||||||
BT_ERR("Rome serdev registration failed");
|
BT_ERR("Rome serdev registration failed");
|
||||||
if (qcadev->susclk)
|
|
||||||
clk_disable_unprepare(qcadev->susclk);
|
clk_disable_unprepare(qcadev->susclk);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2032,8 +2029,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
|||||||
static void qca_serdev_remove(struct serdev_device *serdev)
|
static void qca_serdev_remove(struct serdev_device *serdev)
|
||||||
{
|
{
|
||||||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||||
|
struct qca_power *power = qcadev->bt_power;
|
||||||
|
|
||||||
if (qca_is_wcn399x(qcadev->btsoc_type))
|
if (qca_is_wcn399x(qcadev->btsoc_type) && power->vregs_on)
|
||||||
qca_power_shutdown(&qcadev->serdev_hu);
|
qca_power_shutdown(&qcadev->serdev_hu);
|
||||||
else if (qcadev->susclk)
|
else if (qcadev->susclk)
|
||||||
clk_disable_unprepare(qcadev->susclk);
|
clk_disable_unprepare(qcadev->susclk);
|
||||||
|
@@ -113,8 +113,22 @@ static int hci_uart_flush(struct hci_dev *hdev)
|
|||||||
/* Initialize device */
|
/* Initialize device */
|
||||||
static int hci_uart_open(struct hci_dev *hdev)
|
static int hci_uart_open(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||||
|
int err;
|
||||||
|
|
||||||
BT_DBG("%s %p", hdev->name, hdev);
|
BT_DBG("%s %p", hdev->name, hdev);
|
||||||
|
|
||||||
|
/* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by
|
||||||
|
* driver, BT SoC is completely turned OFF during
|
||||||
|
* BT OFF. Upon next BT ON UART port should be opened.
|
||||||
|
*/
|
||||||
|
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
|
||||||
|
err = serdev_device_open(hu->serdev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
set_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Undo clearing this from hci_uart_close() */
|
/* Undo clearing this from hci_uart_close() */
|
||||||
hdev->flush = hci_uart_flush;
|
hdev->flush = hci_uart_flush;
|
||||||
|
|
||||||
@@ -124,11 +138,25 @@ static int hci_uart_open(struct hci_dev *hdev)
|
|||||||
/* Close device */
|
/* Close device */
|
||||||
static int hci_uart_close(struct hci_dev *hdev)
|
static int hci_uart_close(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
|
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||||
|
|
||||||
BT_DBG("hdev %p", hdev);
|
BT_DBG("hdev %p", hdev);
|
||||||
|
|
||||||
|
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||||
|
return 0;
|
||||||
|
|
||||||
hci_uart_flush(hdev);
|
hci_uart_flush(hdev);
|
||||||
hdev->flush = NULL;
|
hdev->flush = NULL;
|
||||||
|
|
||||||
|
/* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver,
|
||||||
|
* BT SOC is completely powered OFF during BT OFF, holding port
|
||||||
|
* open may drain the battery.
|
||||||
|
*/
|
||||||
|
if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) {
|
||||||
|
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
|
serdev_device_close(hu->serdev);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +382,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
|
|||||||
{
|
{
|
||||||
struct hci_dev *hdev = hu->hdev;
|
struct hci_dev *hdev = hu->hdev;
|
||||||
|
|
||||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
cancel_work_sync(&hu->init_ready);
|
||||||
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
|
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||||
hci_unregister_dev(hdev);
|
hci_unregister_dev(hdev);
|
||||||
hci_free_dev(hdev);
|
hci_free_dev(hdev);
|
||||||
@@ -362,6 +390,10 @@ void hci_uart_unregister_device(struct hci_uart *hu)
|
|||||||
cancel_work_sync(&hu->write_work);
|
cancel_work_sync(&hu->write_work);
|
||||||
|
|
||||||
hu->proto->close(hu);
|
hu->proto->close(hu);
|
||||||
|
|
||||||
|
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
|
||||||
|
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||||
serdev_device_close(hu->serdev);
|
serdev_device_close(hu->serdev);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(hci_uart_unregister_device);
|
EXPORT_SYMBOL_GPL(hci_uart_unregister_device);
|
||||||
|
@@ -197,17 +197,12 @@ int cn_add_callback(struct cb_id *id, const char *name,
|
|||||||
void (*callback)(struct cn_msg *,
|
void (*callback)(struct cn_msg *,
|
||||||
struct netlink_skb_parms *))
|
struct netlink_skb_parms *))
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
struct cn_dev *dev = &cdev;
|
struct cn_dev *dev = &cdev;
|
||||||
|
|
||||||
if (!cn_already_initialized)
|
if (!cn_already_initialized)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
err = cn_queue_add_callback(dev->cbdev, name, id, callback);
|
return cn_queue_add_callback(dev->cbdev, name, id, callback);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cn_add_callback);
|
EXPORT_SYMBOL_GPL(cn_add_callback);
|
||||||
|
|
||||||
|
@@ -21,35 +21,3 @@ config CRYPTO_DEV_CHELSIO
|
|||||||
|
|
||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called chcr.
|
will be called chcr.
|
||||||
|
|
||||||
config CHELSIO_IPSEC_INLINE
|
|
||||||
bool "Chelsio IPSec XFRM Tx crypto offload"
|
|
||||||
depends on CHELSIO_T4
|
|
||||||
depends on CRYPTO_DEV_CHELSIO
|
|
||||||
depends on XFRM_OFFLOAD
|
|
||||||
depends on INET_ESP_OFFLOAD || INET6_ESP_OFFLOAD
|
|
||||||
default n
|
|
||||||
help
|
|
||||||
Enable support for IPSec Tx Inline.
|
|
||||||
|
|
||||||
config CRYPTO_DEV_CHELSIO_TLS
|
|
||||||
tristate "Chelsio Crypto Inline TLS Driver"
|
|
||||||
depends on CHELSIO_T4
|
|
||||||
depends on TLS_TOE
|
|
||||||
select CRYPTO_DEV_CHELSIO
|
|
||||||
help
|
|
||||||
Support Chelsio Inline TLS with Chelsio crypto accelerator.
|
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the module
|
|
||||||
will be called chtls.
|
|
||||||
|
|
||||||
config CHELSIO_TLS_DEVICE
|
|
||||||
bool "Chelsio Inline KTLS Offload"
|
|
||||||
depends on CHELSIO_T4
|
|
||||||
depends on TLS_DEVICE
|
|
||||||
select CRYPTO_DEV_CHELSIO
|
|
||||||
default y
|
|
||||||
help
|
|
||||||
This flag enables support for kernel tls offload over Chelsio T6
|
|
||||||
crypto accelerator. CONFIG_CHELSIO_TLS_DEVICE flag can be enabled
|
|
||||||
only if CONFIG_TLS and CONFIG_TLS_DEVICE flags are enabled.
|
|
||||||
|
@@ -3,8 +3,3 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/chelsio/cxgb4
|
|||||||
|
|
||||||
obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chcr.o
|
obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chcr.o
|
||||||
chcr-objs := chcr_core.o chcr_algo.o
|
chcr-objs := chcr_core.o chcr_algo.o
|
||||||
#ifdef CONFIG_CHELSIO_TLS_DEVICE
|
|
||||||
chcr-objs += chcr_ktls.o
|
|
||||||
#endif
|
|
||||||
chcr-$(CONFIG_CHELSIO_IPSEC_INLINE) += chcr_ipsec.o
|
|
||||||
obj-$(CONFIG_CRYPTO_DEV_CHELSIO_TLS) += chtls/
|
|
||||||
|
@@ -86,39 +86,6 @@
|
|||||||
KEY_CONTEXT_OPAD_PRESENT_M)
|
KEY_CONTEXT_OPAD_PRESENT_M)
|
||||||
#define KEY_CONTEXT_OPAD_PRESENT_F KEY_CONTEXT_OPAD_PRESENT_V(1U)
|
#define KEY_CONTEXT_OPAD_PRESENT_F KEY_CONTEXT_OPAD_PRESENT_V(1U)
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXFLIT_CNT_S 24
|
|
||||||
#define TLS_KEYCTX_RXFLIT_CNT_V(x) ((x) << TLS_KEYCTX_RXFLIT_CNT_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXPROT_VER_S 20
|
|
||||||
#define TLS_KEYCTX_RXPROT_VER_M 0xf
|
|
||||||
#define TLS_KEYCTX_RXPROT_VER_V(x) ((x) << TLS_KEYCTX_RXPROT_VER_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXCIPH_MODE_S 16
|
|
||||||
#define TLS_KEYCTX_RXCIPH_MODE_M 0xf
|
|
||||||
#define TLS_KEYCTX_RXCIPH_MODE_V(x) ((x) << TLS_KEYCTX_RXCIPH_MODE_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXAUTH_MODE_S 12
|
|
||||||
#define TLS_KEYCTX_RXAUTH_MODE_M 0xf
|
|
||||||
#define TLS_KEYCTX_RXAUTH_MODE_V(x) ((x) << TLS_KEYCTX_RXAUTH_MODE_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXCIAU_CTRL_S 11
|
|
||||||
#define TLS_KEYCTX_RXCIAU_CTRL_V(x) ((x) << TLS_KEYCTX_RXCIAU_CTRL_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RX_SEQCTR_S 9
|
|
||||||
#define TLS_KEYCTX_RX_SEQCTR_M 0x3
|
|
||||||
#define TLS_KEYCTX_RX_SEQCTR_V(x) ((x) << TLS_KEYCTX_RX_SEQCTR_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RX_VALID_S 8
|
|
||||||
#define TLS_KEYCTX_RX_VALID_V(x) ((x) << TLS_KEYCTX_RX_VALID_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXCK_SIZE_S 3
|
|
||||||
#define TLS_KEYCTX_RXCK_SIZE_M 0x7
|
|
||||||
#define TLS_KEYCTX_RXCK_SIZE_V(x) ((x) << TLS_KEYCTX_RXCK_SIZE_S)
|
|
||||||
|
|
||||||
#define TLS_KEYCTX_RXMK_SIZE_S 0
|
|
||||||
#define TLS_KEYCTX_RXMK_SIZE_M 0x7
|
|
||||||
#define TLS_KEYCTX_RXMK_SIZE_V(x) ((x) << TLS_KEYCTX_RXMK_SIZE_S)
|
|
||||||
|
|
||||||
#define CHCR_HASH_MAX_DIGEST_SIZE 64
|
#define CHCR_HASH_MAX_DIGEST_SIZE 64
|
||||||
#define CHCR_MAX_SHA_DIGEST_SIZE 64
|
#define CHCR_MAX_SHA_DIGEST_SIZE 64
|
||||||
|
|
||||||
|
@@ -33,23 +33,8 @@ static int cpl_fw6_pld_handler(struct adapter *adap, unsigned char *input);
|
|||||||
static void *chcr_uld_add(const struct cxgb4_lld_info *lld);
|
static void *chcr_uld_add(const struct cxgb4_lld_info *lld);
|
||||||
static int chcr_uld_state_change(void *handle, enum cxgb4_state state);
|
static int chcr_uld_state_change(void *handle, enum cxgb4_state state);
|
||||||
|
|
||||||
#if defined(CONFIG_CHELSIO_TLS_DEVICE)
|
|
||||||
static const struct tlsdev_ops chcr_ktls_ops = {
|
|
||||||
.tls_dev_add = chcr_ktls_dev_add,
|
|
||||||
.tls_dev_del = chcr_ktls_dev_del,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_CHELSIO_IPSEC_INLINE
|
|
||||||
static void update_netdev_features(void);
|
|
||||||
#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
|
|
||||||
|
|
||||||
static chcr_handler_func work_handlers[NUM_CPL_CMDS] = {
|
static chcr_handler_func work_handlers[NUM_CPL_CMDS] = {
|
||||||
[CPL_FW6_PLD] = cpl_fw6_pld_handler,
|
[CPL_FW6_PLD] = cpl_fw6_pld_handler,
|
||||||
#ifdef CONFIG_CHELSIO_TLS_DEVICE
|
|
||||||
[CPL_ACT_OPEN_RPL] = chcr_ktls_cpl_act_open_rpl,
|
|
||||||
[CPL_SET_TCB_RPL] = chcr_ktls_cpl_set_tcb_rpl,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cxgb4_uld_info chcr_uld_info = {
|
static struct cxgb4_uld_info chcr_uld_info = {
|
||||||
@@ -60,12 +45,6 @@ static struct cxgb4_uld_info chcr_uld_info = {
|
|||||||
.add = chcr_uld_add,
|
.add = chcr_uld_add,
|
||||||
.state_change = chcr_uld_state_change,
|
.state_change = chcr_uld_state_change,
|
||||||
.rx_handler = chcr_uld_rx_handler,
|
.rx_handler = chcr_uld_rx_handler,
|
||||||
#if defined(CONFIG_CHELSIO_IPSEC_INLINE) || defined(CONFIG_CHELSIO_TLS_DEVICE)
|
|
||||||
.tx_handler = chcr_uld_tx_handler,
|
|
||||||
#endif /* CONFIG_CHELSIO_IPSEC_INLINE || CONFIG_CHELSIO_TLS_DEVICE */
|
|
||||||
#if defined(CONFIG_CHELSIO_TLS_DEVICE)
|
|
||||||
.tlsdev_ops = &chcr_ktls_ops,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void detach_work_fn(struct work_struct *work)
|
static void detach_work_fn(struct work_struct *work)
|
||||||
@@ -241,23 +220,6 @@ int chcr_uld_rx_handler(void *handle, const __be64 *rsp,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_CHELSIO_IPSEC_INLINE) || defined(CONFIG_CHELSIO_TLS_DEVICE)
|
|
||||||
int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev)
|
|
||||||
{
|
|
||||||
/* In case if skb's decrypted bit is set, it's nic tls packet, else it's
|
|
||||||
* ipsec packet.
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_CHELSIO_TLS_DEVICE
|
|
||||||
if (skb->decrypted)
|
|
||||||
return chcr_ktls_xmit(skb, dev);
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_CHELSIO_IPSEC_INLINE
|
|
||||||
return chcr_ipsec_xmit(skb, dev);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_CHELSIO_IPSEC_INLINE || CONFIG_CHELSIO_TLS_DEVICE */
|
|
||||||
|
|
||||||
static void chcr_detach_device(struct uld_ctx *u_ctx)
|
static void chcr_detach_device(struct uld_ctx *u_ctx)
|
||||||
{
|
{
|
||||||
struct chcr_dev *dev = &u_ctx->dev;
|
struct chcr_dev *dev = &u_ctx->dev;
|
||||||
@@ -305,24 +267,6 @@ static int chcr_uld_state_change(void *handle, enum cxgb4_state state)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CHELSIO_IPSEC_INLINE
|
|
||||||
static void update_netdev_features(void)
|
|
||||||
{
|
|
||||||
struct uld_ctx *u_ctx, *tmp;
|
|
||||||
|
|
||||||
mutex_lock(&drv_data.drv_mutex);
|
|
||||||
list_for_each_entry_safe(u_ctx, tmp, &drv_data.inact_dev, entry) {
|
|
||||||
if (u_ctx->lldi.crypto & ULP_CRYPTO_IPSEC_INLINE)
|
|
||||||
chcr_add_xfrmops(&u_ctx->lldi);
|
|
||||||
}
|
|
||||||
list_for_each_entry_safe(u_ctx, tmp, &drv_data.act_dev, entry) {
|
|
||||||
if (u_ctx->lldi.crypto & ULP_CRYPTO_IPSEC_INLINE)
|
|
||||||
chcr_add_xfrmops(&u_ctx->lldi);
|
|
||||||
}
|
|
||||||
mutex_unlock(&drv_data.drv_mutex);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
|
|
||||||
|
|
||||||
static int __init chcr_crypto_init(void)
|
static int __init chcr_crypto_init(void)
|
||||||
{
|
{
|
||||||
INIT_LIST_HEAD(&drv_data.act_dev);
|
INIT_LIST_HEAD(&drv_data.act_dev);
|
||||||
@@ -332,12 +276,6 @@ static int __init chcr_crypto_init(void)
|
|||||||
drv_data.last_dev = NULL;
|
drv_data.last_dev = NULL;
|
||||||
cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info);
|
cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info);
|
||||||
|
|
||||||
#ifdef CONFIG_CHELSIO_IPSEC_INLINE
|
|
||||||
rtnl_lock();
|
|
||||||
update_netdev_features();
|
|
||||||
rtnl_unlock();
|
|
||||||
#endif /* CONFIG_CHELSIO_IPSEC_INLINE */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,54 +72,6 @@ struct _key_ctx {
|
|||||||
unsigned char key[];
|
unsigned char key[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_IV_S 55
|
|
||||||
#define KEYCTX_TX_WR_IV_M 0x1ffULL
|
|
||||||
#define KEYCTX_TX_WR_IV_V(x) ((x) << KEYCTX_TX_WR_IV_S)
|
|
||||||
#define KEYCTX_TX_WR_IV_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_IV_S) & KEYCTX_TX_WR_IV_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_AAD_S 47
|
|
||||||
#define KEYCTX_TX_WR_AAD_M 0xffULL
|
|
||||||
#define KEYCTX_TX_WR_AAD_V(x) ((x) << KEYCTX_TX_WR_AAD_S)
|
|
||||||
#define KEYCTX_TX_WR_AAD_G(x) (((x) >> KEYCTX_TX_WR_AAD_S) & \
|
|
||||||
KEYCTX_TX_WR_AAD_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_AADST_S 39
|
|
||||||
#define KEYCTX_TX_WR_AADST_M 0xffULL
|
|
||||||
#define KEYCTX_TX_WR_AADST_V(x) ((x) << KEYCTX_TX_WR_AADST_S)
|
|
||||||
#define KEYCTX_TX_WR_AADST_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_AADST_S) & KEYCTX_TX_WR_AADST_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_CIPHER_S 30
|
|
||||||
#define KEYCTX_TX_WR_CIPHER_M 0x1ffULL
|
|
||||||
#define KEYCTX_TX_WR_CIPHER_V(x) ((x) << KEYCTX_TX_WR_CIPHER_S)
|
|
||||||
#define KEYCTX_TX_WR_CIPHER_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_CIPHER_S) & KEYCTX_TX_WR_CIPHER_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_CIPHERST_S 23
|
|
||||||
#define KEYCTX_TX_WR_CIPHERST_M 0x7f
|
|
||||||
#define KEYCTX_TX_WR_CIPHERST_V(x) ((x) << KEYCTX_TX_WR_CIPHERST_S)
|
|
||||||
#define KEYCTX_TX_WR_CIPHERST_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_CIPHERST_S) & KEYCTX_TX_WR_CIPHERST_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_AUTH_S 14
|
|
||||||
#define KEYCTX_TX_WR_AUTH_M 0x1ff
|
|
||||||
#define KEYCTX_TX_WR_AUTH_V(x) ((x) << KEYCTX_TX_WR_AUTH_S)
|
|
||||||
#define KEYCTX_TX_WR_AUTH_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_AUTH_S) & KEYCTX_TX_WR_AUTH_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_AUTHST_S 7
|
|
||||||
#define KEYCTX_TX_WR_AUTHST_M 0x7f
|
|
||||||
#define KEYCTX_TX_WR_AUTHST_V(x) ((x) << KEYCTX_TX_WR_AUTHST_S)
|
|
||||||
#define KEYCTX_TX_WR_AUTHST_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_AUTHST_S) & KEYCTX_TX_WR_AUTHST_M)
|
|
||||||
|
|
||||||
#define KEYCTX_TX_WR_AUTHIN_S 0
|
|
||||||
#define KEYCTX_TX_WR_AUTHIN_M 0x7f
|
|
||||||
#define KEYCTX_TX_WR_AUTHIN_V(x) ((x) << KEYCTX_TX_WR_AUTHIN_S)
|
|
||||||
#define KEYCTX_TX_WR_AUTHIN_G(x) \
|
|
||||||
(((x) >> KEYCTX_TX_WR_AUTHIN_S) & KEYCTX_TX_WR_AUTHIN_M)
|
|
||||||
|
|
||||||
#define WQ_RETRY 5
|
#define WQ_RETRY 5
|
||||||
struct chcr_driver_data {
|
struct chcr_driver_data {
|
||||||
struct list_head act_dev;
|
struct list_head act_dev;
|
||||||
@@ -157,42 +109,6 @@ struct uld_ctx {
|
|||||||
struct chcr_dev dev;
|
struct chcr_dev dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sge_opaque_hdr {
|
|
||||||
void *dev;
|
|
||||||
dma_addr_t addr[MAX_SKB_FRAGS + 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct chcr_ipsec_req {
|
|
||||||
struct ulp_txpkt ulptx;
|
|
||||||
struct ulptx_idata sc_imm;
|
|
||||||
struct cpl_tx_sec_pdu sec_cpl;
|
|
||||||
struct _key_ctx key_ctx;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct chcr_ipsec_wr {
|
|
||||||
struct fw_ulptx_wr wreq;
|
|
||||||
struct chcr_ipsec_req req;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ESN_IV_INSERT_OFFSET 12
|
|
||||||
struct chcr_ipsec_aadiv {
|
|
||||||
__be32 spi;
|
|
||||||
u8 seq_no[8];
|
|
||||||
u8 iv[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ipsec_sa_entry {
|
|
||||||
int hmac_ctrl;
|
|
||||||
u16 esn;
|
|
||||||
u16 resv;
|
|
||||||
unsigned int enckey_len;
|
|
||||||
unsigned int kctx_len;
|
|
||||||
unsigned int authsize;
|
|
||||||
__be32 key_ctx_hdr;
|
|
||||||
char salt[MAX_SALT];
|
|
||||||
char key[2 * AES_MAX_KEY_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sgl_len - calculates the size of an SGL of the given capacity
|
* sgl_len - calculates the size of an SGL of the given capacity
|
||||||
* @n: the number of SGL entries
|
* @n: the number of SGL entries
|
||||||
@@ -221,18 +137,4 @@ int chcr_uld_rx_handler(void *handle, const __be64 *rsp,
|
|||||||
int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev);
|
int chcr_uld_tx_handler(struct sk_buff *skb, struct net_device *dev);
|
||||||
int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input,
|
int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input,
|
||||||
int err);
|
int err);
|
||||||
int chcr_ipsec_xmit(struct sk_buff *skb, struct net_device *dev);
|
|
||||||
void chcr_add_xfrmops(const struct cxgb4_lld_info *lld);
|
|
||||||
#ifdef CONFIG_CHELSIO_TLS_DEVICE
|
|
||||||
int chcr_ktls_cpl_act_open_rpl(struct adapter *adap, unsigned char *input);
|
|
||||||
int chcr_ktls_cpl_set_tcb_rpl(struct adapter *adap, unsigned char *input);
|
|
||||||
int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev);
|
|
||||||
extern int chcr_ktls_dev_add(struct net_device *netdev, struct sock *sk,
|
|
||||||
enum tls_offload_ctx_dir direction,
|
|
||||||
struct tls_crypto_info *crypto_info,
|
|
||||||
u32 start_offload_tcp_sn);
|
|
||||||
extern void chcr_ktls_dev_del(struct net_device *netdev,
|
|
||||||
struct tls_context *tls_ctx,
|
|
||||||
enum tls_offload_ctx_dir direction);
|
|
||||||
#endif
|
|
||||||
#endif /* __CHCR_CORE_H__ */
|
#endif /* __CHCR_CORE_H__ */
|
||||||
|
@@ -97,41 +97,9 @@ static void hfi1_ipoib_dev_get_stats64(struct net_device *dev,
|
|||||||
struct rtnl_link_stats64 *storage)
|
struct rtnl_link_stats64 *storage)
|
||||||
{
|
{
|
||||||
struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
|
struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
|
||||||
u64 rx_packets = 0ull;
|
|
||||||
u64 rx_bytes = 0ull;
|
|
||||||
u64 tx_packets = 0ull;
|
|
||||||
u64 tx_bytes = 0ull;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
netdev_stats_to_stats64(storage, &dev->stats);
|
netdev_stats_to_stats64(storage, &dev->stats);
|
||||||
|
dev_fetch_sw_netstats(storage, priv->netstats);
|
||||||
for_each_possible_cpu(i) {
|
|
||||||
const struct pcpu_sw_netstats *stats;
|
|
||||||
unsigned int start;
|
|
||||||
u64 trx_packets;
|
|
||||||
u64 trx_bytes;
|
|
||||||
u64 ttx_packets;
|
|
||||||
u64 ttx_bytes;
|
|
||||||
|
|
||||||
stats = per_cpu_ptr(priv->netstats, i);
|
|
||||||
do {
|
|
||||||
start = u64_stats_fetch_begin_irq(&stats->syncp);
|
|
||||||
trx_packets = stats->rx_packets;
|
|
||||||
trx_bytes = stats->rx_bytes;
|
|
||||||
ttx_packets = stats->tx_packets;
|
|
||||||
ttx_bytes = stats->tx_bytes;
|
|
||||||
} while (u64_stats_fetch_retry_irq(&stats->syncp, start));
|
|
||||||
|
|
||||||
rx_packets += trx_packets;
|
|
||||||
rx_bytes += trx_bytes;
|
|
||||||
tx_packets += ttx_packets;
|
|
||||||
tx_bytes += ttx_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
storage->rx_packets += rx_packets;
|
|
||||||
storage->rx_bytes += rx_bytes;
|
|
||||||
storage->tx_packets += tx_packets;
|
|
||||||
storage->tx_bytes += tx_bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops hfi1_ipoib_netdev_ops = {
|
static const struct net_device_ops hfi1_ipoib_netdev_ops = {
|
||||||
|
@@ -473,6 +473,10 @@ config NET_SB1000
|
|||||||
|
|
||||||
source "drivers/net/phy/Kconfig"
|
source "drivers/net/phy/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/net/mdio/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/net/pcs/Kconfig"
|
||||||
|
|
||||||
source "drivers/net/plip/Kconfig"
|
source "drivers/net/plip/Kconfig"
|
||||||
|
|
||||||
source "drivers/net/ppp/Kconfig"
|
source "drivers/net/ppp/Kconfig"
|
||||||
|
@@ -21,6 +21,8 @@ obj-$(CONFIG_MDIO) += mdio.o
|
|||||||
obj-$(CONFIG_NET) += Space.o loopback.o
|
obj-$(CONFIG_NET) += Space.o loopback.o
|
||||||
obj-$(CONFIG_NETCONSOLE) += netconsole.o
|
obj-$(CONFIG_NETCONSOLE) += netconsole.o
|
||||||
obj-y += phy/
|
obj-y += phy/
|
||||||
|
obj-y += mdio/
|
||||||
|
obj-y += pcs/
|
||||||
obj-$(CONFIG_RIONET) += rionet.o
|
obj-$(CONFIG_RIONET) += rionet.o
|
||||||
obj-$(CONFIG_NET_TEAM) += team/
|
obj-$(CONFIG_NET_TEAM) += team/
|
||||||
obj-$(CONFIG_TUN) += tun.o
|
obj-$(CONFIG_TUN) += tun.o
|
||||||
|
@@ -70,6 +70,8 @@ static const char *version =
|
|||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
|
||||||
|
#include <net/Space.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/dma.h>
|
#include <asm/dma.h>
|
||||||
|
|
||||||
|
@@ -229,6 +229,8 @@ static int dma;
|
|||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
|
|
||||||
|
#include <net/Space.h>
|
||||||
|
|
||||||
#include <asm/dma.h>
|
#include <asm/dma.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
@@ -54,7 +54,6 @@ struct bareudp_dev {
|
|||||||
static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct metadata_dst *tun_dst = NULL;
|
struct metadata_dst *tun_dst = NULL;
|
||||||
struct pcpu_sw_netstats *stats;
|
|
||||||
struct bareudp_dev *bareudp;
|
struct bareudp_dev *bareudp;
|
||||||
unsigned short family;
|
unsigned short family;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
@@ -160,13 +159,9 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
|||||||
|
|
||||||
len = skb->len;
|
len = skb->len;
|
||||||
err = gro_cells_receive(&bareudp->gro_cells, skb);
|
err = gro_cells_receive(&bareudp->gro_cells, skb);
|
||||||
if (likely(err == NET_RX_SUCCESS)) {
|
if (likely(err == NET_RX_SUCCESS))
|
||||||
stats = this_cpu_ptr(bareudp->dev->tstats);
|
dev_sw_netstats_rx_add(bareudp->dev, len);
|
||||||
u64_stats_update_begin(&stats->syncp);
|
|
||||||
stats->rx_packets++;
|
|
||||||
stats->rx_bytes += len;
|
|
||||||
u64_stats_update_end(&stats->syncp);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
drop:
|
drop:
|
||||||
/* Consume bad packet */
|
/* Consume bad packet */
|
||||||
|
@@ -20,25 +20,6 @@ config CAIF_TTY
|
|||||||
identified as N_CAIF. When this ldisc is opened from user space
|
identified as N_CAIF. When this ldisc is opened from user space
|
||||||
it will redirect the TTY's traffic into the CAIF stack.
|
it will redirect the TTY's traffic into the CAIF stack.
|
||||||
|
|
||||||
config CAIF_SPI_SLAVE
|
|
||||||
tristate "CAIF SPI transport driver for slave interface"
|
|
||||||
depends on CAIF && HAS_DMA
|
|
||||||
default n
|
|
||||||
help
|
|
||||||
The CAIF Link layer SPI Protocol driver for Slave SPI interface.
|
|
||||||
This driver implements a platform driver to accommodate for a
|
|
||||||
platform specific SPI device. A sample CAIF SPI Platform device is
|
|
||||||
provided in <file:Documentation/networking/caif/spi_porting.rst>.
|
|
||||||
|
|
||||||
config CAIF_SPI_SYNC
|
|
||||||
bool "Next command and length in start of frame"
|
|
||||||
depends on CAIF_SPI_SLAVE
|
|
||||||
default n
|
|
||||||
help
|
|
||||||
Putting the next command and length in the start of the frame can
|
|
||||||
help to synchronize to the next transfer in case of over or under-runs.
|
|
||||||
This option also needs to be enabled on the modem.
|
|
||||||
|
|
||||||
config CAIF_HSI
|
config CAIF_HSI
|
||||||
tristate "CAIF HSI transport driver"
|
tristate "CAIF HSI transport driver"
|
||||||
depends on CAIF
|
depends on CAIF
|
||||||
|
@@ -4,10 +4,6 @@ ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG
|
|||||||
# Serial interface
|
# Serial interface
|
||||||
obj-$(CONFIG_CAIF_TTY) += caif_serial.o
|
obj-$(CONFIG_CAIF_TTY) += caif_serial.o
|
||||||
|
|
||||||
# SPI slave physical interfaces module
|
|
||||||
cfspi_slave-objs := caif_spi.o caif_spi_slave.o
|
|
||||||
obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
|
|
||||||
|
|
||||||
# HSI interface
|
# HSI interface
|
||||||
obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
|
obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
|
||||||
|
|
||||||
|
@@ -458,15 +458,7 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
|
|||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
skb->dev = cfhsi->ndev;
|
skb->dev = cfhsi->ndev;
|
||||||
|
|
||||||
/*
|
netif_rx_any_context(skb);
|
||||||
* We are in a callback handler and
|
|
||||||
* unfortunately we don't know what context we're
|
|
||||||
* running in.
|
|
||||||
*/
|
|
||||||
if (in_interrupt())
|
|
||||||
netif_rx(skb);
|
|
||||||
else
|
|
||||||
netif_rx_ni(skb);
|
|
||||||
|
|
||||||
/* Update network statistics. */
|
/* Update network statistics. */
|
||||||
cfhsi->ndev->stats.rx_packets++;
|
cfhsi->ndev->stats.rx_packets++;
|
||||||
@@ -587,14 +579,7 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
|
|||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
skb->dev = cfhsi->ndev;
|
skb->dev = cfhsi->ndev;
|
||||||
|
|
||||||
/*
|
netif_rx_any_context(skb);
|
||||||
* We're called in callback from HSI
|
|
||||||
* and don't know the context we're running in.
|
|
||||||
*/
|
|
||||||
if (in_interrupt())
|
|
||||||
netif_rx(skb);
|
|
||||||
else
|
|
||||||
netif_rx_ni(skb);
|
|
||||||
|
|
||||||
/* Update network statistics. */
|
/* Update network statistics. */
|
||||||
cfhsi->ndev->stats.rx_packets++;
|
cfhsi->ndev->stats.rx_packets++;
|
||||||
|
@@ -1,874 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
/*
|
|
||||||
* Copyright (C) ST-Ericsson AB 2010
|
|
||||||
* Author: Daniel Martensson
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/completion.h>
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/debugfs.h>
|
|
||||||
#include <linux/if_arp.h>
|
|
||||||
#include <net/caif/caif_layer.h>
|
|
||||||
#include <net/caif/caif_spi.h>
|
|
||||||
|
|
||||||
#ifndef CONFIG_CAIF_SPI_SYNC
|
|
||||||
#define FLAVOR "Flavour: Vanilla.\n"
|
|
||||||
#else
|
|
||||||
#define FLAVOR "Flavour: Master CMD&LEN at start.\n"
|
|
||||||
#endif /* CONFIG_CAIF_SPI_SYNC */
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
MODULE_AUTHOR("Daniel Martensson");
|
|
||||||
MODULE_DESCRIPTION("CAIF SPI driver");
|
|
||||||
|
|
||||||
/* Returns the number of padding bytes for alignment. */
|
|
||||||
#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
|
|
||||||
|
|
||||||
static bool spi_loop;
|
|
||||||
module_param(spi_loop, bool, 0444);
|
|
||||||
MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
|
|
||||||
|
|
||||||
/* SPI frame alignment. */
|
|
||||||
module_param(spi_frm_align, int, 0444);
|
|
||||||
MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SPI padding options.
|
|
||||||
* Warning: must be a base of 2 (& operation used) and can not be zero !
|
|
||||||
*/
|
|
||||||
module_param(spi_up_head_align, int, 0444);
|
|
||||||
MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
|
|
||||||
|
|
||||||
module_param(spi_up_tail_align, int, 0444);
|
|
||||||
MODULE_PARM_DESC(spi_up_tail_align, "SPI uplink tail alignment.");
|
|
||||||
|
|
||||||
module_param(spi_down_head_align, int, 0444);
|
|
||||||
MODULE_PARM_DESC(spi_down_head_align, "SPI downlink head alignment.");
|
|
||||||
|
|
||||||
module_param(spi_down_tail_align, int, 0444);
|
|
||||||
MODULE_PARM_DESC(spi_down_tail_align, "SPI downlink tail alignment.");
|
|
||||||
|
|
||||||
#ifdef CONFIG_ARM
|
|
||||||
#define BYTE_HEX_FMT "%02X"
|
|
||||||
#else
|
|
||||||
#define BYTE_HEX_FMT "%02hhX"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPI_MAX_PAYLOAD_SIZE 4096
|
|
||||||
/*
|
|
||||||
* Threshold values for the SPI packet queue. Flowcontrol will be asserted
|
|
||||||
* when the number of packets exceeds HIGH_WATER_MARK. It will not be
|
|
||||||
* deasserted before the number of packets drops below LOW_WATER_MARK.
|
|
||||||
*/
|
|
||||||
#define LOW_WATER_MARK 100
|
|
||||||
#define HIGH_WATER_MARK (LOW_WATER_MARK*5)
|
|
||||||
|
|
||||||
#ifndef CONFIG_HAS_DMA
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We sometimes use UML for debugging, but it cannot handle
|
|
||||||
* dma_alloc_coherent so we have to wrap it.
|
|
||||||
*/
|
|
||||||
static inline void *dma_alloc(struct cfspi *cfspi, dma_addr_t *daddr)
|
|
||||||
{
|
|
||||||
return kmalloc(SPI_DMA_BUF_LEN, GFP_KERNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dma_free(struct cfspi *cfspi, void *cpu_addr,
|
|
||||||
dma_addr_t handle)
|
|
||||||
{
|
|
||||||
kfree(cpu_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline void *dma_alloc(struct cfspi *cfspi, dma_addr_t *daddr)
|
|
||||||
{
|
|
||||||
return dma_alloc_coherent(&cfspi->pdev->dev, SPI_DMA_BUF_LEN, daddr,
|
|
||||||
GFP_KERNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dma_free(struct cfspi *cfspi, void *cpu_addr,
|
|
||||||
dma_addr_t handle)
|
|
||||||
{
|
|
||||||
dma_free_coherent(&cfspi->pdev->dev, SPI_DMA_BUF_LEN, cpu_addr, handle);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_HAS_DMA */
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
|
|
||||||
#define DEBUGFS_BUF_SIZE 4096
|
|
||||||
|
|
||||||
static struct dentry *dbgfs_root;
|
|
||||||
|
|
||||||
static inline void driver_debugfs_create(void)
|
|
||||||
{
|
|
||||||
dbgfs_root = debugfs_create_dir(cfspi_spi_driver.driver.name, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void driver_debugfs_remove(void)
|
|
||||||
{
|
|
||||||
debugfs_remove(dbgfs_root);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dev_debugfs_rem(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
debugfs_remove(cfspi->dbgfs_frame);
|
|
||||||
debugfs_remove(cfspi->dbgfs_state);
|
|
||||||
debugfs_remove(cfspi->dbgfs_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
char *buf;
|
|
||||||
int len = 0;
|
|
||||||
ssize_t size;
|
|
||||||
struct cfspi *cfspi = file->private_data;
|
|
||||||
|
|
||||||
buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
|
|
||||||
if (!buf)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Print out debug information. */
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"CAIF SPI debug information:\n");
|
|
||||||
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
|
|
||||||
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"STATE: %d\n", cfspi->dbg_state);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Previous CMD: 0x%x\n", cfspi->pcmd);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Current CMD: 0x%x\n", cfspi->cmd);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Previous TX len: %d\n", cfspi->tx_ppck_len);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Previous RX len: %d\n", cfspi->rx_ppck_len);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Current TX len: %d\n", cfspi->tx_cpck_len);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Current RX len: %d\n", cfspi->rx_cpck_len);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Next TX len: %d\n", cfspi->tx_npck_len);
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Next RX len: %d\n", cfspi->rx_npck_len);
|
|
||||||
|
|
||||||
if (len > DEBUGFS_BUF_SIZE)
|
|
||||||
len = DEBUGFS_BUF_SIZE;
|
|
||||||
|
|
||||||
size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
||||||
kfree(buf);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t print_frame(char *buf, size_t size, char *frm,
|
|
||||||
size_t count, size_t cut)
|
|
||||||
{
|
|
||||||
int len = 0;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
len += scnprintf((buf + len), (size - len),
|
|
||||||
"[0x" BYTE_HEX_FMT "]",
|
|
||||||
frm[i]);
|
|
||||||
if ((i == cut) && (count > (cut * 2))) {
|
|
||||||
/* Fast forward. */
|
|
||||||
i = count - cut;
|
|
||||||
len += scnprintf((buf + len), (size - len),
|
|
||||||
"--- %zu bytes skipped ---\n",
|
|
||||||
count - (cut * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!(i % 10)) && i) {
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
char *buf;
|
|
||||||
int len = 0;
|
|
||||||
ssize_t size;
|
|
||||||
struct cfspi *cfspi;
|
|
||||||
|
|
||||||
cfspi = file->private_data;
|
|
||||||
buf = kzalloc(DEBUGFS_BUF_SIZE, GFP_KERNEL);
|
|
||||||
if (!buf)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Print out debug information. */
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Current frame:\n");
|
|
||||||
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Tx data (Len: %d):\n", cfspi->tx_cpck_len);
|
|
||||||
|
|
||||||
len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
cfspi->xfer.va_tx[0],
|
|
||||||
(cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
|
|
||||||
|
|
||||||
len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
"Rx data (Len: %d):\n", cfspi->rx_cpck_len);
|
|
||||||
|
|
||||||
len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
|
|
||||||
cfspi->xfer.va_rx,
|
|
||||||
(cfspi->rx_cpck_len + SPI_CMD_SZ), 100);
|
|
||||||
|
|
||||||
size = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
||||||
kfree(buf);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations dbgfs_state_fops = {
|
|
||||||
.open = simple_open,
|
|
||||||
.read = dbgfs_state,
|
|
||||||
.owner = THIS_MODULE
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct file_operations dbgfs_frame_fops = {
|
|
||||||
.open = simple_open,
|
|
||||||
.read = dbgfs_frame,
|
|
||||||
.owner = THIS_MODULE
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void dev_debugfs_add(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
cfspi->dbgfs_dir = debugfs_create_dir(cfspi->pdev->name, dbgfs_root);
|
|
||||||
cfspi->dbgfs_state = debugfs_create_file("state", 0444,
|
|
||||||
cfspi->dbgfs_dir, cfspi,
|
|
||||||
&dbgfs_state_fops);
|
|
||||||
cfspi->dbgfs_frame = debugfs_create_file("frame", 0444,
|
|
||||||
cfspi->dbgfs_dir, cfspi,
|
|
||||||
&dbgfs_frame_fops);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
|
|
||||||
{
|
|
||||||
cfspi->dbg_state = state;
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline void driver_debugfs_create(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void driver_debugfs_remove(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dev_debugfs_add(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dev_debugfs_rem(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void cfspi_dbg_state(struct cfspi *cfspi, int state)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_DEBUG_FS */
|
|
||||||
|
|
||||||
static LIST_HEAD(cfspi_list);
|
|
||||||
static spinlock_t cfspi_list_lock;
|
|
||||||
|
|
||||||
/* SPI uplink head alignment. */
|
|
||||||
static ssize_t up_head_align_show(struct device_driver *driver, char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%d\n", spi_up_head_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DRIVER_ATTR_RO(up_head_align);
|
|
||||||
|
|
||||||
/* SPI uplink tail alignment. */
|
|
||||||
static ssize_t up_tail_align_show(struct device_driver *driver, char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%d\n", spi_up_tail_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DRIVER_ATTR_RO(up_tail_align);
|
|
||||||
|
|
||||||
/* SPI downlink head alignment. */
|
|
||||||
static ssize_t down_head_align_show(struct device_driver *driver, char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%d\n", spi_down_head_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DRIVER_ATTR_RO(down_head_align);
|
|
||||||
|
|
||||||
/* SPI downlink tail alignment. */
|
|
||||||
static ssize_t down_tail_align_show(struct device_driver *driver, char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%d\n", spi_down_tail_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DRIVER_ATTR_RO(down_tail_align);
|
|
||||||
|
|
||||||
/* SPI frame alignment. */
|
|
||||||
static ssize_t frame_align_show(struct device_driver *driver, char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%d\n", spi_frm_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DRIVER_ATTR_RO(frame_align);
|
|
||||||
|
|
||||||
int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
u8 *dst = buf;
|
|
||||||
caif_assert(buf);
|
|
||||||
|
|
||||||
if (cfspi->slave && !cfspi->slave_talked)
|
|
||||||
cfspi->slave_talked = true;
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct sk_buff *skb;
|
|
||||||
struct caif_payload_info *info;
|
|
||||||
int spad = 0;
|
|
||||||
int epad;
|
|
||||||
|
|
||||||
skb = skb_dequeue(&cfspi->chead);
|
|
||||||
if (!skb)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate length of frame including SPI padding.
|
|
||||||
* The payload position is found in the control buffer.
|
|
||||||
*/
|
|
||||||
info = (struct caif_payload_info *)&skb->cb;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute head offset i.e. number of bytes to add to
|
|
||||||
* get the start of the payload aligned.
|
|
||||||
*/
|
|
||||||
if (spi_up_head_align > 1) {
|
|
||||||
spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
|
|
||||||
*dst = (u8)(spad - 1);
|
|
||||||
dst += spad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy in CAIF frame. */
|
|
||||||
skb_copy_bits(skb, 0, dst, skb->len);
|
|
||||||
dst += skb->len;
|
|
||||||
cfspi->ndev->stats.tx_packets++;
|
|
||||||
cfspi->ndev->stats.tx_bytes += skb->len;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute tail offset i.e. number of bytes to add to
|
|
||||||
* get the complete CAIF frame aligned.
|
|
||||||
*/
|
|
||||||
epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
|
|
||||||
dst += epad;
|
|
||||||
|
|
||||||
dev_kfree_skb(skb);
|
|
||||||
|
|
||||||
} while ((dst - buf) < len);
|
|
||||||
|
|
||||||
return dst - buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfspi_xmitlen(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
struct sk_buff *skb = NULL;
|
|
||||||
int frm_len = 0;
|
|
||||||
int pkts = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decommit previously committed frames.
|
|
||||||
* skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead)
|
|
||||||
*/
|
|
||||||
while (skb_peek(&cfspi->chead)) {
|
|
||||||
skb = skb_dequeue_tail(&cfspi->chead);
|
|
||||||
skb_queue_head(&cfspi->qhead, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct caif_payload_info *info = NULL;
|
|
||||||
int spad = 0;
|
|
||||||
int epad = 0;
|
|
||||||
|
|
||||||
skb = skb_dequeue(&cfspi->qhead);
|
|
||||||
if (!skb)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate length of frame including SPI padding.
|
|
||||||
* The payload position is found in the control buffer.
|
|
||||||
*/
|
|
||||||
info = (struct caif_payload_info *)&skb->cb;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute head offset i.e. number of bytes to add to
|
|
||||||
* get the start of the payload aligned.
|
|
||||||
*/
|
|
||||||
if (spi_up_head_align > 1)
|
|
||||||
spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute tail offset i.e. number of bytes to add to
|
|
||||||
* get the complete CAIF frame aligned.
|
|
||||||
*/
|
|
||||||
epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
|
|
||||||
|
|
||||||
if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
|
|
||||||
skb_queue_tail(&cfspi->chead, skb);
|
|
||||||
pkts++;
|
|
||||||
frm_len += skb->len + spad + epad;
|
|
||||||
} else {
|
|
||||||
/* Put back packet. */
|
|
||||||
skb_queue_head(&cfspi->qhead, skb);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (pkts <= CAIF_MAX_SPI_PKTS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send flow on if previously sent flow off
|
|
||||||
* and now go below the low water mark
|
|
||||||
*/
|
|
||||||
if (cfspi->flow_off_sent && cfspi->qhead.qlen < cfspi->qd_low_mark &&
|
|
||||||
cfspi->cfdev.flowctrl) {
|
|
||||||
cfspi->flow_off_sent = 0;
|
|
||||||
cfspi->cfdev.flowctrl(cfspi->ndev, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return frm_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi = (struct cfspi *)ifc->priv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The slave device is the master on the link. Interrupts before the
|
|
||||||
* slave has transmitted are considered spurious.
|
|
||||||
*/
|
|
||||||
if (cfspi->slave && !cfspi->slave_talked) {
|
|
||||||
printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_interrupt())
|
|
||||||
spin_lock(&cfspi->lock);
|
|
||||||
if (assert) {
|
|
||||||
set_bit(SPI_SS_ON, &cfspi->state);
|
|
||||||
set_bit(SPI_XFER, &cfspi->state);
|
|
||||||
} else {
|
|
||||||
set_bit(SPI_SS_OFF, &cfspi->state);
|
|
||||||
}
|
|
||||||
if (!in_interrupt())
|
|
||||||
spin_unlock(&cfspi->lock);
|
|
||||||
|
|
||||||
/* Wake up the xfer thread. */
|
|
||||||
if (assert)
|
|
||||||
wake_up_interruptible(&cfspi->wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi = (struct cfspi *)ifc->priv;
|
|
||||||
|
|
||||||
/* Transfer done, complete work queue */
|
|
||||||
complete(&cfspi->comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static netdev_tx_t cfspi_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi = NULL;
|
|
||||||
unsigned long flags;
|
|
||||||
if (!dev)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
cfspi = netdev_priv(dev);
|
|
||||||
|
|
||||||
skb_queue_tail(&cfspi->qhead, skb);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&cfspi->lock, flags);
|
|
||||||
if (!test_and_set_bit(SPI_XFER, &cfspi->state)) {
|
|
||||||
/* Wake up xfer thread. */
|
|
||||||
wake_up_interruptible(&cfspi->wait);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&cfspi->lock, flags);
|
|
||||||
|
|
||||||
/* Send flow off if number of bytes is above high water mark */
|
|
||||||
if (!cfspi->flow_off_sent &&
|
|
||||||
cfspi->qhead.qlen > cfspi->qd_high_mark &&
|
|
||||||
cfspi->cfdev.flowctrl) {
|
|
||||||
cfspi->flow_off_sent = 1;
|
|
||||||
cfspi->cfdev.flowctrl(cfspi->ndev, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NETDEV_TX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
|
|
||||||
{
|
|
||||||
u8 *src = buf;
|
|
||||||
|
|
||||||
caif_assert(buf != NULL);
|
|
||||||
|
|
||||||
do {
|
|
||||||
int res;
|
|
||||||
struct sk_buff *skb = NULL;
|
|
||||||
int spad = 0;
|
|
||||||
int epad = 0;
|
|
||||||
int pkt_len = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute head offset i.e. number of bytes added to
|
|
||||||
* get the start of the payload aligned.
|
|
||||||
*/
|
|
||||||
if (spi_down_head_align > 1) {
|
|
||||||
spad = 1 + *src;
|
|
||||||
src += spad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read length of CAIF frame (little endian). */
|
|
||||||
pkt_len = *src;
|
|
||||||
pkt_len |= ((*(src+1)) << 8) & 0xFF00;
|
|
||||||
pkt_len += 2; /* Add FCS fields. */
|
|
||||||
|
|
||||||
/* Get a suitable caif packet and copy in data. */
|
|
||||||
|
|
||||||
skb = netdev_alloc_skb(cfspi->ndev, pkt_len + 1);
|
|
||||||
caif_assert(skb != NULL);
|
|
||||||
|
|
||||||
skb_put_data(skb, src, pkt_len);
|
|
||||||
src += pkt_len;
|
|
||||||
|
|
||||||
skb->protocol = htons(ETH_P_CAIF);
|
|
||||||
skb_reset_mac_header(skb);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Push received packet up the stack.
|
|
||||||
*/
|
|
||||||
if (!spi_loop)
|
|
||||||
res = netif_rx_ni(skb);
|
|
||||||
else
|
|
||||||
res = cfspi_xmit(skb, cfspi->ndev);
|
|
||||||
|
|
||||||
if (!res) {
|
|
||||||
cfspi->ndev->stats.rx_packets++;
|
|
||||||
cfspi->ndev->stats.rx_bytes += pkt_len;
|
|
||||||
} else
|
|
||||||
cfspi->ndev->stats.rx_dropped++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute tail offset i.e. number of bytes added to
|
|
||||||
* get the complete CAIF frame aligned.
|
|
||||||
*/
|
|
||||||
epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
|
|
||||||
src += epad;
|
|
||||||
} while ((src - buf) < len);
|
|
||||||
|
|
||||||
return src - buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cfspi_open(struct net_device *dev)
|
|
||||||
{
|
|
||||||
netif_wake_queue(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cfspi_close(struct net_device *dev)
|
|
||||||
{
|
|
||||||
netif_stop_queue(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cfspi_init(struct net_device *dev)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
struct cfspi *cfspi = netdev_priv(dev);
|
|
||||||
|
|
||||||
/* Set flow info. */
|
|
||||||
cfspi->flow_off_sent = 0;
|
|
||||||
cfspi->qd_low_mark = LOW_WATER_MARK;
|
|
||||||
cfspi->qd_high_mark = HIGH_WATER_MARK;
|
|
||||||
|
|
||||||
/* Set slave info. */
|
|
||||||
if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
|
|
||||||
cfspi->slave = true;
|
|
||||||
cfspi->slave_talked = false;
|
|
||||||
} else {
|
|
||||||
cfspi->slave = false;
|
|
||||||
cfspi->slave_talked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate DMA buffers. */
|
|
||||||
cfspi->xfer.va_tx[0] = dma_alloc(cfspi, &cfspi->xfer.pa_tx[0]);
|
|
||||||
if (!cfspi->xfer.va_tx[0]) {
|
|
||||||
res = -ENODEV;
|
|
||||||
goto err_dma_alloc_tx_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfspi->xfer.va_rx = dma_alloc(cfspi, &cfspi->xfer.pa_rx);
|
|
||||||
|
|
||||||
if (!cfspi->xfer.va_rx) {
|
|
||||||
res = -ENODEV;
|
|
||||||
goto err_dma_alloc_rx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the work queue. */
|
|
||||||
INIT_WORK(&cfspi->work, cfspi_xfer);
|
|
||||||
|
|
||||||
/* Initialize spin locks. */
|
|
||||||
spin_lock_init(&cfspi->lock);
|
|
||||||
|
|
||||||
/* Initialize flow control state. */
|
|
||||||
cfspi->flow_stop = false;
|
|
||||||
|
|
||||||
/* Initialize wait queue. */
|
|
||||||
init_waitqueue_head(&cfspi->wait);
|
|
||||||
|
|
||||||
/* Create work thread. */
|
|
||||||
cfspi->wq = create_singlethread_workqueue(dev->name);
|
|
||||||
if (!cfspi->wq) {
|
|
||||||
printk(KERN_WARNING "CFSPI: failed to create work queue.\n");
|
|
||||||
res = -ENODEV;
|
|
||||||
goto err_create_wq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize work queue. */
|
|
||||||
init_completion(&cfspi->comp);
|
|
||||||
|
|
||||||
/* Create debugfs entries. */
|
|
||||||
dev_debugfs_add(cfspi);
|
|
||||||
|
|
||||||
/* Set up the ifc. */
|
|
||||||
cfspi->ifc.ss_cb = cfspi_ss_cb;
|
|
||||||
cfspi->ifc.xfer_done_cb = cfspi_xfer_done_cb;
|
|
||||||
cfspi->ifc.priv = cfspi;
|
|
||||||
|
|
||||||
/* Add CAIF SPI device to list. */
|
|
||||||
spin_lock(&cfspi_list_lock);
|
|
||||||
list_add_tail(&cfspi->list, &cfspi_list);
|
|
||||||
spin_unlock(&cfspi_list_lock);
|
|
||||||
|
|
||||||
/* Schedule the work queue. */
|
|
||||||
queue_work(cfspi->wq, &cfspi->work);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_create_wq:
|
|
||||||
dma_free(cfspi, cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
|
|
||||||
err_dma_alloc_rx:
|
|
||||||
dma_free(cfspi, cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]);
|
|
||||||
err_dma_alloc_tx_0:
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cfspi_uninit(struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi = netdev_priv(dev);
|
|
||||||
|
|
||||||
/* Remove from list. */
|
|
||||||
spin_lock(&cfspi_list_lock);
|
|
||||||
list_del(&cfspi->list);
|
|
||||||
spin_unlock(&cfspi_list_lock);
|
|
||||||
|
|
||||||
cfspi->ndev = NULL;
|
|
||||||
/* Free DMA buffers. */
|
|
||||||
dma_free(cfspi, cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
|
|
||||||
dma_free(cfspi, cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]);
|
|
||||||
set_bit(SPI_TERMINATE, &cfspi->state);
|
|
||||||
wake_up_interruptible(&cfspi->wait);
|
|
||||||
destroy_workqueue(cfspi->wq);
|
|
||||||
/* Destroy debugfs directory and files. */
|
|
||||||
dev_debugfs_rem(cfspi);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct net_device_ops cfspi_ops = {
|
|
||||||
.ndo_open = cfspi_open,
|
|
||||||
.ndo_stop = cfspi_close,
|
|
||||||
.ndo_init = cfspi_init,
|
|
||||||
.ndo_uninit = cfspi_uninit,
|
|
||||||
.ndo_start_xmit = cfspi_xmit
|
|
||||||
};
|
|
||||||
|
|
||||||
static void cfspi_setup(struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi = netdev_priv(dev);
|
|
||||||
dev->features = 0;
|
|
||||||
dev->netdev_ops = &cfspi_ops;
|
|
||||||
dev->type = ARPHRD_CAIF;
|
|
||||||
dev->flags = IFF_NOARP | IFF_POINTOPOINT;
|
|
||||||
dev->priv_flags |= IFF_NO_QUEUE;
|
|
||||||
dev->mtu = SPI_MAX_PAYLOAD_SIZE;
|
|
||||||
dev->needs_free_netdev = true;
|
|
||||||
skb_queue_head_init(&cfspi->qhead);
|
|
||||||
skb_queue_head_init(&cfspi->chead);
|
|
||||||
cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
|
|
||||||
cfspi->cfdev.use_frag = false;
|
|
||||||
cfspi->cfdev.use_stx = false;
|
|
||||||
cfspi->cfdev.use_fcs = false;
|
|
||||||
cfspi->ndev = dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfspi_spi_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi = NULL;
|
|
||||||
struct net_device *ndev;
|
|
||||||
struct cfspi_dev *dev;
|
|
||||||
int res;
|
|
||||||
dev = (struct cfspi_dev *)pdev->dev.platform_data;
|
|
||||||
|
|
||||||
if (!dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d",
|
|
||||||
NET_NAME_UNKNOWN, cfspi_setup);
|
|
||||||
if (!ndev)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
cfspi = netdev_priv(ndev);
|
|
||||||
netif_stop_queue(ndev);
|
|
||||||
cfspi->ndev = ndev;
|
|
||||||
cfspi->pdev = pdev;
|
|
||||||
|
|
||||||
/* Assign the SPI device. */
|
|
||||||
cfspi->dev = dev;
|
|
||||||
/* Assign the device ifc to this SPI interface. */
|
|
||||||
dev->ifc = &cfspi->ifc;
|
|
||||||
|
|
||||||
/* Register network device. */
|
|
||||||
res = register_netdev(ndev);
|
|
||||||
if (res) {
|
|
||||||
printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
|
|
||||||
goto err_net_reg;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
|
|
||||||
err_net_reg:
|
|
||||||
free_netdev(ndev);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfspi_spi_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
/* Everything is done in cfspi_uninit(). */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit cfspi_exit_module(void)
|
|
||||||
{
|
|
||||||
struct list_head *list_node;
|
|
||||||
struct list_head *n;
|
|
||||||
struct cfspi *cfspi = NULL;
|
|
||||||
|
|
||||||
list_for_each_safe(list_node, n, &cfspi_list) {
|
|
||||||
cfspi = list_entry(list_node, struct cfspi, list);
|
|
||||||
unregister_netdev(cfspi->ndev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destroy sysfs files. */
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_up_head_align);
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_up_tail_align);
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_down_head_align);
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_down_tail_align);
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver, &driver_attr_frame_align);
|
|
||||||
/* Unregister platform driver. */
|
|
||||||
platform_driver_unregister(&cfspi_spi_driver);
|
|
||||||
/* Destroy debugfs root directory. */
|
|
||||||
driver_debugfs_remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init cfspi_init_module(void)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
/* Initialize spin lock. */
|
|
||||||
spin_lock_init(&cfspi_list_lock);
|
|
||||||
|
|
||||||
/* Register platform driver. */
|
|
||||||
result = platform_driver_register(&cfspi_spi_driver);
|
|
||||||
if (result) {
|
|
||||||
printk(KERN_ERR "Could not register platform SPI driver.\n");
|
|
||||||
goto err_dev_register;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create sysfs files. */
|
|
||||||
result =
|
|
||||||
driver_create_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_up_head_align);
|
|
||||||
if (result) {
|
|
||||||
printk(KERN_ERR "Sysfs creation failed 1.\n");
|
|
||||||
goto err_create_up_head_align;
|
|
||||||
}
|
|
||||||
|
|
||||||
result =
|
|
||||||
driver_create_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_up_tail_align);
|
|
||||||
if (result) {
|
|
||||||
printk(KERN_ERR "Sysfs creation failed 2.\n");
|
|
||||||
goto err_create_up_tail_align;
|
|
||||||
}
|
|
||||||
|
|
||||||
result =
|
|
||||||
driver_create_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_down_head_align);
|
|
||||||
if (result) {
|
|
||||||
printk(KERN_ERR "Sysfs creation failed 3.\n");
|
|
||||||
goto err_create_down_head_align;
|
|
||||||
}
|
|
||||||
|
|
||||||
result =
|
|
||||||
driver_create_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_down_tail_align);
|
|
||||||
if (result) {
|
|
||||||
printk(KERN_ERR "Sysfs creation failed 4.\n");
|
|
||||||
goto err_create_down_tail_align;
|
|
||||||
}
|
|
||||||
|
|
||||||
result =
|
|
||||||
driver_create_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_frame_align);
|
|
||||||
if (result) {
|
|
||||||
printk(KERN_ERR "Sysfs creation failed 5.\n");
|
|
||||||
goto err_create_frame_align;
|
|
||||||
}
|
|
||||||
driver_debugfs_create();
|
|
||||||
return result;
|
|
||||||
|
|
||||||
err_create_frame_align:
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_down_tail_align);
|
|
||||||
err_create_down_tail_align:
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_down_head_align);
|
|
||||||
err_create_down_head_align:
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_up_tail_align);
|
|
||||||
err_create_up_tail_align:
|
|
||||||
driver_remove_file(&cfspi_spi_driver.driver,
|
|
||||||
&driver_attr_up_head_align);
|
|
||||||
err_create_up_head_align:
|
|
||||||
platform_driver_unregister(&cfspi_spi_driver);
|
|
||||||
err_dev_register:
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(cfspi_init_module);
|
|
||||||
module_exit(cfspi_exit_module);
|
|
@@ -1,254 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
/*
|
|
||||||
* Copyright (C) ST-Ericsson AB 2010
|
|
||||||
* Author: Daniel Martensson
|
|
||||||
*/
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/semaphore.h>
|
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/completion.h>
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/debugfs.h>
|
|
||||||
#include <net/caif/caif_spi.h>
|
|
||||||
|
|
||||||
#ifndef CONFIG_CAIF_SPI_SYNC
|
|
||||||
#define SPI_DATA_POS 0
|
|
||||||
static inline int forward_to_spi_cmd(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
return cfspi->rx_cpck_len;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define SPI_DATA_POS SPI_CMD_SZ
|
|
||||||
static inline int forward_to_spi_cmd(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int spi_frm_align = 2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SPI padding options.
|
|
||||||
* Warning: must be a base of 2 (& operation used) and can not be zero !
|
|
||||||
*/
|
|
||||||
int spi_up_head_align = 1 << 1;
|
|
||||||
int spi_up_tail_align = 1 << 0;
|
|
||||||
int spi_down_head_align = 1 << 2;
|
|
||||||
int spi_down_tail_align = 1 << 1;
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
static inline void debugfs_store_prev(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
/* Store previous command for debugging reasons.*/
|
|
||||||
cfspi->pcmd = cfspi->cmd;
|
|
||||||
/* Store previous transfer. */
|
|
||||||
cfspi->tx_ppck_len = cfspi->tx_cpck_len;
|
|
||||||
cfspi->rx_ppck_len = cfspi->rx_cpck_len;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline void debugfs_store_prev(struct cfspi *cfspi)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void cfspi_xfer(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct cfspi *cfspi;
|
|
||||||
u8 *ptr = NULL;
|
|
||||||
unsigned long flags;
|
|
||||||
int ret;
|
|
||||||
cfspi = container_of(work, struct cfspi, work);
|
|
||||||
|
|
||||||
/* Initialize state. */
|
|
||||||
cfspi->cmd = SPI_CMD_EOT;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
|
|
||||||
|
|
||||||
/* Wait for master talk or transmit event. */
|
|
||||||
wait_event_interruptible(cfspi->wait,
|
|
||||||
test_bit(SPI_XFER, &cfspi->state) ||
|
|
||||||
test_bit(SPI_TERMINATE, &cfspi->state));
|
|
||||||
|
|
||||||
if (test_bit(SPI_TERMINATE, &cfspi->state))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if CFSPI_DBG_PREFILL
|
|
||||||
/* Prefill buffers for easier debugging. */
|
|
||||||
memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
|
|
||||||
memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
|
|
||||||
#endif /* CFSPI_DBG_PREFILL */
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
|
|
||||||
|
|
||||||
/* Check whether we have a committed frame. */
|
|
||||||
if (cfspi->tx_cpck_len) {
|
|
||||||
int len;
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
|
|
||||||
|
|
||||||
/* Copy committed SPI frames after the SPI indication. */
|
|
||||||
ptr = (u8 *) cfspi->xfer.va_tx;
|
|
||||||
ptr += SPI_IND_SZ;
|
|
||||||
len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
|
|
||||||
WARN_ON(len != cfspi->tx_cpck_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
|
|
||||||
|
|
||||||
/* Get length of next frame to commit. */
|
|
||||||
cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
|
|
||||||
|
|
||||||
WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add indication and length at the beginning of the frame,
|
|
||||||
* using little endian.
|
|
||||||
*/
|
|
||||||
ptr = (u8 *) cfspi->xfer.va_tx;
|
|
||||||
*ptr++ = SPI_CMD_IND;
|
|
||||||
*ptr++ = (SPI_CMD_IND & 0xFF00) >> 8;
|
|
||||||
*ptr++ = cfspi->tx_npck_len & 0x00FF;
|
|
||||||
*ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
|
|
||||||
|
|
||||||
/* Calculate length of DMAs. */
|
|
||||||
cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
|
|
||||||
cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
|
|
||||||
|
|
||||||
/* Add SPI TX frame alignment padding, if necessary. */
|
|
||||||
if (cfspi->tx_cpck_len &&
|
|
||||||
(cfspi->xfer.tx_dma_len % spi_frm_align)) {
|
|
||||||
|
|
||||||
cfspi->xfer.tx_dma_len += spi_frm_align -
|
|
||||||
(cfspi->xfer.tx_dma_len % spi_frm_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add SPI RX frame alignment padding, if necessary. */
|
|
||||||
if (cfspi->rx_cpck_len &&
|
|
||||||
(cfspi->xfer.rx_dma_len % spi_frm_align)) {
|
|
||||||
|
|
||||||
cfspi->xfer.rx_dma_len += spi_frm_align -
|
|
||||||
(cfspi->xfer.rx_dma_len % spi_frm_align);
|
|
||||||
}
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
|
|
||||||
|
|
||||||
/* Start transfer. */
|
|
||||||
ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
|
|
||||||
WARN_ON(ret);
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: We might be able to make an assumption if this is the
|
|
||||||
* first loop. Make sure that minimum toggle time is respected.
|
|
||||||
*/
|
|
||||||
udelay(MIN_TRANSITION_TIME_USEC);
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
|
|
||||||
|
|
||||||
/* Signal that we are ready to receive data. */
|
|
||||||
cfspi->dev->sig_xfer(true, cfspi->dev);
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
|
|
||||||
|
|
||||||
/* Wait for transfer completion. */
|
|
||||||
wait_for_completion(&cfspi->comp);
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
|
|
||||||
|
|
||||||
if (cfspi->cmd == SPI_CMD_EOT) {
|
|
||||||
/*
|
|
||||||
* Clear the master talk bit. A xfer is always at
|
|
||||||
* least two bursts.
|
|
||||||
*/
|
|
||||||
clear_bit(SPI_SS_ON, &cfspi->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
|
|
||||||
|
|
||||||
/* Make sure that the minimum toggle time is respected. */
|
|
||||||
if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
|
|
||||||
cfspi->dev->clk_mhz) <
|
|
||||||
MIN_TRANSITION_TIME_USEC) {
|
|
||||||
|
|
||||||
udelay(MIN_TRANSITION_TIME_USEC -
|
|
||||||
SPI_XFER_TIME_USEC
|
|
||||||
(cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
|
|
||||||
}
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
|
|
||||||
|
|
||||||
/* De-assert transfer signal. */
|
|
||||||
cfspi->dev->sig_xfer(false, cfspi->dev);
|
|
||||||
|
|
||||||
/* Check whether we received a CAIF packet. */
|
|
||||||
if (cfspi->rx_cpck_len) {
|
|
||||||
int len;
|
|
||||||
|
|
||||||
cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
|
|
||||||
|
|
||||||
/* Parse SPI frame. */
|
|
||||||
ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
|
|
||||||
|
|
||||||
len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
|
|
||||||
WARN_ON(len != cfspi->rx_cpck_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the next SPI command and length. */
|
|
||||||
ptr = (u8 *) cfspi->xfer.va_rx;
|
|
||||||
|
|
||||||
ptr += forward_to_spi_cmd(cfspi);
|
|
||||||
|
|
||||||
cfspi->cmd = *ptr++;
|
|
||||||
cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
|
|
||||||
cfspi->rx_npck_len = *ptr++;
|
|
||||||
cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
|
|
||||||
|
|
||||||
WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
|
|
||||||
WARN_ON(cfspi->cmd > SPI_CMD_EOT);
|
|
||||||
|
|
||||||
debugfs_store_prev(cfspi);
|
|
||||||
|
|
||||||
/* Check whether the master issued an EOT command. */
|
|
||||||
if (cfspi->cmd == SPI_CMD_EOT) {
|
|
||||||
/* Reset state. */
|
|
||||||
cfspi->tx_cpck_len = 0;
|
|
||||||
cfspi->rx_cpck_len = 0;
|
|
||||||
} else {
|
|
||||||
/* Update state. */
|
|
||||||
cfspi->tx_cpck_len = cfspi->tx_npck_len;
|
|
||||||
cfspi->rx_cpck_len = cfspi->rx_npck_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether we need to clear the xfer bit.
|
|
||||||
* Spin lock needed for packet insertion.
|
|
||||||
* Test and clear of different bits
|
|
||||||
* are not supported.
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave(&cfspi->lock, flags);
|
|
||||||
if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
|
|
||||||
&& !test_bit(SPI_SS_ON, &cfspi->state))
|
|
||||||
clear_bit(SPI_XFER, &cfspi->state);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&cfspi->lock, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct platform_driver cfspi_spi_driver = {
|
|
||||||
.probe = cfspi_spi_probe,
|
|
||||||
.remove = cfspi_spi_remove,
|
|
||||||
.driver = {
|
|
||||||
.name = "cfspi_sspi",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
},
|
|
||||||
};
|
|
@@ -652,7 +652,7 @@ static int cfv_probe(struct virtio_device *vdev)
|
|||||||
const char *cfv_netdev_name = "cfvrt";
|
const char *cfv_netdev_name = "cfvrt";
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
struct cfv_info *cfv;
|
struct cfv_info *cfv;
|
||||||
int err = -EINVAL;
|
int err;
|
||||||
|
|
||||||
netdev = alloc_netdev(sizeof(struct cfv_info), cfv_netdev_name,
|
netdev = alloc_netdev(sizeof(struct cfv_info), cfv_netdev_name,
|
||||||
NET_NAME_UNKNOWN, cfv_netdev_setup);
|
NET_NAME_UNKNOWN, cfv_netdev_setup);
|
||||||
|
@@ -41,8 +41,8 @@ config CAN_SLCAN
|
|||||||
www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
|
www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
|
||||||
|
|
||||||
Userspace tools to attach the SLCAN line discipline (slcan_attach,
|
Userspace tools to attach the SLCAN line discipline (slcan_attach,
|
||||||
slcand) can be found in the can-utils at the SocketCAN SVN, see
|
slcand) can be found in the can-utils at the linux-can project, see
|
||||||
http://developer.berlios.de/projects/socketcan for details.
|
https://github.com/linux-can/can-utils for details.
|
||||||
|
|
||||||
The slcan driver supports up to 10 CAN netdevices by default which
|
The slcan driver supports up to 10 CAN netdevices by default which
|
||||||
can be changed by the 'maxdev=xx' module option. This driver can
|
can be changed by the 'maxdev=xx' module option. This driver can
|
||||||
|
@@ -643,7 +643,7 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
|
|||||||
*
|
*
|
||||||
* The first message goes into mb nr. 1 and issues an interrupt. All
|
* The first message goes into mb nr. 1 and issues an interrupt. All
|
||||||
* rx ints are disabled in the interrupt handler and a napi poll is
|
* rx ints are disabled in the interrupt handler and a napi poll is
|
||||||
* scheduled. We read the mailbox, but do _not_ reenable the mb (to
|
* scheduled. We read the mailbox, but do _not_ re-enable the mb (to
|
||||||
* receive another message).
|
* receive another message).
|
||||||
*
|
*
|
||||||
* lower mbxs upper
|
* lower mbxs upper
|
||||||
@@ -661,13 +661,13 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
|
|||||||
*
|
*
|
||||||
* The variable priv->rx_next points to the next mailbox to read a
|
* The variable priv->rx_next points to the next mailbox to read a
|
||||||
* message from. As long we're in the lower mailboxes we just read the
|
* message from. As long we're in the lower mailboxes we just read the
|
||||||
* mailbox but not reenable it.
|
* mailbox but not re-enable it.
|
||||||
*
|
*
|
||||||
* With completion of the last of the lower mailboxes, we reenable the
|
* With completion of the last of the lower mailboxes, we re-enable the
|
||||||
* whole first group, but continue to look for filled mailboxes in the
|
* whole first group, but continue to look for filled mailboxes in the
|
||||||
* upper mailboxes. Imagine the second group like overflow mailboxes,
|
* upper mailboxes. Imagine the second group like overflow mailboxes,
|
||||||
* which takes CAN messages if the lower goup is full. While in the
|
* which takes CAN messages if the lower goup is full. While in the
|
||||||
* upper group we reenable the mailbox right after reading it. Giving
|
* upper group we re-enable the mailbox right after reading it. Giving
|
||||||
* the chip more room to store messages.
|
* the chip more room to store messages.
|
||||||
*
|
*
|
||||||
* After finishing we look again in the lower group if we've still
|
* After finishing we look again in the lower group if we've still
|
||||||
|
@@ -356,15 +356,6 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
|
|
||||||
int iface)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++)
|
|
||||||
c_can_object_get(dev, iface, i, IF_COMM_CLR_NEWDAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int c_can_handle_lost_msg_obj(struct net_device *dev,
|
static int c_can_handle_lost_msg_obj(struct net_device *dev,
|
||||||
int iface, int objno, u32 ctrl)
|
int iface, int objno, u32 ctrl)
|
||||||
{
|
{
|
||||||
|
@@ -81,7 +81,7 @@ enum reg {
|
|||||||
C_CAN_FUNCTION_REG,
|
C_CAN_FUNCTION_REG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u16 reg_map_c_can[] = {
|
static const u16 __maybe_unused reg_map_c_can[] = {
|
||||||
[C_CAN_CTRL_REG] = 0x00,
|
[C_CAN_CTRL_REG] = 0x00,
|
||||||
[C_CAN_STS_REG] = 0x02,
|
[C_CAN_STS_REG] = 0x02,
|
||||||
[C_CAN_ERR_CNT_REG] = 0x04,
|
[C_CAN_ERR_CNT_REG] = 0x04,
|
||||||
@@ -121,7 +121,7 @@ static const u16 reg_map_c_can[] = {
|
|||||||
[C_CAN_MSGVAL2_REG] = 0xB2,
|
[C_CAN_MSGVAL2_REG] = 0xB2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u16 reg_map_d_can[] = {
|
static const u16 __maybe_unused reg_map_d_can[] = {
|
||||||
[C_CAN_CTRL_REG] = 0x00,
|
[C_CAN_CTRL_REG] = 0x00,
|
||||||
[C_CAN_CTRL_EX_REG] = 0x02,
|
[C_CAN_CTRL_EX_REG] = 0x02,
|
||||||
[C_CAN_STS_REG] = 0x04,
|
[C_CAN_STS_REG] = 0x04,
|
||||||
|
@@ -538,7 +538,7 @@ static int cc770_err(struct net_device *dev, u8 status)
|
|||||||
priv->can.can_stats.error_warning++;
|
priv->can.can_stats.error_warning++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Back to error avtive */
|
/* Back to error active */
|
||||||
cf->can_id |= CAN_ERR_PROT;
|
cf->can_id |= CAN_ERR_PROT;
|
||||||
cf->data[2] = CAN_ERR_PROT_ACTIVE;
|
cf->data[2] = CAN_ERR_PROT_ACTIVE;
|
||||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||||
|
@@ -184,7 +184,7 @@ struct cc770_priv {
|
|||||||
u8 control_normal_mode; /* Control register for normal mode */
|
u8 control_normal_mode; /* Control register for normal mode */
|
||||||
u8 cpu_interface; /* CPU interface register */
|
u8 cpu_interface; /* CPU interface register */
|
||||||
u8 clkout; /* Clock out register */
|
u8 clkout; /* Clock out register */
|
||||||
u8 bus_config; /* Bus conffiguration register */
|
u8 bus_config; /* Bus configuration register */
|
||||||
|
|
||||||
struct sk_buff *tx_skb;
|
struct sk_buff *tx_skb;
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user