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:
Linus Torvalds 2020-12-15 13:22:29 -08:00
commit d635a69dd4
1879 changed files with 72099 additions and 38938 deletions

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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).

View File

@ -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

View File

@ -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>

View File

@ -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";
};
};
};

View File

@ -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 = <&eth0>;
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 = <&eth0>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};

View 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 = <&eth0>;
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 = <&eth0>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
...

View File

@ -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>;
};
};
};

View File

@ -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

View File

@ -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):

View File

@ -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";
};
};

View File

@ -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

View File

@ -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,.*":

View 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,
};

View File

@ -73,6 +73,7 @@ available subsections can be seen below.
thermal/index
fpga/index
acpi/index
auxiliary_bus
backlight/lp855x-driver.rst
connector
console

View File

@ -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

View File

@ -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

View File

@ -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
============================

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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/*``
========================

View File

@ -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

View File

@ -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
======================

View 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

View File

@ -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
===============

View File

@ -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

View 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:

View File

@ -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.

View File

@ -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

View File

@ -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``

View File

@ -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``

View File

@ -114,7 +114,6 @@ Todolist:
unicode
vga-softcursor
video-output
wimax/index
xfs
.. only:: subproject and html

View File

@ -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``

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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__)

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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
View 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>");

View File

@ -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];

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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
{ },

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -563,7 +563,6 @@ struct mhi_chan {
bool configured;
bool offload_ch;
bool pre_alloc;
bool auto_start;
bool wake_capable;
};

View File

@ -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)

View File

@ -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;

View File

@ -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]) {

View File

@ -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;

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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);

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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/

View File

@ -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",
};

View File

@ -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 */
}

View File

@ -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>

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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, &regs->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, &regs->ctrl);
reg_imask = priv->rx_mask | priv->tx_mask;
priv->write(upper_32_bits(reg_imask), &regs->imask2);
priv->write(lower_32_bits(reg_imask), &regs->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, &regs->imask2);
priv->write(0, &regs->imask1);
priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
&regs->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, &regs->ctrl);
reg_imask = priv->rx_mask | priv->tx_mask;
priv->write(upper_32_bits(reg_imask), &regs->imask2);
priv->write(lower_32_bits(reg_imask), &regs->imask1);
enable_irq(dev->irq);
/* print chip status */
netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
priv->read(&regs->mcr), priv->read(&regs->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, &regs->imask2);
priv->write(0, &regs->imask1);
priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
&regs->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);

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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);

View 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");

View File

@ -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);

View File

@ -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;
}

View File

@ -250,16 +250,16 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
void __iomem *data = &regs->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(&regs->tx.dlr, frame->can_dlc);
out_8(&regs->tx.dlr, frame->len);
out_8(&regs->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(&regs->rx.dlr) & 0xf);
frame->len = can_cc_dlc2len(in_8(&regs->rx.dlr) & 0xf);
if (!(frame->can_id & CAN_RTR_FLAG)) {
void __iomem *data = &regs->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(&regs->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(&regs->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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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