forked from Minki/linux
Networking updates for 5.11
Core: - support "prefer busy polling" NAPI operation mode, where we defer softirq for some time expecting applications to periodically busy poll - AF_XDP: improve efficiency by more batching and hindering the adjacency cache prefetcher - af_packet: make packet_fanout.arr size configurable up to 64K - tcp: optimize TCP zero copy receive in presence of partial or unaligned reads making zero copy a performance win for much smaller messages - XDP: add bulk APIs for returning / freeing frames - sched: support fragmenting IP packets as they come out of conntrack - net: allow virtual netdevs to forward UDP L4 and fraglist GSO skbs BPF: - BPF switch from crude rlimit-based to memcg-based memory accounting - BPF type format information for kernel modules and related tracing enhancements - BPF implement task local storage for BPF LSM - allow the FENTRY/FEXIT/RAW_TP tracing programs to use bpf_sk_storage Protocols: - mptcp: improve multiple xmit streams support, memory accounting and many smaller improvements - TLS: support CHACHA20-POLY1305 cipher - seg6: add support for SRv6 End.DT4/DT6 behavior - sctp: Implement RFC 6951: UDP Encapsulation of SCTP - ppp_generic: add ability to bridge channels directly - bridge: Connectivity Fault Management (CFM) support as is defined in IEEE 802.1Q section 12.14. Drivers: - mlx5: make use of the new auxiliary bus to organize the driver internals - mlx5: more accurate port TX timestamping support - mlxsw: - improve the efficiency of offloaded next hop updates by using the new nexthop object API - support blackhole nexthops - support IEEE 802.1ad (Q-in-Q) bridging - rtw88: major bluetooth co-existance improvements - iwlwifi: support new 6 GHz frequency band - ath11k: Fast Initial Link Setup (FILS) - mt7915: dual band concurrent (DBDC) support - net: ipa: add basic support for IPA v4.5 Refactor: - a few pieces of in_interrupt() cleanup work from Sebastian Andrzej Siewior - phy: add support for shared interrupts; get rid of multiple driver APIs and have the drivers write a full IRQ handler, slight growth of driver code should be compensated by the simpler API which also allows shared IRQs - add common code for handling netdev per-cpu counters - move TX packet re-allocation from Ethernet switch tag drivers to a central place - improve efficiency and rename nla_strlcpy - number of W=1 warning cleanups as we now catch those in a patchwork build bot Old code removal: - wan: delete the DLCI / SDLA drivers - wimax: move to staging - wifi: remove old WDS wifi bridging support Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAl/YXmUACgkQMUZtbf5S IrvSQBAAgOrt4EFopEvVqlTHZbqI45IEqgtXS+YWmlgnjZCgshyMj8q1yK1zzane qYxr/NNJ9kV3FdtaynmmHPgEEEfR5kJ/D3B2BsxYDkaDDrD0vbNsBGw+L+/Gbhxl N/5l/9FjLyLY1D+EErknuwR5XGuQ6BSDVaKQMhYOiK2hgdnAAI4hszo8Chf6wdD0 XDBslQ7vpD/05r+eMj0IkS5dSAoGOIFXUxhJ5dqrDbRHiKsIyWqA3PLbYemfAhxI s2XckjfmSgGE3FKL8PSFu+EcfHbJQQjLcULJUnqgVcdwEEtRuE9ggEi52nZRXMWM 4e8sQJAR9Fx7pZy0G1xfS149j6iPU5LjRlU9TNSpVABz14Vvvo3gEL6gyIdsz+xh hMN7UBdp0FEaP028CXoIYpaBesvQqj0BSndmee8qsYAtN6j+QKcM2AOSr7JN1uMH C/86EDoGAATiEQIVWJvnX5MPmlAoblyLA+RuVhmxkIBx2InGXkFmWqRkXT5l4jtk LVl8/TArR4alSQqLXictXCjYlCm9j5N4zFFtEVasSYi7/ZoPfgRNWT+lJ2R8Y+Zv +htzGaFuyj6RJTVeFQMrkl3whAtBamo2a0kwg45NnxmmXcspN6kJX1WOIy82+MhD Yht7uplSs7MGKA78q/CDU0XBeGjpABUvmplUQBIfrR/jKLW2730= =GXs1 -----END PGP SIGNATURE----- Merge tag 'net-next-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - support "prefer busy polling" NAPI operation mode, where we defer softirq for some time expecting applications to periodically busy poll - AF_XDP: improve efficiency by more batching and hindering the adjacency cache prefetcher - af_packet: make packet_fanout.arr size configurable up to 64K - tcp: optimize TCP zero copy receive in presence of partial or unaligned reads making zero copy a performance win for much smaller messages - XDP: add bulk APIs for returning / freeing frames - sched: support fragmenting IP packets as they come out of conntrack - net: allow virtual netdevs to forward UDP L4 and fraglist GSO skbs BPF: - BPF switch from crude rlimit-based to memcg-based memory accounting - BPF type format information for kernel modules and related tracing enhancements - BPF implement task local storage for BPF LSM - allow the FENTRY/FEXIT/RAW_TP tracing programs to use bpf_sk_storage Protocols: - mptcp: improve multiple xmit streams support, memory accounting and many smaller improvements - TLS: support CHACHA20-POLY1305 cipher - seg6: add support for SRv6 End.DT4/DT6 behavior - sctp: Implement RFC 6951: UDP Encapsulation of SCTP - ppp_generic: add ability to bridge channels directly - bridge: Connectivity Fault Management (CFM) support as is defined in IEEE 802.1Q section 12.14. Drivers: - mlx5: make use of the new auxiliary bus to organize the driver internals - mlx5: more accurate port TX timestamping support - mlxsw: - improve the efficiency of offloaded next hop updates by using the new nexthop object API - support blackhole nexthops - support IEEE 802.1ad (Q-in-Q) bridging - rtw88: major bluetooth co-existance improvements - iwlwifi: support new 6 GHz frequency band - ath11k: Fast Initial Link Setup (FILS) - mt7915: dual band concurrent (DBDC) support - net: ipa: add basic support for IPA v4.5 Refactor: - a few pieces of in_interrupt() cleanup work from Sebastian Andrzej Siewior - phy: add support for shared interrupts; get rid of multiple driver APIs and have the drivers write a full IRQ handler, slight growth of driver code should be compensated by the simpler API which also allows shared IRQs - add common code for handling netdev per-cpu counters - move TX packet re-allocation from Ethernet switch tag drivers to a central place - improve efficiency and rename nla_strlcpy - number of W=1 warning cleanups as we now catch those in a patchwork build bot Old code removal: - wan: delete the DLCI / SDLA drivers - wimax: move to staging - wifi: remove old WDS wifi bridging support" * tag 'net-next-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1922 commits) net: hns3: fix expression that is currently always true net: fix proc_fs init handling in af_packet and tls nfc: pn533: convert comma to semicolon af_vsock: Assign the vsock transport considering the vsock address flags af_vsock: Set VMADDR_FLAG_TO_HOST flag on the receive path vsock_addr: Check for supported flag values vm_sockets: Add VMADDR_FLAG_TO_HOST vsock flag vm_sockets: Add flags field in the vsock address data structure net: Disable NETIF_F_HW_TLS_TX when HW_CSUM is disabled tcp: Add logic to check for SYN w/ data in tcp_simple_retransmit net: mscc: ocelot: install MAC addresses in .ndo_set_rx_mode from process context nfc: s3fwrn5: Release the nfc firmware net: vxget: clean up sparse warnings mlxsw: spectrum_router: Use eXtended mezzanine to offload IPv4 router mlxsw: spectrum: Set KVH XLT cache mode for Spectrum2/3 mlxsw: spectrum_router_xm: Introduce basic XM cache flushing mlxsw: reg: Add Router LPM Cache Enable Register mlxsw: reg: Add Router LPM Cache ML Delete Register mlxsw: spectrum_router_xm: Implement L-value tracking for M-index mlxsw: reg: Add XM Router M Table Register ...
This commit is contained in:
commit
d635a69dd4
9
CREDITS
9
CREDITS
@ -2510,15 +2510,6 @@ W: http://www.rdrop.com/users/paulmck/
|
||||
D: RCU and variants
|
||||
D: rcutorture module
|
||||
|
||||
N: Mike McLagan
|
||||
E: mike.mclagan@linux.org
|
||||
W: http://www.invlogic.com/~mmclagan
|
||||
D: DLCI/FRAD drivers for Sangoma SDLAs
|
||||
S: Innovative Logic Corp
|
||||
S: Post Office Box 1068
|
||||
S: Laurel, Maryland 20732
|
||||
S: USA
|
||||
|
||||
N: Bradley McLean
|
||||
E: brad@bradpc.gaylord.com
|
||||
D: Device driver hacker
|
||||
|
@ -1,32 +0,0 @@
|
||||
This ABI is deprecated and will be removed after 2021. It is
|
||||
replaced with the batadv generic netlink family.
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/elp_interval
|
||||
Date: Feb 2014
|
||||
Contact: Linus Lüssing <linus.luessing@web.de>
|
||||
Description:
|
||||
Defines the interval in milliseconds in which batman
|
||||
emits probing packets for neighbor sensing (ELP).
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/iface_status
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Indicates the status of <iface> as it is seen by batman.
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/mesh_iface
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
The /sys/class/net/<iface>/batman-adv/mesh_iface file
|
||||
displays the batman mesh interface this <iface>
|
||||
currently is associated with.
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/throughput_override
|
||||
Date: Feb 2014
|
||||
Contact: Antonio Quartulli <a@unstable.cc>
|
||||
description:
|
||||
Defines the throughput value to be used by B.A.T.M.A.N. V
|
||||
when estimating the link throughput using this interface.
|
||||
If the value is set to 0 then batman-adv will try to
|
||||
estimate the throughput by itself.
|
@ -1,110 +0,0 @@
|
||||
This ABI is deprecated and will be removed after 2021. It is
|
||||
replaced with the batadv generic netlink family.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Indicates whether the batman protocol messages of the
|
||||
mesh <mesh_iface> shall be aggregated or not.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/<vlan_subdir>/ap_isolation
|
||||
Date: May 2011
|
||||
Contact: Antonio Quartulli <a@unstable.cc>
|
||||
Description:
|
||||
Indicates whether the data traffic going from a
|
||||
wireless client to another wireless client will be
|
||||
silently dropped. <vlan_subdir> is empty when referring
|
||||
to the untagged lan.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/bonding
|
||||
Date: June 2010
|
||||
Contact: Simon Wunderlich <sw@simonwunderlich.de>
|
||||
Description:
|
||||
Indicates whether the data traffic going through the
|
||||
mesh will be sent using multiple interfaces at the
|
||||
same time (if available).
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/bridge_loop_avoidance
|
||||
Date: November 2011
|
||||
Contact: Simon Wunderlich <sw@simonwunderlich.de>
|
||||
Description:
|
||||
Indicates whether the bridge loop avoidance feature
|
||||
is enabled. This feature detects and avoids loops
|
||||
between the mesh and devices bridged with the soft
|
||||
interface <mesh_iface>.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/fragmentation
|
||||
Date: October 2010
|
||||
Contact: Andreas Langer <an.langer@gmx.de>
|
||||
Description:
|
||||
Indicates whether the data traffic going through the
|
||||
mesh will be fragmented or silently discarded if the
|
||||
packet size exceeds the outgoing interface MTU.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth
|
||||
Date: October 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Defines the bandwidth which is propagated by this
|
||||
node if gw_mode was set to 'server'.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/gw_mode
|
||||
Date: October 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Defines the state of the gateway features. Can be
|
||||
either 'off', 'client' or 'server'.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class
|
||||
Date: October 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Defines the selection criteria this node will use
|
||||
to choose a gateway if gw_mode was set to 'client'.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/hop_penalty
|
||||
Date: Oct 2010
|
||||
Contact: Linus Lüssing <linus.luessing@web.de>
|
||||
Description:
|
||||
Defines the penalty which will be applied to an
|
||||
originator message's tq-field on every hop.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/isolation_mark
|
||||
Date: Nov 2013
|
||||
Contact: Antonio Quartulli <a@unstable.cc>
|
||||
Description:
|
||||
Defines the isolation mark (and its bitmask) which
|
||||
is used to classify clients as "isolated" by the
|
||||
Extended Isolation feature.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/multicast_mode
|
||||
Date: Feb 2014
|
||||
Contact: Linus Lüssing <linus.luessing@web.de>
|
||||
Description:
|
||||
Indicates whether multicast optimizations are enabled
|
||||
or disabled. If set to zero then all nodes in the
|
||||
mesh are going to use classic flooding for any
|
||||
multicast packet with no optimizations.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/network_coding
|
||||
Date: Nov 2012
|
||||
Contact: Martin Hundeboll <martin@hundeboll.net>
|
||||
Description:
|
||||
Controls whether Network Coding (using some magic
|
||||
to send fewer wifi packets but still the same
|
||||
content) is enabled or not.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/orig_interval
|
||||
Date: May 2010
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Defines the interval in milliseconds in which batman
|
||||
sends its protocol messages.
|
||||
|
||||
What: /sys/class/net/<mesh_iface>/mesh/routing_algo
|
||||
Date: Dec 2011
|
||||
Contact: Marek Lindner <mareklindner@neomailbox.ch>
|
||||
Description:
|
||||
Defines the routing procotol this mesh instance
|
||||
uses to find the optimal paths through the mesh.
|
@ -15,3 +15,11 @@ Description:
|
||||
information with description of all internal kernel types. See
|
||||
Documentation/bpf/btf.rst for detailed description of format
|
||||
itself.
|
||||
|
||||
What: /sys/kernel/btf/<module-name>
|
||||
Date: Nov 2020
|
||||
KernelVersion: 5.11
|
||||
Contact: bpf@vger.kernel.org
|
||||
Description:
|
||||
Read-only binary attribute exposing kernel module's BTF type
|
||||
information as an add-on to the kernel's BTF (/sys/kernel/btf/vmlinux).
|
||||
|
@ -120,7 +120,6 @@ configure specific aspects of kernel behavior to your liking.
|
||||
unicode
|
||||
vga-softcursor
|
||||
video-output
|
||||
wimax/index
|
||||
xfs
|
||||
|
||||
.. only:: subproject and html
|
||||
|
@ -57,6 +57,7 @@ properties:
|
||||
- const: per
|
||||
|
||||
clock-frequency:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
The oscillator frequency driving the flexcan device, filled in by the
|
||||
boot loader. This property should only be used the used operating system
|
||||
@ -99,7 +100,7 @@ properties:
|
||||
by default.
|
||||
0: clock source 0 (oscillator clock)
|
||||
1: clock source 1 (peripheral clock)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
$ref: /schemas/types.yaml#/definitions/uint8
|
||||
default: 1
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
@ -124,7 +125,7 @@ examples:
|
||||
interrupts = <48 0x2>;
|
||||
interrupt-parent = <&mpic>;
|
||||
clock-frequency = <200000000>;
|
||||
fsl,clk-source = <0>;
|
||||
fsl,clk-source = /bits/ 8 <0>;
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
@ -0,0 +1,127 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/dsa/hirschmann,hellcreek.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Hirschmann Hellcreek TSN Switch Device Tree Bindings
|
||||
|
||||
allOf:
|
||||
- $ref: dsa.yaml#
|
||||
|
||||
maintainers:
|
||||
- Andrew Lunn <andrew@lunn.ch>
|
||||
- Florian Fainelli <f.fainelli@gmail.com>
|
||||
- Vivien Didelot <vivien.didelot@gmail.com>
|
||||
- Kurt Kanzenbach <kurt@linutronix.de>
|
||||
|
||||
description:
|
||||
The Hellcreek TSN Switch IP is a 802.1Q Ethernet compliant switch. It supports
|
||||
the Precision Time Protocol, Hardware Timestamping as well the Time Aware
|
||||
Shaper.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: hirschmann,hellcreek-de1soc-r1
|
||||
|
||||
reg:
|
||||
description:
|
||||
The physical base address and size of TSN and PTP memory base
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: tsn
|
||||
- const: ptp
|
||||
|
||||
leds:
|
||||
type: object
|
||||
properties:
|
||||
'#address-cells':
|
||||
const: 1
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^led@[01]$":
|
||||
type: object
|
||||
description: Hellcreek leds
|
||||
$ref: ../../leds/common.yaml#
|
||||
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- enum: [0, 1]
|
||||
description: Led number
|
||||
|
||||
label: true
|
||||
|
||||
default-state: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- ethernet-ports
|
||||
- leds
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
switch0: switch@ff240000 {
|
||||
compatible = "hirschmann,hellcreek-de1soc-r1";
|
||||
reg = <0xff240000 0x1000>,
|
||||
<0xff250000 0x1000>;
|
||||
reg-names = "tsn", "ptp";
|
||||
dsa,member = <0 0>;
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "cpu";
|
||||
ethernet = <&gmac0>;
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan0";
|
||||
phy-handle = <&phy1>;
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan1";
|
||||
phy-handle = <&phy2>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
label = "sync_good";
|
||||
default-state = "on";
|
||||
};
|
||||
|
||||
led@1 {
|
||||
reg = <1>;
|
||||
label = "is_gm";
|
||||
default-state = "off";
|
||||
};
|
||||
};
|
||||
};
|
@ -1,125 +0,0 @@
|
||||
Microchip KSZ Series Ethernet switches
|
||||
==================================
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: For external switch chips, compatible string must be exactly one
|
||||
of the following:
|
||||
- "microchip,ksz8765"
|
||||
- "microchip,ksz8794"
|
||||
- "microchip,ksz8795"
|
||||
- "microchip,ksz9477"
|
||||
- "microchip,ksz9897"
|
||||
- "microchip,ksz9896"
|
||||
- "microchip,ksz9567"
|
||||
- "microchip,ksz8565"
|
||||
- "microchip,ksz9893"
|
||||
- "microchip,ksz9563"
|
||||
- "microchip,ksz8563"
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : Should be a gpio specifier for a reset line
|
||||
- microchip,synclko-125 : Set if the output SYNCLKO frequency should be set to
|
||||
125MHz instead of 25MHz.
|
||||
|
||||
See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional
|
||||
required and optional properties.
|
||||
|
||||
Examples:
|
||||
|
||||
Ethernet switch connected via SPI to the host, CPU port wired to eth0:
|
||||
|
||||
eth0: ethernet@10001000 {
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
spi1: spi@f8008000 {
|
||||
pinctrl-0 = <&pinctrl_spi_ksz>;
|
||||
cs-gpios = <&pioC 25 0>;
|
||||
id = <1>;
|
||||
|
||||
ksz9477: ksz9477@0 {
|
||||
compatible = "microchip,ksz9477";
|
||||
reg = <0>;
|
||||
|
||||
spi-max-frequency = <44000000>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan3";
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan4";
|
||||
};
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "lan5";
|
||||
};
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "cpu";
|
||||
ethernet = <ð0>;
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
ksz8565: ksz8565@0 {
|
||||
compatible = "microchip,ksz8565";
|
||||
reg = <0>;
|
||||
|
||||
spi-max-frequency = <44000000>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan3";
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan4";
|
||||
};
|
||||
port@6 {
|
||||
reg = <6>;
|
||||
label = "cpu";
|
||||
ethernet = <ð0>;
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
148
Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
Normal file
148
Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
Normal file
@ -0,0 +1,148 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/dsa/microchip,ksz.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip KSZ Series Ethernet switches
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
- Woojung Huh <Woojung.Huh@microchip.com>
|
||||
|
||||
allOf:
|
||||
- $ref: dsa.yaml#
|
||||
|
||||
properties:
|
||||
# See Documentation/devicetree/bindings/net/dsa/dsa.yaml for a list of additional
|
||||
# required and optional properties.
|
||||
compatible:
|
||||
enum:
|
||||
- microchip,ksz8765
|
||||
- microchip,ksz8794
|
||||
- microchip,ksz8795
|
||||
- microchip,ksz9477
|
||||
- microchip,ksz9897
|
||||
- microchip,ksz9896
|
||||
- microchip,ksz9567
|
||||
- microchip,ksz8565
|
||||
- microchip,ksz9893
|
||||
- microchip,ksz9563
|
||||
- microchip,ksz8563
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
Should be a gpio specifier for a reset line.
|
||||
maxItems: 1
|
||||
|
||||
microchip,synclko-125:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Set if the output SYNCLKO frequency should be set to 125MHz instead of 25MHz.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
// Ethernet switch connected via SPI to the host, CPU port wired to eth0:
|
||||
eth0 {
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pinctrl-0 = <&pinctrl_spi_ksz>;
|
||||
cs-gpios = <&pioC 25 0>;
|
||||
id = <1>;
|
||||
|
||||
ksz9477: switch@0 {
|
||||
compatible = "microchip,ksz9477";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
spi-max-frequency = <44000000>;
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan3";
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan4";
|
||||
};
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
label = "lan5";
|
||||
};
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
label = "cpu";
|
||||
ethernet = <ð0>;
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ksz8565: switch@1 {
|
||||
compatible = "microchip,ksz8565";
|
||||
reg = <1>;
|
||||
|
||||
spi-max-frequency = <44000000>;
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
label = "lan1";
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
label = "lan2";
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
label = "lan3";
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
label = "lan4";
|
||||
};
|
||||
port@6 {
|
||||
reg = <6>;
|
||||
label = "cpu";
|
||||
ethernet = <ð0>;
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -15,6 +15,7 @@ Required properties:
|
||||
- interrupts: Should contain ethernet controller interrupt
|
||||
|
||||
Optional properties:
|
||||
- phy-handle: See ethernet.txt file in the same directory.
|
||||
- phy-mode: See ethernet.txt file in the same directory. If the property is
|
||||
absent, "rgmii" is assumed. Supported values are "rgmii*" and "rmii" for
|
||||
aspeed parts. Other (unknown) parts will accept any value.
|
||||
@ -32,6 +33,9 @@ Optional properties:
|
||||
- "MACCLK": The MAC IP clock
|
||||
- "RCLK": Clock gate for the RMII RCLK
|
||||
|
||||
Optional subnodes:
|
||||
- mdio: See mdio.txt file in the same directory.
|
||||
|
||||
Example:
|
||||
|
||||
mac0: ethernet@1e660000 {
|
||||
@ -40,3 +44,24 @@ Example:
|
||||
interrupts = <2>;
|
||||
use-ncsi;
|
||||
};
|
||||
|
||||
Example with phy-handle:
|
||||
|
||||
mac1: ethernet@1e680000 {
|
||||
compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
|
||||
reg = <0x1e680000 0x180>;
|
||||
interrupts = <2>;
|
||||
|
||||
phy-handle = <&phy>;
|
||||
phy-mode = "rgmii";
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
phy: ethernet-phy@1 {
|
||||
compatible = "ethernet-phy-ieee802.3-c22";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -16,6 +16,8 @@ Required properties:
|
||||
Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC.
|
||||
Use "cdns,zynqmp-gem" for Zynq Ultrascale+ MPSoC.
|
||||
Use "sifive,fu540-c000-gem" for SiFive FU540-C000 SoC.
|
||||
Use "microchip,sama7g5-emac" for Microchip SAMA7G5 ethernet interface.
|
||||
Use "microchip,sama7g5-gem" for Microchip SAMA7G5 gigabit ethernet interface.
|
||||
Or the generic form: "cdns,emac".
|
||||
- reg: Address and length of the register set for the device
|
||||
For "sifive,fu540-c000-gem", second range is required to specify the
|
||||
|
@ -6,11 +6,11 @@ Required properties:
|
||||
- reg: address on the bus
|
||||
- interrupts: GPIO interrupt to which the chip is connected
|
||||
- enable-gpios: Output GPIO pin used for enabling/disabling the chip
|
||||
- firmware-gpios: Output GPIO pin used to enter firmware download mode
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
- pinctrl-names: Contains only one value - "default".
|
||||
- pintctrl-0: Specifies the pin control groups used for this controller.
|
||||
- firmware-gpios: Output GPIO pin used to enter firmware download mode
|
||||
|
||||
Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2):
|
||||
|
||||
|
@ -12,7 +12,9 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: samsung,s3fwrn5-i2c
|
||||
enum:
|
||||
- samsung,s3fwrn5-i2c
|
||||
- samsung,s3fwrn82
|
||||
|
||||
en-gpios:
|
||||
maxItems: 1
|
||||
@ -47,10 +49,19 @@ additionalProperties: false
|
||||
required:
|
||||
- compatible
|
||||
- en-gpios
|
||||
- interrupts
|
||||
- reg
|
||||
- wake-gpios
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,s3fwrn5-i2c
|
||||
then:
|
||||
required:
|
||||
- interrupts
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
@ -65,9 +76,23 @@ examples:
|
||||
reg = <0x27>;
|
||||
|
||||
interrupt-parent = <&gpa1>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <3 IRQ_TYPE_EDGE_RISING>;
|
||||
|
||||
en-gpios = <&gpf1 4 GPIO_ACTIVE_HIGH>;
|
||||
wake-gpios = <&gpj0 2 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
# UART example on Raspberry Pi
|
||||
- |
|
||||
uart0 {
|
||||
status = "okay";
|
||||
|
||||
nfc {
|
||||
compatible = "samsung,s3fwrn82";
|
||||
|
||||
en-gpios = <&gpio 20 GPIO_ACTIVE_HIGH>;
|
||||
wake-gpios = <&gpio 16 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
@ -144,6 +144,12 @@ properties:
|
||||
* reg
|
||||
* reg-names
|
||||
|
||||
qcom,ath11k-calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
string to uniquely identify variant of the calibration data in the
|
||||
board-2.bin for designs with colliding bus and device specific ids
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -443,6 +443,8 @@ patternProperties:
|
||||
description: HiDeep Inc.
|
||||
"^himax,.*":
|
||||
description: Himax Technologies, Inc.
|
||||
"^hirschmann,.*":
|
||||
description: Hirschmann Automation and Control GmbH
|
||||
"^hisilicon,.*":
|
||||
description: Hisilicon Limited.
|
||||
"^hit,.*":
|
||||
|
234
Documentation/driver-api/auxiliary_bus.rst
Normal file
234
Documentation/driver-api/auxiliary_bus.rst
Normal file
@ -0,0 +1,234 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
=============
|
||||
Auxiliary Bus
|
||||
=============
|
||||
|
||||
In some subsystems, the functionality of the core device (PCI/ACPI/other) is
|
||||
too complex for a single device to be managed by a monolithic driver
|
||||
(e.g. Sound Open Firmware), multiple devices might implement a common
|
||||
intersection of functionality (e.g. NICs + RDMA), or a driver may want to
|
||||
export an interface for another subsystem to drive (e.g. SIOV Physical Function
|
||||
export Virtual Function management). A split of the functinoality into child-
|
||||
devices representing sub-domains of functionality makes it possible to
|
||||
compartmentalize, layer, and distribute domain-specific concerns via a Linux
|
||||
device-driver model.
|
||||
|
||||
An example for this kind of requirement is the audio subsystem where a single
|
||||
IP is handling multiple entities such as HDMI, Soundwire, local devices such as
|
||||
mics/speakers etc. The split for the core's functionality can be arbitrary or
|
||||
be defined by the DSP firmware topology and include hooks for test/debug. This
|
||||
allows for the audio core device to be minimal and focused on hardware-specific
|
||||
control and communication.
|
||||
|
||||
Each auxiliary_device represents a part of its parent functionality. The
|
||||
generic behavior can be extended and specialized as needed by encapsulating an
|
||||
auxiliary_device within other domain-specific structures and the use of .ops
|
||||
callbacks. Devices on the auxiliary bus do not share any structures and the use
|
||||
of a communication channel with the parent is domain-specific.
|
||||
|
||||
Note that ops are intended as a way to augment instance behavior within a class
|
||||
of auxiliary devices, it is not the mechanism for exporting common
|
||||
infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey
|
||||
infrastructure from the parent module to the auxiliary module(s).
|
||||
|
||||
|
||||
When Should the Auxiliary Bus Be Used
|
||||
=====================================
|
||||
|
||||
The auxiliary bus is to be used when a driver and one or more kernel modules,
|
||||
who share a common header file with the driver, need a mechanism to connect and
|
||||
provide access to a shared object allocated by the auxiliary_device's
|
||||
registering driver. The registering driver for the auxiliary_device(s) and the
|
||||
kernel module(s) registering auxiliary_drivers can be from the same subsystem,
|
||||
or from multiple subsystems.
|
||||
|
||||
The emphasis here is on a common generic interface that keeps subsystem
|
||||
customization out of the bus infrastructure.
|
||||
|
||||
One example is a PCI network device that is RDMA-capable and exports a child
|
||||
device to be driven by an auxiliary_driver in the RDMA subsystem. The PCI
|
||||
driver allocates and registers an auxiliary_device for each physical
|
||||
function on the NIC. The RDMA driver registers an auxiliary_driver that claims
|
||||
each of these auxiliary_devices. This conveys data/ops published by the parent
|
||||
PCI device/driver to the RDMA auxiliary_driver.
|
||||
|
||||
Another use case is for the PCI device to be split out into multiple sub
|
||||
functions. For each sub function an auxiliary_device is created. A PCI sub
|
||||
function driver binds to such devices that creates its own one or more class
|
||||
devices. A PCI sub function auxiliary device is likely to be contained in a
|
||||
struct with additional attributes such as user defined sub function number and
|
||||
optional attributes such as resources and a link to the parent device. These
|
||||
attributes could be used by systemd/udev; and hence should be initialized
|
||||
before a driver binds to an auxiliary_device.
|
||||
|
||||
A key requirement for utilizing the auxiliary bus is that there is no
|
||||
dependency on a physical bus, device, register accesses or regmap support.
|
||||
These individual devices split from the core cannot live on the platform bus as
|
||||
they are not physical devices that are controlled by DT/ACPI. The same
|
||||
argument applies for not using MFD in this scenario as MFD relies on individual
|
||||
function devices being physical devices.
|
||||
|
||||
Auxiliary Device
|
||||
================
|
||||
|
||||
An auxiliary_device represents a part of its parent device's functionality. It
|
||||
is given a name that, combined with the registering drivers KBUILD_MODNAME,
|
||||
creates a match_name that is used for driver binding, and an id that combined
|
||||
with the match_name provide a unique name to register with the bus subsystem.
|
||||
|
||||
Registering an auxiliary_device is a two-step process. First call
|
||||
auxiliary_device_init(), which checks several aspects of the auxiliary_device
|
||||
struct and performs a device_initialize(). After this step completes, any
|
||||
error state must have a call to auxiliary_device_uninit() in its resolution path.
|
||||
The second step in registering an auxiliary_device is to perform a call to
|
||||
auxiliary_device_add(), which sets the name of the device and add the device to
|
||||
the bus.
|
||||
|
||||
Unregistering an auxiliary_device is also a two-step process to mirror the
|
||||
register process. First call auxiliary_device_delete(), then call
|
||||
auxiliary_device_uninit().
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct auxiliary_device {
|
||||
struct device dev;
|
||||
const char *name;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
If two auxiliary_devices both with a match_name "mod.foo" are registered onto
|
||||
the bus, they must have unique id values (e.g. "x" and "y") so that the
|
||||
registered devices names are "mod.foo.x" and "mod.foo.y". If match_name + id
|
||||
are not unique, then the device_add fails and generates an error message.
|
||||
|
||||
The auxiliary_device.dev.type.release or auxiliary_device.dev.release must be
|
||||
populated with a non-NULL pointer to successfully register the auxiliary_device.
|
||||
|
||||
The auxiliary_device.dev.parent must also be populated.
|
||||
|
||||
Auxiliary Device Memory Model and Lifespan
|
||||
------------------------------------------
|
||||
|
||||
The registering driver is the entity that allocates memory for the
|
||||
auxiliary_device and register it on the auxiliary bus. It is important to note
|
||||
that, as opposed to the platform bus, the registering driver is wholly
|
||||
responsible for the management for the memory used for the driver object.
|
||||
|
||||
A parent object, defined in the shared header file, contains the
|
||||
auxiliary_device. It also contains a pointer to the shared object(s), which
|
||||
also is defined in the shared header. Both the parent object and the shared
|
||||
object(s) are allocated by the registering driver. This layout allows the
|
||||
auxiliary_driver's registering module to perform a container_of() call to go
|
||||
from the pointer to the auxiliary_device, that is passed during the call to the
|
||||
auxiliary_driver's probe function, up to the parent object, and then have
|
||||
access to the shared object(s).
|
||||
|
||||
The memory for the auxiliary_device is freed only in its release() callback
|
||||
flow as defined by its registering driver.
|
||||
|
||||
The memory for the shared object(s) must have a lifespan equal to, or greater
|
||||
than, the lifespan of the memory for the auxiliary_device. The auxiliary_driver
|
||||
should only consider that this shared object is valid as long as the
|
||||
auxiliary_device is still registered on the auxiliary bus. It is up to the
|
||||
registering driver to manage (e.g. free or keep available) the memory for the
|
||||
shared object beyond the life of the auxiliary_device.
|
||||
|
||||
The registering driver must unregister all auxiliary devices before its own
|
||||
driver.remove() is completed.
|
||||
|
||||
Auxiliary Drivers
|
||||
=================
|
||||
|
||||
Auxiliary drivers follow the standard driver model convention, where
|
||||
discovery/enumeration is handled by the core, and drivers
|
||||
provide probe() and remove() methods. They support power management
|
||||
and shutdown notifications using the standard conventions.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct auxiliary_driver {
|
||||
int (*probe)(struct auxiliary_device *,
|
||||
const struct auxiliary_device_id *id);
|
||||
void (*remove)(struct auxiliary_device *);
|
||||
void (*shutdown)(struct auxiliary_device *);
|
||||
int (*suspend)(struct auxiliary_device *, pm_message_t);
|
||||
int (*resume)(struct auxiliary_device *);
|
||||
struct device_driver driver;
|
||||
const struct auxiliary_device_id *id_table;
|
||||
};
|
||||
|
||||
Auxiliary drivers register themselves with the bus by calling
|
||||
auxiliary_driver_register(). The id_table contains the match_names of auxiliary
|
||||
devices that a driver can bind with.
|
||||
|
||||
Example Usage
|
||||
=============
|
||||
|
||||
Auxiliary devices are created and registered by a subsystem-level core device
|
||||
that needs to break up its functionality into smaller fragments. One way to
|
||||
extend the scope of an auxiliary_device is to encapsulate it within a domain-
|
||||
pecific structure defined by the parent device. This structure contains the
|
||||
auxiliary_device and any associated shared data/callbacks needed to establish
|
||||
the connection with the parent.
|
||||
|
||||
An example is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct foo {
|
||||
struct auxiliary_device auxdev;
|
||||
void (*connect)(struct auxiliary_device *auxdev);
|
||||
void (*disconnect)(struct auxiliary_device *auxdev);
|
||||
void *data;
|
||||
};
|
||||
|
||||
The parent device then registers the auxiliary_device by calling
|
||||
auxiliary_device_init(), and then auxiliary_device_add(), with the pointer to
|
||||
the auxdev member of the above structure. The parent provides a name for the
|
||||
auxiliary_device that, combined with the parent's KBUILD_MODNAME, creates a
|
||||
match_name that is be used for matching and binding with a driver.
|
||||
|
||||
Whenever an auxiliary_driver is registered, based on the match_name, the
|
||||
auxiliary_driver's probe() is invoked for the matching devices. The
|
||||
auxiliary_driver can also be encapsulated inside custom drivers that make the
|
||||
core device's functionality extensible by adding additional domain-specific ops
|
||||
as follows:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct my_ops {
|
||||
void (*send)(struct auxiliary_device *auxdev);
|
||||
void (*receive)(struct auxiliary_device *auxdev);
|
||||
};
|
||||
|
||||
|
||||
struct my_driver {
|
||||
struct auxiliary_driver auxiliary_drv;
|
||||
const struct my_ops ops;
|
||||
};
|
||||
|
||||
An example of this type of usage is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const struct auxiliary_device_id my_auxiliary_id_table[] = {
|
||||
{ .name = "foo_mod.foo_dev" },
|
||||
{ },
|
||||
};
|
||||
|
||||
const struct my_ops my_custom_ops = {
|
||||
.send = my_tx,
|
||||
.receive = my_rx,
|
||||
};
|
||||
|
||||
const struct my_driver my_drv = {
|
||||
.auxiliary_drv = {
|
||||
.name = "myauxiliarydrv",
|
||||
.id_table = my_auxiliary_id_table,
|
||||
.probe = my_probe,
|
||||
.remove = my_remove,
|
||||
.shutdown = my_shutdown,
|
||||
},
|
||||
.ops = my_custom_ops,
|
||||
};
|
@ -73,6 +73,7 @@ available subsections can be seen below.
|
||||
thermal/index
|
||||
fpga/index
|
||||
acpi/index
|
||||
auxiliary_bus
|
||||
backlight/lp855x-driver.rst
|
||||
connector
|
||||
console
|
||||
|
@ -228,20 +228,36 @@ send(2), sendto(2), sendmsg(2) and the recv* counterpart operations
|
||||
on the socket as usual. There are also CAN specific socket options
|
||||
described below.
|
||||
|
||||
The basic CAN frame structure and the sockaddr structure are defined
|
||||
in include/linux/can.h:
|
||||
The Classical CAN frame structure (aka CAN 2.0B), the CAN FD frame structure
|
||||
and the sockaddr structure are defined in include/linux/can.h:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct can_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 can_dlc; /* frame payload length in byte (0 .. 8) */
|
||||
union {
|
||||
/* CAN frame payload length in byte (0 .. CAN_MAX_DLEN)
|
||||
* was previously named can_dlc so we need to carry that
|
||||
* name for legacy support
|
||||
*/
|
||||
__u8 len;
|
||||
__u8 can_dlc; /* deprecated */
|
||||
};
|
||||
__u8 __pad; /* padding */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 __res1; /* reserved / padding */
|
||||
__u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */
|
||||
__u8 data[8] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
Remark: The len element contains the payload length in bytes and should be
|
||||
used instead of can_dlc. The deprecated can_dlc was misleadingly named as
|
||||
it always contained the plain payload length in bytes and not the so called
|
||||
'data length code' (DLC).
|
||||
|
||||
To pass the raw DLC from/to a Classical CAN network device the len8_dlc
|
||||
element can contain values 9 .. 15 when the len element is 8 (the real
|
||||
payload length for all DLC values greater or equal to 8).
|
||||
|
||||
The alignment of the (linear) payload data[] to a 64bit boundary
|
||||
allows the user to define their own structs and unions to easily access
|
||||
the CAN payload. There is no given byteorder on the CAN bus by
|
||||
@ -260,6 +276,23 @@ PF_PACKET socket, that also binds to a specific interface:
|
||||
/* transport protocol class address info (e.g. ISOTP) */
|
||||
struct { canid_t rx_id, tx_id; } tp;
|
||||
|
||||
/* J1939 address information */
|
||||
struct {
|
||||
/* 8 byte name when using dynamic addressing */
|
||||
__u64 name;
|
||||
|
||||
/* pgn:
|
||||
* 8 bit: PS in PDU2 case, else 0
|
||||
* 8 bit: PF
|
||||
* 1 bit: DP
|
||||
* 1 bit: reserved
|
||||
*/
|
||||
__u32 pgn;
|
||||
|
||||
/* 1 byte address */
|
||||
__u8 addr;
|
||||
} j1939;
|
||||
|
||||
/* reserved for future CAN protocols address information */
|
||||
} can_addr;
|
||||
};
|
||||
@ -371,7 +404,7 @@ kernel interfaces (ABI) which heavily rely on the CAN frame with fixed eight
|
||||
bytes of payload (struct can_frame) like the CAN_RAW socket. Therefore e.g.
|
||||
the CAN_RAW socket supports a new socket option CAN_RAW_FD_FRAMES that
|
||||
switches the socket into a mode that allows the handling of CAN FD frames
|
||||
and (legacy) CAN frames simultaneously (see :ref:`socketcan-rawfd`).
|
||||
and Classical CAN frames simultaneously (see :ref:`socketcan-rawfd`).
|
||||
|
||||
The struct canfd_frame is defined in include/linux/can.h:
|
||||
|
||||
@ -397,7 +430,7 @@ code (DLC) of the struct can_frame was used as a length information as the
|
||||
length and the DLC has a 1:1 mapping in the range of 0 .. 8. To preserve
|
||||
the easy handling of the length information the canfd_frame.len element
|
||||
contains a plain length value from 0 .. 64. So both canfd_frame.len and
|
||||
can_frame.can_dlc are equal and contain a length information and no DLC.
|
||||
can_frame.len are equal and contain a length information and no DLC.
|
||||
For details about the distinction of CAN and CAN FD capable devices and
|
||||
the mapping to the bus-relevant data length code (DLC), see :ref:`socketcan-can-fd-driver`.
|
||||
|
||||
@ -407,7 +440,7 @@ definitions are specified for CAN specific MTUs in include/linux/can.h:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define CAN_MTU (sizeof(struct can_frame)) == 16 => 'legacy' CAN frame
|
||||
#define CAN_MTU (sizeof(struct can_frame)) == 16 => Classical CAN frame
|
||||
#define CANFD_MTU (sizeof(struct canfd_frame)) == 72 => CAN FD frame
|
||||
|
||||
|
||||
@ -609,7 +642,7 @@ Example:
|
||||
printf("got CAN FD frame with length %d\n", cfd.len);
|
||||
/* cfd.flags contains valid data */
|
||||
} else if (nbytes == CAN_MTU) {
|
||||
printf("got legacy CAN frame with length %d\n", cfd.len);
|
||||
printf("got Classical CAN frame with length %d\n", cfd.len);
|
||||
/* cfd.flags is undefined */
|
||||
} else {
|
||||
fprintf(stderr, "read: invalid CAN(FD) frame\n");
|
||||
@ -623,7 +656,7 @@ Example:
|
||||
printf("%02X ", cfd.data[i]);
|
||||
|
||||
When reading with size CANFD_MTU only returns CAN_MTU bytes that have
|
||||
been received from the socket a legacy CAN frame has been read into the
|
||||
been received from the socket a Classical CAN frame has been read into the
|
||||
provided CAN FD structure. Note that the canfd_frame.flags data field is
|
||||
not specified in the struct can_frame and therefore it is only valid in
|
||||
CANFD_MTU sized CAN FD frames.
|
||||
@ -633,7 +666,7 @@ Implementation hint for new CAN applications:
|
||||
To build a CAN FD aware application use struct canfd_frame as basic CAN
|
||||
data structure for CAN_RAW based applications. When the application is
|
||||
executed on an older Linux kernel and switching the CAN_RAW_FD_FRAMES
|
||||
socket option returns an error: No problem. You'll get legacy CAN frames
|
||||
socket option returns an error: No problem. You'll get Classical CAN frames
|
||||
or CAN FD frames and can process them the same way.
|
||||
|
||||
When sending to CAN devices make sure that the device is capable to handle
|
||||
@ -842,6 +875,8 @@ TX_RESET_MULTI_IDX:
|
||||
RX_RTR_FRAME:
|
||||
Send reply for RTR-request (placed in op->frames[0]).
|
||||
|
||||
CAN_FD_FRAME:
|
||||
The CAN frames following the bcm_msg_head are struct canfd_frame's
|
||||
|
||||
Broadcast Manager Transmission Timers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -1026,7 +1061,7 @@ Additional procfs files in /proc/net/can::
|
||||
|
||||
stats - SocketCAN core statistics (rx/tx frames, match ratios, ...)
|
||||
reset_stats - manual statistic reset
|
||||
version - prints the SocketCAN core version and the ABI version
|
||||
version - prints SocketCAN core and ABI version (removed in Linux 5.10)
|
||||
|
||||
|
||||
Writing Own CAN Protocol Modules
|
||||
@ -1070,7 +1105,7 @@ General Settings
|
||||
dev->type = ARPHRD_CAN; /* the netdevice hardware type */
|
||||
dev->flags = IFF_NOARP; /* CAN has no arp */
|
||||
|
||||
dev->mtu = CAN_MTU; /* sizeof(struct can_frame) -> legacy CAN interface */
|
||||
dev->mtu = CAN_MTU; /* sizeof(struct can_frame) -> Classical CAN interface */
|
||||
|
||||
or alternative, when the controller supports CAN with flexible data rate:
|
||||
dev->mtu = CANFD_MTU; /* sizeof(struct canfd_frame) -> CAN FD interface */
|
||||
@ -1184,6 +1219,7 @@ Setting CAN device properties::
|
||||
[ fd { on | off } ]
|
||||
[ fd-non-iso { on | off } ]
|
||||
[ presume-ack { on | off } ]
|
||||
[ cc-len8-dlc { on | off } ]
|
||||
|
||||
[ restart-ms TIME-MS ]
|
||||
[ restart ]
|
||||
@ -1326,22 +1362,22 @@ arbitration phase and the payload phase of the CAN FD frame. Therefore a
|
||||
second bit timing has to be specified in order to enable the CAN FD bitrate.
|
||||
|
||||
Additionally CAN FD capable CAN controllers support up to 64 bytes of
|
||||
payload. The representation of this length in can_frame.can_dlc and
|
||||
payload. The representation of this length in can_frame.len and
|
||||
canfd_frame.len for userspace applications and inside the Linux network
|
||||
layer is a plain value from 0 .. 64 instead of the CAN 'data length code'.
|
||||
The data length code was a 1:1 mapping to the payload length in the legacy
|
||||
The data length code was a 1:1 mapping to the payload length in the Classical
|
||||
CAN frames anyway. The payload length to the bus-relevant DLC mapping is
|
||||
only performed inside the CAN drivers, preferably with the helper
|
||||
functions can_dlc2len() and can_len2dlc().
|
||||
functions can_fd_dlc2len() and can_fd_len2dlc().
|
||||
|
||||
The CAN netdevice driver capabilities can be distinguished by the network
|
||||
devices maximum transfer unit (MTU)::
|
||||
|
||||
MTU = 16 (CAN_MTU) => sizeof(struct can_frame) => 'legacy' CAN device
|
||||
MTU = 16 (CAN_MTU) => sizeof(struct can_frame) => Classical CAN device
|
||||
MTU = 72 (CANFD_MTU) => sizeof(struct canfd_frame) => CAN FD capable device
|
||||
|
||||
The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall.
|
||||
N.B. CAN FD capable devices can also handle and send legacy CAN frames.
|
||||
N.B. CAN FD capable devices can also handle and send Classical CAN frames.
|
||||
|
||||
When configuring CAN FD capable CAN controllers an additional 'data' bitrate
|
||||
has to be set. This bitrate for the data phase of the CAN FD frame has to be
|
||||
|
@ -12,6 +12,7 @@ Contents
|
||||
- `Overview`_
|
||||
- `Drivers`_
|
||||
- `Basic packet flow`_
|
||||
- `Devlink health reporters`_
|
||||
|
||||
Overview
|
||||
========
|
||||
@ -157,3 +158,52 @@ Egress
|
||||
3. The SQ descriptor ring is maintained in buffers allocated from SQ mapped pool of NPA block LF.
|
||||
4. NIX block transmits the pkt on the designated channel.
|
||||
5. NPC MCAM entries can be installed to divert pkt onto a different channel.
|
||||
|
||||
Devlink health reporters
|
||||
========================
|
||||
|
||||
NPA Reporters
|
||||
-------------
|
||||
The NPA reporters are responsible for reporting and recovering the following group of errors
|
||||
1. GENERAL events
|
||||
- Error due to operation of unmapped PF.
|
||||
- Error due to disabled alloc/free for other HW blocks (NIX, SSO, TIM, DPI and AURA).
|
||||
2. ERROR events
|
||||
- Fault due to NPA_AQ_INST_S read or NPA_AQ_RES_S write.
|
||||
- AQ Doorbell Error.
|
||||
3. RAS events
|
||||
- RAS Error Reporting for NPA_AQ_INST_S/NPA_AQ_RES_S.
|
||||
4. RVU events
|
||||
- Error due to unmapped slot.
|
||||
|
||||
Sample Output
|
||||
-------------
|
||||
~# devlink health
|
||||
pci/0002:01:00.0:
|
||||
reporter hw_npa_intr
|
||||
state healthy error 2872 recover 2872 last_dump_date 2020-12-10 last_dump_time 09:39:09 grace_period 0 auto_recover true auto_dump true
|
||||
reporter hw_npa_gen
|
||||
state healthy error 2872 recover 2872 last_dump_date 2020-12-11 last_dump_time 04:43:04 grace_period 0 auto_recover true auto_dump true
|
||||
reporter hw_npa_err
|
||||
state healthy error 2871 recover 2871 last_dump_date 2020-12-10 last_dump_time 09:39:17 grace_period 0 auto_recover true auto_dump true
|
||||
reporter hw_npa_ras
|
||||
state healthy error 0 recover 0 last_dump_date 2020-12-10 last_dump_time 09:32:40 grace_period 0 auto_recover true auto_dump true
|
||||
|
||||
Each reporter dumps the
|
||||
- Error Type
|
||||
- Error Register value
|
||||
- Reason in words
|
||||
|
||||
For eg:
|
||||
~# devlink health dump show pci/0002:01:00.0 reporter hw_npa_gen
|
||||
NPA_AF_GENERAL:
|
||||
NPA General Interrupt Reg : 1
|
||||
NIX0: free disabled RX
|
||||
~# devlink health dump show pci/0002:01:00.0 reporter hw_npa_intr
|
||||
NPA_AF_RVU:
|
||||
NPA RVU Interrupt Reg : 1
|
||||
Unmap Slot Error
|
||||
~# devlink health dump show pci/0002:01:00.0 reporter hw_npa_err
|
||||
NPA_AF_ERR:
|
||||
NPA Error Interrupt Reg : 4096
|
||||
AQ Doorbell Error
|
||||
|
@ -476,6 +476,10 @@ be added to the following table:
|
||||
* - ``esp_parsing``
|
||||
- ``drop``
|
||||
- Traps packets dropped due to an error in the ESP header parsing
|
||||
* - ``blackhole_nexthop``
|
||||
- ``drop``
|
||||
- Traps packets that the device decided to drop in case they hit a
|
||||
blackhole nexthop
|
||||
|
||||
Driver-specific Packet Traps
|
||||
============================
|
||||
|
@ -46,7 +46,7 @@ Resources
|
||||
=========
|
||||
|
||||
The ``netdevsim`` driver exposes resources to control the number of FIB
|
||||
entries and FIB rule entries that the driver will allow.
|
||||
entries, FIB rule entries and nexthops that the driver will allow.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@ -54,6 +54,7 @@ entries and FIB rule entries that the driver will allow.
|
||||
$ devlink resource set netdevsim/netdevsim0 path /IPv4/fib-rules size 16
|
||||
$ devlink resource set netdevsim/netdevsim0 path /IPv6/fib size 64
|
||||
$ devlink resource set netdevsim/netdevsim0 path /IPv6/fib-rules size 16
|
||||
$ devlink resource set netdevsim/netdevsim0 path /nexthops size 16
|
||||
$ devlink dev reload netdevsim/netdevsim0
|
||||
|
||||
Driver-specific Traps
|
||||
|
@ -1,44 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
================
|
||||
Frame Relay (FR)
|
||||
================
|
||||
|
||||
Frame Relay (FR) support for linux is built into a two tiered system of device
|
||||
drivers. The upper layer implements RFC1490 FR specification, and uses the
|
||||
Data Link Connection Identifier (DLCI) as its hardware address. Usually these
|
||||
are assigned by your network supplier, they give you the number/numbers of
|
||||
the Virtual Connections (VC) assigned to you.
|
||||
|
||||
Each DLCI is a point-to-point link between your machine and a remote one.
|
||||
As such, a separate device is needed to accommodate the routing. Within the
|
||||
net-tools archives is 'dlcicfg'. This program will communicate with the
|
||||
base "DLCI" device, and create new net devices named 'dlci00', 'dlci01'...
|
||||
The configuration script will ask you how many DLCIs you need, as well as
|
||||
how many DLCIs you want to assign to each Frame Relay Access Device (FRAD).
|
||||
|
||||
The DLCI uses a number of function calls to communicate with the FRAD, all
|
||||
of which are stored in the FRAD's private data area. assoc/deassoc,
|
||||
activate/deactivate and dlci_config. The DLCI supplies a receive function
|
||||
to the FRAD to accept incoming packets.
|
||||
|
||||
With this initial offering, only 1 FRAD driver is available. With many thanks
|
||||
to Sangoma Technologies, David Mandelstam & Gene Kozin, the S502A, S502E &
|
||||
S508 are supported. This driver is currently set up for only FR, but as
|
||||
Sangoma makes more firmware modules available, it can be updated to provide
|
||||
them as well.
|
||||
|
||||
Configuration of the FRAD makes use of another net-tools program, 'fradcfg'.
|
||||
This program makes use of a configuration file (which dlcicfg can also read)
|
||||
to specify the types of boards to be configured as FRADs, as well as perform
|
||||
any board specific configuration. The Sangoma module of fradcfg loads the
|
||||
FR firmware into the card, sets the irq/port/memory information, and provides
|
||||
an initial configuration.
|
||||
|
||||
Additional FRAD device drivers can be added as hardware is available.
|
||||
|
||||
At this time, the dlcicfg and fradcfg programs have not been incorporated into
|
||||
the net-tools distribution. They can be found at ftp.invlogic.com, in
|
||||
/pub/linux. Note that with OS/2 FTPD, you end up in /pub by default, so just
|
||||
use 'cd linux'. v0.10 is for use on pre-2.0.3 and earlier, v0.15 is for
|
||||
pre-2.0.4 and later.
|
@ -52,7 +52,6 @@ Contents:
|
||||
eql
|
||||
fib_trie
|
||||
filter
|
||||
framerelay
|
||||
generic-hdlc
|
||||
generic_netlink
|
||||
gen_stats
|
||||
@ -70,6 +69,7 @@ Contents:
|
||||
lapb-module
|
||||
mac80211-injection
|
||||
mpls-sysctl
|
||||
mptcp-sysctl
|
||||
multiqueue
|
||||
netconsole
|
||||
netdev-features
|
||||
@ -101,6 +101,7 @@ Contents:
|
||||
tcp-thin
|
||||
team
|
||||
timestamping
|
||||
tipc
|
||||
tproxy
|
||||
tuntap
|
||||
udplite
|
||||
|
@ -1554,6 +1554,9 @@ igmpv3_unsolicited_report_interval - INTEGER
|
||||
|
||||
Default: 1000 (1 seconds)
|
||||
|
||||
ignore_routes_with_linkdown - BOOLEAN
|
||||
Ignore routes whose link is down when performing a FIB lookup.
|
||||
|
||||
promote_secondaries - BOOLEAN
|
||||
When a primary IP address is removed from this interface
|
||||
promote a corresponding secondary IP address instead of
|
||||
@ -2642,6 +2645,37 @@ addr_scope_policy - INTEGER
|
||||
|
||||
Default: 1
|
||||
|
||||
udp_port - INTEGER
|
||||
The listening port for the local UDP tunneling sock. Normally it's
|
||||
using the IANA-assigned UDP port number 9899 (sctp-tunneling).
|
||||
|
||||
This UDP sock is used for processing the incoming UDP-encapsulated
|
||||
SCTP packets (from RFC6951), and shared by all applications in the
|
||||
same net namespace. This UDP sock will be closed when the value is
|
||||
set to 0.
|
||||
|
||||
The value will also be used to set the src port of the UDP header
|
||||
for the outgoing UDP-encapsulated SCTP packets. For the dest port,
|
||||
please refer to 'encap_port' below.
|
||||
|
||||
Default: 0
|
||||
|
||||
encap_port - INTEGER
|
||||
The default remote UDP encapsulation port.
|
||||
|
||||
This value is used to set the dest port of the UDP header for the
|
||||
outgoing UDP-encapsulated SCTP packets by default. Users can also
|
||||
change the value for each sock/asoc/transport by using setsockopt.
|
||||
For further information, please refer to RFC6951.
|
||||
|
||||
Note that when connecting to a remote server, the client should set
|
||||
this to the port that the UDP tunneling sock on the peer server is
|
||||
listening to and the local UDP tunneling sock on the client also
|
||||
must be started. On the server, it would get the encap_port from
|
||||
the incoming packet's source port.
|
||||
|
||||
Default: 0
|
||||
|
||||
|
||||
``/proc/sys/net/core/*``
|
||||
========================
|
||||
|
@ -69,18 +69,56 @@ J1939 concepts
|
||||
PGN
|
||||
---
|
||||
|
||||
The J1939 protocol uses the 29-bit CAN identifier with the following structure:
|
||||
|
||||
============ ============== ====================
|
||||
29 bit CAN-ID
|
||||
--------------------------------------------------
|
||||
Bit positions within the CAN-ID
|
||||
--------------------------------------------------
|
||||
28 ... 26 25 ... 8 7 ... 0
|
||||
============ ============== ====================
|
||||
Priority PGN SA (Source Address)
|
||||
============ ============== ====================
|
||||
|
||||
The PGN (Parameter Group Number) is a number to identify a packet. The PGN
|
||||
is composed as follows:
|
||||
1 bit : Reserved Bit
|
||||
1 bit : Data Page
|
||||
8 bits : PF (PDU Format)
|
||||
8 bits : PS (PDU Specific)
|
||||
|
||||
============ ============== ================= =================
|
||||
PGN
|
||||
------------------------------------------------------------------
|
||||
Bit positions within the CAN-ID
|
||||
------------------------------------------------------------------
|
||||
25 24 23 ... 16 15 ... 8
|
||||
============ ============== ================= =================
|
||||
R (Reserved) DP (Data Page) PF (PDU Format) PS (PDU Specific)
|
||||
============ ============== ================= =================
|
||||
|
||||
In J1939-21 distinction is made between PDU1 format (where PF < 240) and PDU2
|
||||
format (where PF >= 240). Furthermore, when using the PDU2 format, the PS-field
|
||||
contains a so-called Group Extension, which is part of the PGN. When using PDU2
|
||||
format, the Group Extension is set in the PS-field.
|
||||
|
||||
============== ========================
|
||||
PDU1 Format (specific) (peer to peer)
|
||||
----------------------------------------
|
||||
Bit positions within the CAN-ID
|
||||
----------------------------------------
|
||||
23 ... 16 15 ... 8
|
||||
============== ========================
|
||||
00h ... EFh DA (Destination address)
|
||||
============== ========================
|
||||
|
||||
============== ========================
|
||||
PDU2 Format (global) (broadcast)
|
||||
----------------------------------------
|
||||
Bit positions within the CAN-ID
|
||||
----------------------------------------
|
||||
23 ... 16 15 ... 8
|
||||
============== ========================
|
||||
F0h ... FFh GE (Group Extenstion)
|
||||
============== ========================
|
||||
|
||||
On the other hand, when using PDU1 format, the PS-field contains a so-called
|
||||
Destination Address, which is _not_ part of the PGN. When communicating a PGN
|
||||
from user space to kernel (or vice versa) and PDU2 format is used, the PS-field
|
||||
|
@ -83,27 +83,6 @@ SUN RPC subsystem
|
||||
.. kernel-doc:: net/sunrpc/clnt.c
|
||||
:export:
|
||||
|
||||
WiMAX
|
||||
-----
|
||||
|
||||
.. kernel-doc:: net/wimax/op-msg.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: net/wimax/op-reset.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: net/wimax/op-rfkill.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: net/wimax/stack.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: include/net/wimax.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/wimax.h
|
||||
:internal:
|
||||
|
||||
Network device support
|
||||
======================
|
||||
|
||||
|
26
Documentation/networking/mptcp-sysctl.rst
Normal file
26
Documentation/networking/mptcp-sysctl.rst
Normal file
@ -0,0 +1,26 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=====================
|
||||
MPTCP Sysfs variables
|
||||
=====================
|
||||
|
||||
/proc/sys/net/mptcp/* Variables
|
||||
===============================
|
||||
|
||||
enabled - INTEGER
|
||||
Control whether MPTCP sockets can be created.
|
||||
|
||||
MPTCP sockets can be created if the value is nonzero. This is
|
||||
a per-namespace sysctl.
|
||||
|
||||
Default: 1
|
||||
|
||||
add_addr_timeout - INTEGER (seconds)
|
||||
Set the timeout after which an ADD_ADDR control message will be
|
||||
resent to an MPTCP peer that has not acknowledged a previous
|
||||
ADD_ADDR message.
|
||||
|
||||
The default value matches TCP_RTO_MAX. This is a per-namespace
|
||||
sysctl.
|
||||
|
||||
Default: 120
|
@ -97,6 +97,14 @@ a page will cause no race conditions is enough.
|
||||
|
||||
* page_pool_get_dma_dir(): Retrieve the stored DMA direction.
|
||||
|
||||
* page_pool_put_page_bulk(): Tries to refill a number of pages into the
|
||||
ptr_ring cache holding ptr_ring producer lock. If the ptr_ring is full,
|
||||
page_pool_put_page_bulk() will release leftover pages to the page allocator.
|
||||
page_pool_put_page_bulk() is suitable to be run inside the driver NAPI tx
|
||||
completion loop for the XDP_REDIRECT use case.
|
||||
Please note the caller must not use data area after running
|
||||
page_pool_put_page_bulk(), as this function overwrites it.
|
||||
|
||||
Coding examples
|
||||
===============
|
||||
|
||||
|
@ -314,6 +314,22 @@ channel are:
|
||||
it is connected to. It will return an EINVAL error if the channel
|
||||
is not connected to an interface.
|
||||
|
||||
* PPPIOCBRIDGECHAN bridges a channel with another. The argument should
|
||||
point to an int containing the channel number of the channel to bridge
|
||||
to. Once two channels are bridged, frames presented to one channel by
|
||||
ppp_input() are passed to the bridge instance for onward transmission.
|
||||
This allows frames to be switched from one channel into another: for
|
||||
example, to pass PPPoE frames into a PPPoL2TP session. Since channel
|
||||
bridging interrupts the normal ppp_input() path, a given channel may
|
||||
not be part of a bridge at the same time as being part of a unit.
|
||||
This ioctl will return an EALREADY error if the channel is already
|
||||
part of a bridge or unit, or ENXIO if the requested channel does not
|
||||
exist.
|
||||
|
||||
* PPPIOCUNBRIDGECHAN performs the inverse of PPPIOCBRIDGECHAN, unbridging
|
||||
a channel pair. This ioctl will return an EINVAL error if the channel
|
||||
does not form part of a bridge.
|
||||
|
||||
* All other ioctl commands are passed to the channel ioctl() function.
|
||||
|
||||
The ioctl calls that are available on an instance that is attached to
|
||||
|
100
Documentation/networking/tipc.rst
Normal file
100
Documentation/networking/tipc.rst
Normal file
@ -0,0 +1,100 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=================
|
||||
Linux Kernel TIPC
|
||||
=================
|
||||
|
||||
TIPC (Transparent Inter Process Communication) is a protocol that is
|
||||
specially designed for intra-cluster communication.
|
||||
|
||||
For more information about TIPC, see http://tipc.sourceforge.net.
|
||||
|
||||
TIPC Base Types
|
||||
---------------
|
||||
|
||||
.. kernel-doc:: net/tipc/subscr.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: net/tipc/bearer.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: net/tipc/name_table.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: net/tipc/name_distr.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: net/tipc/bcast.c
|
||||
:internal:
|
||||
|
||||
TIPC Bearer Interfaces
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/bearer.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: net/tipc/udp_media.c
|
||||
:internal:
|
||||
|
||||
TIPC Crypto Interfaces
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/crypto.c
|
||||
:internal:
|
||||
|
||||
TIPC Discoverer Interfaces
|
||||
--------------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/discover.c
|
||||
:internal:
|
||||
|
||||
TIPC Link Interfaces
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/link.c
|
||||
:internal:
|
||||
|
||||
TIPC msg Interfaces
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/msg.c
|
||||
:internal:
|
||||
|
||||
TIPC Name Interfaces
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/name_table.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: net/tipc/name_distr.c
|
||||
:internal:
|
||||
|
||||
TIPC Node Management Interfaces
|
||||
-------------------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/node.c
|
||||
:internal:
|
||||
|
||||
TIPC Socket Interfaces
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/socket.c
|
||||
:internal:
|
||||
|
||||
TIPC Network Topology Interfaces
|
||||
--------------------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/subscr.c
|
||||
:internal:
|
||||
|
||||
TIPC Server Interfaces
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/topsrv.c
|
||||
:internal:
|
||||
|
||||
TIPC Trace Interfaces
|
||||
---------------------
|
||||
|
||||
.. kernel-doc:: net/tipc/trace.c
|
||||
:internal:
|
@ -524,7 +524,13 @@ on TCP retransmissions to handle corner cases is not acceptable.
|
||||
TLS device features
|
||||
-------------------
|
||||
|
||||
Drivers should ignore the changes to TLS the device feature flags.
|
||||
Drivers should ignore the changes to the TLS device feature flags.
|
||||
These flags will be acted upon accordingly by the core ``ktls`` code.
|
||||
TLS device feature flags only control adding of new TLS connection
|
||||
offloads, old connections will remain active after flags are cleared.
|
||||
|
||||
TLS encryption cannot be offloaded to devices without checksum calculation
|
||||
offload. Hence, TLS TX device feature flag requires NETIF_F_HW_CSUM being set.
|
||||
Disabling the latter implies clearing the former. Disabling TX checksum offload
|
||||
should not affect old connections, and drivers should make sure checksum
|
||||
calculation does not break for them.
|
||||
|
@ -19,13 +19,11 @@ implementation of LAPB. Therefore the LAPB modules would be called by
|
||||
unintelligent X.25 card drivers and not by intelligent ones, this would
|
||||
provide a uniform device driver interface, and simplify configuration.
|
||||
|
||||
To confuse matters a little, an 802.2 LLC implementation for Linux is being
|
||||
written which will allow X.25 to be run over an Ethernet (or Token Ring) and
|
||||
conform with the JNT "Pink Book", this will have a different interface to
|
||||
the Packet Layer but there will be no confusion since the class of device
|
||||
being served by the LLC will be completely separate from LAPB. The LLC
|
||||
implementation is being done as part of another protocol project (SNA) and
|
||||
by a different author.
|
||||
To confuse matters a little, an 802.2 LLC implementation is also possible
|
||||
which could allow X.25 to be run over an Ethernet (or Token Ring) and
|
||||
conform with the JNT "Pink Book", this would have a different interface to
|
||||
the Packet Layer but there would be no confusion since the class of device
|
||||
being served by the LLC would be completely separate from LAPB.
|
||||
|
||||
Just when you thought that it could not become more confusing, another
|
||||
option appeared, XOT. This allows X.25 Packet Layer frames to operate over
|
||||
|
@ -84,7 +84,6 @@ PPP_MAGIC 0x5002 ppp ``include/linux/
|
||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
||||
X25_ASY_MAGIC 0x5303 x25_asy ``drivers/net/x25_asy.h``
|
||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
||||
TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h``
|
||||
|
@ -90,7 +90,6 @@ PPP_MAGIC 0x5002 ppp ``include/linux/
|
||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
||||
X25_ASY_MAGIC 0x5303 x25_asy ``drivers/net/x25_asy.h``
|
||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
||||
TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h``
|
||||
|
@ -114,7 +114,6 @@ Todolist:
|
||||
unicode
|
||||
vga-softcursor
|
||||
video-output
|
||||
wimax/index
|
||||
xfs
|
||||
|
||||
.. only:: subproject and html
|
||||
|
@ -73,7 +73,6 @@ PPP_MAGIC 0x5002 ppp ``include/linux/
|
||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
||||
X25_ASY_MAGIC 0x5303 x25_asy ``drivers/net/x25_asy.h``
|
||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
||||
TTY_MAGIC 0x5401 tty_struct ``include/linux/tty.h``
|
||||
|
58
MAINTAINERS
58
MAINTAINERS
@ -3122,8 +3122,6 @@ Q: https://patchwork.open-mesh.org/project/batman/list/
|
||||
B: https://www.open-mesh.org/projects/batman-adv/issues
|
||||
C: irc://chat.freenode.net/batman
|
||||
T: git https://git.open-mesh.org/linux-merge.git
|
||||
F: Documentation/ABI/obsolete/sysfs-class-net-batman-adv
|
||||
F: Documentation/ABI/obsolete/sysfs-class-net-mesh
|
||||
F: Documentation/networking/batman-adv.rst
|
||||
F: include/uapi/linux/batadv_packet.h
|
||||
F: include/uapi/linux/batman_adv.h
|
||||
@ -3207,8 +3205,9 @@ F: drivers/mtd/devices/block2mtd.c
|
||||
BLUETOOTH DRIVERS
|
||||
M: Marcel Holtmann <marcel@holtmann.org>
|
||||
M: Johan Hedberg <johan.hedberg@gmail.com>
|
||||
M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
|
||||
L: linux-bluetooth@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Supported
|
||||
W: http://www.bluez.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
|
||||
@ -3217,8 +3216,9 @@ F: drivers/bluetooth/
|
||||
BLUETOOTH SUBSYSTEM
|
||||
M: Marcel Holtmann <marcel@holtmann.org>
|
||||
M: Johan Hedberg <johan.hedberg@gmail.com>
|
||||
M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
|
||||
L: linux-bluetooth@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Supported
|
||||
W: http://www.bluez.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
|
||||
@ -6935,12 +6935,6 @@ S: Maintained
|
||||
W: http://floatingpoint.sourceforge.net/emulator/index.html
|
||||
F: arch/x86/math-emu/
|
||||
|
||||
FRAME RELAY DLCI/FRAD (Sangoma drivers too)
|
||||
L: netdev@vger.kernel.org
|
||||
S: Orphan
|
||||
F: drivers/net/wan/dlci.c
|
||||
F: drivers/net/wan/sdla.c
|
||||
|
||||
FRAMEBUFFER LAYER
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
@ -7938,6 +7932,15 @@ F: include/linux/hippidevice.h
|
||||
F: include/uapi/linux/if_hippi.h
|
||||
F: net/802/hippi.c
|
||||
|
||||
HIRSCHMANN HELLCREEK ETHERNET SWITCH DRIVER
|
||||
M: Kurt Kanzenbach <kurt@linutronix.de>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/dsa/hirschmann,hellcreek.yaml
|
||||
F: drivers/net/dsa/hirschmann/*
|
||||
F: include/linux/platform_data/hirschmann-hellcreek.h
|
||||
F: net/dsa/tag_hellcreek.c
|
||||
|
||||
HISILICON DMA DRIVER
|
||||
M: Zhou Wang <wangzhou1@hisilicon.com>
|
||||
L: dmaengine@vger.kernel.org
|
||||
@ -9141,16 +9144,6 @@ W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
|
||||
F: drivers/net/wireless/intel/iwlwifi/
|
||||
|
||||
INTEL WIRELESS WIMAX CONNECTION 2400
|
||||
M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
|
||||
M: linux-wimax@intel.com
|
||||
L: wimax@linuxwimax.org (subscribers-only)
|
||||
S: Supported
|
||||
W: http://linuxwimax.org
|
||||
F: Documentation/admin-guide/wimax/i2400m.rst
|
||||
F: drivers/net/wimax/i2400m/
|
||||
F: include/uapi/linux/wimax/i2400m.h
|
||||
|
||||
INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER
|
||||
M: Jithu Joseph <jithu.joseph@intel.com>
|
||||
R: Maurice Ma <maurice.ma@intel.com>
|
||||
@ -10540,6 +10533,7 @@ M: Srujana Challa <schalla@marvell.com>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/crypto/marvell/
|
||||
F: include/linux/soc/marvell/octeontx2/
|
||||
|
||||
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
|
||||
M: Mirko Lindner <mlindner@marvell.com>
|
||||
@ -10583,6 +10577,14 @@ L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/marvell/mvneta.*
|
||||
|
||||
MARVELL MVPP2 ETHERNET DRIVER
|
||||
M: Marcin Wojtas <mw@semihalf.com>
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/marvell-pp2.txt
|
||||
F: drivers/net/ethernet/marvell/mvpp2/
|
||||
|
||||
MARVELL MWIFIEX WIRELESS DRIVER
|
||||
M: Amitkumar Karwar <amitkarwar@gmail.com>
|
||||
M: Ganapathi Bhat <ganapathi.bhat@nxp.com>
|
||||
@ -10612,6 +10614,7 @@ M: hariprasad <hkelam@marvell.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/marvell/octeontx2/nic/
|
||||
F: include/linux/soc/marvell/octeontx2/
|
||||
|
||||
MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
|
||||
M: Sunil Goutham <sgoutham@marvell.com>
|
||||
@ -11588,7 +11591,7 @@ M: Woojung Huh <woojung.huh@microchip.com>
|
||||
M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/dsa/ksz.txt
|
||||
F: Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
|
||||
F: drivers/net/dsa/microchip/*
|
||||
F: include/linux/platform_data/microchip-ksz.h
|
||||
F: net/dsa/tag_ksz.c
|
||||
@ -12346,6 +12349,7 @@ L: mptcp@lists.01.org
|
||||
S: Maintained
|
||||
W: https://github.com/multipath-tcp/mptcp_net-next/wiki
|
||||
B: https://github.com/multipath-tcp/mptcp_net-next/issues
|
||||
F: Documentation/networking/mptcp-sysctl.rst
|
||||
F: include/net/mptcp.h
|
||||
F: include/uapi/linux/mptcp.h
|
||||
F: net/mptcp/
|
||||
@ -18999,18 +19003,6 @@ S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/wil6210
|
||||
F: drivers/net/wireless/ath/wil6210/
|
||||
|
||||
WIMAX STACK
|
||||
M: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
|
||||
M: linux-wimax@intel.com
|
||||
L: wimax@linuxwimax.org (subscribers-only)
|
||||
S: Supported
|
||||
W: http://linuxwimax.org
|
||||
F: Documentation/admin-guide/wimax/wimax.rst
|
||||
F: include/linux/wimax/debug.h
|
||||
F: include/net/wimax.h
|
||||
F: include/uapi/linux/wimax.h
|
||||
F: net/wimax/
|
||||
|
||||
WINBOND CIR DRIVER
|
||||
M: David Härdeman <david@hardeman.nu>
|
||||
S: Maintained
|
||||
|
@ -124,6 +124,9 @@
|
||||
|
||||
#define SO_DETACH_REUSEPORT_BPF 68
|
||||
|
||||
#define SO_PREFER_BUSY_POLL 69
|
||||
#define SO_BUSY_POLL_BUDGET 70
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
@ -141,7 +141,6 @@ CONFIG_HDLC_CISCO=m
|
||||
CONFIG_HDLC_FR=m
|
||||
CONFIG_HDLC_PPP=m
|
||||
CONFIG_HDLC_X25=m
|
||||
CONFIG_DLCI=m
|
||||
CONFIG_WAN_ROUTER_DRIVERS=m
|
||||
CONFIG_ATM_TCP=m
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
|
@ -228,9 +228,7 @@ CONFIG_FARSYNC=m
|
||||
CONFIG_DSCC4=m
|
||||
CONFIG_DSCC4_PCISYNC=y
|
||||
CONFIG_DSCC4_PCI_RST=y
|
||||
CONFIG_DLCI=m
|
||||
CONFIG_LAPBETHER=m
|
||||
CONFIG_X25_ASY=m
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
# CONFIG_SERIO is not set
|
||||
|
@ -378,9 +378,7 @@ CONFIG_FARSYNC=m
|
||||
CONFIG_DSCC4=m
|
||||
CONFIG_DSCC4_PCISYNC=y
|
||||
CONFIG_DSCC4_PCI_RST=y
|
||||
CONFIG_DLCI=m
|
||||
CONFIG_LAPBETHER=m
|
||||
CONFIG_X25_ASY=m
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
CONFIG_KEYBOARD_GPIO=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
|
@ -135,6 +135,9 @@
|
||||
|
||||
#define SO_DETACH_REUSEPORT_BPF 68
|
||||
|
||||
#define SO_PREFER_BUSY_POLL 69
|
||||
#define SO_BUSY_POLL_BUDGET 70
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
@ -116,6 +116,9 @@
|
||||
|
||||
#define SO_DETACH_REUSEPORT_BPF 0x4042
|
||||
|
||||
#define SO_PREFER_BUSY_POLL 0x4043
|
||||
#define SO_BUSY_POLL_BUDGET 0x4044
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
@ -117,6 +117,9 @@
|
||||
|
||||
#define SO_DETACH_REUSEPORT_BPF 0x0047
|
||||
|
||||
#define SO_PREFER_BUSY_POLL 0x0048
|
||||
#define SO_BUSY_POLL_BUDGET 0x0049
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
|
||||
|
@ -765,8 +765,7 @@ static void lanai_shutdown_tx_vci(struct lanai_dev *lanai,
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags, timeout;
|
||||
int read, write, lastread = -1;
|
||||
APRINTK(!in_interrupt(),
|
||||
"lanai_shutdown_tx_vci called w/o process context!\n");
|
||||
|
||||
if (lvcc->vbase == NULL) /* We were never bound to a VCI */
|
||||
return;
|
||||
/* 15.2.1 - wait for queue to drain */
|
||||
|
@ -130,8 +130,9 @@ static int ns_open(struct atm_vcc *vcc);
|
||||
static void ns_close(struct atm_vcc *vcc);
|
||||
static void fill_tst(ns_dev * card, int n, vc_map * vc);
|
||||
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb);
|
||||
static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb);
|
||||
static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
|
||||
struct sk_buff *skb);
|
||||
struct sk_buff *skb, bool may_sleep);
|
||||
static void process_tsq(ns_dev * card);
|
||||
static void drain_scq(ns_dev * card, scq_info * scq, int pos);
|
||||
static void process_rsq(ns_dev * card);
|
||||
@ -160,6 +161,7 @@ static const struct atmdev_ops atm_ops = {
|
||||
.close = ns_close,
|
||||
.ioctl = ns_ioctl,
|
||||
.send = ns_send,
|
||||
.send_bh = ns_send_bh,
|
||||
.phy_put = ns_phy_put,
|
||||
.phy_get = ns_phy_get,
|
||||
.proc_read = ns_proc_read,
|
||||
@ -1620,7 +1622,7 @@ static void fill_tst(ns_dev * card, int n, vc_map * vc)
|
||||
card->tst_addr = new_tst;
|
||||
}
|
||||
|
||||
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
static int _ns_send(struct atm_vcc *vcc, struct sk_buff *skb, bool may_sleep)
|
||||
{
|
||||
ns_dev *card;
|
||||
vc_map *vc;
|
||||
@ -1704,7 +1706,7 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
scq = card->scq0;
|
||||
}
|
||||
|
||||
if (push_scqe(card, vc, scq, &scqe, skb) != 0) {
|
||||
if (push_scqe(card, vc, scq, &scqe, skb, may_sleep) != 0) {
|
||||
atomic_inc(&vcc->stats->tx_err);
|
||||
dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), skb->len,
|
||||
DMA_TO_DEVICE);
|
||||
@ -1716,8 +1718,18 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
return _ns_send(vcc, skb, true);
|
||||
}
|
||||
|
||||
static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
return _ns_send(vcc, skb, false);
|
||||
}
|
||||
|
||||
static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb, bool may_sleep)
|
||||
{
|
||||
unsigned long flags;
|
||||
ns_scqe tsr;
|
||||
@ -1728,7 +1740,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
|
||||
|
||||
spin_lock_irqsave(&scq->lock, flags);
|
||||
while (scq->tail == scq->next) {
|
||||
if (in_interrupt()) {
|
||||
if (!may_sleep) {
|
||||
spin_unlock_irqrestore(&scq->lock, flags);
|
||||
printk("nicstar%d: Error pushing TBD.\n", card->index);
|
||||
return 1;
|
||||
@ -1773,7 +1785,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
|
||||
int has_run = 0;
|
||||
|
||||
while (scq->tail == scq->next) {
|
||||
if (in_interrupt()) {
|
||||
if (!may_sleep) {
|
||||
data = scq_virt_to_bus(scq, scq->next);
|
||||
ns_write_sram(card, scq->scd, &data, 1);
|
||||
spin_unlock_irqrestore(&scq->lock, flags);
|
||||
|
@ -1,6 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
menu "Generic Driver Options"
|
||||
|
||||
config AUXILIARY_BUS
|
||||
bool
|
||||
|
||||
config UEVENT_HELPER
|
||||
bool "Support for uevent helper"
|
||||
help
|
||||
|
@ -7,6 +7,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
|
||||
attribute_container.o transport_class.o \
|
||||
topology.o container.o property.o cacheinfo.o \
|
||||
swnode.o
|
||||
obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o
|
||||
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
|
||||
obj-y += power/
|
||||
obj-$(CONFIG_ISA_BUS_API) += isa.o
|
||||
|
274
drivers/base/auxiliary.c
Normal file
274
drivers/base/auxiliary.c
Normal file
@ -0,0 +1,274 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2020 Intel Corporation
|
||||
*
|
||||
* Please see Documentation/driver-api/auxiliary_bus.rst for more information.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
|
||||
static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id,
|
||||
const struct auxiliary_device *auxdev)
|
||||
{
|
||||
for (; id->name[0]; id++) {
|
||||
const char *p = strrchr(dev_name(&auxdev->dev), '.');
|
||||
int match_size;
|
||||
|
||||
if (!p)
|
||||
continue;
|
||||
match_size = p - dev_name(&auxdev->dev);
|
||||
|
||||
/* use dev_name(&auxdev->dev) prefix before last '.' char to match to */
|
||||
if (strlen(id->name) == match_size &&
|
||||
!strncmp(dev_name(&auxdev->dev), id->name, match_size))
|
||||
return id;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int auxiliary_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
|
||||
struct auxiliary_driver *auxdrv = to_auxiliary_drv(drv);
|
||||
|
||||
return !!auxiliary_match_id(auxdrv->id_table, auxdev);
|
||||
}
|
||||
|
||||
static int auxiliary_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
const char *name, *p;
|
||||
|
||||
name = dev_name(dev);
|
||||
p = strrchr(name, '.');
|
||||
|
||||
return add_uevent_var(env, "MODALIAS=%s%.*s", AUXILIARY_MODULE_PREFIX,
|
||||
(int)(p - name), name);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops auxiliary_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
|
||||
};
|
||||
|
||||
static int auxiliary_bus_probe(struct device *dev)
|
||||
{
|
||||
struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
|
||||
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = dev_pm_domain_attach(dev, true);
|
||||
if (ret) {
|
||||
dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev));
|
||||
if (ret)
|
||||
dev_pm_domain_detach(dev, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int auxiliary_bus_remove(struct device *dev)
|
||||
{
|
||||
struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
|
||||
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
|
||||
|
||||
if (auxdrv->remove)
|
||||
auxdrv->remove(auxdev);
|
||||
dev_pm_domain_detach(dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void auxiliary_bus_shutdown(struct device *dev)
|
||||
{
|
||||
struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver);
|
||||
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
|
||||
|
||||
if (auxdrv->shutdown)
|
||||
auxdrv->shutdown(auxdev);
|
||||
}
|
||||
|
||||
static struct bus_type auxiliary_bus_type = {
|
||||
.name = "auxiliary",
|
||||
.probe = auxiliary_bus_probe,
|
||||
.remove = auxiliary_bus_remove,
|
||||
.shutdown = auxiliary_bus_shutdown,
|
||||
.match = auxiliary_match,
|
||||
.uevent = auxiliary_uevent,
|
||||
.pm = &auxiliary_dev_pm_ops,
|
||||
};
|
||||
|
||||
/**
|
||||
* auxiliary_device_init - check auxiliary_device and initialize
|
||||
* @auxdev: auxiliary device struct
|
||||
*
|
||||
* This is the first step in the two-step process to register an
|
||||
* auxiliary_device.
|
||||
*
|
||||
* When this function returns an error code, then the device_initialize will
|
||||
* *not* have been performed, and the caller will be responsible to free any
|
||||
* memory allocated for the auxiliary_device in the error path directly.
|
||||
*
|
||||
* It returns 0 on success. On success, the device_initialize has been
|
||||
* performed. After this point any error unwinding will need to include a call
|
||||
* to auxiliary_device_uninit(). In this post-initialize error scenario, a call
|
||||
* to the device's .release callback will be triggered, and all memory clean-up
|
||||
* is expected to be handled there.
|
||||
*/
|
||||
int auxiliary_device_init(struct auxiliary_device *auxdev)
|
||||
{
|
||||
struct device *dev = &auxdev->dev;
|
||||
|
||||
if (!dev->parent) {
|
||||
pr_err("auxiliary_device has a NULL dev->parent\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!auxdev->name) {
|
||||
pr_err("auxiliary_device has a NULL name\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->bus = &auxiliary_bus_type;
|
||||
device_initialize(&auxdev->dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(auxiliary_device_init);
|
||||
|
||||
/**
|
||||
* __auxiliary_device_add - add an auxiliary bus device
|
||||
* @auxdev: auxiliary bus device to add to the bus
|
||||
* @modname: name of the parent device's driver module
|
||||
*
|
||||
* This is the second step in the two-step process to register an
|
||||
* auxiliary_device.
|
||||
*
|
||||
* This function must be called after a successful call to
|
||||
* auxiliary_device_init(), which will perform the device_initialize. This
|
||||
* means that if this returns an error code, then a call to
|
||||
* auxiliary_device_uninit() must be performed so that the .release callback
|
||||
* will be triggered to free the memory associated with the auxiliary_device.
|
||||
*
|
||||
* The expectation is that users will call the "auxiliary_device_add" macro so
|
||||
* that the caller's KBUILD_MODNAME is automatically inserted for the modname
|
||||
* parameter. Only if a user requires a custom name would this version be
|
||||
* called directly.
|
||||
*/
|
||||
int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname)
|
||||
{
|
||||
struct device *dev = &auxdev->dev;
|
||||
int ret;
|
||||
|
||||
if (!modname) {
|
||||
dev_err(dev, "auxiliary device modname is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id);
|
||||
if (ret) {
|
||||
dev_err(dev, "auxiliary device dev_set_name failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_add(dev);
|
||||
if (ret)
|
||||
dev_err(dev, "adding auxiliary device failed!: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__auxiliary_device_add);
|
||||
|
||||
/**
|
||||
* auxiliary_find_device - auxiliary device iterator for locating a particular device.
|
||||
* @start: Device to begin with
|
||||
* @data: Data to pass to match function
|
||||
* @match: Callback function to check device
|
||||
*
|
||||
* This function returns a reference to a device that is 'found'
|
||||
* for later use, as determined by the @match callback.
|
||||
*
|
||||
* The callback should return 0 if the device doesn't match and non-zero
|
||||
* if it does. If the callback returns non-zero, this function will
|
||||
* return to the caller and not iterate over any more devices.
|
||||
*/
|
||||
struct auxiliary_device *auxiliary_find_device(struct device *start,
|
||||
const void *data,
|
||||
int (*match)(struct device *dev, const void *data))
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = bus_find_device(&auxiliary_bus_type, start, data, match);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
return to_auxiliary_dev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(auxiliary_find_device);
|
||||
|
||||
/**
|
||||
* __auxiliary_driver_register - register a driver for auxiliary bus devices
|
||||
* @auxdrv: auxiliary_driver structure
|
||||
* @owner: owning module/driver
|
||||
* @modname: KBUILD_MODNAME for parent driver
|
||||
*/
|
||||
int __auxiliary_driver_register(struct auxiliary_driver *auxdrv,
|
||||
struct module *owner, const char *modname)
|
||||
{
|
||||
if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table))
|
||||
return -EINVAL;
|
||||
|
||||
if (auxdrv->name)
|
||||
auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", modname,
|
||||
auxdrv->name);
|
||||
else
|
||||
auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", modname);
|
||||
if (!auxdrv->driver.name)
|
||||
return -ENOMEM;
|
||||
|
||||
auxdrv->driver.owner = owner;
|
||||
auxdrv->driver.bus = &auxiliary_bus_type;
|
||||
auxdrv->driver.mod_name = modname;
|
||||
|
||||
return driver_register(&auxdrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__auxiliary_driver_register);
|
||||
|
||||
/**
|
||||
* auxiliary_driver_unregister - unregister a driver
|
||||
* @auxdrv: auxiliary_driver structure
|
||||
*/
|
||||
void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
|
||||
{
|
||||
driver_unregister(&auxdrv->driver);
|
||||
kfree(auxdrv->driver.name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(auxiliary_driver_unregister);
|
||||
|
||||
static int __init auxiliary_bus_init(void)
|
||||
{
|
||||
return bus_register(&auxiliary_bus_type);
|
||||
}
|
||||
|
||||
static void __exit auxiliary_bus_exit(void)
|
||||
{
|
||||
bus_unregister(&auxiliary_bus_type);
|
||||
}
|
||||
|
||||
module_init(auxiliary_bus_init);
|
||||
module_exit(auxiliary_bus_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Auxiliary Bus");
|
||||
MODULE_AUTHOR("David Ertman <david.m.ertman@intel.com>");
|
||||
MODULE_AUTHOR("Kiran Patil <kiran.patil@intel.com>");
|
@ -437,31 +437,38 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
tlv = (struct intel_tlv *)skb->data;
|
||||
switch (tlv->type) {
|
||||
case INTEL_TLV_CNVI_TOP:
|
||||
version->cnvi_top = get_unaligned_le32(tlv->val);
|
||||
version->cnvi_top =
|
||||
__le32_to_cpu(get_unaligned_le32(tlv->val));
|
||||
break;
|
||||
case INTEL_TLV_CNVR_TOP:
|
||||
version->cnvr_top = get_unaligned_le32(tlv->val);
|
||||
version->cnvr_top =
|
||||
__le32_to_cpu(get_unaligned_le32(tlv->val));
|
||||
break;
|
||||
case INTEL_TLV_CNVI_BT:
|
||||
version->cnvi_bt = get_unaligned_le32(tlv->val);
|
||||
version->cnvi_bt =
|
||||
__le32_to_cpu(get_unaligned_le32(tlv->val));
|
||||
break;
|
||||
case INTEL_TLV_CNVR_BT:
|
||||
version->cnvr_bt = get_unaligned_le32(tlv->val);
|
||||
version->cnvr_bt =
|
||||
__le32_to_cpu(get_unaligned_le32(tlv->val));
|
||||
break;
|
||||
case INTEL_TLV_DEV_REV_ID:
|
||||
version->dev_rev_id = get_unaligned_le16(tlv->val);
|
||||
version->dev_rev_id =
|
||||
__le16_to_cpu(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);
|
||||
version->timestamp =
|
||||
__le16_to_cpu(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);
|
||||
version->build_num =
|
||||
__le32_to_cpu(get_unaligned_le32(tlv->val));
|
||||
break;
|
||||
case INTEL_TLV_SECURE_BOOT:
|
||||
version->secure_boot = tlv->val[0];
|
||||
|
@ -132,6 +132,12 @@ struct intel_debug_features {
|
||||
__u8 page1[16];
|
||||
} __packed;
|
||||
|
||||
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
|
||||
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
|
||||
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
|
||||
#define INTEL_CNVX_TOP_STEP(cnvx_top) (((cnvx_top) & 0x0f000000) >> 24)
|
||||
#define INTEL_CNVX_TOP_PACK_SWAB(t, s) __swab16(((__u16)(((t) << 4) | (s))))
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_INTEL)
|
||||
|
||||
int btintel_check_bdaddr(struct hci_dev *hdev);
|
||||
|
@ -704,7 +704,7 @@ static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
|
||||
return err;
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data;
|
||||
|
@ -14,12 +14,11 @@
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
|
||||
enum qca_btsoc_type soc_type)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
struct qca_btsoc_version *ver;
|
||||
char cmd;
|
||||
int err = 0;
|
||||
u8 event_type = HCI_EV_VENDOR;
|
||||
@ -70,9 +69,9 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
}
|
||||
|
||||
if (soc_type >= QCA_WCN3991)
|
||||
memmove(&edl->data, &edl->data[1], sizeof(*ver));
|
||||
|
||||
ver = (struct qca_btsoc_version *)(edl->data);
|
||||
memcpy(ver, edl->data + 1, sizeof(*ver));
|
||||
else
|
||||
memcpy(ver, &edl->data, sizeof(*ver));
|
||||
|
||||
bt_dev_info(hdev, "QCA Product ID :0x%08x",
|
||||
le32_to_cpu(ver->product_id));
|
||||
@ -83,13 +82,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
bt_dev_info(hdev, "QCA Patch Version:0x%08x",
|
||||
le16_to_cpu(ver->patch_ver));
|
||||
|
||||
/* QCA chipset version can be decided by patch and SoC
|
||||
* version, combination with upper 2 bytes from SoC
|
||||
* and lower 2 bytes from patch will be used.
|
||||
*/
|
||||
*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
|
||||
(le16_to_cpu(ver->rom_ver) & 0x0000ffff);
|
||||
if (*soc_version == 0)
|
||||
if (ver->soc_id == 0 || ver->rom_ver == 0)
|
||||
err = -EILSEQ;
|
||||
|
||||
out:
|
||||
@ -446,15 +439,20 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
|
||||
|
||||
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, u32 soc_ver,
|
||||
enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
|
||||
const char *firmware_name)
|
||||
{
|
||||
struct qca_fw_config config;
|
||||
int err;
|
||||
u8 rom_ver = 0;
|
||||
u32 soc_ver;
|
||||
|
||||
bt_dev_dbg(hdev, "QCA setup on UART");
|
||||
|
||||
soc_ver = get_soc_ver(ver.soc_id, ver.rom_ver);
|
||||
|
||||
bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
|
||||
|
||||
config.user_baud_rate = baudrate;
|
||||
|
||||
/* Download rampatch file */
|
||||
@ -491,9 +489,15 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
if (firmware_name)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/%s", firmware_name);
|
||||
else if (qca_is_wcn399x(soc_type))
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02x.bin", rom_ver);
|
||||
else if (qca_is_wcn399x(soc_type)) {
|
||||
if (ver.soc_id == QCA_WCN3991_SOC_ID) {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02xu.bin", rom_ver);
|
||||
} else {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02x.bin", rom_ver);
|
||||
}
|
||||
}
|
||||
else if (soc_type == QCA_QCA6390)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
|
@ -34,6 +34,18 @@
|
||||
#define QCA_HCI_CC_OPCODE 0xFC00
|
||||
#define QCA_HCI_CC_SUCCESS 0x00
|
||||
|
||||
#define QCA_WCN3991_SOC_ID (0x40014320)
|
||||
|
||||
/* QCA chipset version can be decided by patch and SoC
|
||||
* version, combination with upper 2 bytes from SoC
|
||||
* and lower 2 bytes from patch will be used.
|
||||
*/
|
||||
#define get_soc_ver(soc_id, rom_ver) \
|
||||
((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver)))
|
||||
|
||||
#define QCA_FW_BUILD_VER_LEN 255
|
||||
|
||||
|
||||
enum qca_baudrate {
|
||||
QCA_BAUDRATE_115200 = 0,
|
||||
QCA_BAUDRATE_57600,
|
||||
@ -136,9 +148,9 @@ enum qca_btsoc_type {
|
||||
|
||||
int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, u32 soc_ver,
|
||||
enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
|
||||
const char *firmware_name);
|
||||
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
|
||||
enum qca_btsoc_type);
|
||||
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
|
||||
@ -155,13 +167,15 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad
|
||||
}
|
||||
|
||||
static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, u32 soc_ver,
|
||||
enum qca_btsoc_type soc_type,
|
||||
struct qca_btsoc_version ver,
|
||||
const char *firmware_name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
|
||||
static inline int qca_read_soc_version(struct hci_dev *hdev,
|
||||
struct qca_btsoc_version *ver,
|
||||
enum qca_btsoc_type)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -18,23 +18,25 @@
|
||||
#define VERSION "0.1"
|
||||
|
||||
#define RTL_EPATCH_SIGNATURE "Realtech"
|
||||
#define RTL_ROM_LMP_3499 0x3499
|
||||
#define RTL_ROM_LMP_8723A 0x1200
|
||||
#define RTL_ROM_LMP_8723B 0x8723
|
||||
#define RTL_ROM_LMP_8723D 0x8873
|
||||
#define RTL_ROM_LMP_8821A 0x8821
|
||||
#define RTL_ROM_LMP_8761A 0x8761
|
||||
#define RTL_ROM_LMP_8822B 0x8822
|
||||
#define RTL_ROM_LMP_8852A 0x8852
|
||||
#define RTL_CONFIG_MAGIC 0x8723ab55
|
||||
|
||||
#define IC_MATCH_FL_LMPSUBV (1 << 0)
|
||||
#define IC_MATCH_FL_HCIREV (1 << 1)
|
||||
#define IC_MATCH_FL_HCIVER (1 << 2)
|
||||
#define IC_MATCH_FL_HCIBUS (1 << 3)
|
||||
#define IC_INFO(lmps, hcir) \
|
||||
.match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \
|
||||
#define IC_INFO(lmps, hcir, hciv, bus) \
|
||||
.match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | \
|
||||
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS, \
|
||||
.lmp_subver = (lmps), \
|
||||
.hci_rev = (hcir)
|
||||
.hci_rev = (hcir), \
|
||||
.hci_ver = (hciv), \
|
||||
.hci_bus = (bus)
|
||||
|
||||
struct id_table {
|
||||
__u16 match_flags;
|
||||
@ -55,119 +57,100 @@ struct btrtl_device_info {
|
||||
int fw_len;
|
||||
u8 *cfg_data;
|
||||
int cfg_len;
|
||||
bool drop_fw;
|
||||
};
|
||||
|
||||
static const struct id_table ic_id_table[] = {
|
||||
{ IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8723A, 0x0,
|
||||
.config_needed = false,
|
||||
.has_rom_version = false,
|
||||
.fw_name = "rtl_bt/rtl8723a_fw.bin",
|
||||
.cfg_name = NULL },
|
||||
|
||||
{ IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_3499, 0x0,
|
||||
/* 8723A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723A, 0xb, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = false,
|
||||
.fw_name = "rtl_bt/rtl8723a_fw.bin",
|
||||
.cfg_name = NULL },
|
||||
|
||||
/* 8723BS */
|
||||
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV |
|
||||
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS,
|
||||
.lmp_subver = RTL_ROM_LMP_8723B,
|
||||
.hci_rev = 0xb,
|
||||
.hci_ver = 6,
|
||||
.hci_bus = HCI_UART,
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723bs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723bs_config" },
|
||||
|
||||
/* 8723B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb),
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723b_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723b_config" },
|
||||
|
||||
/* 8723D */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd),
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723d_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723d_config" },
|
||||
|
||||
/* 8723DS */
|
||||
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV |
|
||||
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS,
|
||||
.lmp_subver = RTL_ROM_LMP_8723B,
|
||||
.hci_rev = 0xd,
|
||||
.hci_ver = 8,
|
||||
.hci_bus = HCI_UART,
|
||||
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723ds_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723ds_config" },
|
||||
|
||||
/* 8723DU */
|
||||
{ IC_INFO(RTL_ROM_LMP_8723D, 0x826C),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8723d_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8723d_config" },
|
||||
|
||||
/* 8821A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xa),
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8821a_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8821a_config" },
|
||||
|
||||
/* 8821C */
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc),
|
||||
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8821c_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8821c_config" },
|
||||
|
||||
/* 8761A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xa),
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8761a_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761a_config" },
|
||||
|
||||
/* 8761B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb),
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8761b_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761b_config" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV |
|
||||
IC_MATCH_FL_HCIBUS,
|
||||
.lmp_subver = RTL_ROM_LMP_8822B,
|
||||
.hci_rev = 0x000c,
|
||||
.hci_ver = 0x0a,
|
||||
.hci_bus = HCI_UART,
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config" },
|
||||
|
||||
/* 8822C with USB interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc),
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8822cu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cu_config" },
|
||||
|
||||
/* 8822B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb),
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8822b_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822b_config" },
|
||||
|
||||
/* 8852A */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8852au_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852au_config" },
|
||||
};
|
||||
|
||||
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
|
||||
@ -275,6 +258,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
||||
{ RTL_ROM_LMP_8821A, 10 }, /* 8821C */
|
||||
{ RTL_ROM_LMP_8822B, 13 }, /* 8822C */
|
||||
{ RTL_ROM_LMP_8761A, 14 }, /* 8761B */
|
||||
{ RTL_ROM_LMP_8852A, 18 }, /* 8852A */
|
||||
};
|
||||
|
||||
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
|
||||
@ -563,6 +547,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
|
||||
u16 hci_rev, lmp_subver;
|
||||
u8 hci_ver;
|
||||
int ret;
|
||||
u16 opcode;
|
||||
u8 cmd[2];
|
||||
|
||||
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
|
||||
if (!btrtl_dev) {
|
||||
@ -584,6 +570,49 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
|
||||
hci_ver = resp->hci_ver;
|
||||
hci_rev = le16_to_cpu(resp->hci_rev);
|
||||
lmp_subver = le16_to_cpu(resp->lmp_subver);
|
||||
|
||||
if (resp->hci_ver == 0x8 && le16_to_cpu(resp->hci_rev) == 0x826c &&
|
||||
resp->lmp_ver == 0x8 && le16_to_cpu(resp->lmp_subver) == 0xa99e)
|
||||
btrtl_dev->drop_fw = true;
|
||||
|
||||
if (btrtl_dev->drop_fw) {
|
||||
opcode = hci_opcode_pack(0x3f, 0x66);
|
||||
cmd[0] = opcode & 0xff;
|
||||
cmd[1] = opcode >> 8;
|
||||
|
||||
skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto out_free;
|
||||
|
||||
skb_put_data(skb, cmd, sizeof(cmd));
|
||||
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
|
||||
|
||||
hdev->send(hdev, skb);
|
||||
|
||||
/* Ensure the above vendor command is sent to controller and
|
||||
* process has done.
|
||||
*/
|
||||
msleep(200);
|
||||
|
||||
/* Read the local version again. Expect to have the vanilla
|
||||
* version as cold boot.
|
||||
*/
|
||||
skb = btrtl_read_local_version(hdev);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
resp = (struct hci_rp_read_local_version *)skb->data;
|
||||
rtl_dev_info(hdev, "examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x lmp_subver=%04x",
|
||||
resp->hci_ver, resp->hci_rev,
|
||||
resp->lmp_ver, resp->lmp_subver);
|
||||
|
||||
hci_ver = resp->hci_ver;
|
||||
hci_rev = le16_to_cpu(resp->hci_rev);
|
||||
lmp_subver = le16_to_cpu(resp->lmp_subver);
|
||||
}
|
||||
out_free:
|
||||
kfree_skb(skb);
|
||||
|
||||
btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
|
||||
@ -654,12 +683,12 @@ int btrtl_download_firmware(struct hci_dev *hdev,
|
||||
|
||||
switch (btrtl_dev->ic_info->lmp_subver) {
|
||||
case RTL_ROM_LMP_8723A:
|
||||
case RTL_ROM_LMP_3499:
|
||||
return btrtl_setup_rtl8723a(hdev, btrtl_dev);
|
||||
case RTL_ROM_LMP_8723B:
|
||||
case RTL_ROM_LMP_8821A:
|
||||
case RTL_ROM_LMP_8761A:
|
||||
case RTL_ROM_LMP_8822B:
|
||||
case RTL_ROM_LMP_8852A:
|
||||
return btrtl_setup_rtl8723b(hdev, btrtl_dev);
|
||||
default:
|
||||
rtl_dev_info(hdev, "assuming no firmware upload needed");
|
||||
@ -835,3 +864,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8821a_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8821a_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852au_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852au_config.bin");
|
||||
|
@ -60,6 +60,7 @@ static struct usb_driver btusb_driver;
|
||||
#define BTUSB_WIDEBAND_SPEECH 0x400000
|
||||
#define BTUSB_VALID_LE_STATES 0x800000
|
||||
#define BTUSB_QCA_WCN6855 0x1000000
|
||||
#define BTUSB_INTEL_NEWGEN 0x2000000
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
@ -365,7 +366,7 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_NEW |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_NEW |
|
||||
{ USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_NEWGEN |
|
||||
BTUSB_WIDEBAND_SPEECH},
|
||||
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
|
||||
@ -386,6 +387,10 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x0bda, 0xb00c), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek 8852AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek Bluetooth devices */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
|
||||
.driver_info = BTUSB_REALTEK },
|
||||
@ -394,6 +399,9 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01),
|
||||
.driver_info = BTUSB_MEDIATEK },
|
||||
|
||||
/* Additional MediaTek MT7615E Bluetooth devices */
|
||||
{ USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},
|
||||
|
||||
/* Additional Realtek 8723AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
|
||||
@ -425,8 +433,26 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },
|
||||
|
||||
/* Additional Realtek 8822CE Bluetooth devices */
|
||||
{ USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3548), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04c5, 0x161f), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0b05, 0x18ef), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3548), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3549), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3553), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3555), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x2ff8, 0x3051), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x1358, 0xc123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xc123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Silicon Wave based devices */
|
||||
{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
|
||||
@ -1763,9 +1789,12 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev)
|
||||
|
||||
static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u16 bcdDevice = le16_to_cpu(data->udev->descriptor.bcdDevice);
|
||||
struct hci_rp_read_local_version *rp;
|
||||
struct sk_buff *skb;
|
||||
bool is_fake = false;
|
||||
int ret;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -1832,6 +1861,12 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
le16_to_cpu(rp->hci_ver) > BLUETOOTH_VER_4_0)
|
||||
is_fake = true;
|
||||
|
||||
/* Other clones which beat all the above checks */
|
||||
else if (bcdDevice == 0x0134 &&
|
||||
le16_to_cpu(rp->lmp_subver) == 0x0c5c &&
|
||||
le16_to_cpu(rp->hci_ver) == BLUETOOTH_VER_2_0)
|
||||
is_fake = true;
|
||||
|
||||
if (is_fake) {
|
||||
bt_dev_warn(hdev, "CSR: Unbranded CSR clone detected; adding workarounds...");
|
||||
|
||||
@ -1848,6 +1883,43 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
*/
|
||||
clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
clear_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
|
||||
/*
|
||||
* Special workaround for clones with a Barrot 8041a02 chip,
|
||||
* these clones are really messed-up:
|
||||
* 1. Their bulk rx endpoint will never report any data unless
|
||||
* the device was suspended at least once (yes really).
|
||||
* 2. They will not wakeup when autosuspended and receiving data
|
||||
* on their bulk rx endpoint from e.g. a keyboard or mouse
|
||||
* (IOW remote-wakeup support is broken for the bulk endpoint).
|
||||
*
|
||||
* To fix 1. enable runtime-suspend, force-suspend the
|
||||
* hci and then wake-it up by disabling runtime-suspend.
|
||||
*
|
||||
* To fix 2. clear the hci's can_wake flag, this way the hci
|
||||
* will still be autosuspended when it is not open.
|
||||
*/
|
||||
if (bcdDevice == 0x8891 &&
|
||||
le16_to_cpu(rp->lmp_subver) == 0x1012 &&
|
||||
le16_to_cpu(rp->hci_rev) == 0x0810 &&
|
||||
le16_to_cpu(rp->hci_ver) == BLUETOOTH_VER_4_0) {
|
||||
bt_dev_warn(hdev, "CSR: detected a fake CSR dongle using a Barrot 8041a02 chip, this chip is very buggy and may have issues\n");
|
||||
|
||||
pm_runtime_allow(&data->udev->dev);
|
||||
|
||||
ret = pm_runtime_suspend(&data->udev->dev);
|
||||
if (ret >= 0)
|
||||
msleep(200);
|
||||
else
|
||||
bt_dev_err(hdev, "Failed to suspend the device for Barrot 8041a02 receive-issue workaround\n");
|
||||
|
||||
pm_runtime_forbid(&data->udev->dev);
|
||||
|
||||
device_set_wakeup_capable(&data->udev->dev, false);
|
||||
/* Re-enable autosuspend if this was requested */
|
||||
if (enable_autosuspend)
|
||||
usb_enable_autosuspend(data->udev);
|
||||
}
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
@ -2359,6 +2431,182 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv *ver_tlv,
|
||||
char *fw_name, size_t len,
|
||||
const char *suffix)
|
||||
{
|
||||
/* The firmware file name for new generation controllers will be
|
||||
* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
|
||||
*/
|
||||
snprintf(fw_name, len, "intel/ibt-%04x-%04x.%s",
|
||||
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver_tlv->cnvi_top),
|
||||
INTEL_CNVX_TOP_STEP(ver_tlv->cnvi_top)),
|
||||
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver_tlv->cnvr_top),
|
||||
INTEL_CNVX_TOP_STEP(ver_tlv->cnvr_top)),
|
||||
suffix);
|
||||
}
|
||||
|
||||
static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver,
|
||||
u32 *boot_param)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
char fwname[64];
|
||||
int err;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
if (!ver || !boot_param)
|
||||
return -EINVAL;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (INTEL_HW_PLATFORM(ver->cnvi_bt) != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
|
||||
INTEL_HW_PLATFORM(ver->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x03 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
* firmware.
|
||||
*
|
||||
* When the operational firmware is already present, then only
|
||||
* the check for valid Bluetooth device address is needed. This
|
||||
* determines if the device will be added as configured or
|
||||
* unconfigured controller.
|
||||
*
|
||||
* It is not possible to use the Secure Boot Parameters in this
|
||||
* case since that command is only available in bootloader mode.
|
||||
*/
|
||||
if (ver->img_type == 0x03) {
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
btintel_check_bdaddr(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (INTEL_HW_VARIANT(ver->cnvi_bt)) {
|
||||
case 0x17: /* TyP */
|
||||
case 0x18: /* Slr */
|
||||
case 0x19: /* Slr-F */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
|
||||
INTEL_HW_VARIANT(ver->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the device is not in bootloader mode, then the only possible
|
||||
* choice is to return an error and abort the device initialization.
|
||||
*/
|
||||
if (ver->img_type != 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware variant (0x%x)",
|
||||
ver->img_type);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* It is required that every single firmware fragment is acknowledged
|
||||
* with a command complete event. If the boot parameters indicate
|
||||
* that this bootloader does not send them, then abort the setup.
|
||||
*/
|
||||
if (ver->limited_cce != 0x00) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
|
||||
ver->limited_cce);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
|
||||
if (ver->sbe_type > 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
|
||||
ver->sbe_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the OTP has no valid Bluetooth device address, then there will
|
||||
* also be no valid address for the operational firmware.
|
||||
*/
|
||||
if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
|
||||
bt_dev_info(hdev, "No device address configured");
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
|
||||
}
|
||||
|
||||
btusb_setup_intel_newgen_get_fw_name(ver, fwname, sizeof(fwname), "sfi");
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "Found device firmware: %s", fwname);
|
||||
|
||||
if (fw->size < 644) {
|
||||
bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
|
||||
fw->size);
|
||||
err = -EBADF;
|
||||
goto done;
|
||||
}
|
||||
|
||||
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
||||
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware_newgen(hdev, fw, boot_param,
|
||||
INTEL_HW_VARIANT(ver->cnvi_bt),
|
||||
ver->sbe_type);
|
||||
if (err < 0) {
|
||||
/* When FW download fails, send Intel Reset to retry
|
||||
* FW download.
|
||||
*/
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
/* Before switching the device into operational mode and with that
|
||||
* booting the loaded firmware, wait for the bootloader notification
|
||||
* that all fragments have been successfully received.
|
||||
*
|
||||
* When the event processing receives the notification, then the
|
||||
* BTUSB_DOWNLOADING flag will be cleared.
|
||||
*
|
||||
* The firmware loading should not take longer than 5 seconds
|
||||
* and thus just timeout if that happens and fail the setup
|
||||
* of this device.
|
||||
*/
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(5000));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
err = -ETIMEDOUT;
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
err = -ENOEXEC;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
struct intel_version *ver,
|
||||
struct intel_boot_params *params,
|
||||
@ -2693,6 +2941,134 @@ finish:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
ktime_t calltime, delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
struct intel_version_tlv version;
|
||||
|
||||
bt_dev_dbg(hdev, "");
|
||||
|
||||
/* Set the default boot parameter to 0x0 and it is updated to
|
||||
* SKU specific boot parameter after reading Intel_Write_Boot_Params
|
||||
* command while downloading the firmware.
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
*/
|
||||
err = btintel_read_version_tlv(hdev, &version);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
btintel_version_info_tlv(hdev, &version);
|
||||
|
||||
err = btusb_intel_download_firmware_newgen(hdev, &version, &boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* check if controller is already having an operational firmware */
|
||||
if (version.img_type == 0x03)
|
||||
goto finish;
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_BOOTING, &data->flags);
|
||||
|
||||
err = btintel_send_intel_reset(hdev, boot_param);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The bootloader will not indicate when the device is ready. This
|
||||
* is done by the operational firmware sending bootup notification.
|
||||
*
|
||||
* Booting into operational firmware should not take longer than
|
||||
* 1 second. However if that happens, then just fail the setup
|
||||
* since something went wrong.
|
||||
*/
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
|
||||
btusb_setup_intel_newgen_get_fw_name(&version, ddcname, sizeof(ddcname),
|
||||
"ddc");
|
||||
/* Once the device is running in operational mode, it needs to
|
||||
* apply the device configuration (DDC) parameters.
|
||||
*
|
||||
* The device can work without DDC parameters, so even if it
|
||||
* fails to load the file, no need to fail the setup.
|
||||
*/
|
||||
btintel_load_ddc_config(hdev, ddcname);
|
||||
|
||||
/* Read the Intel supported features and if new exception formats
|
||||
* supported, need to load the additional DDC config to enable.
|
||||
*/
|
||||
btintel_read_debug_features(hdev, &features);
|
||||
|
||||
/* Set DDC mask for available debug features */
|
||||
btintel_set_debug_features(hdev, &features);
|
||||
|
||||
/* Read the Intel version information after loading the FW */
|
||||
err = btintel_read_version_tlv(hdev, &version);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
btintel_version_info_tlv(hdev, &version);
|
||||
|
||||
finish:
|
||||
/* Set the event mask for Intel specific vendor events. This enables
|
||||
* a few extra events that are useful during general operation. It
|
||||
* does not enable any debugging related events.
|
||||
*
|
||||
* The device will function correctly without these events enabled
|
||||
* and thus no need to fail the setup.
|
||||
*/
|
||||
btintel_set_event_mask(hdev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int btusb_shutdown_intel(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -3067,7 +3443,7 @@ static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
|
||||
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
|
||||
return err;
|
||||
goto err_release_fw;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data;
|
||||
@ -3444,12 +3820,14 @@ static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
|
||||
#define QCA_SYSCFG_UPDATED 0x40
|
||||
#define QCA_PATCH_UPDATED 0x80
|
||||
#define QCA_DFU_TIMEOUT 3000
|
||||
#define QCA_FLAG_MULTI_NVM 0x80
|
||||
|
||||
struct qca_version {
|
||||
__le32 rom_version;
|
||||
__le32 patch_version;
|
||||
__le32 ram_version;
|
||||
__le32 ref_clock;
|
||||
__le16 board_id;
|
||||
__le16 flag;
|
||||
__u8 reserved[4];
|
||||
} __packed;
|
||||
|
||||
@ -3632,8 +4010,14 @@ static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
|
||||
char fwname[64];
|
||||
int err;
|
||||
|
||||
snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
|
||||
le32_to_cpu(ver->rom_version));
|
||||
if (((ver->flag >> 8) & 0xff) == QCA_FLAG_MULTI_NVM) {
|
||||
snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x_%04x.bin",
|
||||
le32_to_cpu(ver->rom_version),
|
||||
le16_to_cpu(ver->board_id));
|
||||
} else {
|
||||
snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
|
||||
le32_to_cpu(ver->rom_version));
|
||||
}
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err) {
|
||||
@ -3700,6 +4084,11 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
|
||||
sizeof(ver));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!(status & QCA_SYSCFG_UPDATED)) {
|
||||
err = btusb_setup_qca_load_nvm(hdev, &ver, info);
|
||||
if (err < 0)
|
||||
@ -4078,6 +4467,24 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL_NEWGEN) {
|
||||
hdev->manufacturer = 2;
|
||||
hdev->send = btusb_send_frame_intel;
|
||||
hdev->setup = btusb_setup_intel_newgen;
|
||||
hdev->shutdown = btusb_shutdown_intel_new;
|
||||
hdev->hw_error = btintel_hw_error;
|
||||
hdev->set_diag = btintel_set_diag;
|
||||
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||
hdev->cmd_timeout = btusb_intel_cmd_timeout;
|
||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
||||
|
||||
data->recv_event = btusb_recv_event_intel;
|
||||
data->recv_bulk = btusb_recv_bulk_intel;
|
||||
set_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_MARVELL)
|
||||
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
|
||||
|
||||
|
@ -245,6 +245,9 @@ static int h5_close(struct hci_uart *hu)
|
||||
skb_queue_purge(&h5->rel);
|
||||
skb_queue_purge(&h5->unrel);
|
||||
|
||||
kfree_skb(h5->rx_skb);
|
||||
h5->rx_skb = NULL;
|
||||
|
||||
if (h5->vnd && h5->vnd->close)
|
||||
h5->vnd->close(h5);
|
||||
|
||||
@ -1001,6 +1004,7 @@ static struct h5_vnd rtl_vnd = {
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id h5_acpi_match[] = {
|
||||
#ifdef CONFIG_BT_HCIUART_RTL
|
||||
{ "OBDA0623", (kernel_ulong_t)&rtl_vnd },
|
||||
{ "OBDA8723", (kernel_ulong_t)&rtl_vnd },
|
||||
#endif
|
||||
{ },
|
||||
|
@ -626,6 +626,7 @@ static int ll_setup(struct hci_uart *hu)
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 0);
|
||||
msleep(5);
|
||||
gpiod_set_value_cansleep(lldev->enable_gpio, 1);
|
||||
mdelay(100);
|
||||
err = serdev_device_wait_for_cts(serdev, true, 200);
|
||||
if (err) {
|
||||
bt_dev_err(hu->hdev, "Failed to get CTS");
|
||||
|
@ -50,6 +50,8 @@
|
||||
#define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
|
||||
#define CMD_TRANS_TIMEOUT_MS 100
|
||||
#define MEMDUMP_TIMEOUT_MS 8000
|
||||
#define IBS_DISABLE_SSR_TIMEOUT_MS (MEMDUMP_TIMEOUT_MS + 1000)
|
||||
#define FW_DOWNLOAD_TIMEOUT_MS 3000
|
||||
|
||||
/* susclk rate */
|
||||
#define SUSCLK_RATE_32KHZ 32768
|
||||
@ -68,16 +70,18 @@
|
||||
#define QCA_MEMDUMP_BYTE 0xFB
|
||||
|
||||
enum qca_flags {
|
||||
QCA_IBS_ENABLED,
|
||||
QCA_IBS_DISABLED,
|
||||
QCA_DROP_VENDOR_EVENT,
|
||||
QCA_SUSPENDING,
|
||||
QCA_MEMDUMP_COLLECTION,
|
||||
QCA_HW_ERROR_EVENT,
|
||||
QCA_SSR_TRIGGERED
|
||||
QCA_SSR_TRIGGERED,
|
||||
QCA_BT_OFF
|
||||
};
|
||||
|
||||
enum qca_capabilities {
|
||||
QCA_CAP_WIDEBAND_SPEECH = BIT(0),
|
||||
QCA_CAP_VALID_LE_STATES = BIT(1),
|
||||
};
|
||||
|
||||
/* HCI_IBS transmit side sleep protocol states */
|
||||
@ -630,7 +634,7 @@ static void qca_debugfs_init(struct hci_dev *hdev)
|
||||
ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);
|
||||
|
||||
/* read only */
|
||||
mode = S_IRUGO;
|
||||
mode = 0444;
|
||||
debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state);
|
||||
debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state);
|
||||
debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir,
|
||||
@ -657,7 +661,7 @@ static void qca_debugfs_init(struct hci_dev *hdev)
|
||||
debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms);
|
||||
|
||||
/* read/write */
|
||||
mode = S_IRUGO | S_IWUSR;
|
||||
mode = 0644;
|
||||
debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans);
|
||||
debugfs_create_u32("tx_idle_delay", mode, ibs_dir,
|
||||
&qca->tx_idle_delay);
|
||||
@ -869,7 +873,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||
* Out-Of-Band(GPIOs control) sleep is selected.
|
||||
* Don't wake the device up when suspending.
|
||||
*/
|
||||
if (!test_bit(QCA_IBS_ENABLED, &qca->flags) ||
|
||||
if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
|
||||
test_bit(QCA_SUSPENDING, &qca->flags)) {
|
||||
skb_queue_tail(&qca->txq, skb);
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
@ -1014,7 +1018,7 @@ static void qca_controller_memdump(struct work_struct *work)
|
||||
* the controller to send the dump is 8 seconds. let us
|
||||
* start timer to handle this asynchronous activity.
|
||||
*/
|
||||
clear_bit(QCA_IBS_ENABLED, &qca->flags);
|
||||
set_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
|
||||
dump = (void *) skb->data;
|
||||
dump_size = __le32_to_cpu(dump->dump_size);
|
||||
@ -1301,7 +1305,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
||||
|
||||
/* Give the controller time to process the request */
|
||||
if (qca_is_wcn399x(qca_soc_type(hu)))
|
||||
msleep(10);
|
||||
usleep_range(1000, 10000);
|
||||
else
|
||||
msleep(300);
|
||||
|
||||
@ -1349,7 +1353,7 @@ static int qca_send_power_pulse(struct hci_uart *hu, bool on)
|
||||
if (on)
|
||||
msleep(100);
|
||||
else
|
||||
msleep(10);
|
||||
usleep_range(1000, 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1618,6 +1622,7 @@ static int qca_power_on(struct hci_dev *hdev)
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
enum qca_btsoc_type soc_type = qca_soc_type(hu);
|
||||
struct qca_serdev *qcadev;
|
||||
struct qca_data *qca = hu->priv;
|
||||
int ret = 0;
|
||||
|
||||
/* Non-serdev device usually is powered by external power
|
||||
@ -1637,6 +1642,7 @@ static int qca_power_on(struct hci_dev *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(QCA_BT_OFF, &qca->flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1649,14 +1655,14 @@ static int qca_setup(struct hci_uart *hu)
|
||||
enum qca_btsoc_type soc_type = qca_soc_type(hu);
|
||||
const char *firmware_name = qca_get_firmware_name(hu);
|
||||
int ret;
|
||||
int soc_ver = 0;
|
||||
struct qca_btsoc_version ver;
|
||||
|
||||
ret = qca_check_speeds(hu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Patch downloading has to be done without IBS mode */
|
||||
clear_bit(QCA_IBS_ENABLED, &qca->flags);
|
||||
set_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
|
||||
/* Enable controller to do both LE scan and BR/EDR inquiry
|
||||
* simultaneously.
|
||||
@ -1671,16 +1677,16 @@ static int qca_setup(struct hci_uart *hu)
|
||||
retry:
|
||||
ret = qca_power_on(hdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
|
||||
|
||||
ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
|
||||
ret = qca_read_soc_version(hdev, &ver, soc_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
} else {
|
||||
qca_set_speed(hu, QCA_INIT_SPEED);
|
||||
}
|
||||
@ -1690,24 +1696,23 @@ retry:
|
||||
if (speed) {
|
||||
ret = qca_set_speed(hu, QCA_OPER_SPEED);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
qca_baudrate = qca_get_baudrate_value(speed);
|
||||
}
|
||||
|
||||
if (!qca_is_wcn399x(soc_type)) {
|
||||
/* Get QCA version information */
|
||||
ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
|
||||
ret = qca_read_soc_version(hdev, &ver, soc_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
|
||||
/* Setup patch / NVM configurations */
|
||||
ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver,
|
||||
ret = qca_uart_setup(hdev, qca_baudrate, soc_type, ver,
|
||||
firmware_name);
|
||||
if (!ret) {
|
||||
set_bit(QCA_IBS_ENABLED, &qca->flags);
|
||||
clear_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
qca_debugfs_init(hdev);
|
||||
hu->hdev->hw_error = qca_hw_error;
|
||||
hu->hdev->cmd_timeout = qca_cmd_timeout;
|
||||
@ -1720,20 +1725,22 @@ retry:
|
||||
* patch/nvm-config is found, so run with original fw/config.
|
||||
*/
|
||||
ret = 0;
|
||||
} else {
|
||||
if (retries < MAX_INIT_RETRIES) {
|
||||
qca_power_shutdown(hu);
|
||||
if (hu->serdev) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hdev, "failed to open port");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret && retries < MAX_INIT_RETRIES) {
|
||||
bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
|
||||
qca_power_shutdown(hu);
|
||||
if (hu->serdev) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hdev, "failed to open port");
|
||||
return ret;
|
||||
}
|
||||
retries++;
|
||||
goto retry;
|
||||
}
|
||||
retries++;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Setup bdaddr */
|
||||
@ -1780,7 +1787,7 @@ static const struct qca_device_data qca_soc_data_wcn3991 = {
|
||||
{ "vddch0", 450000 },
|
||||
},
|
||||
.num_vregs = 4,
|
||||
.capabilities = QCA_CAP_WIDEBAND_SPEECH,
|
||||
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_wcn3998 = {
|
||||
@ -1813,7 +1820,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
* data in skb's.
|
||||
*/
|
||||
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
|
||||
clear_bit(QCA_IBS_ENABLED, &qca->flags);
|
||||
set_bit(QCA_IBS_DISABLED, &qca->flags);
|
||||
qca_flush(hu);
|
||||
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
|
||||
|
||||
@ -1830,6 +1837,8 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
} else if (qcadev->bt_en) {
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
}
|
||||
|
||||
set_bit(QCA_BT_OFF, &qca->flags);
|
||||
}
|
||||
|
||||
static int qca_power_off(struct hci_dev *hdev)
|
||||
@ -2017,11 +2026,17 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
hdev->shutdown = qca_power_off;
|
||||
}
|
||||
|
||||
/* Wideband speech support must be set per driver since it can't be
|
||||
* queried via hci.
|
||||
*/
|
||||
if (data && (data->capabilities & QCA_CAP_WIDEBAND_SPEECH))
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
if (data) {
|
||||
/* Wideband speech support must be set per driver since it can't
|
||||
* be queried via hci. Same with the valid le states quirk.
|
||||
*/
|
||||
if (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
|
||||
&hdev->quirks);
|
||||
|
||||
if (data->capabilities & QCA_CAP_VALID_LE_STATES)
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2081,11 +2096,34 @@ static int __maybe_unused qca_suspend(struct device *dev)
|
||||
bool tx_pending = false;
|
||||
int ret = 0;
|
||||
u8 cmd;
|
||||
u32 wait_timeout = 0;
|
||||
|
||||
set_bit(QCA_SUSPENDING, &qca->flags);
|
||||
|
||||
/* Device is downloading patch or doesn't support in-band sleep. */
|
||||
if (!test_bit(QCA_IBS_ENABLED, &qca->flags))
|
||||
if (test_bit(QCA_BT_OFF, &qca->flags))
|
||||
return 0;
|
||||
|
||||
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
|
||||
wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
|
||||
IBS_DISABLE_SSR_TIMEOUT_MS :
|
||||
FW_DOWNLOAD_TIMEOUT_MS;
|
||||
|
||||
/* QCA_IBS_DISABLED flag is set to true, During FW download
|
||||
* and during memory dump collection. It is reset to false,
|
||||
* After FW download complete and after memory dump collections.
|
||||
*/
|
||||
wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
|
||||
TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
|
||||
|
||||
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
|
||||
bt_dev_err(hu->hdev, "SSR or FW download time out");
|
||||
ret = -ETIMEDOUT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* After memory dump collection, Controller is powered off.*/
|
||||
if (test_bit(QCA_BT_OFF, &qca->flags))
|
||||
return 0;
|
||||
|
||||
cancel_work_sync(&qca->ws_awake_device);
|
||||
|
@ -758,7 +758,6 @@ static int parse_ch_cfg(struct mhi_controller *mhi_cntrl,
|
||||
mhi_chan->offload_ch = ch_cfg->offload_channel;
|
||||
mhi_chan->db_cfg.reset_req = ch_cfg->doorbell_mode_switch;
|
||||
mhi_chan->pre_alloc = ch_cfg->auto_queue;
|
||||
mhi_chan->auto_start = ch_cfg->auto_start;
|
||||
|
||||
/*
|
||||
* If MHI host allocates buffers, then the channel direction
|
||||
@ -1160,11 +1159,6 @@ static int mhi_driver_probe(struct device *dev)
|
||||
goto exit_probe;
|
||||
|
||||
ul_chan->xfer_cb = mhi_drv->ul_xfer_cb;
|
||||
if (ul_chan->auto_start) {
|
||||
ret = mhi_prepare_channel(mhi_cntrl, ul_chan);
|
||||
if (ret)
|
||||
goto exit_probe;
|
||||
}
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
@ -1198,9 +1192,6 @@ static int mhi_driver_probe(struct device *dev)
|
||||
if (ret)
|
||||
goto exit_probe;
|
||||
|
||||
if (dl_chan && dl_chan->auto_start)
|
||||
mhi_prepare_channel(mhi_cntrl, dl_chan);
|
||||
|
||||
mhi_device_put(mhi_dev);
|
||||
|
||||
return ret;
|
||||
|
@ -563,7 +563,6 @@ struct mhi_chan {
|
||||
bool configured;
|
||||
bool offload_ch;
|
||||
bool pre_alloc;
|
||||
bool auto_start;
|
||||
bool wake_capable;
|
||||
};
|
||||
|
||||
|
@ -1165,6 +1165,17 @@ int mhi_queue_buf(struct mhi_device *mhi_dev, enum dma_data_direction dir,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_queue_buf);
|
||||
|
||||
bool mhi_queue_is_full(struct mhi_device *mhi_dev, enum dma_data_direction dir)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ?
|
||||
mhi_dev->ul_chan : mhi_dev->dl_chan;
|
||||
struct mhi_ring *tre_ring = &mhi_chan->tre_ring;
|
||||
|
||||
return mhi_is_ring_full(mhi_cntrl, tre_ring);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mhi_queue_is_full);
|
||||
|
||||
int mhi_send_cmd(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan,
|
||||
enum mhi_cmd_type cmd)
|
||||
|
@ -545,14 +545,10 @@ static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested)
|
||||
}
|
||||
}
|
||||
|
||||
static int caam_qi_napi_schedule(struct qman_portal *p, struct caam_napi *np)
|
||||
static int caam_qi_napi_schedule(struct qman_portal *p, struct caam_napi *np,
|
||||
bool sched_napi)
|
||||
{
|
||||
/*
|
||||
* In case of threaded ISR, for RT kernels in_irq() does not return
|
||||
* appropriate value, so use in_serving_softirq to distinguish between
|
||||
* softirq and irq contexts.
|
||||
*/
|
||||
if (unlikely(in_irq() || !in_serving_softirq())) {
|
||||
if (sched_napi) {
|
||||
/* Disable QMan IRQ source and invoke NAPI */
|
||||
qman_p_irqsource_remove(p, QM_PIRQ_DQRI);
|
||||
np->p = p;
|
||||
@ -564,7 +560,8 @@ static int caam_qi_napi_schedule(struct qman_portal *p, struct caam_napi *np)
|
||||
|
||||
static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
|
||||
struct qman_fq *rsp_fq,
|
||||
const struct qm_dqrr_entry *dqrr)
|
||||
const struct qm_dqrr_entry *dqrr,
|
||||
bool sched_napi)
|
||||
{
|
||||
struct caam_napi *caam_napi = raw_cpu_ptr(&pcpu_qipriv.caam_napi);
|
||||
struct caam_drv_req *drv_req;
|
||||
@ -573,7 +570,7 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
|
||||
struct caam_drv_private *priv = dev_get_drvdata(qidev);
|
||||
u32 status;
|
||||
|
||||
if (caam_qi_napi_schedule(p, caam_napi))
|
||||
if (caam_qi_napi_schedule(p, caam_napi, sched_napi))
|
||||
return qman_cb_dqrr_stop;
|
||||
|
||||
fd = &dqrr->fd;
|
||||
|
@ -932,7 +932,7 @@ static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (tb[RDMA_NLDEV_ATTR_DEV_NAME]) {
|
||||
char name[IB_DEVICE_NAME_MAX] = {};
|
||||
|
||||
nla_strlcpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
|
||||
nla_strscpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
|
||||
IB_DEVICE_NAME_MAX);
|
||||
if (strlen(name) == 0) {
|
||||
err = -EINVAL;
|
||||
@ -1529,13 +1529,13 @@ static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
!tb[RDMA_NLDEV_ATTR_LINK_TYPE] || !tb[RDMA_NLDEV_ATTR_NDEV_NAME])
|
||||
return -EINVAL;
|
||||
|
||||
nla_strlcpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
|
||||
nla_strscpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
|
||||
sizeof(ibdev_name));
|
||||
if (strchr(ibdev_name, '%') || strlen(ibdev_name) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
nla_strlcpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type));
|
||||
nla_strlcpy(ndev_name, tb[RDMA_NLDEV_ATTR_NDEV_NAME],
|
||||
nla_strscpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type));
|
||||
nla_strscpy(ndev_name, tb[RDMA_NLDEV_ATTR_NDEV_NAME],
|
||||
sizeof(ndev_name));
|
||||
|
||||
ndev = dev_get_by_name(sock_net(skb->sk), ndev_name);
|
||||
@ -1602,7 +1602,7 @@ static int nldev_get_chardev(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
if (err || !tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE])
|
||||
return -EINVAL;
|
||||
|
||||
nla_strlcpy(client_name, tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE],
|
||||
nla_strscpy(client_name, tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE],
|
||||
sizeof(client_name));
|
||||
|
||||
if (tb[RDMA_NLDEV_ATTR_DEV_INDEX]) {
|
||||
|
@ -1686,7 +1686,6 @@ static void hfi1_ipoib_ib_rcv(struct hfi1_packet *packet)
|
||||
u32 extra_bytes;
|
||||
u32 tlen, qpnum;
|
||||
bool do_work, do_cnp;
|
||||
struct hfi1_ipoib_dev_priv *priv;
|
||||
|
||||
trace_hfi1_rcvhdr(packet);
|
||||
|
||||
@ -1734,8 +1733,7 @@ static void hfi1_ipoib_ib_rcv(struct hfi1_packet *packet)
|
||||
if (unlikely(!skb))
|
||||
goto drop;
|
||||
|
||||
priv = hfi1_ipoib_priv(netdev);
|
||||
hfi1_ipoib_update_rx_netstats(priv, 1, skb->len);
|
||||
dev_sw_netstats_rx_add(netdev, skb->len);
|
||||
|
||||
skb->dev = netdev;
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
@ -110,7 +110,6 @@ struct hfi1_ipoib_dev_priv {
|
||||
|
||||
const struct net_device_ops *netdev_ops;
|
||||
struct rvt_qp *qp;
|
||||
struct pcpu_sw_netstats __percpu *netstats;
|
||||
};
|
||||
|
||||
/* hfi1 ipoib rdma netdev's private data structure */
|
||||
@ -126,32 +125,6 @@ hfi1_ipoib_priv(const struct net_device *dev)
|
||||
return &((struct hfi1_ipoib_rdma_netdev *)netdev_priv(dev))->dev_priv;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hfi1_ipoib_update_rx_netstats(struct hfi1_ipoib_dev_priv *priv,
|
||||
u64 packets,
|
||||
u64 bytes)
|
||||
{
|
||||
struct pcpu_sw_netstats *netstats = this_cpu_ptr(priv->netstats);
|
||||
|
||||
u64_stats_update_begin(&netstats->syncp);
|
||||
netstats->rx_packets += packets;
|
||||
netstats->rx_bytes += bytes;
|
||||
u64_stats_update_end(&netstats->syncp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hfi1_ipoib_update_tx_netstats(struct hfi1_ipoib_dev_priv *priv,
|
||||
u64 packets,
|
||||
u64 bytes)
|
||||
{
|
||||
struct pcpu_sw_netstats *netstats = this_cpu_ptr(priv->netstats);
|
||||
|
||||
u64_stats_update_begin(&netstats->syncp);
|
||||
netstats->tx_packets += packets;
|
||||
netstats->tx_bytes += bytes;
|
||||
u64_stats_update_end(&netstats->syncp);
|
||||
}
|
||||
|
||||
int hfi1_ipoib_send_dma(struct net_device *dev,
|
||||
struct sk_buff *skb,
|
||||
struct ib_ah *address,
|
||||
|
@ -21,7 +21,7 @@ static int hfi1_ipoib_dev_init(struct net_device *dev)
|
||||
struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
|
||||
int ret;
|
||||
|
||||
priv->netstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
|
||||
ret = priv->netdev_ops->ndo_init(dev);
|
||||
if (ret)
|
||||
@ -93,21 +93,12 @@ static int hfi1_ipoib_dev_stop(struct net_device *dev)
|
||||
return priv->netdev_ops->ndo_stop(dev);
|
||||
}
|
||||
|
||||
static void hfi1_ipoib_dev_get_stats64(struct net_device *dev,
|
||||
struct rtnl_link_stats64 *storage)
|
||||
{
|
||||
struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
|
||||
|
||||
netdev_stats_to_stats64(storage, &dev->stats);
|
||||
dev_fetch_sw_netstats(storage, priv->netstats);
|
||||
}
|
||||
|
||||
static const struct net_device_ops hfi1_ipoib_netdev_ops = {
|
||||
.ndo_init = hfi1_ipoib_dev_init,
|
||||
.ndo_uninit = hfi1_ipoib_dev_uninit,
|
||||
.ndo_open = hfi1_ipoib_dev_open,
|
||||
.ndo_stop = hfi1_ipoib_dev_stop,
|
||||
.ndo_get_stats64 = hfi1_ipoib_dev_get_stats64,
|
||||
.ndo_get_stats64 = dev_get_tstats64,
|
||||
};
|
||||
|
||||
static int hfi1_ipoib_send(struct net_device *dev,
|
||||
@ -182,7 +173,7 @@ static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
|
||||
hfi1_ipoib_txreq_deinit(priv);
|
||||
hfi1_ipoib_rxq_deinit(priv->netdev);
|
||||
|
||||
free_percpu(priv->netstats);
|
||||
free_percpu(dev->tstats);
|
||||
}
|
||||
|
||||
static void hfi1_ipoib_free_rdma_netdev(struct net_device *dev)
|
||||
|
@ -121,7 +121,7 @@ static void hfi1_ipoib_free_tx(struct ipoib_txreq *tx, int budget)
|
||||
struct hfi1_ipoib_dev_priv *priv = tx->priv;
|
||||
|
||||
if (likely(!tx->sdma_status)) {
|
||||
hfi1_ipoib_update_tx_netstats(priv, 1, tx->skb->len);
|
||||
dev_sw_netstats_tx_add(priv->netdev, 1, tx->skb->len);
|
||||
} else {
|
||||
++priv->netdev->stats.tx_errors;
|
||||
dd_dev_warn(priv->dd,
|
||||
|
@ -138,13 +138,6 @@ static int mlx5_ib_create_counters(struct ib_counters *counters,
|
||||
}
|
||||
|
||||
|
||||
static bool is_mdev_switchdev_mode(const struct mlx5_core_dev *mdev)
|
||||
{
|
||||
return MLX5_ESWITCH_MANAGER(mdev) &&
|
||||
mlx5_ib_eswitch_mode(mdev->priv.eswitch) ==
|
||||
MLX5_ESWITCH_OFFLOADS;
|
||||
}
|
||||
|
||||
static const struct mlx5_ib_counters *get_counters(struct mlx5_ib_dev *dev,
|
||||
u8 port_num)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
||||
struct mlx5_ib_dev *ibdev;
|
||||
int vport_index;
|
||||
|
||||
ibdev = mlx5_ib_get_uplink_ibdev(dev->priv.eswitch);
|
||||
ibdev = mlx5_eswitch_uplink_get_proto_dev(dev->priv.eswitch, REP_IB);
|
||||
vport_index = rep->vport_index;
|
||||
|
||||
ibdev->port[vport_index].rep = rep;
|
||||
@ -33,6 +33,7 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
||||
const struct mlx5_ib_profile *profile;
|
||||
struct mlx5_ib_dev *ibdev;
|
||||
int vport_index;
|
||||
int ret;
|
||||
|
||||
if (rep->vport == MLX5_VPORT_UPLINK)
|
||||
profile = &raw_eth_profile;
|
||||
@ -46,8 +47,8 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
||||
ibdev->port = kcalloc(num_ports, sizeof(*ibdev->port),
|
||||
GFP_KERNEL);
|
||||
if (!ibdev->port) {
|
||||
ib_dealloc_device(&ibdev->ib_dev);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto fail_port;
|
||||
}
|
||||
|
||||
ibdev->is_rep = true;
|
||||
@ -58,12 +59,24 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
||||
ibdev->mdev = dev;
|
||||
ibdev->num_ports = num_ports;
|
||||
|
||||
if (!__mlx5_ib_add(ibdev, profile))
|
||||
return -EINVAL;
|
||||
ret = __mlx5_ib_add(ibdev, profile);
|
||||
if (ret)
|
||||
goto fail_add;
|
||||
|
||||
rep->rep_data[REP_IB].priv = ibdev;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_add:
|
||||
kfree(ibdev->port);
|
||||
fail_port:
|
||||
ib_dealloc_device(&ibdev->ib_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *mlx5_ib_rep_to_dev(struct mlx5_eswitch_rep *rep)
|
||||
{
|
||||
return rep->rep_data[REP_IB].priv;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -83,59 +96,18 @@ mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep)
|
||||
__mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX);
|
||||
}
|
||||
|
||||
static void *mlx5_ib_vport_get_proto_dev(struct mlx5_eswitch_rep *rep)
|
||||
{
|
||||
return mlx5_ib_rep_to_dev(rep);
|
||||
}
|
||||
|
||||
static const struct mlx5_eswitch_rep_ops rep_ops = {
|
||||
.load = mlx5_ib_vport_rep_load,
|
||||
.unload = mlx5_ib_vport_rep_unload,
|
||||
.get_proto_dev = mlx5_ib_vport_get_proto_dev,
|
||||
.get_proto_dev = mlx5_ib_rep_to_dev,
|
||||
};
|
||||
|
||||
void mlx5_ib_register_vport_reps(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
struct mlx5_eswitch *esw = mdev->priv.eswitch;
|
||||
|
||||
mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
|
||||
}
|
||||
|
||||
void mlx5_ib_unregister_vport_reps(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
struct mlx5_eswitch *esw = mdev->priv.eswitch;
|
||||
|
||||
mlx5_eswitch_unregister_vport_reps(esw, REP_IB);
|
||||
}
|
||||
|
||||
u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw)
|
||||
{
|
||||
return mlx5_eswitch_mode(esw);
|
||||
}
|
||||
|
||||
struct mlx5_ib_dev *mlx5_ib_get_rep_ibdev(struct mlx5_eswitch *esw,
|
||||
u16 vport_num)
|
||||
{
|
||||
return mlx5_eswitch_get_proto_dev(esw, vport_num, REP_IB);
|
||||
}
|
||||
|
||||
struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
|
||||
u16 vport_num)
|
||||
{
|
||||
return mlx5_eswitch_get_proto_dev(esw, vport_num, REP_ETH);
|
||||
}
|
||||
|
||||
struct mlx5_ib_dev *mlx5_ib_get_uplink_ibdev(struct mlx5_eswitch *esw)
|
||||
{
|
||||
return mlx5_eswitch_uplink_get_proto_dev(esw, REP_IB);
|
||||
}
|
||||
|
||||
struct mlx5_eswitch_rep *mlx5_ib_vport_rep(struct mlx5_eswitch *esw,
|
||||
u16 vport_num)
|
||||
{
|
||||
return mlx5_eswitch_vport_rep(esw, vport_num);
|
||||
}
|
||||
|
||||
struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
|
||||
struct mlx5_ib_sq *sq,
|
||||
u16 port)
|
||||
@ -154,3 +126,49 @@ struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
|
||||
return mlx5_eswitch_add_send_to_vport_rule(esw, rep->vport,
|
||||
sq->base.mqp.qpn);
|
||||
}
|
||||
|
||||
static int mlx5r_rep_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
|
||||
struct mlx5_core_dev *mdev = idev->mdev;
|
||||
struct mlx5_eswitch *esw;
|
||||
|
||||
esw = mdev->priv.eswitch;
|
||||
mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlx5r_rep_remove(struct auxiliary_device *adev)
|
||||
{
|
||||
struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
|
||||
struct mlx5_core_dev *mdev = idev->mdev;
|
||||
struct mlx5_eswitch *esw;
|
||||
|
||||
esw = mdev->priv.eswitch;
|
||||
mlx5_eswitch_unregister_vport_reps(esw, REP_IB);
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id mlx5r_rep_id_table[] = {
|
||||
{ .name = MLX5_ADEV_NAME ".rdma-rep", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(auxiliary, mlx5r_rep_id_table);
|
||||
|
||||
static struct auxiliary_driver mlx5r_rep_driver = {
|
||||
.name = "rep",
|
||||
.probe = mlx5r_rep_probe,
|
||||
.remove = mlx5r_rep_remove,
|
||||
.id_table = mlx5r_rep_id_table,
|
||||
};
|
||||
|
||||
int mlx5r_rep_init(void)
|
||||
{
|
||||
return auxiliary_driver_register(&mlx5r_rep_driver);
|
||||
}
|
||||
|
||||
void mlx5r_rep_cleanup(void)
|
||||
{
|
||||
auxiliary_driver_unregister(&mlx5r_rep_driver);
|
||||
}
|
||||
|
@ -12,47 +12,16 @@
|
||||
extern const struct mlx5_ib_profile raw_eth_profile;
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw);
|
||||
struct mlx5_ib_dev *mlx5_ib_get_rep_ibdev(struct mlx5_eswitch *esw,
|
||||
u16 vport_num);
|
||||
struct mlx5_ib_dev *mlx5_ib_get_uplink_ibdev(struct mlx5_eswitch *esw);
|
||||
struct mlx5_eswitch_rep *mlx5_ib_vport_rep(struct mlx5_eswitch *esw,
|
||||
u16 vport_num);
|
||||
void mlx5_ib_register_vport_reps(struct mlx5_core_dev *mdev);
|
||||
void mlx5_ib_unregister_vport_reps(struct mlx5_core_dev *mdev);
|
||||
int mlx5r_rep_init(void);
|
||||
void mlx5r_rep_cleanup(void);
|
||||
struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
|
||||
struct mlx5_ib_sq *sq,
|
||||
u16 port);
|
||||
struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
|
||||
u16 vport_num);
|
||||
#else /* CONFIG_MLX5_ESWITCH */
|
||||
static inline u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw)
|
||||
{
|
||||
return MLX5_ESWITCH_NONE;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct mlx5_ib_dev *mlx5_ib_get_rep_ibdev(struct mlx5_eswitch *esw,
|
||||
u16 vport_num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct mlx5_ib_dev *mlx5_ib_get_uplink_ibdev(struct mlx5_eswitch *esw)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct mlx5_eswitch_rep *mlx5_ib_vport_rep(struct mlx5_eswitch *esw,
|
||||
u16 vport_num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void mlx5_ib_register_vport_reps(struct mlx5_core_dev *mdev) {}
|
||||
static inline void mlx5_ib_unregister_vport_reps(struct mlx5_core_dev *mdev) {}
|
||||
static inline int mlx5r_rep_init(void) { return 0; }
|
||||
static inline void mlx5r_rep_cleanup(void) {}
|
||||
static inline
|
||||
struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
|
||||
struct mlx5_ib_sq *sq,
|
||||
@ -68,10 +37,4 @@ struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline
|
||||
struct mlx5_ib_dev *mlx5_ib_rep_to_dev(struct mlx5_eswitch_rep *rep)
|
||||
{
|
||||
return rep->rep_data[REP_IB].priv;
|
||||
}
|
||||
#endif /* __MLX5_IB_REP_H__ */
|
||||
|
@ -4593,8 +4593,8 @@ void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
|
||||
ib_dealloc_device(&dev->ib_dev);
|
||||
}
|
||||
|
||||
void *__mlx5_ib_add(struct mlx5_ib_dev *dev,
|
||||
const struct mlx5_ib_profile *profile)
|
||||
int __mlx5_ib_add(struct mlx5_ib_dev *dev,
|
||||
const struct mlx5_ib_profile *profile)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
@ -4610,13 +4610,16 @@ void *__mlx5_ib_add(struct mlx5_ib_dev *dev,
|
||||
}
|
||||
|
||||
dev->ib_active = true;
|
||||
|
||||
return dev;
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
__mlx5_ib_remove(dev, profile, i);
|
||||
|
||||
return NULL;
|
||||
/* Clean up stages which were initialized */
|
||||
while (i) {
|
||||
i--;
|
||||
if (profile->stage[i].cleanup)
|
||||
profile->stage[i].cleanup(dev);
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static const struct mlx5_ib_profile pf_profile = {
|
||||
@ -4739,8 +4742,11 @@ const struct mlx5_ib_profile raw_eth_profile = {
|
||||
NULL),
|
||||
};
|
||||
|
||||
static void *mlx5_ib_add_slave_port(struct mlx5_core_dev *mdev)
|
||||
static int mlx5r_mp_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
|
||||
struct mlx5_core_dev *mdev = idev->mdev;
|
||||
struct mlx5_ib_multiport_info *mpi;
|
||||
struct mlx5_ib_dev *dev;
|
||||
bool bound = false;
|
||||
@ -4748,15 +4754,14 @@ static void *mlx5_ib_add_slave_port(struct mlx5_core_dev *mdev)
|
||||
|
||||
mpi = kzalloc(sizeof(*mpi), GFP_KERNEL);
|
||||
if (!mpi)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
mpi->mdev = mdev;
|
||||
|
||||
err = mlx5_query_nic_vport_system_image_guid(mdev,
|
||||
&mpi->sys_image_guid);
|
||||
if (err) {
|
||||
kfree(mpi);
|
||||
return NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_lock(&mlx5_ib_multiport_mutex);
|
||||
@ -4777,40 +4782,46 @@ static void *mlx5_ib_add_slave_port(struct mlx5_core_dev *mdev)
|
||||
}
|
||||
mutex_unlock(&mlx5_ib_multiport_mutex);
|
||||
|
||||
return mpi;
|
||||
dev_set_drvdata(&adev->dev, mpi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
|
||||
static void mlx5r_mp_remove(struct auxiliary_device *adev)
|
||||
{
|
||||
struct mlx5_ib_multiport_info *mpi;
|
||||
|
||||
mpi = dev_get_drvdata(&adev->dev);
|
||||
mutex_lock(&mlx5_ib_multiport_mutex);
|
||||
if (mpi->ibdev)
|
||||
mlx5_ib_unbind_slave_port(mpi->ibdev, mpi);
|
||||
list_del(&mpi->list);
|
||||
mutex_unlock(&mlx5_ib_multiport_mutex);
|
||||
kfree(mpi);
|
||||
}
|
||||
|
||||
static int mlx5r_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
|
||||
struct mlx5_core_dev *mdev = idev->mdev;
|
||||
const struct mlx5_ib_profile *profile;
|
||||
int port_type_cap, num_ports, ret;
|
||||
enum rdma_link_layer ll;
|
||||
struct mlx5_ib_dev *dev;
|
||||
int port_type_cap;
|
||||
int num_ports;
|
||||
|
||||
if (MLX5_ESWITCH_MANAGER(mdev) &&
|
||||
mlx5_ib_eswitch_mode(mdev->priv.eswitch) == MLX5_ESWITCH_OFFLOADS) {
|
||||
if (!mlx5_core_mp_enabled(mdev))
|
||||
mlx5_ib_register_vport_reps(mdev);
|
||||
return mdev;
|
||||
}
|
||||
|
||||
port_type_cap = MLX5_CAP_GEN(mdev, port_type);
|
||||
ll = mlx5_port_type_cap_to_rdma_ll(port_type_cap);
|
||||
|
||||
if (mlx5_core_is_mp_slave(mdev) && ll == IB_LINK_LAYER_ETHERNET)
|
||||
return mlx5_ib_add_slave_port(mdev);
|
||||
|
||||
num_ports = max(MLX5_CAP_GEN(mdev, num_ports),
|
||||
MLX5_CAP_GEN(mdev, num_vhca_ports));
|
||||
dev = ib_alloc_device(mlx5_ib_dev, ib_dev);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
dev->port = kcalloc(num_ports, sizeof(*dev->port),
|
||||
GFP_KERNEL);
|
||||
if (!dev->port) {
|
||||
ib_dealloc_device(&dev->ib_dev);
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->mdev = mdev;
|
||||
@ -4821,38 +4832,50 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
|
||||
else
|
||||
profile = &pf_profile;
|
||||
|
||||
return __mlx5_ib_add(dev, profile);
|
||||
ret = __mlx5_ib_add(dev, profile);
|
||||
if (ret) {
|
||||
kfree(dev->port);
|
||||
ib_dealloc_device(&dev->ib_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&adev->dev, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context)
|
||||
static void mlx5r_remove(struct auxiliary_device *adev)
|
||||
{
|
||||
struct mlx5_ib_multiport_info *mpi;
|
||||
struct mlx5_ib_dev *dev;
|
||||
|
||||
if (MLX5_ESWITCH_MANAGER(mdev) && context == mdev) {
|
||||
mlx5_ib_unregister_vport_reps(mdev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mlx5_core_is_mp_slave(mdev)) {
|
||||
mpi = context;
|
||||
mutex_lock(&mlx5_ib_multiport_mutex);
|
||||
if (mpi->ibdev)
|
||||
mlx5_ib_unbind_slave_port(mpi->ibdev, mpi);
|
||||
list_del(&mpi->list);
|
||||
mutex_unlock(&mlx5_ib_multiport_mutex);
|
||||
kfree(mpi);
|
||||
return;
|
||||
}
|
||||
|
||||
dev = context;
|
||||
dev = dev_get_drvdata(&adev->dev);
|
||||
__mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX);
|
||||
}
|
||||
|
||||
static struct mlx5_interface mlx5_ib_interface = {
|
||||
.add = mlx5_ib_add,
|
||||
.remove = mlx5_ib_remove,
|
||||
.protocol = MLX5_INTERFACE_PROTOCOL_IB,
|
||||
static const struct auxiliary_device_id mlx5r_mp_id_table[] = {
|
||||
{ .name = MLX5_ADEV_NAME ".multiport", },
|
||||
{},
|
||||
};
|
||||
|
||||
static const struct auxiliary_device_id mlx5r_id_table[] = {
|
||||
{ .name = MLX5_ADEV_NAME ".rdma", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(auxiliary, mlx5r_mp_id_table);
|
||||
MODULE_DEVICE_TABLE(auxiliary, mlx5r_id_table);
|
||||
|
||||
static struct auxiliary_driver mlx5r_mp_driver = {
|
||||
.name = "multiport",
|
||||
.probe = mlx5r_mp_probe,
|
||||
.remove = mlx5r_mp_remove,
|
||||
.id_table = mlx5r_mp_id_table,
|
||||
};
|
||||
|
||||
static struct auxiliary_driver mlx5r_driver = {
|
||||
.name = "rdma",
|
||||
.probe = mlx5r_probe,
|
||||
.remove = mlx5r_remove,
|
||||
.id_table = mlx5r_id_table,
|
||||
};
|
||||
|
||||
unsigned long mlx5_ib_get_xlt_emergency_page(void)
|
||||
@ -4868,7 +4891,7 @@ void mlx5_ib_put_xlt_emergency_page(void)
|
||||
|
||||
static int __init mlx5_ib_init(void)
|
||||
{
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
xlt_emergency_page = __get_free_page(GFP_KERNEL);
|
||||
if (!xlt_emergency_page)
|
||||
@ -4883,15 +4906,33 @@ static int __init mlx5_ib_init(void)
|
||||
}
|
||||
|
||||
mlx5_ib_odp_init();
|
||||
ret = mlx5r_rep_init();
|
||||
if (ret)
|
||||
goto rep_err;
|
||||
ret = auxiliary_driver_register(&mlx5r_mp_driver);
|
||||
if (ret)
|
||||
goto mp_err;
|
||||
ret = auxiliary_driver_register(&mlx5r_driver);
|
||||
if (ret)
|
||||
goto drv_err;
|
||||
return 0;
|
||||
|
||||
err = mlx5_register_interface(&mlx5_ib_interface);
|
||||
|
||||
return err;
|
||||
drv_err:
|
||||
auxiliary_driver_unregister(&mlx5r_mp_driver);
|
||||
mp_err:
|
||||
mlx5r_rep_cleanup();
|
||||
rep_err:
|
||||
destroy_workqueue(mlx5_ib_event_wq);
|
||||
free_page((unsigned long)xlt_emergency_page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit mlx5_ib_cleanup(void)
|
||||
{
|
||||
mlx5_unregister_interface(&mlx5_ib_interface);
|
||||
auxiliary_driver_unregister(&mlx5r_driver);
|
||||
auxiliary_driver_unregister(&mlx5r_mp_driver);
|
||||
mlx5r_rep_cleanup();
|
||||
|
||||
destroy_workqueue(mlx5_ib_event_wq);
|
||||
mutex_destroy(&xlt_emergency_page_mutex);
|
||||
free_page(xlt_emergency_page);
|
||||
|
@ -1317,8 +1317,8 @@ extern const struct mmu_interval_notifier_ops mlx5_mn_ops;
|
||||
void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
|
||||
const struct mlx5_ib_profile *profile,
|
||||
int stage);
|
||||
void *__mlx5_ib_add(struct mlx5_ib_dev *dev,
|
||||
const struct mlx5_ib_profile *profile);
|
||||
int __mlx5_ib_add(struct mlx5_ib_dev *dev,
|
||||
const struct mlx5_ib_profile *profile);
|
||||
|
||||
int mlx5_ib_get_vf_config(struct ib_device *device, int vf,
|
||||
u8 port, struct ifla_vf_info *info);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
|
@ -11,6 +11,7 @@
|
||||
* the project's page is at https://linuxtv.org
|
||||
*/
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
|
@ -287,7 +287,7 @@ config GTP
|
||||
3GPP TS 29.060 standards.
|
||||
|
||||
To compile this drivers as a module, choose M here: the module
|
||||
wil be called gtp.
|
||||
will be called gtp.
|
||||
|
||||
config MACSEC
|
||||
tristate "IEEE 802.1AE MAC-level encryption (MACsec)"
|
||||
@ -426,6 +426,13 @@ config VSOCKMON
|
||||
mostly intended for developers or support to debug vsock issues. If
|
||||
unsure, say N.
|
||||
|
||||
config MHI_NET
|
||||
tristate "MHI network driver"
|
||||
depends on MHI_BUS
|
||||
help
|
||||
This is the network driver for MHI bus. It can be used with
|
||||
QCOM based WWAN modems (like SDX55). Say Y or M.
|
||||
|
||||
endif # NET_CORE
|
||||
|
||||
config SUNGEM_PHY
|
||||
@ -489,8 +496,6 @@ source "drivers/net/usb/Kconfig"
|
||||
|
||||
source "drivers/net/wireless/Kconfig"
|
||||
|
||||
source "drivers/net/wimax/Kconfig"
|
||||
|
||||
source "drivers/net/wan/Kconfig"
|
||||
|
||||
source "drivers/net/ieee802154/Kconfig"
|
||||
|
@ -36,6 +36,7 @@ obj-$(CONFIG_GTP) += gtp.o
|
||||
obj-$(CONFIG_NLMON) += nlmon.o
|
||||
obj-$(CONFIG_NET_VRF) += vrf.o
|
||||
obj-$(CONFIG_VSOCKMON) += vsockmon.o
|
||||
obj-$(CONFIG_MHI_NET) += mhi_net.o
|
||||
|
||||
#
|
||||
# Networking Drivers
|
||||
@ -66,7 +67,6 @@ obj-$(CONFIG_NET_SB1000) += sb1000.o
|
||||
obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o
|
||||
obj-$(CONFIG_WAN) += wan/
|
||||
obj-$(CONFIG_WLAN) += wireless/
|
||||
obj-$(CONFIG_WIMAX) += wimax/
|
||||
obj-$(CONFIG_IEEE802154) += ieee802154/
|
||||
|
||||
obj-$(CONFIG_VMXNET3) += vmxnet3/
|
||||
|
@ -510,7 +510,7 @@ static const struct net_device_ops bareudp_netdev_ops = {
|
||||
.ndo_open = bareudp_open,
|
||||
.ndo_stop = bareudp_stop,
|
||||
.ndo_start_xmit = bareudp_xmit,
|
||||
.ndo_get_stats64 = ip_tunnel_get_stats64,
|
||||
.ndo_get_stats64 = dev_get_tstats64,
|
||||
.ndo_fill_metadata_dst = bareudp_fill_metadata_dst,
|
||||
};
|
||||
|
||||
@ -522,7 +522,7 @@ static const struct nla_policy bareudp_policy[IFLA_BAREUDP_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* Info for udev, that this is a virtual tunnel endpoint */
|
||||
static struct device_type bareudp_type = {
|
||||
static const struct device_type bareudp_type = {
|
||||
.name = "bareudp",
|
||||
};
|
||||
|
||||
|
@ -1228,14 +1228,14 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
|
||||
}
|
||||
|
||||
#define BOND_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
|
||||
NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \
|
||||
NETIF_F_HIGHDMA | NETIF_F_LRO)
|
||||
|
||||
#define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
NETIF_F_RXCSUM | NETIF_F_ALL_TSO)
|
||||
NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE)
|
||||
|
||||
#define BOND_MPLS_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||
NETIF_F_ALL_TSO)
|
||||
NETIF_F_GSO_SOFTWARE)
|
||||
|
||||
|
||||
static void bond_compute_features(struct bonding *bond)
|
||||
@ -1291,8 +1291,7 @@ done:
|
||||
bond_dev->vlan_features = vlan_features;
|
||||
bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
|
||||
NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_STAG_TX |
|
||||
NETIF_F_GSO_UDP_L4;
|
||||
NETIF_F_HW_VLAN_STAG_TX;
|
||||
#ifdef CONFIG_XFRM_OFFLOAD
|
||||
bond_dev->hw_enc_features |= xfrm_features;
|
||||
#endif /* CONFIG_XFRM_OFFLOAD */
|
||||
@ -4746,16 +4745,14 @@ void bond_setup(struct net_device *bond_dev)
|
||||
NETIF_F_HW_VLAN_CTAG_RX |
|
||||
NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
|
||||
bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
|
||||
#ifdef CONFIG_XFRM_OFFLOAD
|
||||
bond_dev->hw_features |= BOND_XFRM_FEATURES;
|
||||
#endif /* CONFIG_XFRM_OFFLOAD */
|
||||
bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL;
|
||||
bond_dev->features |= bond_dev->hw_features;
|
||||
bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
|
||||
#ifdef CONFIG_XFRM_OFFLOAD
|
||||
/* Disable XFRM features if this isn't an active-backup config */
|
||||
if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)
|
||||
bond_dev->features &= ~BOND_XFRM_FEATURES;
|
||||
bond_dev->hw_features |= BOND_XFRM_FEATURES;
|
||||
/* Only enable XFRM features if this is an active-backup config */
|
||||
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
|
||||
bond_dev->features |= BOND_XFRM_FEATURES;
|
||||
#endif /* CONFIG_XFRM_OFFLOAD */
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/export.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
@ -468,7 +468,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
}
|
||||
reg_mid = at91_can_id_to_reg_mid(cf->can_id);
|
||||
reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) |
|
||||
(cf->can_dlc << 16) | AT91_MCR_MTCR;
|
||||
(cf->len << 16) | AT91_MCR_MTCR;
|
||||
|
||||
/* disable MB while writing ID (see datasheet) */
|
||||
set_mb_mode(priv, mb, AT91_MB_MODE_DISABLED);
|
||||
@ -481,7 +481,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
/* This triggers transmission */
|
||||
at91_write(priv, AT91_MCR(mb), reg_mcr);
|
||||
|
||||
stats->tx_bytes += cf->can_dlc;
|
||||
stats->tx_bytes += cf->len;
|
||||
|
||||
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
|
||||
can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv));
|
||||
@ -554,7 +554,7 @@ static void at91_rx_overflow_err(struct net_device *dev)
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
@ -580,7 +580,7 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
|
||||
cf->can_id = (reg_mid >> 18) & CAN_SFF_MASK;
|
||||
|
||||
reg_msr = at91_read(priv, AT91_MSR(mb));
|
||||
cf->can_dlc = get_can_dlc((reg_msr >> 16) & 0xf);
|
||||
cf->len = can_cc_dlc2len((reg_msr >> 16) & 0xf);
|
||||
|
||||
if (reg_msr & AT91_MSR_MRTR)
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
@ -619,7 +619,7 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
|
||||
at91_read_mb(dev, mb, cf);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_RX);
|
||||
@ -780,7 +780,7 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr)
|
||||
at91_poll_err_frame(dev, cf, reg_sr);
|
||||
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += cf->can_dlc;
|
||||
dev->stats.rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -1047,7 +1047,7 @@ static void at91_irq_err(struct net_device *dev)
|
||||
at91_irq_err_state(dev, cf, new_state);
|
||||
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += cf->can_dlc;
|
||||
dev->stats.rx_bytes += cf->len;
|
||||
netif_rx(skb);
|
||||
|
||||
priv->can.state = new_state;
|
||||
|
@ -306,7 +306,7 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
|
||||
struct can_frame *frame, int idx)
|
||||
{
|
||||
struct c_can_priv *priv = netdev_priv(dev);
|
||||
u16 ctrl = IF_MCONT_TX | frame->can_dlc;
|
||||
u16 ctrl = IF_MCONT_TX | frame->len;
|
||||
bool rtr = frame->can_id & CAN_RTR_FLAG;
|
||||
u32 arb = IF_ARB_MSGVAL;
|
||||
int i;
|
||||
@ -339,7 +339,7 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
|
||||
if (priv->type == BOSCH_D_CAN) {
|
||||
u32 data = 0, dreg = C_CAN_IFACE(DATA1_REG, iface);
|
||||
|
||||
for (i = 0; i < frame->can_dlc; i += 4, dreg += 2) {
|
||||
for (i = 0; i < frame->len; i += 4, dreg += 2) {
|
||||
data = (u32)frame->data[i];
|
||||
data |= (u32)frame->data[i + 1] << 8;
|
||||
data |= (u32)frame->data[i + 2] << 16;
|
||||
@ -347,7 +347,7 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
|
||||
priv->write_reg32(priv, dreg, data);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < frame->can_dlc; i += 2) {
|
||||
for (i = 0; i < frame->len; i += 2) {
|
||||
priv->write_reg(priv,
|
||||
C_CAN_IFACE(DATA1_REG, iface) + i / 2,
|
||||
frame->data[i] |
|
||||
@ -397,7 +397,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
frame->can_dlc = get_can_dlc(ctrl & 0x0F);
|
||||
frame->len = can_cc_dlc2len(ctrl & 0x0F);
|
||||
|
||||
arb = priv->read_reg32(priv, C_CAN_IFACE(ARB1_REG, iface));
|
||||
|
||||
@ -412,7 +412,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
|
||||
int i, dreg = C_CAN_IFACE(DATA1_REG, iface);
|
||||
|
||||
if (priv->type == BOSCH_D_CAN) {
|
||||
for (i = 0; i < frame->can_dlc; i += 4, dreg += 2) {
|
||||
for (i = 0; i < frame->len; i += 4, dreg += 2) {
|
||||
data = priv->read_reg32(priv, dreg);
|
||||
frame->data[i] = data;
|
||||
frame->data[i + 1] = data >> 8;
|
||||
@ -420,7 +420,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
|
||||
frame->data[i + 3] = data >> 24;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < frame->can_dlc; i += 2, dreg++) {
|
||||
for (i = 0; i < frame->len; i += 2, dreg++) {
|
||||
data = priv->read_reg(priv, dreg);
|
||||
frame->data[i] = data;
|
||||
frame->data[i + 1] = data >> 8;
|
||||
@ -429,7 +429,7 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += frame->can_dlc;
|
||||
stats->rx_bytes += frame->len;
|
||||
|
||||
netif_receive_skb(skb);
|
||||
return 0;
|
||||
@ -475,7 +475,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
|
||||
* transmit as we might race against do_tx().
|
||||
*/
|
||||
c_can_setup_tx_object(dev, IF_TX, frame, idx);
|
||||
priv->dlc[idx] = frame->can_dlc;
|
||||
priv->dlc[idx] = frame->len;
|
||||
can_put_echo_skb(skb, dev, idx);
|
||||
|
||||
/* Update the active bits */
|
||||
@ -977,7 +977,7 @@ static int c_can_handle_state_change(struct net_device *dev,
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -1047,7 +1047,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
return 1;
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ static void cc770_tx(struct net_device *dev, int mo)
|
||||
u32 id;
|
||||
int i;
|
||||
|
||||
dlc = cf->can_dlc;
|
||||
dlc = cf->len;
|
||||
id = cf->can_id;
|
||||
rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR;
|
||||
|
||||
@ -470,7 +470,7 @@ static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1)
|
||||
cf->can_id = CAN_RTR_FLAG;
|
||||
if (config & MSGCFG_XTD)
|
||||
cf->can_id |= CAN_EFF_FLAG;
|
||||
cf->can_dlc = 0;
|
||||
cf->len = 0;
|
||||
} else {
|
||||
if (config & MSGCFG_XTD) {
|
||||
id = cc770_read_reg(priv, msgobj[mo].id[3]);
|
||||
@ -486,13 +486,13 @@ static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1)
|
||||
}
|
||||
|
||||
cf->can_id = id;
|
||||
cf->can_dlc = get_can_dlc((config & 0xf0) >> 4);
|
||||
for (i = 0; i < cf->can_dlc; i++)
|
||||
cf->len = can_cc_dlc2len((config & 0xf0) >> 4);
|
||||
for (i = 0; i < cf->len; i++)
|
||||
cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]);
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
@ -572,7 +572,7 @@ static int cc770_err(struct net_device *dev, u8 status)
|
||||
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_rx(skb);
|
||||
|
||||
return 0;
|
||||
@ -699,7 +699,7 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
|
||||
}
|
||||
|
||||
cf = (struct can_frame *)priv->tx_skb->data;
|
||||
stats->tx_bytes += cf->can_dlc;
|
||||
stats->tx_bytes += cf->len;
|
||||
stats->tx_packets++;
|
||||
|
||||
can_put_echo_skb(priv->tx_skb, dev, 0);
|
||||
|
@ -30,12 +30,12 @@ MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
||||
static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
u8 can_dlc2len(u8 can_dlc)
|
||||
/* get data length from raw data length code (DLC) */
|
||||
u8 can_fd_dlc2len(u8 dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
return dlc2len[dlc & 0x0F];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_dlc2len);
|
||||
EXPORT_SYMBOL_GPL(can_fd_dlc2len);
|
||||
|
||||
static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
9, 9, 9, 9, /* 9 - 12 */
|
||||
@ -49,14 +49,14 @@ static const u8 len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
u8 can_len2dlc(u8 len)
|
||||
u8 can_fd_len2dlc(u8 len)
|
||||
{
|
||||
if (unlikely(len > 64))
|
||||
return 0xF;
|
||||
|
||||
return len2dlc[len];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_len2dlc);
|
||||
EXPORT_SYMBOL_GPL(can_fd_len2dlc);
|
||||
|
||||
#ifdef CONFIG_CAN_CALC_BITTIMING
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
@ -595,7 +595,7 @@ static void can_restart(struct net_device *dev)
|
||||
netif_rx_ni(skb);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
|
||||
restart:
|
||||
netdev_dbg(dev, "restarted\n");
|
||||
@ -737,7 +737,7 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
||||
return NULL;
|
||||
|
||||
(*cf)->can_id = CAN_ERR_FLAG;
|
||||
(*cf)->can_dlc = CAN_ERR_DLC;
|
||||
(*cf)->len = CAN_ERR_DLC;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
@ -236,8 +236,8 @@
|
||||
#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6)
|
||||
/* default to BE register access */
|
||||
#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7)
|
||||
/* Setup stop mode to support wakeup */
|
||||
#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8)
|
||||
/* Setup stop mode with GPR to support wakeup */
|
||||
#define FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR BIT(8)
|
||||
/* Support CAN-FD mode */
|
||||
#define FLEXCAN_QUIRK_SUPPORT_FD BIT(9)
|
||||
/* support memory detection and correction */
|
||||
@ -381,7 +381,7 @@ static const struct flexcan_devtype_data fsl_imx28_devtype_data = {
|
||||
static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_SETUP_STOP_MODE,
|
||||
FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
|
||||
@ -393,7 +393,7 @@ static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
|
||||
static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR |
|
||||
FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC,
|
||||
};
|
||||
|
||||
@ -746,7 +746,7 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
u32 can_id;
|
||||
u32 data;
|
||||
u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16);
|
||||
u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_fd_len2dlc(cfd->len)) << 16);
|
||||
int i;
|
||||
|
||||
if (can_dropped_invalid_skb(dev, skb))
|
||||
@ -1000,12 +1000,12 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK;
|
||||
|
||||
if (reg_ctrl & FLEXCAN_MB_CNT_EDL) {
|
||||
cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf));
|
||||
cfd->len = can_fd_dlc2len((reg_ctrl >> 16) & 0xf);
|
||||
|
||||
if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
|
||||
cfd->flags |= CANFD_BRS;
|
||||
} else {
|
||||
cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf);
|
||||
cfd->len = can_cc_dlc2len((reg_ctrl >> 16) & 0xf);
|
||||
|
||||
if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
|
||||
cfd->can_id |= CAN_RTR_FLAG;
|
||||
@ -1346,6 +1346,72 @@ static void flexcan_ram_init(struct net_device *dev)
|
||||
priv->write(reg_ctrl2, ®s->ctrl2);
|
||||
}
|
||||
|
||||
static int flexcan_rx_offload_setup(struct net_device *dev)
|
||||
{
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
|
||||
else
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
|
||||
priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
|
||||
(sizeof(priv->regs->mb[1]) / priv->mb_size);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
||||
priv->tx_mb_reserved =
|
||||
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP);
|
||||
else
|
||||
priv->tx_mb_reserved =
|
||||
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
|
||||
priv->tx_mb_idx = priv->mb_count - 1;
|
||||
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
|
||||
priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
||||
|
||||
priv->offload.mailbox_read = flexcan_mailbox_read;
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||
priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
|
||||
priv->offload.mb_last = priv->mb_count - 2;
|
||||
|
||||
priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
|
||||
priv->offload.mb_first);
|
||||
err = can_rx_offload_add_timestamp(dev, &priv->offload);
|
||||
} else {
|
||||
priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
|
||||
FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
|
||||
err = can_rx_offload_add_fifo(dev, &priv->offload,
|
||||
FLEXCAN_NAPI_WEIGHT);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void flexcan_chip_interrupts_enable(const struct net_device *dev)
|
||||
{
|
||||
const struct flexcan_priv *priv = netdev_priv(dev);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
u64 reg_imask;
|
||||
|
||||
disable_irq(dev->irq);
|
||||
priv->write(priv->reg_ctrl_default, ®s->ctrl);
|
||||
reg_imask = priv->rx_mask | priv->tx_mask;
|
||||
priv->write(upper_32_bits(reg_imask), ®s->imask2);
|
||||
priv->write(lower_32_bits(reg_imask), ®s->imask1);
|
||||
enable_irq(dev->irq);
|
||||
}
|
||||
|
||||
static void flexcan_chip_interrupts_disable(const struct net_device *dev)
|
||||
{
|
||||
const struct flexcan_priv *priv = netdev_priv(dev);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
|
||||
priv->write(0, ®s->imask2);
|
||||
priv->write(0, ®s->imask1);
|
||||
priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
|
||||
®s->ctrl);
|
||||
}
|
||||
|
||||
/* flexcan_chip_start
|
||||
*
|
||||
* this functions is entered with clocks enabled
|
||||
@ -1356,7 +1422,6 @@ static int flexcan_chip_start(struct net_device *dev)
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
|
||||
u64 reg_imask;
|
||||
int err, i;
|
||||
struct flexcan_mb __iomem *mb;
|
||||
|
||||
@ -1574,14 +1639,6 @@ static int flexcan_chip_start(struct net_device *dev)
|
||||
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
/* enable interrupts atomically */
|
||||
disable_irq(dev->irq);
|
||||
priv->write(priv->reg_ctrl_default, ®s->ctrl);
|
||||
reg_imask = priv->rx_mask | priv->tx_mask;
|
||||
priv->write(upper_32_bits(reg_imask), ®s->imask2);
|
||||
priv->write(lower_32_bits(reg_imask), ®s->imask1);
|
||||
enable_irq(dev->irq);
|
||||
|
||||
/* print chip status */
|
||||
netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
|
||||
priv->read(®s->mcr), priv->read(®s->ctrl));
|
||||
@ -1600,7 +1657,6 @@ static int flexcan_chip_start(struct net_device *dev)
|
||||
static int __flexcan_chip_stop(struct net_device *dev, bool disable_on_error)
|
||||
{
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
int err;
|
||||
|
||||
/* freeze + disable module */
|
||||
@ -1611,12 +1667,6 @@ static int __flexcan_chip_stop(struct net_device *dev, bool disable_on_error)
|
||||
if (err && !disable_on_error)
|
||||
goto out_chip_unfreeze;
|
||||
|
||||
/* Disable all interrupts */
|
||||
priv->write(0, ®s->imask2);
|
||||
priv->write(0, ®s->imask1);
|
||||
priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
|
||||
®s->ctrl);
|
||||
|
||||
priv->can.state = CAN_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
@ -1662,61 +1712,33 @@ static int flexcan_open(struct net_device *dev)
|
||||
if (err)
|
||||
goto out_close;
|
||||
|
||||
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||||
err = flexcan_rx_offload_setup(dev);
|
||||
if (err)
|
||||
goto out_transceiver_disable;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
|
||||
else
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
|
||||
priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
|
||||
(sizeof(priv->regs->mb[1]) / priv->mb_size);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
||||
priv->tx_mb_reserved =
|
||||
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP);
|
||||
else
|
||||
priv->tx_mb_reserved =
|
||||
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
|
||||
priv->tx_mb_idx = priv->mb_count - 1;
|
||||
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
|
||||
priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
||||
|
||||
priv->offload.mailbox_read = flexcan_mailbox_read;
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||
priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
|
||||
priv->offload.mb_last = priv->mb_count - 2;
|
||||
|
||||
priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
|
||||
priv->offload.mb_first);
|
||||
err = can_rx_offload_add_timestamp(dev, &priv->offload);
|
||||
} else {
|
||||
priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
|
||||
FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
|
||||
err = can_rx_offload_add_fifo(dev, &priv->offload,
|
||||
FLEXCAN_NAPI_WEIGHT);
|
||||
}
|
||||
if (err)
|
||||
goto out_free_irq;
|
||||
|
||||
/* start chip and queuing */
|
||||
err = flexcan_chip_start(dev);
|
||||
if (err)
|
||||
goto out_offload_del;
|
||||
goto out_can_rx_offload_del;
|
||||
|
||||
can_rx_offload_enable(&priv->offload);
|
||||
|
||||
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||||
if (err)
|
||||
goto out_can_rx_offload_disable;
|
||||
|
||||
flexcan_chip_interrupts_enable(dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||
|
||||
can_rx_offload_enable(&priv->offload);
|
||||
netif_start_queue(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
out_offload_del:
|
||||
out_can_rx_offload_disable:
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
flexcan_chip_stop(dev);
|
||||
out_can_rx_offload_del:
|
||||
can_rx_offload_del(&priv->offload);
|
||||
out_free_irq:
|
||||
free_irq(dev->irq, dev);
|
||||
out_transceiver_disable:
|
||||
flexcan_transceiver_disable(priv);
|
||||
out_close:
|
||||
@ -1732,14 +1754,15 @@ static int flexcan_close(struct net_device *dev)
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
flexcan_chip_interrupts_disable(dev);
|
||||
free_irq(dev->irq, dev);
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
flexcan_chip_stop_disable_on_error(dev);
|
||||
|
||||
can_rx_offload_del(&priv->offload);
|
||||
free_irq(dev->irq, dev);
|
||||
flexcan_transceiver_disable(priv);
|
||||
|
||||
close_candev(dev);
|
||||
|
||||
pm_runtime_put(priv->dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_STOP);
|
||||
@ -1757,6 +1780,8 @@ static int flexcan_set_mode(struct net_device *dev, enum can_mode mode)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
flexcan_chip_interrupts_enable(dev);
|
||||
|
||||
netif_wake_queue(dev);
|
||||
break;
|
||||
|
||||
@ -1915,15 +1940,8 @@ static const struct of_device_id flexcan_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, flexcan_of_match);
|
||||
|
||||
static const struct platform_device_id flexcan_id_table[] = {
|
||||
{ .name = "flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, flexcan_id_table);
|
||||
|
||||
static int flexcan_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id;
|
||||
const struct flexcan_devtype_data *devtype_data;
|
||||
struct net_device *dev;
|
||||
struct flexcan_priv *priv;
|
||||
@ -1972,15 +1990,7 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
of_id = of_match_device(flexcan_of_match, &pdev->dev);
|
||||
if (of_id) {
|
||||
devtype_data = of_id->data;
|
||||
} else if (platform_get_device_id(pdev)->driver_data) {
|
||||
devtype_data = (struct flexcan_devtype_data *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
devtype_data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) &&
|
||||
!(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) {
|
||||
@ -2047,7 +2057,7 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
of_can_transceiver(dev);
|
||||
devm_can_led_init(dev);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) {
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
|
||||
err = flexcan_setup_stop_mode(pdev);
|
||||
if (err)
|
||||
dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
|
||||
@ -2095,6 +2105,8 @@ static int __maybe_unused flexcan_suspend(struct device *device)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
flexcan_chip_interrupts_disable(dev);
|
||||
|
||||
err = pinctrl_pm_select_sleep_state(device);
|
||||
if (err)
|
||||
return err;
|
||||
@ -2130,6 +2142,8 @@ static int __maybe_unused flexcan_resume(struct device *device)
|
||||
err = flexcan_chip_start(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
flexcan_chip_interrupts_enable(dev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2206,7 +2220,6 @@ static struct platform_driver flexcan_driver = {
|
||||
},
|
||||
.probe = flexcan_probe,
|
||||
.remove = flexcan_remove,
|
||||
.id_table = flexcan_id_table,
|
||||
};
|
||||
|
||||
module_platform_driver(flexcan_driver);
|
||||
|
@ -1201,12 +1201,12 @@ static int grcan_receive(struct net_device *dev, int budget)
|
||||
cf->can_id = ((slot[0] & GRCAN_MSG_BID)
|
||||
>> GRCAN_MSG_BID_BIT);
|
||||
}
|
||||
cf->can_dlc = get_can_dlc((slot[1] & GRCAN_MSG_DLC)
|
||||
cf->len = can_cc_dlc2len((slot[1] & GRCAN_MSG_DLC)
|
||||
>> GRCAN_MSG_DLC_BIT);
|
||||
if (rtr) {
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
} else {
|
||||
for (i = 0; i < cf->can_dlc; i++) {
|
||||
for (i = 0; i < cf->len; i++) {
|
||||
j = GRCAN_MSG_DATA_SLOT_INDEX(i);
|
||||
shift = GRCAN_MSG_DATA_SHIFT(i);
|
||||
cf->data[i] = (u8)(slot[j] >> shift);
|
||||
@ -1215,7 +1215,7 @@ static int grcan_receive(struct net_device *dev, int budget)
|
||||
|
||||
/* Update statistics and read pointer */
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
|
||||
@ -1399,7 +1399,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
|
||||
eff = cf->can_id & CAN_EFF_FLAG;
|
||||
rtr = cf->can_id & CAN_RTR_FLAG;
|
||||
id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
|
||||
dlc = cf->can_dlc;
|
||||
dlc = cf->len;
|
||||
if (eff)
|
||||
tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID;
|
||||
else
|
||||
@ -1447,7 +1447,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
|
||||
* can_put_echo_skb would be an error unless other measures are
|
||||
* taken.
|
||||
*/
|
||||
priv->txdlc[slotindex] = cf->can_dlc; /* Store dlc for statistics */
|
||||
priv->txdlc[slotindex] = cf->len; /* Store dlc for statistics */
|
||||
can_put_echo_skb(skb, dev, slotindex);
|
||||
|
||||
/* Make sure everything is written before allowing hardware to
|
||||
|
@ -271,9 +271,9 @@ static void ifi_canfd_read_fifo(struct net_device *ndev)
|
||||
dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
|
||||
IFI_CANFD_RXFIFO_DLC_DLC_MASK;
|
||||
if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
|
||||
cf->len = can_dlc2len(dlc);
|
||||
cf->len = can_fd_dlc2len(dlc);
|
||||
else
|
||||
cf->len = get_can_dlc(dlc);
|
||||
cf->len = can_cc_dlc2len(dlc);
|
||||
|
||||
rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
|
||||
id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
|
||||
@ -431,7 +431,7 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev)
|
||||
writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -523,7 +523,7 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -900,7 +900,7 @@ static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
|
||||
txid = cf->can_id & CAN_SFF_MASK;
|
||||
}
|
||||
|
||||
txdlc = can_len2dlc(cf->len);
|
||||
txdlc = can_fd_len2dlc(cf->len);
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) {
|
||||
txdlc |= IFI_CANFD_TXFIFO_DLC_EDL;
|
||||
if (cf->flags & CANFD_BRS)
|
||||
|
@ -916,10 +916,10 @@ static void ican3_to_can_frame(struct ican3_dev *mod,
|
||||
|
||||
cf->can_id |= desc->data[0] << 3;
|
||||
cf->can_id |= (desc->data[1] & 0xe0) >> 5;
|
||||
cf->can_dlc = get_can_dlc(desc->data[1] & ICAN3_CAN_DLC_MASK);
|
||||
memcpy(cf->data, &desc->data[2], cf->can_dlc);
|
||||
cf->len = can_cc_dlc2len(desc->data[1] & ICAN3_CAN_DLC_MASK);
|
||||
memcpy(cf->data, &desc->data[2], cf->len);
|
||||
} else {
|
||||
cf->can_dlc = get_can_dlc(desc->data[0] & ICAN3_CAN_DLC_MASK);
|
||||
cf->len = can_cc_dlc2len(desc->data[0] & ICAN3_CAN_DLC_MASK);
|
||||
if (desc->data[0] & ICAN3_EFF_RTR)
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
|
||||
@ -934,7 +934,7 @@ static void ican3_to_can_frame(struct ican3_dev *mod,
|
||||
cf->can_id |= desc->data[3] >> 5; /* 2-0 */
|
||||
}
|
||||
|
||||
memcpy(cf->data, &desc->data[6], cf->can_dlc);
|
||||
memcpy(cf->data, &desc->data[6], cf->len);
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,7 +947,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod,
|
||||
|
||||
/* we always use the extended format, with the ECHO flag set */
|
||||
desc->command = ICAN3_CAN_TYPE_EFF;
|
||||
desc->data[0] |= cf->can_dlc;
|
||||
desc->data[0] |= cf->len;
|
||||
desc->data[1] |= ICAN3_ECHO;
|
||||
|
||||
/* support single transmission (no retries) mode */
|
||||
@ -970,7 +970,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod,
|
||||
}
|
||||
|
||||
/* copy the data bits into the descriptor */
|
||||
memcpy(&desc->data[6], cf->data, cf->can_dlc);
|
||||
memcpy(&desc->data[6], cf->data, cf->len);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1294,7 +1294,7 @@ static unsigned int ican3_get_echo_skb(struct ican3_dev *mod)
|
||||
}
|
||||
|
||||
cf = (struct can_frame *)skb->data;
|
||||
dlc = cf->can_dlc;
|
||||
dlc = cf->len;
|
||||
|
||||
/* check flag whether this packet has to be looped back */
|
||||
if (skb->pkt_type != PACKET_LOOPBACK) {
|
||||
@ -1332,10 +1332,10 @@ static bool ican3_echo_skb_matches(struct ican3_dev *mod, struct sk_buff *skb)
|
||||
if (cf->can_id != echo_cf->can_id)
|
||||
return false;
|
||||
|
||||
if (cf->can_dlc != echo_cf->can_dlc)
|
||||
if (cf->len != echo_cf->len)
|
||||
return false;
|
||||
|
||||
return memcmp(cf->data, echo_cf->data, cf->can_dlc) == 0;
|
||||
return memcmp(cf->data, echo_cf->data, cf->len) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1421,7 +1421,7 @@ static int ican3_recv_skb(struct ican3_dev *mod)
|
||||
|
||||
/* update statistics, receive the skb */
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
err_noalloc:
|
||||
|
@ -742,7 +742,7 @@ static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p,
|
||||
p->header[0] |= KVASER_PCIEFD_RPACKET_IDE;
|
||||
|
||||
p->header[0] |= cf->can_id & CAN_EFF_MASK;
|
||||
p->header[1] |= can_len2dlc(cf->len) << KVASER_PCIEFD_RPACKET_DLC_SHIFT;
|
||||
p->header[1] |= can_fd_len2dlc(cf->len) << KVASER_PCIEFD_RPACKET_DLC_SHIFT;
|
||||
p->header[1] |= KVASER_PCIEFD_TPACKET_AREQ;
|
||||
|
||||
if (can_is_canfd_skb(skb)) {
|
||||
@ -1176,7 +1176,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie,
|
||||
if (p->header[0] & KVASER_PCIEFD_RPACKET_IDE)
|
||||
cf->can_id |= CAN_EFF_FLAG;
|
||||
|
||||
cf->len = can_dlc2len(p->header[1] >> KVASER_PCIEFD_RPACKET_DLC_SHIFT);
|
||||
cf->len = can_fd_dlc2len(p->header[1] >> KVASER_PCIEFD_RPACKET_DLC_SHIFT);
|
||||
|
||||
if (p->header[0] & KVASER_PCIEFD_RPACKET_RTR)
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
@ -1301,7 +1301,7 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can,
|
||||
cf->data[7] = bec.rxerr;
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
|
||||
netif_rx(skb);
|
||||
return 0;
|
||||
@ -1500,7 +1500,7 @@ static void kvaser_pciefd_handle_nack_packet(struct kvaser_pciefd_can *can,
|
||||
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_BUSERROR;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
stats->rx_packets++;
|
||||
netif_rx(skb);
|
||||
} else {
|
||||
@ -1602,7 +1602,7 @@ static int kvaser_pciefd_read_packet(struct kvaser_pciefd *pcie, int *start_pos,
|
||||
if (!(p->header[0] & KVASER_PCIEFD_RPACKET_RTR)) {
|
||||
u8 data_len;
|
||||
|
||||
data_len = can_dlc2len(p->header[1] >>
|
||||
data_len = can_fd_dlc2len(p->header[1] >>
|
||||
KVASER_PCIEFD_RPACKET_DLC_SHIFT);
|
||||
pos += DIV_ROUND_UP(data_len, 4);
|
||||
}
|
||||
|
@ -1,21 +1,28 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config CAN_M_CAN
|
||||
menuconfig CAN_M_CAN
|
||||
tristate "Bosch M_CAN support"
|
||||
help
|
||||
Say Y here if you want support for Bosch M_CAN controller framework.
|
||||
This is common support for devices that embed the Bosch M_CAN IP.
|
||||
|
||||
if CAN_M_CAN
|
||||
|
||||
config CAN_M_CAN_PCI
|
||||
tristate "Generic PCI Bus based M_CAN driver"
|
||||
depends on PCI
|
||||
help
|
||||
Say Y here if you want to support Bosch M_CAN controller connected
|
||||
to the pci bus.
|
||||
|
||||
config CAN_M_CAN_PLATFORM
|
||||
tristate "Bosch M_CAN support for io-mapped devices"
|
||||
depends on HAS_IOMEM
|
||||
depends on CAN_M_CAN
|
||||
help
|
||||
Say Y here if you want support for IO Mapped Bosch M_CAN controller.
|
||||
This support is for devices that have the Bosch M_CAN controller
|
||||
IP embedded into the device and the IP is IO Mapped to the processor.
|
||||
|
||||
config CAN_M_CAN_TCAN4X5X
|
||||
depends on CAN_M_CAN
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
tristate "TCAN4X5X M_CAN device"
|
||||
@ -23,3 +30,5 @@ config CAN_M_CAN_TCAN4X5X
|
||||
Say Y here if you want support for Texas Instruments TCAN4x5x
|
||||
M_CAN controller. This device is a peripheral device that uses the
|
||||
SPI bus for communication.
|
||||
|
||||
endif
|
||||
|
@ -4,5 +4,6 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_CAN_M_CAN) += m_can.o
|
||||
obj-$(CONFIG_CAN_M_CAN_PCI) += m_can_pci.o
|
||||
obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o
|
||||
obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.o
|
||||
|
@ -5,8 +5,7 @@
|
||||
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
/* Bosch M_CAN user manual can be obtained from:
|
||||
* http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/
|
||||
* mcan_users_manual_v302.pdf
|
||||
* https://github.com/linux-can/can-doc/tree/master/m_can
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
@ -40,7 +39,7 @@ enum m_can_reg {
|
||||
M_CAN_TOCV = 0x2c,
|
||||
M_CAN_ECR = 0x40,
|
||||
M_CAN_PSR = 0x44,
|
||||
/* TDCR Register only available for version >=3.1.x */
|
||||
/* TDCR Register only available for version >=3.1.x */
|
||||
M_CAN_TDCR = 0x48,
|
||||
M_CAN_IR = 0x50,
|
||||
M_CAN_IE = 0x54,
|
||||
@ -336,7 +335,7 @@ static u32 m_can_fifo_read(struct m_can_classdev *cdev,
|
||||
u32 fgi, unsigned int offset)
|
||||
{
|
||||
u32 addr_offset = cdev->mcfg[MRAM_RXF0].off + fgi * RXF0_ELEMENT_SIZE +
|
||||
offset;
|
||||
offset;
|
||||
|
||||
return cdev->ops->read_fifo(cdev, addr_offset);
|
||||
}
|
||||
@ -345,7 +344,7 @@ static void m_can_fifo_write(struct m_can_classdev *cdev,
|
||||
u32 fpi, unsigned int offset, u32 val)
|
||||
{
|
||||
u32 addr_offset = cdev->mcfg[MRAM_TXB].off + fpi * TXB_ELEMENT_SIZE +
|
||||
offset;
|
||||
offset;
|
||||
|
||||
cdev->ops->write_fifo(cdev, addr_offset, val);
|
||||
}
|
||||
@ -359,17 +358,17 @@ static inline void m_can_fifo_write_no_off(struct m_can_classdev *cdev,
|
||||
static u32 m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset)
|
||||
{
|
||||
u32 addr_offset = cdev->mcfg[MRAM_TXE].off + fgi * TXE_ELEMENT_SIZE +
|
||||
offset;
|
||||
offset;
|
||||
|
||||
return cdev->ops->read_fifo(cdev, addr_offset);
|
||||
}
|
||||
|
||||
static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev)
|
||||
{
|
||||
return !!(m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQF);
|
||||
return !!(m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQF);
|
||||
}
|
||||
|
||||
void m_can_config_endisable(struct m_can_classdev *cdev, bool enable)
|
||||
static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable)
|
||||
{
|
||||
u32 cccr = m_can_read(cdev, M_CAN_CCCR);
|
||||
u32 timeout = 10;
|
||||
@ -380,10 +379,6 @@ void m_can_config_endisable(struct m_can_classdev *cdev, bool enable)
|
||||
cccr &= ~CCCR_CSR;
|
||||
|
||||
if (enable) {
|
||||
/* Clear the Clock stop request if it was set */
|
||||
if (cccr & CCCR_CSR)
|
||||
cccr &= ~CCCR_CSR;
|
||||
|
||||
/* enable m_can configuration */
|
||||
m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT);
|
||||
udelay(5);
|
||||
@ -457,9 +452,9 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
|
||||
}
|
||||
|
||||
if (dlc & RX_BUF_FDF)
|
||||
cf->len = can_dlc2len((dlc >> 16) & 0x0F);
|
||||
cf->len = can_fd_dlc2len((dlc >> 16) & 0x0F);
|
||||
else
|
||||
cf->len = get_can_dlc((dlc >> 16) & 0x0F);
|
||||
cf->len = can_cc_dlc2len((dlc >> 16) & 0x0F);
|
||||
|
||||
id = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID);
|
||||
if (id & RX_BUF_XTD)
|
||||
@ -596,7 +591,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -617,18 +612,10 @@ static int __m_can_get_berr_counter(const struct net_device *dev,
|
||||
|
||||
static int m_can_clk_start(struct m_can_classdev *cdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (cdev->pm_clock_support == 0)
|
||||
return 0;
|
||||
|
||||
err = pm_runtime_get_sync(cdev->dev);
|
||||
if (err < 0) {
|
||||
pm_runtime_put_noidle(cdev->dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return pm_runtime_resume_and_get(cdev->dev);
|
||||
}
|
||||
|
||||
static void m_can_clk_stop(struct m_can_classdev *cdev)
|
||||
@ -723,7 +710,7 @@ static int m_can_handle_state_change(struct net_device *dev,
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -926,14 +913,13 @@ static void m_can_echo_tx_event(struct net_device *dev)
|
||||
m_can_txefs = m_can_read(cdev, M_CAN_TXEFS);
|
||||
|
||||
/* Get Tx Event fifo element count */
|
||||
txe_count = (m_can_txefs & TXEFS_EFFL_MASK)
|
||||
>> TXEFS_EFFL_SHIFT;
|
||||
txe_count = (m_can_txefs & TXEFS_EFFL_MASK) >> TXEFS_EFFL_SHIFT;
|
||||
|
||||
/* Get and process all sent elements */
|
||||
for (i = 0; i < txe_count; i++) {
|
||||
/* retrieve get index */
|
||||
fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK)
|
||||
>> TXEFS_EFGI_SHIFT;
|
||||
fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK) >>
|
||||
TXEFS_EFGI_SHIFT;
|
||||
|
||||
/* get message marker */
|
||||
msg_mark = (m_can_txe_fifo_read(cdev, fgi, 4) &
|
||||
@ -1092,7 +1078,7 @@ static int m_can_set_bittiming(struct net_device *dev)
|
||||
* Transmitter Delay Compensation Section
|
||||
*/
|
||||
tdco = (cdev->can.clock.freq / 1000) *
|
||||
ssp / dbt->bitrate;
|
||||
ssp / dbt->bitrate;
|
||||
|
||||
/* Max valid TDCO value is 127 */
|
||||
if (tdco > 127) {
|
||||
@ -1107,9 +1093,9 @@ static int m_can_set_bittiming(struct net_device *dev)
|
||||
}
|
||||
|
||||
reg_btp |= (brp << DBTP_DBRP_SHIFT) |
|
||||
(sjw << DBTP_DSJW_SHIFT) |
|
||||
(tseg1 << DBTP_DTSEG1_SHIFT) |
|
||||
(tseg2 << DBTP_DTSEG2_SHIFT);
|
||||
(sjw << DBTP_DSJW_SHIFT) |
|
||||
(tseg1 << DBTP_DTSEG1_SHIFT) |
|
||||
(tseg2 << DBTP_DTSEG2_SHIFT);
|
||||
|
||||
m_can_write(cdev, M_CAN_DBTP, reg_btp);
|
||||
}
|
||||
@ -1142,7 +1128,7 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
if (cdev->version == 30) {
|
||||
/* only support one Tx Buffer currently */
|
||||
m_can_write(cdev, M_CAN_TXBC, (1 << TXBC_NDTB_SHIFT) |
|
||||
cdev->mcfg[MRAM_TXB].off);
|
||||
cdev->mcfg[MRAM_TXB].off);
|
||||
} else {
|
||||
/* TX FIFO is used for newer IP Core versions */
|
||||
m_can_write(cdev, M_CAN_TXBC,
|
||||
@ -1156,7 +1142,7 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
/* TX Event FIFO */
|
||||
if (cdev->version == 30) {
|
||||
m_can_write(cdev, M_CAN_TXEFC, (1 << TXEFC_EFS_SHIFT) |
|
||||
cdev->mcfg[MRAM_TXE].off);
|
||||
cdev->mcfg[MRAM_TXE].off);
|
||||
} else {
|
||||
/* Full TX Event FIFO is used */
|
||||
m_can_write(cdev, M_CAN_TXEFC,
|
||||
@ -1168,27 +1154,27 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
/* rx fifo configuration, blocking mode, fifo size 1 */
|
||||
m_can_write(cdev, M_CAN_RXF0C,
|
||||
(cdev->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT) |
|
||||
cdev->mcfg[MRAM_RXF0].off);
|
||||
cdev->mcfg[MRAM_RXF0].off);
|
||||
|
||||
m_can_write(cdev, M_CAN_RXF1C,
|
||||
(cdev->mcfg[MRAM_RXF1].num << RXFC_FS_SHIFT) |
|
||||
cdev->mcfg[MRAM_RXF1].off);
|
||||
cdev->mcfg[MRAM_RXF1].off);
|
||||
|
||||
cccr = m_can_read(cdev, M_CAN_CCCR);
|
||||
test = m_can_read(cdev, M_CAN_TEST);
|
||||
test &= ~TEST_LBCK;
|
||||
if (cdev->version == 30) {
|
||||
/* Version 3.0.x */
|
||||
/* Version 3.0.x */
|
||||
|
||||
cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR |
|
||||
(CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
|
||||
(CCCR_CME_MASK << CCCR_CME_SHIFT));
|
||||
(CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
|
||||
(CCCR_CME_MASK << CCCR_CME_SHIFT));
|
||||
|
||||
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
|
||||
cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT;
|
||||
|
||||
} else {
|
||||
/* Version 3.1.x or 3.2.x */
|
||||
/* Version 3.1.x or 3.2.x */
|
||||
cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE |
|
||||
CCCR_NISO | CCCR_DAR);
|
||||
|
||||
@ -1333,80 +1319,79 @@ static bool m_can_niso_supported(struct m_can_classdev *cdev)
|
||||
return !niso_timeout;
|
||||
}
|
||||
|
||||
static int m_can_dev_setup(struct m_can_classdev *m_can_dev)
|
||||
static int m_can_dev_setup(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct net_device *dev = m_can_dev->net;
|
||||
struct net_device *dev = cdev->net;
|
||||
int m_can_version;
|
||||
|
||||
m_can_version = m_can_check_core_release(m_can_dev);
|
||||
m_can_version = m_can_check_core_release(cdev);
|
||||
/* return if unsupported version */
|
||||
if (!m_can_version) {
|
||||
dev_err(m_can_dev->dev, "Unsupported version number: %2d",
|
||||
dev_err(cdev->dev, "Unsupported version number: %2d",
|
||||
m_can_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!m_can_dev->is_peripheral)
|
||||
netif_napi_add(dev, &m_can_dev->napi,
|
||||
if (!cdev->is_peripheral)
|
||||
netif_napi_add(dev, &cdev->napi,
|
||||
m_can_poll, M_CAN_NAPI_WEIGHT);
|
||||
|
||||
/* Shared properties of all M_CAN versions */
|
||||
m_can_dev->version = m_can_version;
|
||||
m_can_dev->can.do_set_mode = m_can_set_mode;
|
||||
m_can_dev->can.do_get_berr_counter = m_can_get_berr_counter;
|
||||
cdev->version = m_can_version;
|
||||
cdev->can.do_set_mode = m_can_set_mode;
|
||||
cdev->can.do_get_berr_counter = m_can_get_berr_counter;
|
||||
|
||||
/* Set M_CAN supported operations */
|
||||
m_can_dev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_LISTENONLY |
|
||||
CAN_CTRLMODE_BERR_REPORTING |
|
||||
CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_ONE_SHOT;
|
||||
cdev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_LISTENONLY |
|
||||
CAN_CTRLMODE_BERR_REPORTING |
|
||||
CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_ONE_SHOT;
|
||||
|
||||
/* Set properties depending on M_CAN version */
|
||||
switch (m_can_dev->version) {
|
||||
switch (cdev->version) {
|
||||
case 30:
|
||||
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
|
||||
can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
|
||||
m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
|
||||
m_can_dev->bit_timing : &m_can_bittiming_const_30X;
|
||||
cdev->can.bittiming_const = cdev->bit_timing ?
|
||||
cdev->bit_timing : &m_can_bittiming_const_30X;
|
||||
|
||||
m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ?
|
||||
m_can_dev->data_timing :
|
||||
&m_can_data_bittiming_const_30X;
|
||||
cdev->can.data_bittiming_const = cdev->data_timing ?
|
||||
cdev->data_timing :
|
||||
&m_can_data_bittiming_const_30X;
|
||||
break;
|
||||
case 31:
|
||||
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
|
||||
can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
|
||||
m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
|
||||
m_can_dev->bit_timing : &m_can_bittiming_const_31X;
|
||||
cdev->can.bittiming_const = cdev->bit_timing ?
|
||||
cdev->bit_timing : &m_can_bittiming_const_31X;
|
||||
|
||||
m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ?
|
||||
m_can_dev->data_timing :
|
||||
&m_can_data_bittiming_const_31X;
|
||||
cdev->can.data_bittiming_const = cdev->data_timing ?
|
||||
cdev->data_timing :
|
||||
&m_can_data_bittiming_const_31X;
|
||||
break;
|
||||
case 32:
|
||||
case 33:
|
||||
/* Support both MCAN version v3.2.x and v3.3.0 */
|
||||
m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
|
||||
m_can_dev->bit_timing : &m_can_bittiming_const_31X;
|
||||
cdev->can.bittiming_const = cdev->bit_timing ?
|
||||
cdev->bit_timing : &m_can_bittiming_const_31X;
|
||||
|
||||
m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ?
|
||||
m_can_dev->data_timing :
|
||||
&m_can_data_bittiming_const_31X;
|
||||
cdev->can.data_bittiming_const = cdev->data_timing ?
|
||||
cdev->data_timing :
|
||||
&m_can_data_bittiming_const_31X;
|
||||
|
||||
m_can_dev->can.ctrlmode_supported |=
|
||||
(m_can_niso_supported(m_can_dev)
|
||||
? CAN_CTRLMODE_FD_NON_ISO
|
||||
: 0);
|
||||
cdev->can.ctrlmode_supported |=
|
||||
(m_can_niso_supported(cdev) ?
|
||||
CAN_CTRLMODE_FD_NON_ISO : 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(m_can_dev->dev, "Unsupported version number: %2d",
|
||||
m_can_dev->version);
|
||||
dev_err(cdev->dev, "Unsupported version number: %2d",
|
||||
cdev->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (m_can_dev->ops->init)
|
||||
m_can_dev->ops->init(m_can_dev);
|
||||
if (cdev->ops->init)
|
||||
cdev->ops->init(cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1491,7 +1476,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
|
||||
/* message ram configuration */
|
||||
m_can_fifo_write(cdev, 0, M_CAN_FIFO_ID, id);
|
||||
m_can_fifo_write(cdev, 0, M_CAN_FIFO_DLC,
|
||||
can_len2dlc(cf->len) << 16);
|
||||
can_fd_len2dlc(cf->len) << 16);
|
||||
|
||||
for (i = 0; i < cf->len; i += 4)
|
||||
m_can_fifo_write(cdev, 0,
|
||||
@ -1539,7 +1524,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
|
||||
|
||||
/* get put index for frame */
|
||||
putidx = ((m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQPI_MASK)
|
||||
>> TXFQS_TFQPI_SHIFT);
|
||||
>> TXFQS_TFQPI_SHIFT);
|
||||
/* Write ID Field to FIFO Element */
|
||||
m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, id);
|
||||
|
||||
@ -1559,7 +1544,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
|
||||
m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DLC,
|
||||
((putidx << TX_BUF_MM_SHIFT) &
|
||||
TX_BUF_MM_MASK) |
|
||||
(can_len2dlc(cf->len) << 16) |
|
||||
(can_fd_len2dlc(cf->len) << 16) |
|
||||
fdflags | TX_BUF_EFC);
|
||||
|
||||
for (i = 0; i < cf->len; i += 4)
|
||||
@ -1586,7 +1571,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
|
||||
static void m_can_tx_work_queue(struct work_struct *ws)
|
||||
{
|
||||
struct m_can_classdev *cdev = container_of(ws, struct m_can_classdev,
|
||||
tx_work);
|
||||
tx_work);
|
||||
|
||||
m_can_tx_handler(cdev);
|
||||
cdev->tx_skb = NULL;
|
||||
@ -1710,26 +1695,26 @@ static void m_can_of_parse_mram(struct m_can_classdev *cdev,
|
||||
cdev->mcfg[MRAM_SIDF].off = mram_config_vals[0];
|
||||
cdev->mcfg[MRAM_SIDF].num = mram_config_vals[1];
|
||||
cdev->mcfg[MRAM_XIDF].off = cdev->mcfg[MRAM_SIDF].off +
|
||||
cdev->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_XIDF].num = mram_config_vals[2];
|
||||
cdev->mcfg[MRAM_RXF0].off = cdev->mcfg[MRAM_XIDF].off +
|
||||
cdev->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_RXF0].num = mram_config_vals[3] &
|
||||
(RXFC_FS_MASK >> RXFC_FS_SHIFT);
|
||||
(RXFC_FS_MASK >> RXFC_FS_SHIFT);
|
||||
cdev->mcfg[MRAM_RXF1].off = cdev->mcfg[MRAM_RXF0].off +
|
||||
cdev->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_RXF1].num = mram_config_vals[4] &
|
||||
(RXFC_FS_MASK >> RXFC_FS_SHIFT);
|
||||
(RXFC_FS_MASK >> RXFC_FS_SHIFT);
|
||||
cdev->mcfg[MRAM_RXB].off = cdev->mcfg[MRAM_RXF1].off +
|
||||
cdev->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_RXB].num = mram_config_vals[5];
|
||||
cdev->mcfg[MRAM_TXE].off = cdev->mcfg[MRAM_RXB].off +
|
||||
cdev->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_TXE].num = mram_config_vals[6];
|
||||
cdev->mcfg[MRAM_TXB].off = cdev->mcfg[MRAM_TXE].off +
|
||||
cdev->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
|
||||
cdev->mcfg[MRAM_TXB].num = mram_config_vals[7] &
|
||||
(TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
|
||||
(TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
|
||||
|
||||
dev_dbg(cdev->dev,
|
||||
"sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
|
||||
@ -1758,15 +1743,15 @@ void m_can_init_ram(struct m_can_classdev *cdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_init_ram);
|
||||
|
||||
int m_can_class_get_clocks(struct m_can_classdev *m_can_dev)
|
||||
int m_can_class_get_clocks(struct m_can_classdev *cdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
m_can_dev->hclk = devm_clk_get(m_can_dev->dev, "hclk");
|
||||
m_can_dev->cclk = devm_clk_get(m_can_dev->dev, "cclk");
|
||||
cdev->hclk = devm_clk_get(cdev->dev, "hclk");
|
||||
cdev->cclk = devm_clk_get(cdev->dev, "cclk");
|
||||
|
||||
if (IS_ERR(m_can_dev->cclk)) {
|
||||
dev_err(m_can_dev->dev, "no clock found\n");
|
||||
if (IS_ERR(cdev->cclk)) {
|
||||
dev_err(cdev->dev, "no clock found\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
@ -1774,7 +1759,8 @@ int m_can_class_get_clocks(struct m_can_classdev *m_can_dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_get_clocks);
|
||||
|
||||
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev)
|
||||
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev,
|
||||
int sizeof_priv)
|
||||
{
|
||||
struct m_can_classdev *class_dev = NULL;
|
||||
u32 mram_config_vals[MRAM_CFG_LEN];
|
||||
@ -1797,7 +1783,7 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev)
|
||||
tx_fifo_size = mram_config_vals[7];
|
||||
|
||||
/* allocate the m_can device */
|
||||
net_dev = alloc_candev(sizeof(*class_dev), tx_fifo_size);
|
||||
net_dev = alloc_candev(sizeof_priv, tx_fifo_size);
|
||||
if (!net_dev) {
|
||||
dev_err(dev, "Failed to allocate CAN device");
|
||||
goto out;
|
||||
@ -1825,54 +1811,56 @@ void m_can_class_free_dev(struct net_device *net)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_free_dev);
|
||||
|
||||
int m_can_class_register(struct m_can_classdev *m_can_dev)
|
||||
int m_can_class_register(struct m_can_classdev *cdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (m_can_dev->pm_clock_support) {
|
||||
pm_runtime_enable(m_can_dev->dev);
|
||||
ret = m_can_clk_start(m_can_dev);
|
||||
if (cdev->pm_clock_support) {
|
||||
ret = m_can_clk_start(cdev);
|
||||
if (ret)
|
||||
goto pm_runtime_fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = m_can_dev_setup(m_can_dev);
|
||||
ret = m_can_dev_setup(cdev);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
ret = register_m_can_dev(m_can_dev->net);
|
||||
ret = register_m_can_dev(cdev->net);
|
||||
if (ret) {
|
||||
dev_err(m_can_dev->dev, "registering %s failed (err=%d)\n",
|
||||
m_can_dev->net->name, ret);
|
||||
dev_err(cdev->dev, "registering %s failed (err=%d)\n",
|
||||
cdev->net->name, ret);
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
devm_can_led_init(m_can_dev->net);
|
||||
devm_can_led_init(cdev->net);
|
||||
|
||||
of_can_transceiver(m_can_dev->net);
|
||||
of_can_transceiver(cdev->net);
|
||||
|
||||
dev_info(m_can_dev->dev, "%s device registered (irq=%d, version=%d)\n",
|
||||
KBUILD_MODNAME, m_can_dev->net->irq, m_can_dev->version);
|
||||
dev_info(cdev->dev, "%s device registered (irq=%d, version=%d)\n",
|
||||
KBUILD_MODNAME, cdev->net->irq, cdev->version);
|
||||
|
||||
/* Probe finished
|
||||
* Stop clocks. They will be reactivated once the M_CAN device is opened
|
||||
*/
|
||||
clk_disable:
|
||||
m_can_clk_stop(m_can_dev);
|
||||
pm_runtime_fail:
|
||||
if (ret) {
|
||||
if (m_can_dev->pm_clock_support)
|
||||
pm_runtime_disable(m_can_dev->dev);
|
||||
}
|
||||
m_can_clk_stop(cdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_register);
|
||||
|
||||
void m_can_class_unregister(struct m_can_classdev *cdev)
|
||||
{
|
||||
unregister_candev(cdev->net);
|
||||
|
||||
m_can_clk_stop(cdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_unregister);
|
||||
|
||||
int m_can_class_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct m_can_classdev *cdev = netdev_priv(ndev);
|
||||
struct m_can_classdev *cdev = dev_get_drvdata(dev);
|
||||
struct net_device *ndev = cdev->net;
|
||||
|
||||
if (netif_running(ndev)) {
|
||||
netif_stop_queue(ndev);
|
||||
@ -1891,8 +1879,8 @@ EXPORT_SYMBOL_GPL(m_can_class_suspend);
|
||||
|
||||
int m_can_class_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct m_can_classdev *cdev = netdev_priv(ndev);
|
||||
struct m_can_classdev *cdev = dev_get_drvdata(dev);
|
||||
struct net_device *ndev = cdev->net;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
@ -1915,14 +1903,6 @@ int m_can_class_resume(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_resume);
|
||||
|
||||
void m_can_class_unregister(struct m_can_classdev *m_can_dev)
|
||||
{
|
||||
unregister_candev(m_can_dev->net);
|
||||
|
||||
m_can_clk_stop(m_can_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_unregister);
|
||||
|
||||
MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
|
||||
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -86,10 +86,7 @@ struct m_can_classdev {
|
||||
|
||||
struct m_can_ops *ops;
|
||||
|
||||
void *device_data;
|
||||
|
||||
int version;
|
||||
int freq;
|
||||
u32 irqstatus;
|
||||
|
||||
int pm_clock_support;
|
||||
@ -98,13 +95,12 @@ struct m_can_classdev {
|
||||
struct mram_cfg mcfg[MRAM_CFG_NUM];
|
||||
};
|
||||
|
||||
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev);
|
||||
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv);
|
||||
void m_can_class_free_dev(struct net_device *net);
|
||||
int m_can_class_register(struct m_can_classdev *cdev);
|
||||
void m_can_class_unregister(struct m_can_classdev *cdev);
|
||||
int m_can_class_get_clocks(struct m_can_classdev *cdev);
|
||||
void m_can_init_ram(struct m_can_classdev *priv);
|
||||
void m_can_config_endisable(struct m_can_classdev *priv, bool enable);
|
||||
|
||||
int m_can_class_suspend(struct device *dev);
|
||||
int m_can_class_resume(struct device *dev);
|
||||
|
190
drivers/net/can/m_can/m_can_pci.c
Normal file
190
drivers/net/can/m_can/m_can_pci.c
Normal file
@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCI Specific M_CAN Glue
|
||||
*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
* Author: Felipe Balbi (Intel)
|
||||
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
* Author: Raymond Tan <raymond.tan@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "m_can.h"
|
||||
|
||||
#define M_CAN_PCI_MMIO_BAR 0
|
||||
|
||||
#define M_CAN_CLOCK_FREQ_EHL 100000000
|
||||
#define CTL_CSR_INT_CTL_OFFSET 0x508
|
||||
|
||||
struct m_can_pci_priv {
|
||||
struct m_can_classdev cdev;
|
||||
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static inline struct m_can_pci_priv *cdev_to_priv(struct m_can_classdev *cdev)
|
||||
{
|
||||
return container_of(cdev, struct m_can_pci_priv, cdev);
|
||||
}
|
||||
|
||||
static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
|
||||
{
|
||||
struct m_can_pci_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return readl(priv->base + reg);
|
||||
}
|
||||
|
||||
static u32 iomap_read_fifo(struct m_can_classdev *cdev, int offset)
|
||||
{
|
||||
struct m_can_pci_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return readl(priv->base + offset);
|
||||
}
|
||||
|
||||
static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
|
||||
{
|
||||
struct m_can_pci_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
writel(val, priv->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, int val)
|
||||
{
|
||||
struct m_can_pci_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
writel(val, priv->base + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct m_can_ops m_can_pci_ops = {
|
||||
.read_reg = iomap_read_reg,
|
||||
.write_reg = iomap_write_reg,
|
||||
.write_fifo = iomap_write_fifo,
|
||||
.read_fifo = iomap_read_fifo,
|
||||
};
|
||||
|
||||
static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
{
|
||||
struct device *dev = &pci->dev;
|
||||
struct m_can_classdev *mcan_class;
|
||||
struct m_can_pci_priv *priv;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
ret = pcim_iomap_regions(pci, BIT(M_CAN_PCI_MMIO_BAR), pci_name(pci));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
base = pcim_iomap_table(pci)[M_CAN_PCI_MMIO_BAR];
|
||||
|
||||
if (!base) {
|
||||
dev_err(dev, "failed to map BARs\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mcan_class = m_can_class_allocate_dev(&pci->dev,
|
||||
sizeof(struct m_can_pci_priv));
|
||||
if (!mcan_class)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = cdev_to_priv(mcan_class);
|
||||
|
||||
priv->base = base;
|
||||
|
||||
ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mcan_class->dev = &pci->dev;
|
||||
mcan_class->net->irq = pci_irq_vector(pci, 0);
|
||||
mcan_class->pm_clock_support = 1;
|
||||
mcan_class->can.clock.freq = id->driver_data;
|
||||
mcan_class->ops = &m_can_pci_ops;
|
||||
|
||||
pci_set_drvdata(pci, mcan_class);
|
||||
|
||||
ret = m_can_class_register(mcan_class);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Enable interrupt control at CAN wrapper IP */
|
||||
writel(0x1, base + CTL_CSR_INT_CTL_OFFSET);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, 1000);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
pm_runtime_allow(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pci_free_irq_vectors(pci);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void m_can_pci_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct m_can_classdev *mcan_class = pci_get_drvdata(pci);
|
||||
struct m_can_pci_priv *priv = cdev_to_priv(mcan_class);
|
||||
|
||||
pm_runtime_forbid(&pci->dev);
|
||||
pm_runtime_get_noresume(&pci->dev);
|
||||
|
||||
/* Disable interrupt control at CAN wrapper IP */
|
||||
writel(0x0, priv->base + CTL_CSR_INT_CTL_OFFSET);
|
||||
|
||||
m_can_class_unregister(mcan_class);
|
||||
pci_free_irq_vectors(pci);
|
||||
}
|
||||
|
||||
static __maybe_unused int m_can_pci_suspend(struct device *dev)
|
||||
{
|
||||
return m_can_class_suspend(dev);
|
||||
}
|
||||
|
||||
static __maybe_unused int m_can_pci_resume(struct device *dev)
|
||||
{
|
||||
return m_can_class_resume(dev);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
|
||||
m_can_pci_suspend, m_can_pci_resume);
|
||||
|
||||
static const struct pci_device_id m_can_pci_id_table[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x4bc1), M_CAN_CLOCK_FREQ_EHL, },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bc2), M_CAN_CLOCK_FREQ_EHL, },
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, m_can_pci_id_table);
|
||||
|
||||
static struct pci_driver m_can_pci_driver = {
|
||||
.name = "m_can_pci",
|
||||
.probe = m_can_pci_probe,
|
||||
.remove = m_can_pci_remove,
|
||||
.id_table = m_can_pci_id_table,
|
||||
.driver = {
|
||||
.pm = &m_can_pci_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(m_can_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi (Intel)");
|
||||
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
|
||||
MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller on PCI bus");
|
@ -10,27 +10,34 @@
|
||||
#include "m_can.h"
|
||||
|
||||
struct m_can_plat_priv {
|
||||
struct m_can_classdev cdev;
|
||||
|
||||
void __iomem *base;
|
||||
void __iomem *mram_base;
|
||||
};
|
||||
|
||||
static inline struct m_can_plat_priv *cdev_to_priv(struct m_can_classdev *cdev)
|
||||
{
|
||||
return container_of(cdev, struct m_can_plat_priv, cdev);
|
||||
}
|
||||
|
||||
static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
|
||||
{
|
||||
struct m_can_plat_priv *priv = cdev->device_data;
|
||||
struct m_can_plat_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return readl(priv->base + reg);
|
||||
}
|
||||
|
||||
static u32 iomap_read_fifo(struct m_can_classdev *cdev, int offset)
|
||||
{
|
||||
struct m_can_plat_priv *priv = cdev->device_data;
|
||||
struct m_can_plat_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return readl(priv->mram_base + offset);
|
||||
}
|
||||
|
||||
static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
|
||||
{
|
||||
struct m_can_plat_priv *priv = cdev->device_data;
|
||||
struct m_can_plat_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
writel(val, priv->base + reg);
|
||||
|
||||
@ -39,7 +46,7 @@ static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
|
||||
|
||||
static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, int val)
|
||||
{
|
||||
struct m_can_plat_priv *priv = cdev->device_data;
|
||||
struct m_can_plat_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
writel(val, priv->mram_base + offset);
|
||||
|
||||
@ -62,17 +69,12 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
void __iomem *mram_addr;
|
||||
int irq, ret = 0;
|
||||
|
||||
mcan_class = m_can_class_allocate_dev(&pdev->dev);
|
||||
mcan_class = m_can_class_allocate_dev(&pdev->dev,
|
||||
sizeof(struct m_can_plat_priv));
|
||||
if (!mcan_class)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
mcan_class->device_data = priv;
|
||||
priv = cdev_to_priv(mcan_class);
|
||||
|
||||
ret = m_can_class_get_clocks(mcan_class);
|
||||
if (ret)
|
||||
@ -111,12 +113,19 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
|
||||
mcan_class->is_peripheral = false;
|
||||
|
||||
platform_set_drvdata(pdev, mcan_class->net);
|
||||
platform_set_drvdata(pdev, mcan_class);
|
||||
|
||||
m_can_init_ram(mcan_class);
|
||||
|
||||
return m_can_class_register(mcan_class);
|
||||
pm_runtime_enable(mcan_class->dev);
|
||||
ret = m_can_class_register(mcan_class);
|
||||
if (ret)
|
||||
goto out_runtime_disable;
|
||||
|
||||
return ret;
|
||||
|
||||
out_runtime_disable:
|
||||
pm_runtime_disable(mcan_class->dev);
|
||||
probe_fail:
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
return ret;
|
||||
@ -134,22 +143,20 @@ static __maybe_unused int m_can_resume(struct device *dev)
|
||||
|
||||
static int m_can_plat_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
struct m_can_classdev *mcan_class = netdev_priv(dev);
|
||||
struct m_can_plat_priv *priv = platform_get_drvdata(pdev);
|
||||
struct m_can_classdev *mcan_class = &priv->cdev;
|
||||
|
||||
m_can_class_unregister(mcan_class);
|
||||
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused m_can_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct m_can_classdev *mcan_class = netdev_priv(ndev);
|
||||
struct m_can_plat_priv *priv = dev_get_drvdata(dev);
|
||||
struct m_can_classdev *mcan_class = &priv->cdev;
|
||||
|
||||
clk_disable_unprepare(mcan_class->cclk);
|
||||
clk_disable_unprepare(mcan_class->hclk);
|
||||
@ -159,8 +166,8 @@ static int __maybe_unused m_can_runtime_suspend(struct device *dev)
|
||||
|
||||
static int __maybe_unused m_can_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct m_can_classdev *mcan_class = netdev_priv(ndev);
|
||||
struct m_can_plat_priv *priv = dev_get_drvdata(dev);
|
||||
struct m_can_classdev *mcan_class = &priv->cdev;
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(mcan_class->hclk);
|
||||
|
@ -114,21 +114,23 @@
|
||||
#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29))
|
||||
|
||||
struct tcan4x5x_priv {
|
||||
struct m_can_classdev cdev;
|
||||
|
||||
struct regmap *regmap;
|
||||
struct spi_device *spi;
|
||||
|
||||
struct m_can_classdev *mcan_dev;
|
||||
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *device_wake_gpio;
|
||||
struct gpio_desc *device_state_gpio;
|
||||
struct regulator *power;
|
||||
|
||||
/* Register based ip */
|
||||
int mram_start;
|
||||
int reg_offset;
|
||||
};
|
||||
|
||||
static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev)
|
||||
{
|
||||
return container_of(cdev, struct tcan4x5x_priv, cdev);
|
||||
|
||||
}
|
||||
|
||||
static struct can_bittiming_const tcan4x5x_bittiming_const = {
|
||||
.name = DEVICE_NAME,
|
||||
.tseg1_min = 2,
|
||||
@ -257,37 +259,37 @@ static struct regmap_bus tcan4x5x_bus = {
|
||||
|
||||
static u32 tcan4x5x_read_reg(struct m_can_classdev *cdev, int reg)
|
||||
{
|
||||
struct tcan4x5x_priv *priv = cdev->device_data;
|
||||
struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->regmap, priv->reg_offset + reg, &val);
|
||||
regmap_read(priv->regmap, TCAN4X5X_MCAN_OFFSET + reg, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static u32 tcan4x5x_read_fifo(struct m_can_classdev *cdev, int addr_offset)
|
||||
{
|
||||
struct tcan4x5x_priv *priv = cdev->device_data;
|
||||
struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->regmap, priv->mram_start + addr_offset, &val);
|
||||
regmap_read(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val)
|
||||
{
|
||||
struct tcan4x5x_priv *priv = cdev->device_data;
|
||||
struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return regmap_write(priv->regmap, priv->reg_offset + reg, val);
|
||||
return regmap_write(priv->regmap, TCAN4X5X_MCAN_OFFSET + reg, val);
|
||||
}
|
||||
|
||||
static int tcan4x5x_write_fifo(struct m_can_classdev *cdev,
|
||||
int addr_offset, int val)
|
||||
{
|
||||
struct tcan4x5x_priv *priv = cdev->device_data;
|
||||
struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return regmap_write(priv->regmap, priv->mram_start + addr_offset, val);
|
||||
return regmap_write(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val);
|
||||
}
|
||||
|
||||
static int tcan4x5x_power_enable(struct regulator *reg, int enable)
|
||||
@ -304,7 +306,7 @@ static int tcan4x5x_power_enable(struct regulator *reg, int enable)
|
||||
static int tcan4x5x_write_tcan_reg(struct m_can_classdev *cdev,
|
||||
int reg, int val)
|
||||
{
|
||||
struct tcan4x5x_priv *priv = cdev->device_data;
|
||||
struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
|
||||
|
||||
return regmap_write(priv->regmap, reg, val);
|
||||
}
|
||||
@ -328,17 +330,13 @@ static int tcan4x5x_clear_interrupts(struct m_can_classdev *cdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS,
|
||||
TCAN4X5X_CLEAR_ALL_INT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS,
|
||||
TCAN4X5X_CLEAR_ALL_INT);
|
||||
}
|
||||
|
||||
static int tcan4x5x_init(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
int ret;
|
||||
|
||||
tcan4x5x_check_wake(tcan4x5x);
|
||||
@ -365,7 +363,7 @@ static int tcan4x5x_init(struct m_can_classdev *cdev)
|
||||
|
||||
static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
|
||||
return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
|
||||
TCAN4X5X_DISABLE_WAKE_MSK, 0x00);
|
||||
@ -373,15 +371,15 @@ static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
|
||||
|
||||
static int tcan4x5x_disable_state(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
|
||||
return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
|
||||
TCAN4X5X_DISABLE_INH_MSK, 0x01);
|
||||
}
|
||||
|
||||
static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
|
||||
static int tcan4x5x_get_gpios(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
int ret;
|
||||
|
||||
tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
|
||||
@ -435,15 +433,12 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
struct m_can_classdev *mcan_class;
|
||||
int freq, ret;
|
||||
|
||||
mcan_class = m_can_class_allocate_dev(&spi->dev);
|
||||
mcan_class = m_can_class_allocate_dev(&spi->dev,
|
||||
sizeof(struct tcan4x5x_priv));
|
||||
if (!mcan_class)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out_m_can_class_free_dev;
|
||||
}
|
||||
priv = cdev_to_priv(mcan_class);
|
||||
|
||||
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
|
||||
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
|
||||
@ -453,8 +448,6 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
priv->power = NULL;
|
||||
}
|
||||
|
||||
mcan_class->device_data = priv;
|
||||
|
||||
m_can_class_get_clocks(mcan_class);
|
||||
if (IS_ERR(mcan_class->cclk)) {
|
||||
dev_err(&spi->dev, "no CAN clock source defined\n");
|
||||
@ -469,10 +462,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
goto out_m_can_class_free_dev;
|
||||
}
|
||||
|
||||
priv->reg_offset = TCAN4X5X_MCAN_OFFSET;
|
||||
priv->mram_start = TCAN4X5X_MRAM_START;
|
||||
priv->spi = spi;
|
||||
priv->mcan_dev = mcan_class;
|
||||
|
||||
mcan_class->pm_clock_support = 0;
|
||||
mcan_class->can.clock.freq = freq;
|
||||
@ -502,7 +492,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
goto out_m_can_class_free_dev;
|
||||
|
||||
ret = tcan4x5x_parse_config(mcan_class);
|
||||
ret = tcan4x5x_get_gpios(mcan_class);
|
||||
if (ret)
|
||||
goto out_power;
|
||||
|
||||
@ -521,8 +511,6 @@ out_power:
|
||||
tcan4x5x_power_enable(priv->power, 0);
|
||||
out_m_can_class_free_dev:
|
||||
m_can_class_free_dev(mcan_class->net);
|
||||
dev_err(&spi->dev, "Probe failed, err=%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -530,11 +518,11 @@ static int tcan4x5x_can_remove(struct spi_device *spi)
|
||||
{
|
||||
struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
|
||||
|
||||
m_can_class_unregister(priv->mcan_dev);
|
||||
m_can_class_unregister(&priv->cdev);
|
||||
|
||||
tcan4x5x_power_enable(priv->power, 0);
|
||||
|
||||
m_can_class_free_dev(priv->mcan_dev->net);
|
||||
m_can_class_free_dev(priv->cdev.net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -250,16 +250,16 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
void __iomem *data = ®s->tx.dsr1_0;
|
||||
u16 *payload = (u16 *)frame->data;
|
||||
|
||||
for (i = 0; i < frame->can_dlc / 2; i++) {
|
||||
for (i = 0; i < frame->len / 2; i++) {
|
||||
out_be16(data, *payload++);
|
||||
data += 2 + _MSCAN_RESERVED_DSR_SIZE;
|
||||
}
|
||||
/* write remaining byte if necessary */
|
||||
if (frame->can_dlc & 1)
|
||||
out_8(data, frame->data[frame->can_dlc - 1]);
|
||||
if (frame->len & 1)
|
||||
out_8(data, frame->data[frame->len - 1]);
|
||||
}
|
||||
|
||||
out_8(®s->tx.dlr, frame->can_dlc);
|
||||
out_8(®s->tx.dlr, frame->len);
|
||||
out_8(®s->tx.tbpr, priv->cur_pri);
|
||||
|
||||
/* Start transmission. */
|
||||
@ -312,19 +312,19 @@ static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
|
||||
if (can_id & 1)
|
||||
frame->can_id |= CAN_RTR_FLAG;
|
||||
|
||||
frame->can_dlc = get_can_dlc(in_8(®s->rx.dlr) & 0xf);
|
||||
frame->len = can_cc_dlc2len(in_8(®s->rx.dlr) & 0xf);
|
||||
|
||||
if (!(frame->can_id & CAN_RTR_FLAG)) {
|
||||
void __iomem *data = ®s->rx.dsr1_0;
|
||||
u16 *payload = (u16 *)frame->data;
|
||||
|
||||
for (i = 0; i < frame->can_dlc / 2; i++) {
|
||||
for (i = 0; i < frame->len / 2; i++) {
|
||||
*payload++ = in_be16(data);
|
||||
data += 2 + _MSCAN_RESERVED_DSR_SIZE;
|
||||
}
|
||||
/* read remaining byte if necessary */
|
||||
if (frame->can_dlc & 1)
|
||||
frame->data[frame->can_dlc - 1] = in_8(data);
|
||||
if (frame->len & 1)
|
||||
frame->data[frame->len - 1] = in_8(data);
|
||||
}
|
||||
|
||||
out_8(®s->canrflg, MSCAN_RXF);
|
||||
@ -372,7 +372,7 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
|
||||
}
|
||||
}
|
||||
priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
|
||||
frame->can_dlc = CAN_ERR_DLC;
|
||||
frame->len = CAN_ERR_DLC;
|
||||
out_8(®s->canrflg, MSCAN_ERR_IF);
|
||||
}
|
||||
|
||||
@ -407,7 +407,7 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)
|
||||
mscan_get_err_frame(dev, frame, canrflg);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += frame->can_dlc;
|
||||
stats->rx_bytes += frame->len;
|
||||
work_done++;
|
||||
netif_receive_skb(skb);
|
||||
}
|
||||
|
@ -563,7 +563,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
|
||||
netif_receive_skb(skb);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
}
|
||||
|
||||
static irqreturn_t pch_can_interrupt(int irq, void *dev_id)
|
||||
@ -683,10 +683,10 @@ static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
|
||||
if (id2 & PCH_ID2_DIR)
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
|
||||
cf->can_dlc = get_can_dlc((ioread32(&priv->regs->
|
||||
cf->len = can_cc_dlc2len((ioread32(&priv->regs->
|
||||
ifregs[0].mcont)) & 0xF);
|
||||
|
||||
for (i = 0; i < cf->can_dlc; i += 2) {
|
||||
for (i = 0; i < cf->len; i += 2) {
|
||||
data_reg = ioread16(&priv->regs->ifregs[0].data[i / 2]);
|
||||
cf->data[i] = data_reg;
|
||||
cf->data[i + 1] = data_reg >> 8;
|
||||
@ -696,7 +696,7 @@ static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
|
||||
rcv_pkts++;
|
||||
stats->rx_packets++;
|
||||
quota--;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
|
||||
pch_fifo_thresh(priv, obj_num);
|
||||
obj_num++;
|
||||
@ -715,7 +715,7 @@ static void pch_can_tx_complete(struct net_device *ndev, u32 int_stat)
|
||||
iowrite32(PCH_CMASK_RX_TX_GET | PCH_CMASK_CLRINTPND,
|
||||
&priv->regs->ifregs[1].cmask);
|
||||
pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, int_stat);
|
||||
dlc = get_can_dlc(ioread32(&priv->regs->ifregs[1].mcont) &
|
||||
dlc = can_cc_dlc2len(ioread32(&priv->regs->ifregs[1].mcont) &
|
||||
PCH_IF_MCONT_DLC);
|
||||
stats->tx_bytes += dlc;
|
||||
stats->tx_packets++;
|
||||
@ -919,7 +919,7 @@ static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
iowrite32(id2, &priv->regs->ifregs[1].id2);
|
||||
|
||||
/* Copy data to register */
|
||||
for (i = 0; i < cf->can_dlc; i += 2) {
|
||||
for (i = 0; i < cf->len; i += 2) {
|
||||
iowrite16(cf->data[i] | (cf->data[i + 1] << 8),
|
||||
&priv->regs->ifregs[1].data[i / 2]);
|
||||
}
|
||||
@ -927,7 +927,7 @@ static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1);
|
||||
|
||||
/* Set the size of the data. Update if2_mcont */
|
||||
iowrite32(cf->can_dlc | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT |
|
||||
iowrite32(cf->len | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT |
|
||||
PCH_IF_MCONT_TXIE, &priv->regs->ifregs[1].mcont);
|
||||
|
||||
pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, tx_obj_no);
|
||||
|
@ -257,9 +257,9 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
|
||||
u8 cf_len;
|
||||
|
||||
if (rx_msg_flags & PUCAN_MSG_EXT_DATA_LEN)
|
||||
cf_len = can_dlc2len(get_canfd_dlc(pucan_msg_get_dlc(msg)));
|
||||
cf_len = can_fd_dlc2len(pucan_msg_get_dlc(msg));
|
||||
else
|
||||
cf_len = get_can_dlc(pucan_msg_get_dlc(msg));
|
||||
cf_len = can_cc_dlc2len(pucan_msg_get_dlc(msg));
|
||||
|
||||
/* if this frame is an echo, */
|
||||
if (rx_msg_flags & PUCAN_MSG_LOOPED_BACK) {
|
||||
@ -410,7 +410,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
|
||||
}
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
|
||||
|
||||
return 0;
|
||||
@ -438,7 +438,7 @@ static int pucan_handle_cache_critical(struct peak_canfd_priv *priv)
|
||||
cf->data[6] = priv->bec.txerr;
|
||||
cf->data[7] = priv->bec.rxerr;
|
||||
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
stats->rx_packets++;
|
||||
netif_rx(skb);
|
||||
|
||||
@ -652,7 +652,7 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
|
||||
unsigned long flags;
|
||||
bool should_stop_tx_queue;
|
||||
int room_left;
|
||||
u8 can_dlc;
|
||||
u8 len;
|
||||
|
||||
if (can_dropped_invalid_skb(ndev, skb))
|
||||
return NETDEV_TX_OK;
|
||||
@ -682,7 +682,7 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
|
||||
|
||||
if (can_is_canfd_skb(skb)) {
|
||||
/* CAN FD frame format */
|
||||
can_dlc = can_len2dlc(cf->len);
|
||||
len = can_fd_len2dlc(cf->len);
|
||||
|
||||
msg_flags |= PUCAN_MSG_EXT_DATA_LEN;
|
||||
|
||||
@ -693,7 +693,7 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
|
||||
msg_flags |= PUCAN_MSG_ERROR_STATE_IND;
|
||||
} else {
|
||||
/* CAN 2.0 frame format */
|
||||
can_dlc = cf->len;
|
||||
len = cf->len;
|
||||
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
msg_flags |= PUCAN_MSG_RTR;
|
||||
@ -707,7 +707,7 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
|
||||
msg_flags |= PUCAN_MSG_SELF_RECEIVE;
|
||||
|
||||
msg->flags = cpu_to_le16(msg_flags);
|
||||
msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(priv->index, can_dlc);
|
||||
msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(priv->index, len);
|
||||
memcpy(msg->d, cf->data, cf->len);
|
||||
|
||||
/* struct msg client field is used as an index in the echo skbs ring */
|
||||
|
@ -364,7 +364,7 @@ static void rcar_can_error(struct net_device *ndev)
|
||||
|
||||
if (skb) {
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
netif_rx(skb);
|
||||
}
|
||||
}
|
||||
@ -607,16 +607,16 @@ static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
|
||||
if (cf->can_id & CAN_RTR_FLAG) { /* Remote transmission request */
|
||||
data |= RCAR_CAN_RTR;
|
||||
} else {
|
||||
for (i = 0; i < cf->can_dlc; i++)
|
||||
for (i = 0; i < cf->len; i++)
|
||||
writeb(cf->data[i],
|
||||
&priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].data[i]);
|
||||
}
|
||||
|
||||
writel(data, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].id);
|
||||
|
||||
writeb(cf->can_dlc, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc);
|
||||
writeb(cf->len, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc);
|
||||
|
||||
priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->can_dlc;
|
||||
priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->len;
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH);
|
||||
priv->tx_head++;
|
||||
/* Start Tx: write 0xff to the TFPCR register to increment
|
||||
@ -659,18 +659,18 @@ static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
|
||||
cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK;
|
||||
|
||||
dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc);
|
||||
cf->can_dlc = get_can_dlc(dlc);
|
||||
cf->len = can_cc_dlc2len(dlc);
|
||||
if (data & RCAR_CAN_RTR) {
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
} else {
|
||||
for (dlc = 0; dlc < cf->can_dlc; dlc++)
|
||||
for (dlc = 0; dlc < cf->len; dlc++)
|
||||
cf->data[dlc] =
|
||||
readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].data[dlc]);
|
||||
}
|
||||
|
||||
can_led_event(priv->ndev, CAN_LED_EVENT_RX);
|
||||
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
stats->rx_bytes += cf->len;
|
||||
stats->rx_packets++;
|
||||
netif_receive_skb(skb);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user