Networking changes for 6.11. Not much excitement - a handful of large

patchsets (devmem among them) did not make it in time.
 
 Core & protocols
 ----------------
 
  - Use local_lock in addition to local_bh_disable() to protect per-CPU
    resources in networking, a step closer for local_bh_disable() not
    to act as a big lock on PREEMPT_RT.
 
  - Use flex array for netdevice priv area, ensure its cache alignment.
 
  - Add a sysctl knob to allow user to specify a default rto_min at socket
    init time. Bit of a big hammer but multiple companies were
    independently carrying such patch downstream so clearly it's useful.
 
  - Support scheduling transmission of packets based on CLOCK_TAI.
 
  - Un-pin TCP TIMEWAIT timer to avoid it firing on CPUs later cordoned off
    using cpusets.
 
  - Support multiple L2TPv3 UDP tunnels using the same 5-tuple address.
 
  - Allow configuration of multipath hash seed, to both allow synchronizing
    hashing of two routers, and preventing partial accidental sync.
 
  - Improve TCP compliance with RFC 9293 for simultaneous connect().
 
  - Support sending NAT keepalives in IPsec ESP in UDP states. Userspace
    IKE daemon had to do this before, but the kernel can better keep
    track of it.
 
  - Support sending supervision HSR frames with MAC addresses stored in
    ProxyNodeTable when RedBox (i.e. HSR-SAN) is enabled.
 
  - Introduce IPPROTO_SMC for selecting SMC when socket is created.
 
  - Allow UDP GSO transmit from devices with no checksum offload.
 
  - openvswitch: add packet sampling via psample, separating the sampled
    traffic from "upcall" packets sent to user space for forwarding.
 
  - nf_tables: shrink memory consumption for transaction objects.
 
 Things we sprinkled into general kernel code
 --------------------------------------------
 
  - Power Sequencing subsystem (used by Qualcomm Bluetooth driver
    for QCA6390).
 
  - Add IRQ information in sysfs for auxiliary bus.
 
  - Introduce guard definition for local_lock.
 
  - Add aligned flavor of __cacheline_group_{begin, end}() markings for
    grouping fields in structures.
 
 BPF
 ---
 
  - Notify user space (via epoll) when a struct_ops object is getting
    detached/unregistered.
 
  - Add new kfuncs for a generic, open-coded bits iterator.
 
  - Enable BPF programs to declare arrays of kptr, bpf_rb_root, and
    bpf_list_head.
 
  - Support resilient split BTF which cuts down on duplication and makes
    BTF as compact as possible WRT BTF from modules.
 
  - Add support for dumping kfunc prototypes from BTF which enables both
    detecting as well as dumping compilable prototypes for kfuncs.
 
  - riscv64 BPF JIT improvements in particular to add 12-argument support
    for BPF trampolines and to utilize bpf_prog_pack for the latter.
 
  - Add the capability to offload the netfilter flowtable in XDP layer
    through kfuncs.
 
 Driver API
 ----------
 
  - Allow users to configure IRQ tresholds between which automatic IRQ
    moderation can choose.
 
  - Expand Power Sourcing (PoE) status with power, class and failure
    reason. Support setting power limits.
 
  - Track additional RSS contexts in the core, make sure configuration
    changes don't break them.
 
  - Support IPsec crypto offload for IPv6 ESP and IPv4 UDP-encapsulated ESP
    data paths.
 
  - Support updating firmware on SFP modules.
 
 Tests and tooling
 -----------------
 
  - mptcp: use net/lib.sh to manage netns.
 
  - TCP-AO and TCP-MD5: replace debug prints used by tests with
    tracepoints.
 
  - openvswitch: make test self-contained (don't depend on OvS CLI tools).
 
 Drivers
 -------
 
  - Ethernet high-speed NICs:
    - Broadcom (bnxt):
      - increase the max total outstanding PTP TX packets to 4
      - add timestamping statistics support
      - implement netdev_queue_mgmt_ops
      - support new RSS context API
    - Intel (100G, ice, idpf):
      - implement FEC statistics and dumping signal quality indicators
      - support E825C products (with 56Gbps PHYs)
    - nVidia/Mellanox:
      - support HW-GRO
      - mlx4/mlx5: support per-queue statistics via netlink
      - obey the max number of EQs setting in sub-functions
    - AMD/Solarflare:
      - support new RSS context API
    - AMD/Pensando:
      - ionic: rework fix for doorbell miss to lower overhead
        and skip it on new HW
    - Wangxun:
      - txgbe: support Flow Director perfect filters
 
  - Ethernet NICs consumer, embedded and virtual:
    - Add driver for Tehuti Networks TN40xx chips
    - Add driver for Meta's internal NIC chips
    - Add driver for Ethernet MAC on Airoha EN7581 SoCs
    - Add driver for Renesas Ethernet-TSN devices
    - Google cloud vNIC:
      - flow steering support
    - Microsoft vNIC:
      - support page sizes other than 4KB on ARM64
    - vmware vNIC:
      - support latency measurement (update to version 9)
    - VirtIO net:
      - support for Byte Queue Limits
      - support configuring thresholds for automatic IRQ moderation
      - support for AF_XDP Rx zero-copy
    - Synopsys (stmmac):
      - support for STM32MP13 SoC
      - let platforms select the right PCS implementation
    - TI:
      - icssg-prueth: add multicast filtering support
      - icssg-prueth: enable PTP timestamping and PPS
    - Renesas:
      - ravb: improve Rx performance 30-400% by using page pool,
        theaded NAPI and timer-based IRQ coalescing
      - ravb: add MII support for R-Car V4M
    - Cadence (macb):
      - macb: add ARP support to Wake-On-LAN
    - Cortina:
      - use phylib for RX and TX pause configuration
 
  - Ethernet switches:
    - nVidia/Mellanox:
      - support configuration of multipath hash seed
      - report more accurate max MTU
      - use page_pool to improve Rx performance
    - MediaTek:
      - mt7530: add support for bridge port isolation
    - Qualcomm:
      - qca8k: add support for bridge port isolation
    - Microchip:
      - lan9371/2: add 100BaseTX PHY support
    - NXP:
      - vsc73xx: implement VLAN operations
 
  - Ethernet PHYs:
    - aquantia: enable support for aqr115c
    - aquantia: add support for PHY LEDs
    - realtek: add support for rtl8224 2.5Gbps PHY
    - xpcs: add memory-mapped device support
    - add BroadR-Reach link mode and support in Broadcom's PHY driver
 
  - CAN:
    - add document for ISO 15765-2 protocol support
    - mcp251xfd: workaround for erratum DS80000789E, use timestamps
      to catch when device returns incorrect FIFO status
 
  - WiFi:
    - mac80211/cfg80211:
      - parse Transmit Power Envelope (TPE) data in mac80211 instead of
        in drivers
      - improvements for 6 GHz regulatory flexibility
      - multi-link improvements
      - support multiple radios per wiphy
      - remove DEAUTH_NEED_MGD_TX_PREP flag
    - Intel (iwlwifi):
      - bump FW API to 91 for BZ/SC devices
      - report 64-bit radiotap timestamp
      - enable P2P low latency by default
      - handle Transmit Power Envelope (TPE) advertised by AP
      - remove support for older FW for new devices
      - fast resume (keeping the device configured)
      - mvm: re-enable Multi-Link Operation (MLO)
      - aggregation (A-MSDU) optimizations
    - MediaTek (mt76):
      - mt7925 Multi-Link Operation (MLO) support
    - Qualcomm (ath10k):
      - LED support for various chipsets
    - Qualcomm (ath12k):
      - remove unsupported Tx monitor handling
      - support channel 2 in 6 GHz band
      - support Spatial Multiplexing Power Save (SMPS) in 6 GHz band
      - supprt multiple BSSID (MBSSID) and Enhanced Multi-BSSID
        Advertisements (EMA)
      - support dynamic VLAN
      - add panic handler for resetting the firmware state
      - DebugFS support for datapath statistics
      - WCN7850: support for Wake on WLAN
    - Microchip (wilc1000):
      - read MAC address during probe to make it visible to user space
      - suspend/resume improvements
    - TI (wl18xx):
      - support newer firmware versions
    - RealTek (rtw89):
      - preparation for RTL8852BE-VT support
      - Wake on WLAN support for WiFi 6 chips
      - 36-bit PCI DMA support
    - RealTek (rtlwifi):
      - RTL8192DU support
    - Broadcom (brcmfmac):
      - Management Frame Protection support (to enable WPA3)
 
  - Bluetooth:
    - qualcomm: use the power sequencer for QCA6390
    - btusb: mediatek: add ISO data transmission functions
    - hci_bcm4377: add BCM4388 support
    - btintel: add support for BlazarU core
    - btintel: add support for Whale Peak2
    - btnxpuart: add support for AW693 A1 chipset
    - btnxpuart: add support for IW615 chipset
    - btusb: add Realtek RTL8852BE support ID 0x13d3:0x3591
 
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmaWjBwACgkQMUZtbf5S
 IrvuSRAAkJuEzTRqgURBCe4eNEQde6mJJig7l2CKHwCbFiHZpRkFHf8qKbcGWbL6
 uLW33SWnKtJVDhxVKWHLq635XW7BAa80YhqGw21GDi+mIEhWXZglHj3xbXNxsMfE
 4eg/kG4BkfYWFmHaXOwVWV/mr7nXf6j7WmXNeXEi32ufE1j0OL+YlQenKnMj8yP2
 j9JmYa2Chwppng1SblHmcjmGkdNVwFhStKeCG+2K7v06wdDH/QYBlbgUv9gw/cxp
 NlW//wgiaeX40U4O3kDwt9C+LDoh+0VrDDeVdQ+IsScLtY3PhAzEoKolFYTq2HSr
 I1JpoaHNnyNsJq3DZrACQ5WlH4yDn6C2EUB6dxNnFaI9F1ZPsi+7MTl6Sei1AklD
 TuQTj/lxOACBwW2Q77NU72uoxiIUauesGPHcnrAFuoCIEhZF0mso7k59BvrXhsOP
 QwcLbQdc1YHNkqv/Vc7NBY+ruMsYB+5Ubbhhj2p27dp/CWFIwxI29fze4dn2uhO6
 ejHN3mbqwPdSzg12YJtM6Iq61Cnwo2eVSvhTxl+ZVSZtI4nu2arzR+y7QTYmNrXP
 6tkgVN9UsWeLl2xJ8wyyqL5mcvNHP2rPXWZ2X56iTaa26m+UlleeQ7YRaYtQAAr0
 Ec/vlDMX64SwHhd+qwE99DXGQf2g+KklHKSLsnajJUVrWFTlRI0=
 =opz8
 -----END PGP SIGNATURE-----

Merge tag 'net-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next

Pull networking updates from Jakub Kicinski:
 "Not much excitement - a handful of large patchsets (devmem among them)
  did not make it in time.

  Core & protocols:

   - Use local_lock in addition to local_bh_disable() to protect per-CPU
     resources in networking, a step closer for local_bh_disable() not
     to act as a big lock on PREEMPT_RT

   - Use flex array for netdevice priv area, ensure its cache alignment

   - Add a sysctl knob to allow user to specify a default rto_min at
     socket init time. Bit of a big hammer but multiple companies were
     independently carrying such patch downstream so clearly it's useful

   - Support scheduling transmission of packets based on CLOCK_TAI

   - Un-pin TCP TIMEWAIT timer to avoid it firing on CPUs later cordoned
     off using cpusets

   - Support multiple L2TPv3 UDP tunnels using the same 5-tuple address

   - Allow configuration of multipath hash seed, to both allow
     synchronizing hashing of two routers, and preventing partial
     accidental sync

   - Improve TCP compliance with RFC 9293 for simultaneous connect()

   - Support sending NAT keepalives in IPsec ESP in UDP states.
     Userspace IKE daemon had to do this before, but the kernel can
     better keep track of it

   - Support sending supervision HSR frames with MAC addresses stored in
     ProxyNodeTable when RedBox (i.e. HSR-SAN) is enabled

   - Introduce IPPROTO_SMC for selecting SMC when socket is created

   - Allow UDP GSO transmit from devices with no checksum offload

   - openvswitch: add packet sampling via psample, separating the
     sampled traffic from "upcall" packets sent to user space for
     forwarding

   - nf_tables: shrink memory consumption for transaction objects

  Things we sprinkled into general kernel code:

   - Power Sequencing subsystem (used by Qualcomm Bluetooth driver for
     QCA6390)           [ Already merged separately - Linus ]

   - Add IRQ information in sysfs for auxiliary bus

   - Introduce guard definition for local_lock

   - Add aligned flavor of __cacheline_group_{begin, end}() markings for
     grouping fields in structures

  BPF:

   - Notify user space (via epoll) when a struct_ops object is getting
     detached/unregistered

   - Add new kfuncs for a generic, open-coded bits iterator

   - Enable BPF programs to declare arrays of kptr, bpf_rb_root, and
     bpf_list_head

   - Support resilient split BTF which cuts down on duplication and
     makes BTF as compact as possible WRT BTF from modules

   - Add support for dumping kfunc prototypes from BTF which enables
     both detecting as well as dumping compilable prototypes for kfuncs

   - riscv64 BPF JIT improvements in particular to add 12-argument
     support for BPF trampolines and to utilize bpf_prog_pack for the
     latter

   - Add the capability to offload the netfilter flowtable in XDP layer
     through kfuncs

  Driver API:

   - Allow users to configure IRQ tresholds between which automatic IRQ
     moderation can choose

   - Expand Power Sourcing (PoE) status with power, class and failure
     reason. Support setting power limits

   - Track additional RSS contexts in the core, make sure configuration
     changes don't break them

   - Support IPsec crypto offload for IPv6 ESP and IPv4 UDP-encapsulated
     ESP data paths

   - Support updating firmware on SFP modules

  Tests and tooling:

   - mptcp: use net/lib.sh to manage netns

   - TCP-AO and TCP-MD5: replace debug prints used by tests with
     tracepoints

   - openvswitch: make test self-contained (don't depend on OvS CLI
     tools)

  Drivers:

   - Ethernet high-speed NICs:
      - Broadcom (bnxt):
         - increase the max total outstanding PTP TX packets to 4
         - add timestamping statistics support
         - implement netdev_queue_mgmt_ops
         - support new RSS context API
      - Intel (100G, ice, idpf):
         - implement FEC statistics and dumping signal quality indicators
         - support E825C products (with 56Gbps PHYs)
      - nVidia/Mellanox:
         - support HW-GRO
         - mlx4/mlx5: support per-queue statistics via netlink
         - obey the max number of EQs setting in sub-functions
      - AMD/Solarflare:
         - support new RSS context API
      - AMD/Pensando:
         - ionic: rework fix for doorbell miss to lower overhead and
           skip it on new HW
      - Wangxun:
         - txgbe: support Flow Director perfect filters

   - Ethernet NICs consumer, embedded and virtual:
      - Add driver for Tehuti Networks TN40xx chips
      - Add driver for Meta's internal NIC chips
      - Add driver for Ethernet MAC on Airoha EN7581 SoCs
      - Add driver for Renesas Ethernet-TSN devices
      - Google cloud vNIC:
         - flow steering support
      - Microsoft vNIC:
         - support page sizes other than 4KB on ARM64
      - vmware vNIC:
         - support latency measurement (update to version 9)
      - VirtIO net:
         - support for Byte Queue Limits
         - support configuring thresholds for automatic IRQ moderation
         - support for AF_XDP Rx zero-copy
      - Synopsys (stmmac):
         - support for STM32MP13 SoC
         - let platforms select the right PCS implementation
      - TI:
         - icssg-prueth: add multicast filtering support
         - icssg-prueth: enable PTP timestamping and PPS
      - Renesas:
         - ravb: improve Rx performance 30-400% by using page pool,
           theaded NAPI and timer-based IRQ coalescing
         - ravb: add MII support for R-Car V4M
      - Cadence (macb):
         - macb: add ARP support to Wake-On-LAN
      - Cortina:
         - use phylib for RX and TX pause configuration

   - Ethernet switches:
      - nVidia/Mellanox:
         - support configuration of multipath hash seed
         - report more accurate max MTU
         - use page_pool to improve Rx performance
      - MediaTek:
         - mt7530: add support for bridge port isolation
      - Qualcomm:
         - qca8k: add support for bridge port isolation
      - Microchip:
         - lan9371/2: add 100BaseTX PHY support
      - NXP:
         - vsc73xx: implement VLAN operations

   - Ethernet PHYs:
      - aquantia: enable support for aqr115c
      - aquantia: add support for PHY LEDs
      - realtek: add support for rtl8224 2.5Gbps PHY
      - xpcs: add memory-mapped device support
      - add BroadR-Reach link mode and support in Broadcom's PHY driver

   - CAN:
      - add document for ISO 15765-2 protocol support
      - mcp251xfd: workaround for erratum DS80000789E, use timestamps to
        catch when device returns incorrect FIFO status

   - WiFi:
      - mac80211/cfg80211:
         - parse Transmit Power Envelope (TPE) data in mac80211 instead
           of in drivers
         - improvements for 6 GHz regulatory flexibility
         - multi-link improvements
         - support multiple radios per wiphy
         - remove DEAUTH_NEED_MGD_TX_PREP flag
      - Intel (iwlwifi):
         - bump FW API to 91 for BZ/SC devices
         - report 64-bit radiotap timestamp
         - enable P2P low latency by default
         - handle Transmit Power Envelope (TPE) advertised by AP
         - remove support for older FW for new devices
         - fast resume (keeping the device configured)
         - mvm: re-enable Multi-Link Operation (MLO)
         - aggregation (A-MSDU) optimizations
      - MediaTek (mt76):
         - mt7925 Multi-Link Operation (MLO) support
      - Qualcomm (ath10k):
         - LED support for various chipsets
      - Qualcomm (ath12k):
         - remove unsupported Tx monitor handling
         - support channel 2 in 6 GHz band
         - support Spatial Multiplexing Power Save (SMPS) in 6 GHz band
         - supprt multiple BSSID (MBSSID) and Enhanced Multi-BSSID
           Advertisements (EMA)
         - support dynamic VLAN
         - add panic handler for resetting the firmware state
         - DebugFS support for datapath statistics
         - WCN7850: support for Wake on WLAN
      - Microchip (wilc1000):
         - read MAC address during probe to make it visible to user space
         - suspend/resume improvements
      - TI (wl18xx):
         - support newer firmware versions
      - RealTek (rtw89):
         - preparation for RTL8852BE-VT support
         - Wake on WLAN support for WiFi 6 chips
         - 36-bit PCI DMA support
      - RealTek (rtlwifi):
         - RTL8192DU support
      - Broadcom (brcmfmac):
         - Management Frame Protection support (to enable WPA3)

   - Bluetooth:
      - qualcomm: use the power sequencer for QCA6390
      - btusb: mediatek: add ISO data transmission functions
      - hci_bcm4377: add BCM4388 support
      - btintel: add support for BlazarU core
      - btintel: add support for Whale Peak2
      - btnxpuart: add support for AW693 A1 chipset
      - btnxpuart: add support for IW615 chipset
      - btusb: add Realtek RTL8852BE support ID 0x13d3:0x3591"

* tag 'net-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1589 commits)
  eth: fbnic: Fix spelling mistake "tiggerring" -> "triggering"
  tcp: Replace strncpy() with strscpy()
  wifi: ath12k: fix build vs old compiler
  tcp: Don't access uninit tcp_rsk(req)->ao_keyid in tcp_create_openreq_child().
  eth: fbnic: Write the TCAM tables used for RSS control and Rx to host
  eth: fbnic: Add L2 address programming
  eth: fbnic: Add basic Rx handling
  eth: fbnic: Add basic Tx handling
  eth: fbnic: Add link detection
  eth: fbnic: Add initial messaging to notify FW of our presence
  eth: fbnic: Implement Rx queue alloc/start/stop/free
  eth: fbnic: Implement Tx queue alloc/start/stop/free
  eth: fbnic: Allocate a netdevice and napi vectors with queues
  eth: fbnic: Add FW communication mechanism
  eth: fbnic: Add message parsing for FW messages
  eth: fbnic: Add register init to set PCIe/Ethernet device config
  eth: fbnic: Allocate core device specific structures and devlink interface
  eth: fbnic: Add scaffolding for Meta's NIC driver
  PCI: Add Meta Platforms vendor ID
  net/sched: cls_flower: propagate tca[TCA_OPTIONS] to NL_REQ_ATTR_CHECK
  ...
This commit is contained in:
Linus Torvalds 2024-07-16 19:28:34 -07:00
commit 51835949dd
1575 changed files with 94136 additions and 25791 deletions

View File

@ -0,0 +1,9 @@
What: /sys/bus/auxiliary/devices/.../irqs/
Date: April, 2024
Contact: Shay Drory <shayd@nvidia.com>
Description:
The /sys/devices/.../irqs directory contains a variable set of
files, with each file is named as irq number similar to PCI PF
or VF's irq number located in msi_irqs directory.
These irq files are added and removed dynamically when an IRQ
is requested and freed respectively for the PCI SF.

View File

@ -219,6 +219,14 @@ compilation and skeleton generation. Using Libbpf-rs will make building user
space part of the BPF application easier. Note that the BPF program themselves
must still be written in plain C.
libbpf logging
==============
By default, libbpf logs informational and warning messages to stderr. The
verbosity of these messages can be controlled by setting the environment
variable LIBBPF_LOG_LEVEL to either warn, info, or debug. A custom log
callback can be set using ``libbpf_set_print()``.
Additional Documentation
========================

View File

@ -23,3 +23,6 @@ The BPF calling convention is defined as:
R0 - R5 are scratch registers and BPF programs needs to spill/fill them if
necessary across calls.
The BPF program needs to store the return value into register R0 before doing an
``EXIT``.

View File

@ -5,15 +5,29 @@
BPF Instruction Set Architecture (ISA)
======================================
eBPF (which is no longer an acronym for anything), also commonly
eBPF, also commonly
referred to as BPF, is a technology with origins in the Linux kernel
that can run untrusted programs in a privileged context such as an
operating system kernel. This document specifies the BPF instruction
set architecture (ISA).
As a historical note, BPF originally stood for Berkeley Packet Filter,
but now that it can do so much more than packet filtering, the acronym
no longer makes sense. BPF is now considered a standalone term that
does not stand for anything. The original BPF is sometimes referred to
as cBPF (classic BPF) to distinguish it from the now widely deployed
eBPF (extended BPF).
Documentation conventions
=========================
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in
BCP 14 `<https://www.rfc-editor.org/info/rfc2119>`_
`<https://www.rfc-editor.org/info/rfc8174>`_
when, and only when, they appear in all capitals, as shown here.
For brevity and consistency, this document refers to families
of types using a shorthand syntax and refers to several expository,
mnemonic functions when describing the semantics of instructions.
@ -25,7 +39,7 @@ Types
This document refers to integer types with the notation `SN` to specify
a type's signedness (`S`) and bit width (`N`), respectively.
.. table:: Meaning of signedness notation.
.. table:: Meaning of signedness notation
==== =========
S Meaning
@ -34,7 +48,7 @@ a type's signedness (`S`) and bit width (`N`), respectively.
s signed
==== =========
.. table:: Meaning of bit-width notation.
.. table:: Meaning of bit-width notation
===== =========
N Bit width
@ -52,24 +66,18 @@ numbers.
Functions
---------
* htobe16: Takes an unsigned 16-bit number in host-endian format and
returns the equivalent number as an unsigned 16-bit number in big-endian
format.
* htobe32: Takes an unsigned 32-bit number in host-endian format and
returns the equivalent number as an unsigned 32-bit number in big-endian
format.
* htobe64: Takes an unsigned 64-bit number in host-endian format and
returns the equivalent number as an unsigned 64-bit number in big-endian
format.
* htole16: Takes an unsigned 16-bit number in host-endian format and
returns the equivalent number as an unsigned 16-bit number in little-endian
format.
* htole32: Takes an unsigned 32-bit number in host-endian format and
returns the equivalent number as an unsigned 32-bit number in little-endian
format.
* htole64: Takes an unsigned 64-bit number in host-endian format and
returns the equivalent number as an unsigned 64-bit number in little-endian
format.
The following byteswap functions are direction-agnostic. That is,
the same function is used for conversion in either direction discussed
below.
* be16: Takes an unsigned 16-bit number and converts it between
host byte order and big-endian
(`IEN137 <https://www.rfc-editor.org/ien/ien137.txt>`_) byte order.
* be32: Takes an unsigned 32-bit number and converts it between
host byte order and big-endian byte order.
* be64: Takes an unsigned 64-bit number and converts it between
host byte order and big-endian byte order.
* bswap16: Takes an unsigned 16-bit number in either big- or little-endian
format and returns the equivalent number with the same bit width but
opposite endianness.
@ -79,7 +87,12 @@ Functions
* bswap64: Takes an unsigned 64-bit number in either big- or little-endian
format and returns the equivalent number with the same bit width but
opposite endianness.
* le16: Takes an unsigned 16-bit number and converts it between
host byte order and little-endian byte order.
* le32: Takes an unsigned 32-bit number and converts it between
host byte order and little-endian byte order.
* le64: Takes an unsigned 64-bit number and converts it between
host byte order and little-endian byte order.
Definitions
-----------
@ -106,9 +119,9 @@ Conformance groups
An implementation does not need to support all instructions specified in this
document (e.g., deprecated instructions). Instead, a number of conformance
groups are specified. An implementation must support the base32 conformance
group and may support additional conformance groups, where supporting a
conformance group means it must support all instructions in that conformance
groups are specified. An implementation MUST support the base32 conformance
group and MAY support additional conformance groups, where supporting a
conformance group means it MUST support all instructions in that conformance
group.
The use of named conformance groups enables interoperability between a runtime
@ -209,7 +222,7 @@ For example::
07 1 0 00 00 11 22 33 44 r1 += 0x11223344 // big
Note that most instructions do not use all of the fields.
Unused fields shall be cleared to zero.
Unused fields SHALL be cleared to zero.
Wide instruction encoding
--------------------------
@ -256,18 +269,20 @@ Instruction classes
The three least significant bits of the 'opcode' field store the instruction class:
===== ===== =============================== ===================================
class value description reference
===== ===== =============================== ===================================
LD 0x0 non-standard load operations `Load and store instructions`_
LDX 0x1 load into register operations `Load and store instructions`_
ST 0x2 store from immediate operations `Load and store instructions`_
STX 0x3 store from register operations `Load and store instructions`_
ALU 0x4 32-bit arithmetic operations `Arithmetic and jump instructions`_
JMP 0x5 64-bit jump operations `Arithmetic and jump instructions`_
JMP32 0x6 32-bit jump operations `Arithmetic and jump instructions`_
ALU64 0x7 64-bit arithmetic operations `Arithmetic and jump instructions`_
===== ===== =============================== ===================================
.. table:: Instruction class
===== ===== =============================== ===================================
class value description reference
===== ===== =============================== ===================================
LD 0x0 non-standard load operations `Load and store instructions`_
LDX 0x1 load into register operations `Load and store instructions`_
ST 0x2 store from immediate operations `Load and store instructions`_
STX 0x3 store from register operations `Load and store instructions`_
ALU 0x4 32-bit arithmetic operations `Arithmetic and jump instructions`_
JMP 0x5 64-bit jump operations `Arithmetic and jump instructions`_
JMP32 0x6 32-bit jump operations `Arithmetic and jump instructions`_
ALU64 0x7 64-bit arithmetic operations `Arithmetic and jump instructions`_
===== ===== =============================== ===================================
Arithmetic and jump instructions
================================
@ -285,12 +300,14 @@ For arithmetic and jump instructions (``ALU``, ``ALU64``, ``JMP`` and
**s (source)**
the source operand location, which unless otherwise specified is one of:
====== ===== ==============================================
source value description
====== ===== ==============================================
K 0 use 32-bit 'imm' value as source operand
X 1 use 'src_reg' register value as source operand
====== ===== ==============================================
.. table:: Source operand location
====== ===== ==============================================
source value description
====== ===== ==============================================
K 0 use 32-bit 'imm' value as source operand
X 1 use 'src_reg' register value as source operand
====== ===== ==============================================
**instruction class**
the instruction class (see `Instruction classes`_)
@ -305,27 +322,29 @@ The 'code' field encodes the operation as below, where 'src' refers to the
the source operand and 'dst' refers to the value of the destination
register.
===== ===== ======= ==========================================================
name code offset description
===== ===== ======= ==========================================================
ADD 0x0 0 dst += src
SUB 0x1 0 dst -= src
MUL 0x2 0 dst \*= src
DIV 0x3 0 dst = (src != 0) ? (dst / src) : 0
SDIV 0x3 1 dst = (src != 0) ? (dst s/ src) : 0
OR 0x4 0 dst \|= src
AND 0x5 0 dst &= src
LSH 0x6 0 dst <<= (src & mask)
RSH 0x7 0 dst >>= (src & mask)
NEG 0x8 0 dst = -dst
MOD 0x9 0 dst = (src != 0) ? (dst % src) : dst
SMOD 0x9 1 dst = (src != 0) ? (dst s% src) : dst
XOR 0xa 0 dst ^= src
MOV 0xb 0 dst = src
MOVSX 0xb 8/16/32 dst = (s8,s16,s32)src
ARSH 0xc 0 :term:`sign extending<Sign Extend>` dst >>= (src & mask)
END 0xd 0 byte swap operations (see `Byte swap instructions`_ below)
===== ===== ======= ==========================================================
.. table:: Arithmetic instructions
===== ===== ======= ==========================================================
name code offset description
===== ===== ======= ==========================================================
ADD 0x0 0 dst += src
SUB 0x1 0 dst -= src
MUL 0x2 0 dst \*= src
DIV 0x3 0 dst = (src != 0) ? (dst / src) : 0
SDIV 0x3 1 dst = (src != 0) ? (dst s/ src) : 0
OR 0x4 0 dst \|= src
AND 0x5 0 dst &= src
LSH 0x6 0 dst <<= (src & mask)
RSH 0x7 0 dst >>= (src & mask)
NEG 0x8 0 dst = -dst
MOD 0x9 0 dst = (src != 0) ? (dst % src) : dst
SMOD 0x9 1 dst = (src != 0) ? (dst s% src) : dst
XOR 0xa 0 dst ^= src
MOV 0xb 0 dst = src
MOVSX 0xb 8/16/32 dst = (s8,s16,s32)src
ARSH 0xc 0 :term:`sign extending<Sign Extend>` dst >>= (src & mask)
END 0xd 0 byte swap operations (see `Byte swap instructions`_ below)
===== ===== ======= ==========================================================
Underflow and overflow are allowed during arithmetic operations, meaning
the 64-bit or 32-bit value will wrap. If BPF program execution would
@ -374,7 +393,7 @@ interpreted as a 64-bit signed value.
Note that there are varying definitions of the signed modulo operation
when the dividend or divisor are negative, where implementations often
vary by language such that Python, Ruby, etc. differ from C, Go, Java,
etc. This specification requires that signed modulo use truncated division
etc. This specification requires that signed modulo MUST use truncated division
(where -13 % 3 == -1) as implemented in C, Go, etc.::
a % n = a - n * trunc(a / n)
@ -386,6 +405,19 @@ The ``MOVSX`` instruction does a move operation with sign extension.
operands into 64-bit operands. Unlike other arithmetic instructions,
``MOVSX`` is only defined for register source operands (``X``).
``{MOV, K, ALU64}`` means::
dst = (s64)imm
``{MOV, X, ALU}`` means::
dst = (u32)src
``{MOVSX, X, ALU}`` with 'offset' 8 means::
dst = (u32)(s32)(s8)src
The ``NEG`` instruction is only defined when the source bit is clear
(``K``).
@ -404,15 +436,17 @@ only and do not use a separate source register or immediate value.
For ``ALU``, the 1-bit source operand field in the opcode is used to
select what byte order the operation converts from or to. For
``ALU64``, the 1-bit source operand field in the opcode is reserved
and must be set to 0.
and MUST be set to 0.
===== ======== ===== =================================================
class source value description
===== ======== ===== =================================================
ALU TO_LE 0 convert between host byte order and little endian
ALU TO_BE 1 convert between host byte order and big endian
ALU64 Reserved 0 do byte swap unconditionally
===== ======== ===== =================================================
.. table:: Byte swap instructions
===== ======== ===== =================================================
class source value description
===== ======== ===== =================================================
ALU LE 0 convert between host byte order and little endian
ALU BE 1 convert between host byte order and big endian
ALU64 Reserved 0 do byte swap unconditionally
===== ======== ===== =================================================
The 'imm' field encodes the width of the swap operations. The following widths
are supported: 16, 32 and 64. Width 64 operations belong to the base64
@ -421,19 +455,19 @@ conformance group.
Examples:
``{END, TO_LE, ALU}`` with 'imm' = 16/32/64 means::
``{END, LE, ALU}`` with 'imm' = 16/32/64 means::
dst = htole16(dst)
dst = htole32(dst)
dst = htole64(dst)
dst = le16(dst)
dst = le32(dst)
dst = le64(dst)
``{END, TO_BE, ALU}`` with 'imm' = 16/32/64 means::
``{END, BE, ALU}`` with 'imm' = 16/32/64 means::
dst = htobe16(dst)
dst = htobe32(dst)
dst = htobe64(dst)
dst = be16(dst)
dst = be32(dst)
dst = be64(dst)
``{END, TO_LE, ALU64}`` with 'imm' = 16/32/64 means::
``{END, TO, ALU64}`` with 'imm' = 16/32/64 means::
dst = bswap16(dst)
dst = bswap32(dst)
@ -448,27 +482,29 @@ otherwise identical operations, and indicates the base64 conformance
group unless otherwise specified.
The 'code' field encodes the operation as below:
======== ===== ======= ================================= ===================================================
code value src_reg description notes
======== ===== ======= ================================= ===================================================
JA 0x0 0x0 PC += offset {JA, K, JMP} only
JA 0x0 0x0 PC += imm {JA, K, JMP32} only
JEQ 0x1 any PC += offset if dst == src
JGT 0x2 any PC += offset if dst > src unsigned
JGE 0x3 any PC += offset if dst >= src unsigned
JSET 0x4 any PC += offset if dst & src
JNE 0x5 any PC += offset if dst != src
JSGT 0x6 any PC += offset if dst > src signed
JSGE 0x7 any PC += offset if dst >= src signed
CALL 0x8 0x0 call helper function by static ID {CALL, K, JMP} only, see `Helper functions`_
CALL 0x8 0x1 call PC += imm {CALL, K, JMP} only, see `Program-local functions`_
CALL 0x8 0x2 call helper function by BTF ID {CALL, K, JMP} only, see `Helper functions`_
EXIT 0x9 0x0 return {CALL, K, JMP} only
JLT 0xa any PC += offset if dst < src unsigned
JLE 0xb any PC += offset if dst <= src unsigned
JSLT 0xc any PC += offset if dst < src signed
JSLE 0xd any PC += offset if dst <= src signed
======== ===== ======= ================================= ===================================================
.. table:: Jump instructions
======== ===== ======= ================================= ===================================================
code value src_reg description notes
======== ===== ======= ================================= ===================================================
JA 0x0 0x0 PC += offset {JA, K, JMP} only
JA 0x0 0x0 PC += imm {JA, K, JMP32} only
JEQ 0x1 any PC += offset if dst == src
JGT 0x2 any PC += offset if dst > src unsigned
JGE 0x3 any PC += offset if dst >= src unsigned
JSET 0x4 any PC += offset if dst & src
JNE 0x5 any PC += offset if dst != src
JSGT 0x6 any PC += offset if dst > src signed
JSGE 0x7 any PC += offset if dst >= src signed
CALL 0x8 0x0 call helper function by static ID {CALL, K, JMP} only, see `Helper functions`_
CALL 0x8 0x1 call PC += imm {CALL, K, JMP} only, see `Program-local functions`_
CALL 0x8 0x2 call helper function by BTF ID {CALL, K, JMP} only, see `Helper functions`_
EXIT 0x9 0x0 return {CALL, K, JMP} only
JLT 0xa any PC += offset if dst < src unsigned
JLE 0xb any PC += offset if dst <= src unsigned
JSLT 0xc any PC += offset if dst < src signed
JSLE 0xd any PC += offset if dst <= src signed
======== ===== ======= ================================= ===================================================
where 'PC' denotes the program counter, and the offset to increment by
is in units of 64-bit instructions relative to the instruction following
@ -476,9 +512,6 @@ the jump instruction. Thus 'PC += 1' skips execution of the next
instruction if it's a basic instruction or results in undefined behavior
if the next instruction is a 128-bit wide instruction.
The BPF program needs to store the return value into register R0 before doing an
``EXIT``.
Example:
``{JSGE, X, JMP32}`` means::
@ -487,6 +520,10 @@ Example:
where 's>=' indicates a signed '>=' comparison.
``{JLE, K, JMP}`` means::
if dst <= (u64)(s64)imm goto +offset
``{JA, K, JMP32}`` means::
gotol +imm
@ -510,19 +547,25 @@ Helper functions are a concept whereby BPF programs can call into a
set of function calls exposed by the underlying platform.
Historically, each helper function was identified by a static ID
encoded in the 'imm' field. The available helper functions may differ
for each program type, but static IDs are unique across all program types.
encoded in the 'imm' field. Further documentation of helper functions
is outside the scope of this document and standardization is left for
future work, but use is widely deployed and more information can be
found in platform-specific documentation (e.g., Linux kernel documentation).
Platforms that support the BPF Type Format (BTF) support identifying
a helper function by a BTF ID encoded in the 'imm' field, where the BTF ID
identifies the helper name and type.
identifies the helper name and type. Further documentation of BTF
is outside the scope of this document and standardization is left for
future work, but use is widely deployed and more information can be
found in platform-specific documentation (e.g., Linux kernel documentation).
Program-local functions
~~~~~~~~~~~~~~~~~~~~~~~
Program-local functions are functions exposed by the same BPF program as the
caller, and are referenced by offset from the call instruction, similar to
``JA``. The offset is encoded in the 'imm' field of the call instruction.
An ``EXIT`` within the program-local function will return to the caller.
caller, and are referenced by offset from the instruction following the call
instruction, similar to ``JA``. The offset is encoded in the 'imm' field of
the call instruction. An ``EXIT`` within the program-local function will
return to the caller.
Load and store instructions
===========================
@ -537,6 +580,8 @@ For load and store instructions (``LD``, ``LDX``, ``ST``, and ``STX``), the
**mode**
The mode modifier is one of:
.. table:: Mode modifier
============= ===== ==================================== =============
mode modifier value description reference
============= ===== ==================================== =============
@ -551,6 +596,8 @@ For load and store instructions (``LD``, ``LDX``, ``ST``, and ``STX``), the
**sz (size)**
The size modifier is one of:
.. table:: Size modifier
==== ===== =====================
size value description
==== ===== =====================
@ -619,14 +666,16 @@ The 'imm' field is used to encode the actual atomic operation.
Simple atomic operation use a subset of the values defined to encode
arithmetic operations in the 'imm' field to encode the atomic operation:
======== ===== ===========
imm value description
======== ===== ===========
ADD 0x00 atomic add
OR 0x40 atomic or
AND 0x50 atomic and
XOR 0xa0 atomic xor
======== ===== ===========
.. table:: Simple atomic operations
======== ===== ===========
imm value description
======== ===== ===========
ADD 0x00 atomic add
OR 0x40 atomic or
AND 0x50 atomic and
XOR 0xa0 atomic xor
======== ===== ===========
``{ATOMIC, W, STX}`` with 'imm' = ADD means::
@ -640,13 +689,15 @@ XOR 0xa0 atomic xor
In addition to the simple atomic operations, there also is a modifier and
two complex atomic operations:
=========== ================ ===========================
imm value description
=========== ================ ===========================
FETCH 0x01 modifier: return old value
XCHG 0xe0 | FETCH atomic exchange
CMPXCHG 0xf0 | FETCH atomic compare and exchange
=========== ================ ===========================
.. table:: Complex atomic operations
=========== ================ ===========================
imm value description
=========== ================ ===========================
FETCH 0x01 modifier: return old value
XCHG 0xe0 | FETCH atomic exchange
CMPXCHG 0xf0 | FETCH atomic compare and exchange
=========== ================ ===========================
The ``FETCH`` modifier is optional for simple atomic operations, and
always set for the complex atomic operations. If the ``FETCH`` flag
@ -673,17 +724,19 @@ The following table defines a set of ``{IMM, DW, LD}`` instructions
with opcode subtypes in the 'src_reg' field, using new terms such as "map"
defined further below:
======= ========================================= =========== ==============
src_reg pseudocode imm type dst type
======= ========================================= =========== ==============
0x0 dst = (next_imm << 32) | imm integer integer
0x1 dst = map_by_fd(imm) map fd map
0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data address
0x3 dst = var_addr(imm) variable id data address
0x4 dst = code_addr(imm) integer code address
0x5 dst = map_by_idx(imm) map index map
0x6 dst = map_val(map_by_idx(imm)) + next_imm map index data address
======= ========================================= =========== ==============
.. table:: 64-bit immediate instructions
======= ========================================= =========== ==============
src_reg pseudocode imm type dst type
======= ========================================= =========== ==============
0x0 dst = (next_imm << 32) | imm integer integer
0x1 dst = map_by_fd(imm) map fd map
0x2 dst = map_val(map_by_fd(imm)) + next_imm map fd data address
0x3 dst = var_addr(imm) variable id data address
0x4 dst = code_addr(imm) integer code address
0x5 dst = map_by_idx(imm) map index map
0x6 dst = map_val(map_by_idx(imm)) + next_imm map index data address
======= ========================================= =========== ==============
where
@ -725,5 +778,5 @@ carried over from classic BPF. These instructions used an instruction
class of ``LD``, a size modifier of ``W``, ``H``, or ``B``, and a
mode modifier of ``ABS`` or ``IND``. The 'dst_reg' and 'offset' fields were
set to zero, and 'src_reg' was set to zero for ``ABS``. However, these
instructions are deprecated and should no longer be used. All legacy packet
instructions are deprecated and SHOULD no longer be used. All legacy packet
access instructions belong to the "packet" conformance group.

View File

@ -0,0 +1,143 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/airoha,en7581-eth.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Airoha EN7581 Frame Engine Ethernet controller
maintainers:
- Lorenzo Bianconi <lorenzo@kernel.org>
description:
The frame engine ethernet controller can be found on Airoha SoCs.
These SoCs have multi-GMAC ports.
properties:
compatible:
enum:
- airoha,en7581-eth
reg:
items:
- description: Frame engine base address
- description: QDMA0 base address
- description: QDMA1 base address
reg-names:
items:
- const: fe
- const: qdma0
- const: qdma1
interrupts:
items:
- description: QDMA lan irq0
- description: QDMA lan irq1
- description: QDMA lan irq2
- description: QDMA lan irq3
- description: QDMA wan irq0
- description: QDMA wan irq1
- description: QDMA wan irq2
- description: QDMA wan irq3
- description: FE error irq
- description: PDMA irq
resets:
maxItems: 8
reset-names:
items:
- const: fe
- const: pdma
- const: qdma
- const: xsi-mac
- const: hsi0-mac
- const: hsi1-mac
- const: hsi-mac
- const: xfp-mac
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^ethernet@[1-4]$":
type: object
unevaluatedProperties: false
$ref: ethernet-controller.yaml#
description:
Ethernet GMAC port associated to the MAC controller
properties:
compatible:
const: airoha,eth-mac
reg:
minimum: 1
maximum: 4
description: GMAC port identifier
required:
- reg
- compatible
required:
- compatible
- reg
- interrupts
- resets
- reset-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/en7523-clk.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
eth: ethernet@1fb50000 {
compatible = "airoha,en7581-eth";
reg = <0 0x1fb50000 0 0x2600>,
<0 0x1fb54000 0 0x2000>,
<0 0x1fb56000 0 0x2000>;
reg-names = "fe", "qdma0", "qdma1";
resets = <&scuclk 44>,
<&scuclk 30>,
<&scuclk 31>,
<&scuclk 6>,
<&scuclk 15>,
<&scuclk 16>,
<&scuclk 17>,
<&scuclk 26>;
reset-names = "fe", "pdma", "qdma", "xsi-mac",
"hsi0-mac", "hsi1-mac", "hsi-mac",
"xfp-mac";
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
mac: ethernet@1 {
compatible = "airoha,eth-mac";
reg = <1>;
};
};
};

View File

@ -1,46 +0,0 @@
* Synopsys ARC EMAC 10/100 Ethernet driver (EMAC)
Required properties:
- compatible: Should be "snps,arc-emac"
- reg: Address and length of the register set for the device
- interrupts: Should contain the EMAC interrupts
- max-speed: see ethernet.txt file in the same directory.
- phy: see ethernet.txt file in the same directory.
Optional properties:
- phy-reset-gpios : Should specify the gpio for phy reset
- phy-reset-duration : Reset duration in milliseconds. Should present
only if property "phy-reset-gpios" is available. Missing the property
will have the duration be 1 millisecond. Numbers greater than 1000 are
invalid and 1 millisecond will be used instead.
Clock handling:
The clock frequency is needed to calculate and set polling period of EMAC.
It must be provided by one of:
- clock-frequency: CPU frequency.
- clocks: reference to the clock supplying the EMAC.
Child nodes of the driver are the individual PHY devices connected to the
MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus.
Examples:
ethernet@c0fc2000 {
compatible = "snps,arc-emac";
reg = <0xc0fc2000 0x3c>;
interrupts = <6>;
mac-address = [ 00 11 22 33 44 55 ];
clock-frequency = <80000000>;
/* or */
clocks = <&emac_clock>;
max-speed = <100>;
phy = <&phy0>;
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
reg = <1>;
};
};

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/bluetooth/mediatek,mt7622-bluetooth.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek SoC built-in Bluetooth
description:
This device is a serial attached device to BTIF device and thus it must be a
child node of the serial node with BTIF. The dt-bindings details for BTIF
device can be known via Documentation/devicetree/bindings/serial/8250.yaml.
maintainers:
- Sean Wang <sean.wang@mediatek.com>
allOf:
- $ref: bluetooth-controller.yaml#
properties:
compatible:
const: mediatek,mt7622-bluetooth
clocks:
maxItems: 1
clock-names:
const: ref
power-domains:
maxItems: 1
required:
- clocks
- clock-names
- power-domains
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/power/mt7622-power.h>
serial {
bluetooth {
compatible = "mediatek,mt7622-bluetooth";
power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
clocks = <&clk25m>;
clock-names = "ref";
};
};

View File

@ -31,6 +31,9 @@ properties:
This property depends on the module vendor's
configuration.
firmware-name:
maxItems: 1
required:
- compatible
@ -42,5 +45,6 @@ examples:
bluetooth {
compatible = "nxp,88w8987-bt";
fw-init-baudrate = <3000000>;
firmware-name = "uartuart8987_bt_v0.bin";
};
};

View File

@ -62,6 +62,9 @@ properties:
vdddig-supply:
description: VDD_DIG supply regulator handle
vddbtcmx-supply:
description: VDD_BT_CMX supply regulator handle
vddbtcxmx-supply:
description: VDD_BT_CXMX supply regulator handle
@ -74,6 +77,9 @@ properties:
vddrfa1p7-supply:
description: VDD_RFA_1P7 supply regulator handle
vddrfa1p8-supply:
description: VDD_RFA_1P8 supply regulator handle
vddrfa1p2-supply:
description: VDD_RFA_1P2 supply regulator handle
@ -86,6 +92,12 @@ properties:
vddasd-supply:
description: VDD_ASD supply regulator handle
vddwlcx-supply:
description: VDD_WLCX supply regulator handle
vddwlmx-supply:
description: VDD_WLMX supply regulator handle
max-speed:
description: see Documentation/devicetree/bindings/serial/serial.yaml
@ -176,14 +188,27 @@ allOf:
- qcom,wcn7850-bt
then:
required:
- enable-gpios
- swctrl-gpios
- vddio-supply
- vddrfacmn-supply
- vddaon-supply
- vdddig-supply
- vddwlcx-supply
- vddwlmx-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p9-supply
- vddrfa1p8-supply
- if:
properties:
compatible:
contains:
enum:
- qcom,qca6390-bt
then:
required:
- vddrfacmn-supply
- vddaon-supply
- vddbtcmx-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p7-supply
examples:
- |

View File

@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/net/can/xilinx,can.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title:
Xilinx Axi CAN/Zynq CANPS controller
Xilinx CAN and CANFD controller
maintainers:
- Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>

View File

@ -146,6 +146,7 @@ patternProperties:
magic-packet:
type: boolean
deprecated: true
description:
Indicates that the hardware supports waking up via magic packet.

View File

@ -0,0 +1,202 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/dsa/lantiq,gswip.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Lantiq GSWIP Ethernet switches
allOf:
- $ref: dsa.yaml#/$defs/ethernet-ports
maintainers:
- Hauke Mehrtens <hauke@hauke-m.de>
properties:
compatible:
enum:
- lantiq,xrx200-gswip
- lantiq,xrx300-gswip
- lantiq,xrx330-gswip
reg:
minItems: 3
maxItems: 3
reg-names:
items:
- const: switch
- const: mdio
- const: mii
mdio:
$ref: /schemas/net/mdio.yaml#
unevaluatedProperties: false
properties:
compatible:
const: lantiq,xrx200-mdio
required:
- compatible
gphy-fw:
type: object
properties:
'#address-cells':
const: 1
'#size-cells':
const: 0
compatible:
items:
- enum:
- lantiq,xrx200-gphy-fw
- lantiq,xrx300-gphy-fw
- lantiq,xrx330-gphy-fw
- const: lantiq,gphy-fw
lantiq,rcu:
$ref: /schemas/types.yaml#/definitions/phandle
description: phandle to the RCU syscon
patternProperties:
"^gphy@[0-9a-f]{1,2}$":
type: object
additionalProperties: false
properties:
reg:
minimum: 0
maximum: 255
description:
Offset of the GPHY firmware register in the RCU register range
resets:
items:
- description: GPHY reset line
reset-names:
items:
- const: gphy
required:
- reg
required:
- compatible
- lantiq,rcu
additionalProperties: false
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
switch@e108000 {
compatible = "lantiq,xrx200-gswip";
reg = <0xe108000 0x3100>, /* switch */
<0xe10b100 0xd8>, /* mdio */
<0xe10b1d8 0x130>; /* mii */
dsa,member = <0 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan3";
phy-mode = "rgmii";
phy-handle = <&phy0>;
};
port@1 {
reg = <1>;
label = "lan4";
phy-mode = "rgmii";
phy-handle = <&phy1>;
};
port@2 {
reg = <2>;
label = "lan2";
phy-mode = "internal";
phy-handle = <&phy11>;
};
port@4 {
reg = <4>;
label = "lan1";
phy-mode = "internal";
phy-handle = <&phy13>;
};
port@5 {
reg = <5>;
label = "wan";
phy-mode = "rgmii";
phy-handle = <&phy5>;
};
port@6 {
reg = <0x6>;
phy-mode = "internal";
ethernet = <&eth0>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "lantiq,xrx200-mdio";
phy0: ethernet-phy@0 {
reg = <0x0>;
};
phy1: ethernet-phy@1 {
reg = <0x1>;
};
phy5: ethernet-phy@5 {
reg = <0x5>;
};
phy11: ethernet-phy@11 {
reg = <0x11>;
};
phy13: ethernet-phy@13 {
reg = <0x13>;
};
};
gphy-fw {
#address-cells = <1>;
#size-cells = <0>;
compatible = "lantiq,xrx200-gphy-fw", "lantiq,gphy-fw";
lantiq,rcu = <&rcu0>;
gphy@20 {
reg = <0x20>;
resets = <&reset0 31 30>;
reset-names = "gphy";
};
gphy@68 {
reg = <0x68>;
resets = <&reset0 29 28>;
reset-names = "gphy";
};
};
};

View File

@ -1,146 +0,0 @@
Lantiq GSWIP Ethernet switches
==================================
Required properties for GSWIP core:
- compatible : "lantiq,xrx200-gswip" for the embedded GSWIP in the
xRX200 SoC
"lantiq,xrx300-gswip" for the embedded GSWIP in the
xRX300 SoC
"lantiq,xrx330-gswip" for the embedded GSWIP in the
xRX330 SoC
- reg : memory range of the GSWIP core registers
: memory range of the GSWIP MDIO registers
: memory range of the GSWIP MII registers
See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of
additional required and optional properties.
Required properties for MDIO bus:
- compatible : "lantiq,xrx200-mdio" for the MDIO bus inside the GSWIP
core of the xRX200 SoC and the PHYs connected to it.
See Documentation/devicetree/bindings/net/mdio.txt for a list of additional
required and optional properties.
Required properties for GPHY firmware loading:
- compatible : "lantiq,xrx200-gphy-fw", "lantiq,gphy-fw"
"lantiq,xrx300-gphy-fw", "lantiq,gphy-fw"
"lantiq,xrx330-gphy-fw", "lantiq,gphy-fw"
for the loading of the firmware into the embedded
GPHY core of the SoC.
- lantiq,rcu : reference to the rcu syscon
The GPHY firmware loader has a list of GPHY entries, one for each
embedded GPHY
- reg : Offset of the GPHY firmware register in the RCU
register range
- resets : list of resets of the embedded GPHY
- reset-names : list of names of the resets
Example:
Ethernet switch on the VRX200 SoC:
switch@e108000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "lantiq,xrx200-gswip";
reg = < 0xe108000 0x3100 /* switch */
0xe10b100 0xd8 /* mdio */
0xe10b1d8 0x130 /* mii */
>;
dsa,member = <0 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan3";
phy-mode = "rgmii";
phy-handle = <&phy0>;
};
port@1 {
reg = <1>;
label = "lan4";
phy-mode = "rgmii";
phy-handle = <&phy1>;
};
port@2 {
reg = <2>;
label = "lan2";
phy-mode = "internal";
phy-handle = <&phy11>;
};
port@4 {
reg = <4>;
label = "lan1";
phy-mode = "internal";
phy-handle = <&phy13>;
};
port@5 {
reg = <5>;
label = "wan";
phy-mode = "rgmii";
phy-handle = <&phy5>;
};
port@6 {
reg = <0x6>;
ethernet = <&eth0>;
};
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "lantiq,xrx200-mdio";
reg = <0>;
phy0: ethernet-phy@0 {
reg = <0x0>;
};
phy1: ethernet-phy@1 {
reg = <0x1>;
};
phy5: ethernet-phy@5 {
reg = <0x5>;
};
phy11: ethernet-phy@11 {
reg = <0x11>;
};
phy13: ethernet-phy@13 {
reg = <0x13>;
};
};
gphy-fw {
compatible = "lantiq,xrx200-gphy-fw", "lantiq,gphy-fw";
lantiq,rcu = <&rcu0>;
#address-cells = <1>;
#size-cells = <0>;
gphy@20 {
reg = <0x20>;
resets = <&reset0 31 30>;
reset-names = "gphy";
};
gphy@68 {
reg = <0x68>;
resets = <&reset0 29 28>;
reset-names = "gphy";
};
};
};

View File

@ -22,16 +22,16 @@ description: |
The MT7988 SoC comes with a built-in switch similar to MT7531 as well as four
Gigabit Ethernet PHYs. The switch registers are directly mapped into the SoC's
memory map rather than using MDIO. The switch got an internally connected 10G
memory map rather than using MDIO. The switch has an internally connected 10G
CPU port and 4 user ports connected to the built-in Gigabit Ethernet PHYs.
MT7530 in MT7620AN, MT7620DA, MT7620DAN and MT7620NN SoCs has got 10/100 PHYs
The MT7530 in MT7620AN, MT7620DA, MT7620DAN and MT7620NN SoCs has 10/100 PHYs
and the switch registers are directly mapped into SoC's memory map rather than
using MDIO. The DSA driver currently doesn't support MT7620 variants.
There is only the standalone version of MT7531.
Port 5 on MT7530 has got various ways of configuration:
Port 5 on MT7530 supports various configurations:
- Port 5 can be used as a CPU port.

View File

@ -1,129 +0,0 @@
Vitesse VSC73xx Switches
========================
This defines device tree bindings for the Vitesse VSC73xx switch chips.
The Vitesse company has been acquired by Microsemi and Microsemi has
been acquired Microchip but retains this vendor branding.
The currently supported switch chips are:
Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
This switch could have two different management interface.
If SPI interface is used, the device tree node is an SPI device so it must
reside inside a SPI bus device tree node, see spi/spi-bus.txt
When the chip is connected to a parallel memory bus and work in memory-mapped
I/O mode, a platform device is used to represent the vsc73xx. In this case it
must reside inside a platform bus device tree node.
Required properties:
- compatible: must be exactly one of:
"vitesse,vsc7385"
"vitesse,vsc7388"
"vitesse,vsc7395"
"vitesse,vsc7398"
- gpio-controller: indicates that this switch is also a GPIO controller,
see gpio/gpio.txt
- #gpio-cells: this must be set to <2> and indicates that we are a twocell
GPIO controller, see gpio/gpio.txt
Optional properties:
- reset-gpios: a handle to a GPIO line that can issue reset of the chip.
It should be tagged as active low.
Required subnodes:
See net/dsa/dsa.txt for a list of additional required and optional properties
and subnodes of DSA switches.
Examples:
SPI:
switch@0 {
compatible = "vitesse,vsc7395";
reg = <0>;
/* Specified for 2.5 MHz or below */
spi-max-frequency = <2500000>;
gpio-controller;
#gpio-cells = <2>;
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";
};
vsc: port@6 {
reg = <6>;
ethernet = <&gmac1>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
};
Platform:
switch@2,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "vitesse,vsc7385";
reg = <0x2 0x0 0x20000>;
reset-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
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";
};
vsc: port@6 {
reg = <6>;
ethernet = <&enet0>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
};

View File

@ -0,0 +1,162 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/dsa/vitesse,vsc73xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Vitesse VSC73xx DSA Switches
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description:
The Vitesse DSA Switches were produced in the early-to-mid 2000s.
The Vitesse company has been acquired by Microsemi and Microsemi has
been acquired Microchip but the new owner retains this vendor branding.
The currently supported switch chips are
Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
This switch can use one of two different management interfaces.
If SPI interface is used, the device tree node is an SPI device so it must
reside inside a SPI bus device tree node, see spi/spi-bus.txt
When the chip is connected to a parallel memory bus and work in memory-mapped
I/O mode, a platform device is used to represent the vsc73xx. In this case it
must reside inside a platform bus device tree node.
properties:
compatible:
enum:
- vitesse,vsc7385
- vitesse,vsc7388
- vitesse,vsc7395
- vitesse,vsc7398
reg:
maxItems: 1
gpio-controller: true
"#gpio-cells":
const: 2
reset-gpios:
description: GPIO to be used to reset the whole device
maxItems: 1
allOf:
- $ref: dsa.yaml#/$defs/ethernet-ports
# This checks if reg is a chipselect so the device is on an SPI
# bus, the if-clause will fail if reg is a tuple such as for a
# platform device.
if:
properties:
reg:
minimum: 0
maximum: 256
then:
$ref: /schemas/spi/spi-peripheral-props.yaml#
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
ethernet-switch@0 {
compatible = "vitesse,vsc7395";
reg = <0>;
spi-max-frequency = <2500000>;
gpio-controller;
#gpio-cells = <2>;
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
ethernet-port@0 {
reg = <0>;
label = "lan1";
};
ethernet-port@1 {
reg = <1>;
label = "lan2";
};
ethernet-port@2 {
reg = <2>;
label = "lan3";
};
ethernet-port@3 {
reg = <3>;
label = "lan4";
};
ethernet-port@6 {
reg = <6>;
ethernet = <&gmac1>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
};
};
bus {
#address-cells = <1>;
#size-cells = <1>;
ethernet-switch@10000000 {
compatible = "vitesse,vsc7385";
reg = <0x10000000 0x20000>;
reset-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
ethernet-port@0 {
reg = <0>;
label = "lan1";
};
ethernet-port@1 {
reg = <1>;
label = "lan2";
};
ethernet-port@2 {
reg = <2>;
label = "lan3";
};
ethernet-port@3 {
reg = <3>;
label = "lan4";
};
ethernet-port@6 {
reg = <6>;
ethernet = <&enet0>;
phy-mode = "rgmii";
fixed-link {
speed = <1000>;
full-duplex;
pause;
};
};
};
};
};

View File

@ -103,6 +103,7 @@ properties:
- usxgmii
- 10gbase-r
- 25gbase-r
- 10g-qxgmii
phy-mode:
$ref: "#/properties/phy-connection-type"

View File

@ -93,6 +93,14 @@ properties:
the turn around line low at end of the control phase of the
MDIO transaction.
brr-mode:
$ref: /schemas/types.yaml#/definitions/flag
description:
If set, indicates the network cable interface is an alternative one as
defined in the BroadR-Reach link mode specification under 1BR-100 and
1BR-10 names. The PHY must be configured to operate in BroadR-Reach mode
by software.
clocks:
maxItems: 1
description:

View File

@ -0,0 +1,38 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,enetc-ierb.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Integrated Endpoint Register Block
description:
The fsl_enetc driver can probe on the Integrated Endpoint Register Block,
which preconfigures the FIFO limits for the ENETC ports.
maintainers:
- Frank Li <Frank.Li@nxp.com>
- Vladimir Oltean <vladimir.oltean@nxp.com>
- Wei Fang <wei.fang@nxp.com>
- Claudiu Manoil <claudiu.manoil@nxp.com>
properties:
compatible:
enum:
- fsl,ls1028a-enetc-ierb
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
endpoint-config@f0800000 {
compatible = "fsl,ls1028a-enetc-ierb";
reg = <0xf0800000 0x10000>;
};

View File

@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,enetc-mdio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ENETC external MDIO PCIe endpoint device
description:
NETC provides an external master MDIO interface (EMDIO) for managing external
devices (PHYs). EMDIO supports both Clause 22 and 45 protocols. And the EMDIO
provides a means for different software modules to share a single set of MDIO
signals to access their PHYs.
maintainers:
- Frank Li <Frank.Li@nxp.com>
- Vladimir Oltean <vladimir.oltean@nxp.com>
- Wei Fang <wei.fang@nxp.com>
- Claudiu Manoil <claudiu.manoil@nxp.com>
properties:
compatible:
items:
- enum:
- pci1957,ee01
- const: fsl,enetc-mdio
reg:
maxItems: 1
required:
- compatible
- reg
allOf:
- $ref: mdio.yaml
- $ref: /schemas/pci/pci-device.yaml
unevaluatedProperties: false
examples:
- |
pcie{
#address-cells = <3>;
#size-cells = <2>;
mdio@0,3 {
compatible = "pci1957,ee01", "fsl,enetc-mdio";
reg = <0x000300 0 0 0 0>;
#address-cells = <1>;
#size-cells = <0>;
ethernet-phy@2 {
reg = <0x2>;
};
};
};

View File

@ -0,0 +1,66 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,enetc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: The NIC functionality of NXP NETC
description:
The NIC functionality in NETC is known as EtherNET Controller (ENETC). ENETC
supports virtualization/isolation based on PCIe Single Root IO Virtualization
(SR-IOV), advanced QoS with 8 traffic classes and 4 drop resilience levels,
and a full range of TSN standards and NIC offload capabilities
maintainers:
- Frank Li <Frank.Li@nxp.com>
- Vladimir Oltean <vladimir.oltean@nxp.com>
- Wei Fang <wei.fang@nxp.com>
- Claudiu Manoil <claudiu.manoil@nxp.com>
properties:
compatible:
items:
- enum:
- pci1957,e100
- const: fsl,enetc
reg:
maxItems: 1
mdio:
$ref: mdio.yaml
unevaluatedProperties: false
description: Optional child node for ENETC instance, otherwise use NETC EMDIO.
required:
- compatible
- reg
allOf:
- $ref: /schemas/pci/pci-device.yaml
- $ref: ethernet-controller.yaml
unevaluatedProperties: false
examples:
- |
pcie {
#address-cells = <3>;
#size-cells = <2>;
ethernet@0,0 {
compatible = "pci1957,e100", "fsl,enetc";
reg = <0x000000 0 0 0 0>;
phy-handle = <&sgmii_phy0>;
phy-connection-type = "sgmii";
mdio {
#address-cells = <1>;
#size-cells = <0>;
phy@2 {
reg = <0x2>;
};
};
};
};

View File

@ -0,0 +1,123 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,fman-mdio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Frame Manager MDIO Device
maintainers:
- Frank Li <Frank.Li@nxp.com>
description: FMan MDIO Node.
The MDIO is a bus to which the PHY devices are connected.
properties:
compatible:
enum:
- fsl,fman-mdio
- fsl,fman-xmdio
- fsl,fman-memac-mdio
description:
Must include "fsl,fman-mdio" for 1 Gb/s MDIO from FMan v2.
Must include "fsl,fman-xmdio" for 10 Gb/s MDIO from FMan v2.
Must include "fsl,fman-memac-mdio" for 1/10 Gb/s MDIO from
FMan v3.
reg:
maxItems: 1
clocks:
items:
- description: A reference to the input clock of the controller
from which the MDC frequency is derived.
interrupts:
maxItems: 1
fsl,fman-internal-mdio:
$ref: /schemas/types.yaml#/definitions/flag
description:
Fman has internal MDIO for internal PCS(Physical
Coding Sublayer) PHYs and external MDIO for external PHYs.
The settings and programming routines for internal/external
MDIO are different. Must be included for internal MDIO.
fsl,erratum-a009885:
$ref: /schemas/types.yaml#/definitions/flag
description: Indicates the presence of the A009885
erratum describing that the contents of MDIO_DATA may
become corrupt unless it is read within 16 MDC cycles
of MDIO_CFG[BSY] being cleared, when performing an
MDIO read operation.
fsl,erratum-a011043:
$ref: /schemas/types.yaml#/definitions/flag
description:
Indicates the presence of the A011043 erratum
describing that the MDIO_CFG[MDIO_RD_ER] bit may be falsely
set when reading internal PCS registers. MDIO reads to
internal PCS registers may result in having the
MDIO_CFG[MDIO_RD_ER] bit set, even when there is no error and
read data (MDIO_DATA[MDIO_DATA]) is correct.
Software may get false read error when reading internal
PCS registers through MDIO. As a workaround, all internal
MDIO accesses should ignore the MDIO_CFG[MDIO_RD_ER] bit.
For internal PHY device on internal mdio bus, a PHY node should be created.
See the definition of the PHY node in booting-without-of.txt for an
example of how to define a PHY (Internal PHY has no interrupt line).
- For "fsl,fman-mdio" compatible internal mdio bus, the PHY is TBI PHY.
- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY.
The PCS PHY address should correspond to the value of the appropriate
MDEV_PORT.
little-endian:
$ref: /schemas/types.yaml#/definitions/flag
description:
IP block is little-endian mode. The default endian mode is big-endian.
required:
- compatible
- reg
allOf:
- $ref: mdio.yaml#
unevaluatedProperties: false
examples:
- |
mdio@f1000 {
compatible = "fsl,fman-xmdio";
reg = <0xf1000 0x1000>;
interrupts = <101 2 0 0>;
};
- |
mdio@e3120 {
compatible = "fsl,fman-mdio";
reg = <0xe3120 0xee0>;
fsl,fman-internal-mdio;
#address-cells = <1>;
#size-cells = <0>;
tbi-phy@8 {
reg = <0x8>;
device_type = "tbi-phy";
};
};
- |
mdio@f1000 {
compatible = "fsl,fman-memac-mdio";
reg = <0xf1000 0x1000>;
fsl,fman-internal-mdio;
#address-cells = <1>;
#size-cells = <0>;
pcsphy6: ethernet-phy@0 {
reg = <0x0>;
};
};

View File

@ -0,0 +1,40 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,fman-muram.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Frame Manager MURAM Device
maintainers:
- Frank Li <Frank.Li@nxp.com>
description: |
FMan Internal memory - shared between all the FMan modules.
It contains data structures that are common and written to or read by
the modules.
FMan internal memory is split into the following parts:
Packet buffering (Tx/Rx FIFOs)
Frames internal context
properties:
compatible:
enum:
- fsl,fman-muram
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
muram@0 {
compatible = "fsl,fman-muram";
reg = <0x0 0x28000>;
};

View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,fman-port.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Frame Manager Port Device
maintainers:
- Frank Li <Frank.Li@nxp.com>
description: |
The Frame Manager (FMan) supports several types of hardware ports:
Ethernet receiver (RX)
Ethernet transmitter (TX)
Offline/Host command (O/H)
properties:
compatible:
enum:
- fsl,fman-v2-port-oh
- fsl,fman-v2-port-rx
- fsl,fman-v2-port-tx
- fsl,fman-v3-port-oh
- fsl,fman-v3-port-rx
- fsl,fman-v3-port-tx
cell-index:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Specifies the hardware port id.
Each hardware port on the FMan has its own hardware PortID.
Super set of all hardware Port IDs available at FMan Reference
Manual under "FMan Hardware Ports in Freescale Devices" table.
Each hardware port is assigned a 4KB, port-specific page in
the FMan hardware port memory region (which is part of the
FMan memory map). The first 4 KB in the FMan hardware ports
memory region is used for what are called common registers.
The subsequent 63 4KB pages are allocated to the hardware
ports.
The page of a specific port is determined by the cell-index.
reg:
items:
- description: There is one reg region describing the port
configuration registers.
fsl,fman-10g-port:
$ref: /schemas/types.yaml#/definitions/flag
description: The default port rate is 1G.
If this property exists, the port is s 10G port.
fsl,fman-best-effort-port:
$ref: /schemas/types.yaml#/definitions/flag
description: The default port rate is 1G.
Can be defined only if 10G-support is set.
This property marks a best-effort 10G port (10G port that
may not be capable of line rate).
required:
- compatible
- reg
- cell-index
additionalProperties: false
examples:
- |
port@a8000 {
compatible = "fsl,fman-v2-port-tx";
reg = <0xa8000 0x1000>;
cell-index = <0x28>;
};

View File

@ -0,0 +1,210 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/fsl,fman.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Frame Manager Device
maintainers:
- Frank Li <Frank.Li@nxp.com>
description:
Due to the fact that the FMan is an aggregation of sub-engines (ports, MACs,
etc.) the FMan node will have child nodes for each of them.
properties:
compatible:
enum:
- fsl,fman
description:
FMan version can be determined via FM_IP_REV_1 register in the
FMan block. The offset is 0xc4 from the beginning of the
Frame Processing Manager memory map (0xc3000 from the
beginning of the FMan node).
cell-index:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Specifies the index of the FMan unit.
The cell-index value may be used by the SoC, to identify the
FMan unit in the SoC memory map. In the table below,
there's a description of the cell-index use in each SoC:
- P1023:
register[bit] FMan unit cell-index
============================================================
DEVDISR[1] 1 0
- P2041, P3041, P4080 P5020, P5040:
register[bit] FMan unit cell-index
============================================================
DCFG_DEVDISR2[6] 1 0
DCFG_DEVDISR2[14] 2 1
(Second FM available only in P4080 and P5040)
- B4860, T1040, T2080, T4240:
register[bit] FMan unit cell-index
============================================================
DCFG_CCSR_DEVDISR2[24] 1 0
DCFG_CCSR_DEVDISR2[25] 2 1
(Second FM available only in T4240)
DEVDISR, DCFG_DEVDISR2 and DCFG_CCSR_DEVDISR2 are located in
the specific SoC "Device Configuration/Pin Control" Memory
Map.
reg:
items:
- description: BMI configuration registers.
- description: QMI configuration registers.
- description: DMA configuration registers.
- description: FPM configuration registers.
- description: FMan controller configuration registers.
minItems: 1
ranges: true
clocks:
maxItems: 1
clock-names:
items:
- const: fmanclk
interrupts:
items:
- description: The first element is associated with the event interrupts.
- description: the second element is associated with the error interrupts.
dma-coherent: true
ptimer-handle:
$ref: /schemas/types.yaml#/definitions/phandle
description: see ptp/fsl,ptp.yaml
fsl,qman-channel-range:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Specifies the range of the available dedicated
channels in the FMan. The first cell specifies the beginning
of the range and the second cell specifies the number of
channels
items:
- description: The first cell specifies the beginning of the range.
- description: |
The second cell specifies the number of channels.
Further information available at:
"Work Queue (WQ) Channel Assignments in the QMan" section
in DPAA Reference Manual.
fsl,qman:
$ref: /schemas/types.yaml#/definitions/phandle
description: See soc/fsl/qman.txt
fsl,bman:
$ref: /schemas/types.yaml#/definitions/phandle
description: See soc/fsl/bman.txt
fsl,erratum-a050385:
$ref: /schemas/types.yaml#/definitions/flag
description: A boolean property. Indicates the presence of the
erratum A050385 which indicates that DMA transactions that are
split can result in a FMan lock.
'#address-cells':
const: 1
'#size-cells':
const: 1
patternProperties:
'^muram@[a-f0-9]+$':
$ref: fsl,fman-muram.yaml
'^port@[a-f0-9]+$':
$ref: fsl,fman-port.yaml
'^ethernet@[a-f0-9]+$':
$ref: fsl,fman-dtsec.yaml
'^mdio@[a-f0-9]+$':
$ref: fsl,fman-mdio.yaml
'^phc@[a-f0-9]+$':
$ref: /schemas/ptp/fsl,ptp.yaml
required:
- compatible
- cell-index
- reg
- ranges
- clocks
- clock-names
- interrupts
- fsl,qman-channel-range
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
fman@400000 {
compatible = "fsl,fman";
reg = <0x400000 0x100000>;
ranges = <0 0x400000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
cell-index = <1>;
clocks = <&fman_clk>;
clock-names = "fmanclk";
interrupts = <96 IRQ_TYPE_EDGE_FALLING>,
<16 IRQ_TYPE_EDGE_FALLING>;
fsl,qman-channel-range = <0x40 0xc>;
muram@0 {
compatible = "fsl,fman-muram";
reg = <0x0 0x28000>;
};
port@81000 {
cell-index = <1>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x81000 0x1000>;
};
fman1_rx_0x8: port@88000 {
cell-index = <0x8>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x88000 0x1000>;
};
fman1_tx_0x28: port@a8000 {
cell-index = <0x28>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xa8000 0x1000>;
};
ethernet@e0000 {
compatible = "fsl,fman-dtsec";
cell-index = <0>;
reg = <0xe0000 0x1000>;
ptp-timer = <&ptp_timer>;
fsl,fman-ports = <&fman1_rx_0x8 &fman1_tx_0x28>;
tbi-handle = <&tbi5>;
};
ptp_timer: phc@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
};
mdio@f1000 {
compatible = "fsl,fman-xmdio";
reg = <0xf1000 0x1000>;
interrupts = <101 IRQ_TYPE_EDGE_FALLING>;
};
};

View File

@ -1,119 +0,0 @@
* ENETC ethernet device tree bindings
Depending on board design and ENETC port type (internal or
external) there are two supported link modes specified by
below device tree bindings.
Required properties:
- reg : Specifies PCIe Device Number and Function
Number of the ENETC endpoint device, according
to parent node bindings.
- compatible : Should be "fsl,enetc".
1. The ENETC external port is connected to a MDIO configurable phy
1.1. Using the local ENETC Port MDIO interface
In this case, the ENETC node should include a "mdio" sub-node
that in turn should contain the "ethernet-phy" node describing the
external phy. Below properties are required, their bindings
already defined in Documentation/devicetree/bindings/net/ethernet.txt or
Documentation/devicetree/bindings/net/phy.txt.
Required:
- phy-handle : Phandle to a PHY on the MDIO bus.
Defined in ethernet.txt.
- phy-connection-type : Defined in ethernet.txt.
- mdio : "mdio" node, defined in mdio.txt.
- ethernet-phy : "ethernet-phy" node, defined in phy.txt.
Example:
ethernet@0,0 {
compatible = "fsl,enetc";
reg = <0x000000 0 0 0 0>;
phy-handle = <&sgmii_phy0>;
phy-connection-type = "sgmii";
mdio {
#address-cells = <1>;
#size-cells = <0>;
sgmii_phy0: ethernet-phy@2 {
reg = <0x2>;
};
};
};
1.2. Using the central MDIO PCIe endpoint device
In this case, the mdio node should be defined as another PCIe
endpoint node, at the same level with the ENETC port nodes.
Required properties:
- reg : Specifies PCIe Device Number and Function
Number of the ENETC endpoint device, according
to parent node bindings.
- compatible : Should be "fsl,enetc-mdio".
The remaining required mdio bus properties are standard, their bindings
already defined in Documentation/devicetree/bindings/net/mdio.txt.
Example:
ethernet@0,0 {
compatible = "fsl,enetc";
reg = <0x000000 0 0 0 0>;
phy-handle = <&sgmii_phy0>;
phy-connection-type = "sgmii";
};
mdio@0,3 {
compatible = "fsl,enetc-mdio";
reg = <0x000300 0 0 0 0>;
#address-cells = <1>;
#size-cells = <0>;
sgmii_phy0: ethernet-phy@2 {
reg = <0x2>;
};
};
2. The ENETC port is an internal port or has a fixed-link external
connection
In this case, the ENETC port node defines a fixed link connection,
as specified by Documentation/devicetree/bindings/net/fixed-link.txt.
Required:
- fixed-link : "fixed-link" node, defined in "fixed-link.txt".
Example:
ethernet@0,2 {
compatible = "fsl,enetc";
reg = <0x000200 0 0 0 0>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
* Integrated Endpoint Register Block bindings
Optionally, the fsl_enetc driver can probe on the Integrated Endpoint Register
Block, which preconfigures the FIFO limits for the ENETC ports. This is a node
with the following properties:
- reg : Specifies the address in the SoC memory space.
- compatible : Must be "fsl,ls1028a-enetc-ierb".
Example:
ierb@1f0800000 {
compatible = "fsl,ls1028a-enetc-ierb";
reg = <0x01 0xf0800000 0x0 0x10000>;
};

View File

@ -1,548 +0,0 @@
=============================================================================
Freescale Frame Manager Device Bindings
CONTENTS
- FMan Node
- FMan Port Node
- FMan MURAM Node
- FMan dTSEC/XGEC/mEMAC Node
- FMan IEEE 1588 Node
- FMan MDIO Node
- Example
=============================================================================
FMan Node
DESCRIPTION
Due to the fact that the FMan is an aggregation of sub-engines (ports, MACs,
etc.) the FMan node will have child nodes for each of them.
PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
Definition: Must include "fsl,fman"
FMan version can be determined via FM_IP_REV_1 register in the
FMan block. The offset is 0xc4 from the beginning of the
Frame Processing Manager memory map (0xc3000 from the
beginning of the FMan node).
- cell-index
Usage: required
Value type: <u32>
Definition: Specifies the index of the FMan unit.
The cell-index value may be used by the SoC, to identify the
FMan unit in the SoC memory map. In the table below,
there's a description of the cell-index use in each SoC:
- P1023:
register[bit] FMan unit cell-index
============================================================
DEVDISR[1] 1 0
- P2041, P3041, P4080 P5020, P5040:
register[bit] FMan unit cell-index
============================================================
DCFG_DEVDISR2[6] 1 0
DCFG_DEVDISR2[14] 2 1
(Second FM available only in P4080 and P5040)
- B4860, T1040, T2080, T4240:
register[bit] FMan unit cell-index
============================================================
DCFG_CCSR_DEVDISR2[24] 1 0
DCFG_CCSR_DEVDISR2[25] 2 1
(Second FM available only in T4240)
DEVDISR, DCFG_DEVDISR2 and DCFG_CCSR_DEVDISR2 are located in
the specific SoC "Device Configuration/Pin Control" Memory
Map.
- reg
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property. Specifies the offset of the
following configuration registers:
- BMI configuration registers.
- QMI configuration registers.
- DMA configuration registers.
- FPM configuration registers.
- FMan controller configuration registers.
- ranges
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property.
- clocks
Usage: required
Value type: <prop-encoded-array>
Definition: phandle for the fman input clock.
- clock-names
usage: required
Value type: <stringlist>
Definition: "fmanclk" for the fman input clock.
- interrupts
Usage: required
Value type: <prop-encoded-array>
Definition: A pair of IRQs are specified in this property.
The first element is associated with the event interrupts and
the second element is associated with the error interrupts.
- fsl,qman-channel-range
Usage: required
Value type: <prop-encoded-array>
Definition: Specifies the range of the available dedicated
channels in the FMan. The first cell specifies the beginning
of the range and the second cell specifies the number of
channels.
Further information available at:
"Work Queue (WQ) Channel Assignments in the QMan" section
in DPAA Reference Manual.
- fsl,qman
- fsl,bman
Usage: required
Definition: See soc/fsl/qman.txt and soc/fsl/bman.txt
- fsl,erratum-a050385
Usage: optional
Value type: boolean
Definition: A boolean property. Indicates the presence of the
erratum A050385 which indicates that DMA transactions that are
split can result in a FMan lock.
=============================================================================
FMan MURAM Node
DESCRIPTION
FMan Internal memory - shared between all the FMan modules.
It contains data structures that are common and written to or read by
the modules.
FMan internal memory is split into the following parts:
Packet buffering (Tx/Rx FIFOs)
Frames internal context
PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
Definition: Must include "fsl,fman-muram"
- ranges
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property.
Specifies the multi-user memory offset and the size within
the FMan.
EXAMPLE
muram@0 {
compatible = "fsl,fman-muram";
ranges = <0 0x000000 0x28000>;
};
=============================================================================
FMan Port Node
DESCRIPTION
The Frame Manager (FMan) supports several types of hardware ports:
Ethernet receiver (RX)
Ethernet transmitter (TX)
Offline/Host command (O/H)
PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
Definition: A standard property.
Must include one of the following:
- "fsl,fman-v2-port-oh" for FManV2 OH ports
- "fsl,fman-v2-port-rx" for FManV2 RX ports
- "fsl,fman-v2-port-tx" for FManV2 TX ports
- "fsl,fman-v3-port-oh" for FManV3 OH ports
- "fsl,fman-v3-port-rx" for FManV3 RX ports
- "fsl,fman-v3-port-tx" for FManV3 TX ports
- cell-index
Usage: required
Value type: <u32>
Definition: Specifies the hardware port id.
Each hardware port on the FMan has its own hardware PortID.
Super set of all hardware Port IDs available at FMan Reference
Manual under "FMan Hardware Ports in Freescale Devices" table.
Each hardware port is assigned a 4KB, port-specific page in
the FMan hardware port memory region (which is part of the
FMan memory map). The first 4 KB in the FMan hardware ports
memory region is used for what are called common registers.
The subsequent 63 4KB pages are allocated to the hardware
ports.
The page of a specific port is determined by the cell-index.
- reg
Usage: required
Value type: <prop-encoded-array>
Definition: There is one reg region describing the port
configuration registers.
- fsl,fman-10g-port
Usage: optional
Value type: boolean
Definition: The default port rate is 1G.
If this property exists, the port is s 10G port.
- fsl,fman-best-effort-port
Usage: optional
Value type: boolean
Definition: Can be defined only if 10G-support is set.
This property marks a best-effort 10G port (10G port that
may not be capable of line rate).
EXAMPLE
port@a8000 {
cell-index = <0x28>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xa8000 0x1000>;
};
port@88000 {
cell-index = <0x8>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x88000 0x1000>;
};
port@81000 {
cell-index = <0x1>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x81000 0x1000>;
};
=============================================================================
FMan dTSEC/XGEC/mEMAC Node
Refer to Documentation/devicetree/bindings/net/fsl,fman-dtsec.yaml
============================================================================
FMan IEEE 1588 Node
Refer to Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
=============================================================================
FMan MDIO Node
DESCRIPTION
The MDIO is a bus to which the PHY devices are connected.
PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
Definition: A standard property.
Must include "fsl,fman-mdio" for 1 Gb/s MDIO from FMan v2.
Must include "fsl,fman-xmdio" for 10 Gb/s MDIO from FMan v2.
Must include "fsl,fman-memac-mdio" for 1/10 Gb/s MDIO from
FMan v3.
- reg
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property.
- clocks
Usage: optional
Value type: <phandle>
Definition: A reference to the input clock of the controller
from which the MDC frequency is derived.
- clock-frequency
Usage: optional
Value type: <u32>
Definition: Specifies the external MDC frequency, in Hertz, to
be used. Requires that the input clock is specified in the
"clocks" property. See also: mdio.yaml.
- suppress-preamble
Usage: optional
Value type: <boolean>
Definition: Disable generation of preamble bits. See also:
mdio.yaml.
- interrupts
Usage: required for external MDIO
Value type: <prop-encoded-array>
Definition: Event interrupt of external MDIO controller.
- fsl,fman-internal-mdio
Usage: required for internal MDIO
Value type: boolean
Definition: Fman has internal MDIO for internal PCS(Physical
Coding Sublayer) PHYs and external MDIO for external PHYs.
The settings and programming routines for internal/external
MDIO are different. Must be included for internal MDIO.
- fsl,erratum-a009885
Usage: optional
Value type: <boolean>
Definition: Indicates the presence of the A009885
erratum describing that the contents of MDIO_DATA may
become corrupt unless it is read within 16 MDC cycles
of MDIO_CFG[BSY] being cleared, when performing an
MDIO read operation.
- fsl,erratum-a011043
Usage: optional
Value type: <boolean>
Definition: Indicates the presence of the A011043 erratum
describing that the MDIO_CFG[MDIO_RD_ER] bit may be falsely
set when reading internal PCS registers. MDIO reads to
internal PCS registers may result in having the
MDIO_CFG[MDIO_RD_ER] bit set, even when there is no error and
read data (MDIO_DATA[MDIO_DATA]) is correct.
Software may get false read error when reading internal
PCS registers through MDIO. As a workaround, all internal
MDIO accesses should ignore the MDIO_CFG[MDIO_RD_ER] bit.
For internal PHY device on internal mdio bus, a PHY node should be created.
See the definition of the PHY node in booting-without-of.txt for an
example of how to define a PHY (Internal PHY has no interrupt line).
- For "fsl,fman-mdio" compatible internal mdio bus, the PHY is TBI PHY.
- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY.
The PCS PHY address should correspond to the value of the appropriate
MDEV_PORT.
EXAMPLE
Example for FMan v2 external MDIO:
mdio@f1000 {
compatible = "fsl,fman-xmdio";
reg = <0xf1000 0x1000>;
interrupts = <101 2 0 0>;
};
Example for FMan v2 internal MDIO:
mdio@e3120 {
compatible = "fsl,fman-mdio";
reg = <0xe3120 0xee0>;
fsl,fman-internal-mdio;
tbi1: tbi-phy@8 {
reg = <0x8>;
device_type = "tbi-phy";
};
};
Example for FMan v3 internal MDIO:
mdio@f1000 {
compatible = "fsl,fman-memac-mdio";
reg = <0xf1000 0x1000>;
fsl,fman-internal-mdio;
pcsphy6: ethernet-phy@0 {
reg = <0x0>;
};
};
=============================================================================
Example
fman@400000 {
#address-cells = <1>;
#size-cells = <1>;
cell-index = <1>;
compatible = "fsl,fman"
ranges = <0 0x400000 0x100000>;
reg = <0x400000 0x100000>;
clocks = <&fman_clk>;
clock-names = "fmanclk";
interrupts = <
96 2 0 0
16 2 1 1>;
fsl,qman-channel-range = <0x40 0xc>;
muram@0 {
compatible = "fsl,fman-muram";
reg = <0x0 0x28000>;
};
port@81000 {
cell-index = <1>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x81000 0x1000>;
};
port@82000 {
cell-index = <2>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x82000 0x1000>;
};
port@83000 {
cell-index = <3>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x83000 0x1000>;
};
port@84000 {
cell-index = <4>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x84000 0x1000>;
};
port@85000 {
cell-index = <5>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x85000 0x1000>;
};
port@86000 {
cell-index = <6>;
compatible = "fsl,fman-v2-port-oh";
reg = <0x86000 0x1000>;
};
fman1_rx_0x8: port@88000 {
cell-index = <0x8>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x88000 0x1000>;
};
fman1_rx_0x9: port@89000 {
cell-index = <0x9>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x89000 0x1000>;
};
fman1_rx_0xa: port@8a000 {
cell-index = <0xa>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x8a000 0x1000>;
};
fman1_rx_0xb: port@8b000 {
cell-index = <0xb>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x8b000 0x1000>;
};
fman1_rx_0xc: port@8c000 {
cell-index = <0xc>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x8c000 0x1000>;
};
fman1_rx_0x10: port@90000 {
cell-index = <0x10>;
compatible = "fsl,fman-v2-port-rx";
reg = <0x90000 0x1000>;
};
fman1_tx_0x28: port@a8000 {
cell-index = <0x28>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xa8000 0x1000>;
};
fman1_tx_0x29: port@a9000 {
cell-index = <0x29>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xa9000 0x1000>;
};
fman1_tx_0x2a: port@aa000 {
cell-index = <0x2a>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xaa000 0x1000>;
};
fman1_tx_0x2b: port@ab000 {
cell-index = <0x2b>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xab000 0x1000>;
};
fman1_tx_0x2c: port@ac0000 {
cell-index = <0x2c>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xac000 0x1000>;
};
fman1_tx_0x30: port@b0000 {
cell-index = <0x30>;
compatible = "fsl,fman-v2-port-tx";
reg = <0xb0000 0x1000>;
};
ethernet@e0000 {
compatible = "fsl,fman-dtsec";
cell-index = <0>;
reg = <0xe0000 0x1000>;
fsl,fman-ports = <&fman1_rx_0x8 &fman1_tx_0x28>;
tbi-handle = <&tbi5>;
};
ethernet@e2000 {
compatible = "fsl,fman-dtsec";
cell-index = <1>;
reg = <0xe2000 0x1000>;
fsl,fman-ports = <&fman1_rx_0x9 &fman1_tx_0x29>;
tbi-handle = <&tbi6>;
};
ethernet@e4000 {
compatible = "fsl,fman-dtsec";
cell-index = <2>;
reg = <0xe4000 0x1000>;
fsl,fman-ports = <&fman1_rx_0xa &fman1_tx_0x2a>;
tbi-handle = <&tbi7>;
};
ethernet@e6000 {
compatible = "fsl,fman-dtsec";
cell-index = <3>;
reg = <0xe6000 0x1000>;
fsl,fman-ports = <&fman1_rx_0xb &fman1_tx_0x2b>;
tbi-handle = <&tbi8>;
};
ethernet@e8000 {
compatible = "fsl,fman-dtsec";
cell-index = <4>;
reg = <0xf0000 0x1000>;
fsl,fman-ports = <&fman1_rx_0xc &fman1_tx_0x2c>;
tbi-handle = <&tbi9>;
ethernet@f0000 {
cell-index = <8>;
compatible = "fsl,fman-xgec";
reg = <0xf0000 0x1000>;
fsl,fman-ports = <&fman1_rx_0x10 &fman1_tx_0x30>;
};
ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
mdio@f1000 {
compatible = "fsl,fman-xmdio";
reg = <0xf1000 0x1000>;
interrupts = <101 2 0 0>;
};
};

View File

@ -86,4 +86,4 @@ Example:
* Gianfar PTP clock nodes
Refer to Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
Refer to Documentation/devicetree/bindings/ptp/fsl,ptp.yaml

View File

@ -68,6 +68,17 @@ properties:
Phandle to the syscon node that handles the path from GMAC to
PHY variants.
mediatek,pcie-mirror:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the mediatek pcie-mirror controller.
mediatek,pctl:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the syscon node that handles the ports slew rate and
driver current.
mediatek,sgmiisys:
$ref: /schemas/types.yaml#/definitions/phandle-array
minItems: 1
@ -131,15 +142,12 @@ allOf:
mediatek,infracfg: false
mediatek,pctl:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the syscon node that handles the ports slew rate and
driver current.
mediatek,wed: false
mediatek,wed-pcie: false
else:
properties:
mediatek,pctl: false
- if:
properties:
@ -201,12 +209,10 @@ allOf:
minItems: 1
maxItems: 1
mediatek,pcie-mirror:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the mediatek pcie-mirror controller.
mediatek,wed-pcie: false
else:
properties:
mediatek,pcie-mirror: false
- if:
properties:

View File

@ -1,39 +1,3 @@
MediaTek SoC built-in Bluetooth Devices
==================================
This device is a serial attached device to BTIF device and thus it must be a
child node of the serial node with BTIF. The dt-bindings details for BTIF
device can be known via Documentation/devicetree/bindings/serial/8250.yaml.
Required properties:
- compatible: Must be
"mediatek,mt7622-bluetooth": for MT7622 SoC
- clocks: Should be the clock specifiers corresponding to the entry in
clock-names property.
- clock-names: Should contain "ref" entries.
- power-domains: Phandle to the power domain that the device is part of
Example:
btif: serial@1100c000 {
compatible = "mediatek,mt7622-btif",
"mediatek,mtk-btif";
reg = <0 0x1100c000 0 0x1000>;
interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_BTIF_PD>;
clock-names = "main";
reg-shift = <2>;
reg-io-width = <4>;
bluetooth {
compatible = "mediatek,mt7622-bluetooth";
power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
clocks = <&clk25m>;
clock-names = "ref";
};
};
MediaTek UART based Bluetooth Devices
==================================

View File

@ -38,6 +38,16 @@ properties:
clock-frequency: true
resets:
items:
- description:
Reset shared with all blocks attached to the Switch Core Register
Bus (CSR) including VRAP slave.
reset-names:
items:
- const: switch
required:
- compatible
- reg

View File

@ -0,0 +1,136 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/pcs/snps,dw-xpcs.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys DesignWare Ethernet PCS
maintainers:
- Serge Semin <fancer.lancer@gmail.com>
description:
Synopsys DesignWare Ethernet Physical Coding Sublayer provides an interface
between Media Access Control and Physical Medium Attachment Sublayer through
the Media Independent Interface (XGMII, USXGMII, XLGMII, GMII, etc)
controlled by means of the IEEE std. Clause 45 registers set. The PCS can be
optionally synthesized with a vendor-specific interface connected to
Synopsys PMA (also called DesignWare Consumer/Enterprise PHY) although in
general it can be used to communicate with any compatible PHY.
The PCS CSRs can be accessible either over the Ethernet MDIO bus or directly
by means of the APB3/MCI interfaces. In the later case the XPCS can be mapped
right to the system IO memory space.
properties:
compatible:
oneOf:
- description: Synopsys DesignWare XPCS with none or unknown PMA
const: snps,dw-xpcs
- description: Synopsys DesignWare XPCS with Consumer Gen1 3G PMA
const: snps,dw-xpcs-gen1-3g
- description: Synopsys DesignWare XPCS with Consumer Gen2 3G PMA
const: snps,dw-xpcs-gen2-3g
- description: Synopsys DesignWare XPCS with Consumer Gen2 6G PMA
const: snps,dw-xpcs-gen2-6g
- description: Synopsys DesignWare XPCS with Consumer Gen4 3G PMA
const: snps,dw-xpcs-gen4-3g
- description: Synopsys DesignWare XPCS with Consumer Gen4 6G PMA
const: snps,dw-xpcs-gen4-6g
- description: Synopsys DesignWare XPCS with Consumer Gen5 10G PMA
const: snps,dw-xpcs-gen5-10g
- description: Synopsys DesignWare XPCS with Consumer Gen5 12G PMA
const: snps,dw-xpcs-gen5-12g
reg:
items:
- description:
In case of the MDIO management interface this just a 5-bits ID
of the MDIO bus device. If DW XPCS CSRs space is accessed over the
MCI or APB3 management interfaces, then the space mapping can be
either 'direct' or 'indirect'. In the former case all Clause 45
registers are contiguously mapped within the address space
MMD '[20:16]', Reg '[15:0]'. In the later case the space is divided
to the multiple 256 register sets. There is a special viewport CSR
which is responsible for the set selection. The upper part of
the CSR address MMD+REG[20:8] is supposed to be written in there
so the corresponding subset would be mapped to the lowest 255 CSRs.
reg-names:
items:
- enum: [ direct, indirect ]
reg-io-width:
description:
The way the CSRs are mapped to the memory is platform depended. Since
each Clause 45 CSR is of 16-bits wide the access instructions must be
two bytes aligned at least.
default: 2
enum: [ 2, 4 ]
interrupts:
description:
System interface interrupt output (sbd_intr_o) indicating Clause 73/37
auto-negotiation events':' Page received, AN is completed or incompatible
link partner.
maxItems: 1
clocks:
description:
The MCI and APB3 interfaces are supposed to be equipped with a clock
source connected to the clk_csr_i line.
PCS/PMA layer can be clocked by an internal reference clock source
(phyN_core_refclk) or by an externally connected (phyN_pad_refclk) clock
generator. Both clocks can be supplied at a time.
minItems: 1
maxItems: 3
clock-names:
oneOf:
- minItems: 1
items: # MDIO
- enum: [core, pad]
- const: pad
- minItems: 1
items: # MCI or APB
- const: csr
- enum: [core, pad]
- const: pad
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
ethernet-pcs@1f05d000 {
compatible = "snps,dw-xpcs";
reg = <0x1f05d000 0x1000>;
reg-names = "indirect";
reg-io-width = <4>;
interrupts = <79 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu_pclk>, <&ccu_core>, <&ccu_pad>;
clock-names = "csr", "core", "pad";
};
- |
mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
ethernet-pcs@0 {
compatible = "snps,dw-xpcs";
reg = <0>;
clocks = <&ccu_core>, <&ccu_pad>;
clock-names = "core", "pad";
};
};
...

View File

@ -14,10 +14,32 @@ maintainers:
description:
Bindings for Realtek RTL82xx PHYs
allOf:
- $ref: ethernet-phy.yaml#
properties:
compatible:
enum:
- ethernet-phy-id001c.c800
- ethernet-phy-id001c.c816
- ethernet-phy-id001c.c838
- ethernet-phy-id001c.c840
- ethernet-phy-id001c.c848
- ethernet-phy-id001c.c849
- ethernet-phy-id001c.c84a
- ethernet-phy-id001c.c862
- ethernet-phy-id001c.c878
- ethernet-phy-id001c.c880
- ethernet-phy-id001c.c910
- ethernet-phy-id001c.c912
- ethernet-phy-id001c.c913
- ethernet-phy-id001c.c914
- ethernet-phy-id001c.c915
- ethernet-phy-id001c.c916
- ethernet-phy-id001c.c942
- ethernet-phy-id001c.c961
- ethernet-phy-id001c.cad0
- ethernet-phy-id001c.cb00
leds: true
realtek,clkout-disable:
type: boolean
description:
@ -31,6 +53,18 @@ properties:
unevaluatedProperties: false
allOf:
- $ref: ethernet-phy.yaml#
- if:
not:
properties:
compatible:
contains:
const: ethernet-phy-id001c.c916
then:
properties:
leds: false
examples:
- |
mdio {

View File

@ -76,6 +76,7 @@ properties:
- rockchip,rk3128-gmac
- rockchip,rk3228-gmac
- rockchip,rk3288-gmac
- rockchip,rk3308-gmac
- rockchip,rk3328-gmac
- rockchip,rk3366-gmac
- rockchip,rk3368-gmac
@ -435,6 +436,32 @@ properties:
description:
Use Address-Aligned Beats
snps,pbl:
description:
Programmable Burst Length (tx and rx)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32]
snps,txpbl:
description:
Tx Programmable Burst Length. If set, DMA tx will use this
value rather than snps,pbl.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32]
snps,rxpbl:
description:
Rx Programmable Burst Length. If set, DMA rx will use this
value rather than snps,pbl.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32]
snps,no-pbl-x8:
$ref: /schemas/types.yaml#/definitions/flag
description:
Don\'t multiply the pbl/txpbl/rxpbl values by 8. For core
rev < 3.50, don\'t multiply the values by 4.
snps,fixed-burst:
$ref: /schemas/types.yaml#/definitions/flag
description:
@ -485,6 +512,12 @@ properties:
description:
Frequency division factor for MDC clock.
snps,tso:
$ref: /schemas/types.yaml#/definitions/flag
description:
Enables the TSO feature otherwise it will be managed by MAC HW capability
register.
mdio:
$ref: mdio.yaml#
unevaluatedProperties: false
@ -568,95 +601,38 @@ allOf:
- if:
properties:
compatible:
contains:
enum:
- allwinner,sun7i-a20-gmac
- allwinner,sun8i-a83t-emac
- allwinner,sun8i-h3-emac
- allwinner,sun8i-r40-gmac
- allwinner,sun8i-v3s-emac
- allwinner,sun50i-a64-emac
- ingenic,jz4775-mac
- ingenic,x1000-mac
- ingenic,x1600-mac
- ingenic,x1830-mac
- ingenic,x2000-mac
- qcom,sa8775p-ethqos
- qcom,sc8280xp-ethqos
- snps,dwmac-3.50a
- snps,dwmac-4.10a
- snps,dwmac-4.20a
- snps,dwmac-5.20
- snps,dwxgmac
- snps,dwxgmac-2.10
- st,spear600-gmac
not:
contains:
enum:
- allwinner,sun7i-a20-gmac
- allwinner,sun8i-a83t-emac
- allwinner,sun8i-h3-emac
- allwinner,sun8i-r40-gmac
- allwinner,sun8i-v3s-emac
- allwinner,sun50i-a64-emac
- loongson,ls2k-dwmac
- loongson,ls7a-dwmac
- ingenic,jz4775-mac
- ingenic,x1000-mac
- ingenic,x1600-mac
- ingenic,x1830-mac
- ingenic,x2000-mac
- qcom,qcs404-ethqos
- qcom,sa8775p-ethqos
- qcom,sc8280xp-ethqos
- qcom,sm8150-ethqos
- snps,dwmac-4.00
- snps,dwmac-4.10a
- snps,dwmac-4.20a
- snps,dwmac-5.10a
- snps,dwmac-5.20
- snps,dwxgmac
- snps,dwxgmac-2.10
- st,spear600-gmac
then:
properties:
snps,pbl:
description:
Programmable Burst Length (tx and rx)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32]
snps,txpbl:
description:
Tx Programmable Burst Length. If set, DMA tx will use this
value rather than snps,pbl.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32]
snps,rxpbl:
description:
Rx Programmable Burst Length. If set, DMA rx will use this
value rather than snps,pbl.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32]
snps,no-pbl-x8:
$ref: /schemas/types.yaml#/definitions/flag
description:
Don\'t multiply the pbl/txpbl/rxpbl values by 8. For core
rev < 3.50, don\'t multiply the values by 4.
- if:
properties:
compatible:
contains:
enum:
- allwinner,sun7i-a20-gmac
- allwinner,sun8i-a83t-emac
- allwinner,sun8i-h3-emac
- allwinner,sun8i-r40-gmac
- allwinner,sun8i-v3s-emac
- allwinner,sun50i-a64-emac
- loongson,ls2k-dwmac
- loongson,ls7a-dwmac
- ingenic,jz4775-mac
- ingenic,x1000-mac
- ingenic,x1600-mac
- ingenic,x1830-mac
- ingenic,x2000-mac
- qcom,qcs404-ethqos
- qcom,sa8775p-ethqos
- qcom,sc8280xp-ethqos
- qcom,sm8150-ethqos
- snps,dwmac-4.00
- snps,dwmac-4.10a
- snps,dwmac-4.20a
- snps,dwmac-5.10a
- snps,dwmac-5.20
- snps,dwxgmac
- snps,dwxgmac-2.10
- st,spear600-gmac
then:
properties:
snps,tso:
$ref: /schemas/types.yaml#/definitions/flag
description:
Enables the TSO feature otherwise it will be managed by
MAC HW capability register.
snps,tso: false
additionalProperties: true

View File

@ -22,18 +22,22 @@ select:
enum:
- st,stm32-dwmac
- st,stm32mp1-dwmac
- st,stm32mp13-dwmac
- st,stm32mp25-dwmac
required:
- compatible
allOf:
- $ref: snps,dwmac.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- st,stm32mp25-dwmac
- const: snps,dwmac-5.20
- items:
- enum:
- st,stm32mp1-dwmac
- st,stm32mp13-dwmac
- const: snps,dwmac-4.20a
- items:
- enum:
@ -75,12 +79,15 @@ properties:
st,syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- minItems: 2
items:
- description: phandle to the syscon node which encompases the glue register
- description: offset of the control register
- description: field to set mask in register
description:
Should be phandle/offset pair. The phandle to the syscon node which
encompases the glue register, and the offset of the control register
encompases the glue register, the offset of the control register and
the mask to set bitfield in control register
st,ext-phyclk:
description:
@ -112,12 +119,40 @@ required:
unevaluatedProperties: false
allOf:
- $ref: snps,dwmac.yaml#
- if:
properties:
compatible:
contains:
enum:
- st,stm32-dwmac
- st,stm32mp1-dwmac
- st,stm32mp25-dwmac
then:
properties:
st,syscon:
items:
minItems: 2
maxItems: 2
- if:
properties:
compatible:
contains:
enum:
- st,stm32mp13-dwmac
then:
properties:
st,syscon:
items:
minItems: 3
maxItems: 3
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
#include <dt-bindings/mfd/stm32h7-rcc.h>
//Example 1
ethernet0: ethernet@5800a000 {
compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";

View File

@ -28,6 +28,15 @@ properties:
maxItems: 1
description: phandle to the IEP source clock
interrupts:
maxItems: 1
description:
Interrupt specifier for capture/compare IRQ.
interrupt-names:
items:
- const: iep_cap_cmp
required:
- compatible
- reg

View File

@ -55,6 +55,14 @@ properties:
description:
phandle to MII_RT module's syscon regmap
ti,pa-stats:
$ref: /schemas/types.yaml#/definitions/phandle
description:
phandle to PA_STATS module's syscon regmap. PA_STATS is a set of
registers where different statistics related to ICSSG, are dumped by
ICSSG firmware. PA_STATS module's syscon regmap will help the device to
access/read/write those statistics.
ti,iep:
$ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 2
@ -194,6 +202,7 @@ examples:
"tx1-0", "tx1-1", "tx1-2", "tx1-3",
"rx0", "rx1";
ti,mii-g-rt = <&icssg2_mii_g_rt>;
ti,pa-stats = <&icssg2_pa_stats>;
ti,iep = <&icssg2_iep0>, <&icssg2_iep1>;
interrupt-parent = <&icssg2_intc>;
interrupts = <24 0 2>, <25 1 3>;

View File

@ -128,6 +128,11 @@ properties:
Whether to skip executing an SCM call that reassigns the memory
region ownership.
qcom,no-msa-ready-indicator:
type: boolean
description:
Don't wait for MSA_READY indicator to complete init.
qcom,smem-states:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: State bits used by the AP to signal the WLAN Q6.

View File

@ -17,6 +17,7 @@ description: |
properties:
compatible:
enum:
- pci17cb,1101 # QCA6390
- pci17cb,1103 # WCN6855
reg:
@ -28,10 +29,55 @@ properties:
string to uniquely identify variant of the calibration data for designs
with colliding bus and device ids
vddrfacmn-supply:
description: VDD_RFA_CMN supply regulator handle
vddaon-supply:
description: VDD_AON supply regulator handle
vddwlcx-supply:
description: VDD_WL_CX supply regulator handle
vddwlmx-supply:
description: VDD_WL_MX supply regulator handle
vddrfa0p8-supply:
description: VDD_RFA_0P8 supply regulator handle
vddrfa1p2-supply:
description: VDD_RFA_1P2 supply regulator handle
vddrfa1p7-supply:
description: VDD_RFA_1P7 supply regulator handle
vddpcie0p9-supply:
description: VDD_PCIE_0P9 supply regulator handle
vddpcie1p8-supply:
description: VDD_PCIE_1P8 supply regulator handle
required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
const: pci17cb,1101
then:
required:
- vddrfacmn-supply
- vddaon-supply
- vddwlcx-supply
- vddwlmx-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p7-supply
- vddpcie0p9-supply
- vddpcie1p8-supply
additionalProperties: false
examples:

View File

@ -265,15 +265,6 @@ allOf:
examples:
- |
q6v5_wcss: remoteproc@cd00000 {
compatible = "qcom,ipq8074-wcss-pil";
reg = <0xcd00000 0x4040>,
<0x4ab000 0x20>;
reg-names = "qdsp6",
"rmb";
};
wifi0: wifi@c000000 {
compatible = "qcom,ipq8074-wifi";
reg = <0xc000000 0x2000000>;

View File

@ -0,0 +1,99 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2024 Linaro Limited
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/wireless/qcom,ath12k.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies ath12k wireless devices (PCIe)
maintainers:
- Jeff Johnson <quic_jjohnson@quicinc.com>
- Kalle Valo <kvalo@kernel.org>
description:
Qualcomm Technologies IEEE 802.11be PCIe devices.
properties:
compatible:
enum:
- pci17cb,1107 # WCN7850
reg:
maxItems: 1
vddaon-supply:
description: VDD_AON supply regulator handle
vddwlcx-supply:
description: VDD_WLCX supply regulator handle
vddwlmx-supply:
description: VDD_WLMX supply regulator handle
vddrfacmn-supply:
description: VDD_RFA_CMN supply regulator handle
vddrfa0p8-supply:
description: VDD_RFA_0P8 supply regulator handle
vddrfa1p2-supply:
description: VDD_RFA_1P2 supply regulator handle
vddrfa1p8-supply:
description: VDD_RFA_1P8 supply regulator handle
vddpcie0p9-supply:
description: VDD_PCIE_0P9 supply regulator handle
vddpcie1p8-supply:
description: VDD_PCIE_1P8 supply regulator handle
required:
- compatible
- reg
- vddaon-supply
- vddwlcx-supply
- vddwlmx-supply
- vddrfacmn-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p8-supply
- vddpcie0p9-supply
- vddpcie1p8-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/gpio/gpio.h>
pcie {
#address-cells = <3>;
#size-cells = <2>;
pcie@0 {
device_type = "pci";
reg = <0x0 0x0 0x0 0x0 0x0>;
#address-cells = <3>;
#size-cells = <2>;
ranges;
bus-range = <0x01 0xff>;
wifi@0 {
compatible = "pci17cb,1107";
reg = <0x10000 0x0 0x0 0x0 0x0>;
vddaon-supply = <&vreg_pmu_aon_0p59>;
vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
vddwlmx-supply = <&vreg_pmu_wlmx_0p85>;
vddrfacmn-supply = <&vreg_pmu_rfa_cmn>;
vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
vddrfa1p8-supply = <&vreg_pmu_rfa_1p8>;
vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
};
};
};

View File

@ -31,6 +31,10 @@ properties:
phy-handle:
$ref: ethernet-controller.yaml#/properties/phy-handle
clocks:
items:
- description: 200/375 MHz free-running clock is used as input clock.
required:
- compatible
- reg
@ -51,5 +55,6 @@ examples:
compatible = "xlnx,gmii-to-rgmii-1.0";
reg = <8>;
phy-handle = <&phy>;
clocks = <&dummy>;
};
};

View File

@ -0,0 +1,144 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/ptp/fsl,ptp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale QorIQ 1588 timer based PTP clock
maintainers:
- Frank Li <Frank.Li@nxp.com>
properties:
compatible:
enum:
- fsl,etsec-ptp
- fsl,fman-ptp-timer
- fsl,dpaa2-ptp
- fsl,enetc-ptp
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
fsl,cksel:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Timer reference clock source.
Reference clock source is determined by the value, which is holded
in CKSEL bits in TMR_CTRL register. "fsl,cksel" property keeps the
value, which will be directly written in those bits, that is why,
according to reference manual, the next clock sources can be used:
For eTSEC,
<0> - external high precision timer reference clock (TSEC_TMR_CLK
input is used for this purpose);
<1> - eTSEC system clock;
<2> - eTSEC1 transmit clock;
<3> - RTC clock input.
For DPAA FMan,
<0> - external high precision timer reference clock (TMR_1588_CLK)
<1> - MAC system clock (1/2 FMan clock)
<2> - reserved
<3> - RTC clock oscillator
fsl,tclk-period:
$ref: /schemas/types.yaml#/definitions/uint32
description: Timer reference clock period in nanoseconds.
fsl,tmr-prsc:
$ref: /schemas/types.yaml#/definitions/uint32
description: Prescaler, divides the output clock.
fsl,tmr-add:
$ref: /schemas/types.yaml#/definitions/uint32
description: Frequency compensation value.
fsl,tmr-fiper1:
$ref: /schemas/types.yaml#/definitions/uint32
description: Fixed interval period pulse generator.
fsl,tmr-fiper2:
$ref: /schemas/types.yaml#/definitions/uint32
description: Fixed interval period pulse generator.
fsl,tmr-fiper3:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Fixed interval period pulse generator.
Supported only on DPAA2 and ENETC hardware.
fsl,max-adj:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Maximum frequency adjustment in parts per billion.
These properties set the operational parameters for the PTP
clock. You must choose these carefully for the clock to work right.
Here is how to figure good values:
TimerOsc = selected reference clock MHz
tclk_period = desired clock period nanoseconds
NominalFreq = 1000 / tclk_period MHz
FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0)
tmr_add = ceil(2^32 / FreqDivRatio)
OutputClock = NominalFreq / tmr_prsc MHz
PulseWidth = 1 / OutputClock microseconds
FiperFreq1 = desired frequency in Hz
FiperDiv1 = 1000000 * OutputClock / FiperFreq1
tmr_fiper1 = tmr_prsc * tclk_period * FiperDiv1 - tclk_period
max_adj = 1000000000 * (FreqDivRatio - 1.0) - 1
The calculation for tmr_fiper2 is the same as for tmr_fiper1. The
driver expects that tmr_fiper1 will be correctly set to produce a 1
Pulse Per Second (PPS) signal, since this will be offered to the PPS
subsystem to synchronize the Linux clock.
When this attribute is not used, the IEEE 1588 timer reference clock
will use the eTSEC system clock (for Gianfar) or the MAC system
clock (for DPAA).
fsl,extts-fifo:
$ref: /schemas/types.yaml#/definitions/flag
description:
The presence of this property indicates hardware
support for the external trigger stamp FIFO
little-endian:
$ref: /schemas/types.yaml#/definitions/flag
description:
The presence of this property indicates the 1588 timer
support for the external trigger stamp FIFO.
IP block is little-endian mode. The default endian mode
is big-endian.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
phc@24e00 {
compatible = "fsl,etsec-ptp";
reg = <0x24e00 0xb0>;
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&ipic>;
fsl,cksel = <1>;
fsl,tclk-period = <10>;
fsl,tmr-prsc = <100>;
fsl,tmr-add = <0x999999a4>;
fsl,tmr-fiper1 = <0x3b9ac9f6>;
fsl,tmr-fiper2 = <0x00018696>;
fsl,max-adj = <659999998>;
};

View File

@ -1,87 +0,0 @@
* Freescale QorIQ 1588 timer based PTP clock
General Properties:
- compatible Should be "fsl,etsec-ptp" for eTSEC
Should be "fsl,fman-ptp-timer" for DPAA FMan
Should be "fsl,dpaa2-ptp" for DPAA2
Should be "fsl,enetc-ptp" for ENETC
- reg Offset and length of the register set for the device
- interrupts There should be at least two interrupts. Some devices
have as many as four PTP related interrupts.
Clock Properties:
- fsl,cksel Timer reference clock source.
- fsl,tclk-period Timer reference clock period in nanoseconds.
- fsl,tmr-prsc Prescaler, divides the output clock.
- fsl,tmr-add Frequency compensation value.
- fsl,tmr-fiper1 Fixed interval period pulse generator.
- fsl,tmr-fiper2 Fixed interval period pulse generator.
- fsl,tmr-fiper3 Fixed interval period pulse generator.
Supported only on DPAA2 and ENETC hardware.
- fsl,max-adj Maximum frequency adjustment in parts per billion.
- fsl,extts-fifo The presence of this property indicates hardware
support for the external trigger stamp FIFO.
- little-endian The presence of this property indicates the 1588 timer
IP block is little-endian mode. The default endian mode
is big-endian.
These properties set the operational parameters for the PTP
clock. You must choose these carefully for the clock to work right.
Here is how to figure good values:
TimerOsc = selected reference clock MHz
tclk_period = desired clock period nanoseconds
NominalFreq = 1000 / tclk_period MHz
FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0)
tmr_add = ceil(2^32 / FreqDivRatio)
OutputClock = NominalFreq / tmr_prsc MHz
PulseWidth = 1 / OutputClock microseconds
FiperFreq1 = desired frequency in Hz
FiperDiv1 = 1000000 * OutputClock / FiperFreq1
tmr_fiper1 = tmr_prsc * tclk_period * FiperDiv1 - tclk_period
max_adj = 1000000000 * (FreqDivRatio - 1.0) - 1
The calculation for tmr_fiper2 is the same as for tmr_fiper1. The
driver expects that tmr_fiper1 will be correctly set to produce a 1
Pulse Per Second (PPS) signal, since this will be offered to the PPS
subsystem to synchronize the Linux clock.
Reference clock source is determined by the value, which is holded
in CKSEL bits in TMR_CTRL register. "fsl,cksel" property keeps the
value, which will be directly written in those bits, that is why,
according to reference manual, the next clock sources can be used:
For eTSEC,
<0> - external high precision timer reference clock (TSEC_TMR_CLK
input is used for this purpose);
<1> - eTSEC system clock;
<2> - eTSEC1 transmit clock;
<3> - RTC clock input.
For DPAA FMan,
<0> - external high precision timer reference clock (TMR_1588_CLK)
<1> - MAC system clock (1/2 FMan clock)
<2> - reserved
<3> - RTC clock oscillator
When this attribute is not used, the IEEE 1588 timer reference clock
will use the eTSEC system clock (for Gianfar) or the MAC system
clock (for DPAA).
Example:
ptp_clock@24e00 {
compatible = "fsl,etsec-ptp";
reg = <0x24E00 0xB0>;
interrupts = <12 0x8 13 0x8>;
interrupt-parent = < &ipic >;
fsl,cksel = <1>;
fsl,tclk-period = <10>;
fsl,tmr-prsc = <100>;
fsl,tmr-add = <0x999999A4>;
fsl,tmr-fiper1 = <0x3B9AC9F6>;
fsl,tmr-fiper2 = <0x00018696>;
fsl,max-adj = <659999998>;
};

View File

@ -479,6 +479,7 @@ operations:
name: pin-get
doc: |
Get list of pins and its attributes.
- dump request without any attributes given - list all the pins in the
system
- dump request with target dpll - list all the pins registered with

View File

@ -20,6 +20,25 @@ definitions:
name: header-flags
type: flags
entries: [ compact-bitsets, omit-reply, stats ]
-
name: module-fw-flash-status
type: enum
entries: [ started, in_progress, completed, error ]
-
name: c33-pse-ext-state
enum-name:
type: enum
name-prefix: ethtool-c33-pse-ext-state-
entries:
- none
- error-condition
- mr-mps-valid
- mr-pse-enable
- option-detect-ted
- option-vport-lim
- ovld-detected
- power-not-available
- short-detected
attribute-sets:
-
@ -414,6 +433,26 @@ attribute-sets:
name: combined-count
type: u32
-
name: irq-moderation
attributes:
-
name: usec
type: u32
-
name: pkts
type: u32
-
name: comps
type: u32
-
name: profile
attributes:
-
name: irq-moderation
type: nest
multi-attr: true
nested-attributes: irq-moderation
-
name: coalesce
attributes:
@ -502,6 +541,15 @@ attribute-sets:
-
name: tx-aggr-time-usecs
type: u32
-
name: rx-profile
type: nest
nested-attributes: profile
-
name: tx-profile
type: nest
nested-attributes: profile
-
name: pause-stat
attributes:
@ -891,6 +939,15 @@ attribute-sets:
-
name: power-mode
type: u8
-
name: c33-pse-pw-limit
attributes:
-
name: min
type: u32
-
name: max
type: u32
-
name: pse
attributes:
@ -922,6 +979,33 @@ attribute-sets:
name: c33-pse-pw-d-status
type: u32
name-prefix: ethtool-a-
-
name: c33-pse-pw-class
type: u32
name-prefix: ethtool-a-
-
name: c33-pse-actual-pw
type: u32
name-prefix: ethtool-a-
-
name: c33-pse-ext-state
type: u32
name-prefix: ethtool-a-
enum: c33-pse-ext-state
-
name: c33-pse-ext-substate
type: u32
name-prefix: ethtool-a-
-
name: c33-pse-avail-pw-limit
type: u32
name-prefix: ethtool-a-
-
name: c33-pse-pw-limit-ranges
name-prefix: ethtool-a-
type: nest
multi-attr: true
nested-attributes: c33-pse-pw-limit
-
name: rss
attributes:
@ -975,6 +1059,32 @@ attribute-sets:
-
name: burst-tmr
type: u32
-
name: module-fw-flash
attributes:
-
name: header
type: nest
nested-attributes: header
-
name: file-name
type: string
-
name: password
type: u32
-
name: status
type: u32
enum: module-fw-flash-status
-
name: status-msg
type: string
-
name: done
type: uint
-
name: total
type: uint
operations:
enum-model: directional
@ -1325,6 +1435,8 @@ operations:
- tx-aggr-max-bytes
- tx-aggr-max-frames
- tx-aggr-time-usecs
- rx-profile
- tx-profile
dump: *coalesce-get-op
-
name: coalesce-set
@ -1611,6 +1723,12 @@ operations:
- c33-pse-admin-state
- c33-pse-admin-control
- c33-pse-pw-d-status
- c33-pse-pw-class
- c33-pse-actual-pw
- c33-pse-ext-state
- c33-pse-ext-substate
- c33-pse-avail-pw-limit
- c33-pse-pw-limit-ranges
dump: *pse-get-op
-
name: pse-set
@ -1624,6 +1742,7 @@ operations:
- header
- podl-pse-admin-control
- c33-pse-admin-control
- c33-pse-avail-pw-limit
-
name: rss-get
doc: Get RSS params.
@ -1733,3 +1852,28 @@ operations:
name: mm-ntf
doc: Notification for change in MAC Merge configuration.
notify: mm-get
-
name: module-fw-flash-act
doc: Flash transceiver module firmware.
attribute-set: module-fw-flash
do:
request:
attributes:
- header
- file-name
- password
-
name: module-fw-flash-ntf
doc: Notification for firmware flashing progress and status.
attribute-set: module-fw-flash
event:
attributes:
- header
- status
- status-msg
- done
- total

View File

@ -727,6 +727,12 @@ attribute-sets:
name: dec-ttl
type: nest
nested-attributes: dec-ttl-attrs
-
name: psample
type: nest
nested-attributes: psample-attrs
doc: |
Sends a packet sample to psample for external observation.
-
name: tunnel-key-attrs
enum-name: ovs-tunnel-key-attr
@ -938,6 +944,17 @@ attribute-sets:
-
name: gbp
type: u32
-
name: psample-attrs
enum-name: ovs-psample-attr
name-prefix: ovs-psample-attr-
attributes:
-
name: group
type: u32
-
name: cookie
type: binary
operations:
name-prefix: ovs-flow-cmd-

View File

@ -41,6 +41,16 @@ definitions:
- in-hw
- not-in-nw
- verbose
-
name: tc-flower-key-ctrl-flags
type: flags
entries:
- frag
- firstfrag
- tuncsum
- tundf
- tunoam
- tuncrit
-
name: tc-stats
type: struct
@ -2536,10 +2546,14 @@ attribute-sets:
name: key-flags
type: u32
byte-order: big-endian
enum: tc-flower-key-ctrl-flags
enum-as-flags: true
-
name: key-flags-mask
type: u32
byte-order: big-endian
enum: tc-flower-key-ctrl-flags
enum-as-flags: true
-
name: key-icmpv4-code
type: u8
@ -2749,6 +2763,18 @@ attribute-sets:
name: key-spi-mask
type: u32
byte-order: big-endian
-
name: key-enc-flags
type: u32
byte-order: big-endian
enum: tc-flower-key-ctrl-flags
enum-as-flags: true
-
name: key-enc-flags-mask
type: u32
byte-order: big-endian
enum: tc-flower-key-ctrl-flags
enum-as-flags: true
-
name: tc-flower-key-enc-opts-attrs
attributes:

View File

@ -0,0 +1,169 @@
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
name: tcp_metrics
protocol: genetlink-legacy
doc: |
Management interface for TCP metrics.
c-family-name: tcp-metrics-genl-name
c-version-name: tcp-metrics-genl-version
max-by-define: true
kernel-policy: global
definitions:
-
name: tcp-fastopen-cookie-max
type: const
value: 16
attribute-sets:
-
name: tcp-metrics
name-prefix: tcp-metrics-attr-
attributes:
-
name: addr-ipv4
type: u32
byte-order: big-endian
display-hint: ipv4
-
name: addr-ipv6
type: binary
checks:
min-len: 16
byte-order: big-endian
display-hint: ipv6
-
name: age
type: u64
-
name: tw-tsval
type: u32
doc: unused
-
name: tw-ts-stamp
type: s32
doc: unused
-
name: vals
type: nest
nested-attributes: metrics
-
name: fopen-mss
type: u16
-
name: fopen-syn-drops
type: u16
-
name: fopen-syn-drop-ts
type: u64
-
name: fopen-cookie
type: binary
checks:
min-len: tcp-fastopen-cookie-max
-
name: saddr-ipv4
type: u32
byte-order: big-endian
display-hint: ipv4
-
name: saddr-ipv6
type: binary
checks:
min-len: 16
byte-order: big-endian
display-hint: ipv6
-
name: pad
type: pad
-
name: metrics
# Intentionally don't define the name-prefix, see below.
doc: |
Attributes with metrics. Note that the values here do not match
the TCP_METRIC_* defines in the kernel, because kernel defines
are off-by one (e.g. rtt is defined as enum 0, while netlink carries
attribute type 1).
attributes:
-
name: rtt
type: u32
doc: |
Round Trip Time (RTT), in msecs with 3 bits fractional
(left-shift by 3 to get the msec value).
-
name: rttvar
type: u32
doc: |
Round Trip Time VARiance (RTT), in msecs with 2 bits fractional
(left-shift by 2 to get the msec value).
-
name: ssthresh
type: u32
doc: Slow Start THRESHold.
-
name: cwnd
type: u32
doc: Congestion Window.
-
name: reodering
type: u32
doc: Reodering metric.
-
name: rtt-us
type: u32
doc: |
Round Trip Time (RTT), in usecs, with 3 bits fractional
(left-shift by 3 to get the msec value).
-
name: rttvar-us
type: u32
doc: |
Round Trip Time (RTT), in usecs, with 2 bits fractional
(left-shift by 3 to get the msec value).
operations:
list:
-
name: get
doc: Retrieve metrics.
attribute-set: tcp-metrics
dont-validate: [ strict, dump ]
do:
request: &sel_attrs
attributes:
- addr-ipv4
- addr-ipv6
- saddr-ipv4
- saddr-ipv6
reply: &all_attrs
attributes:
- addr-ipv4
- addr-ipv6
- saddr-ipv4
- saddr-ipv6
- age
- vals
- fopen-mss
- fopen-syn-drops
- fopen-syn-drop-ts
- fopen-cookie
dump:
reply: *all_attrs
-
name: del
doc: Delete metrics.
attribute-set: tcp-metrics
dont-validate: [ strict, dump ]
flags: [ admin-perm ]
do:
request: *sel_attrs

View File

@ -189,22 +189,19 @@ the software port.
* - `rx[i]_gro_packets`
- Number of received packets processed using hardware-accelerated GRO. The
number of hardware GRO offloaded packets received on ring i.
number of hardware GRO offloaded packets received on ring i. Only true GRO
packets are counted: only packets that are in an SKB with a GRO count > 1.
- Acceleration
* - `rx[i]_gro_bytes`
- Number of received bytes processed using hardware-accelerated GRO. The
number of hardware GRO offloaded bytes received on ring i.
number of hardware GRO offloaded bytes received on ring i. Only true GRO
packets are counted: only packets that are in an SKB with a GRO count > 1.
- Acceleration
* - `rx[i]_gro_skbs`
- The number of receive SKBs constructed while performing
hardware-accelerated GRO.
- Informative
* - `rx[i]_gro_match_packets`
- Number of received packets processed using hardware-accelerated GRO that
met the flow table match criteria.
- The number of GRO SKBs constructed from hardware-accelerated GRO. Only SKBs
with a GRO count > 1 are counted.
- Informative
* - `rx[i]_gro_large_hds`
@ -212,6 +209,15 @@ the software port.
headers that require additional memory to be allocated.
- Informative
* - `rx[i]_hds_nodata_packets`
- Number of header only packets in header/data split mode [#accel]_.
- Informative
* - `rx[i]_hds_nodata_bytes`
- Number of bytes for header only packets in header/data split mode
[#accel]_.
- Informative
* - `rx[i]_lro_packets`
- The number of LRO packets received on ring i [#accel]_.
- Acceleration

View File

@ -11,6 +11,7 @@ Parameters
==========
.. list-table:: Generic parameters implemented
:widths: 5 5 90
* - Name
- Mode
@ -68,6 +69,30 @@ Parameters
To verify that value has been set:
$ devlink dev param show pci/0000:16:00.0 name tx_scheduling_layers
.. list-table:: Driver specific parameters implemented
:widths: 5 5 90
* - Name
- Mode
- Description
* - ``local_forwarding``
- runtime
- Controls loopback behavior by tuning scheduler bandwidth.
It impacts all kinds of functions: physical, virtual and
subfunctions.
Supported values are:
``enabled`` - loopback traffic is allowed on port
``disabled`` - loopback traffic is not allowed on this port
``prioritized`` - loopback traffic is prioritized on this port
Default value of ``local_forwarding`` parameter is ``enabled``.
``prioritized`` provides ability to adjust loopback traffic rate to increase
one port capacity at cost of the another. User needs to disable
local forwarding on one of the ports in order have increased capacity
on the ``prioritized`` port.
Info versions
=============

View File

@ -40,3 +40,19 @@ The ``octeontx2 AF`` driver implements the following driver-specific parameters.
- runtime
- Use to set the quantum which hardware uses for scheduling among transmit queues.
Hardware uses weighted DWRR algorithm to schedule among all transmit queues.
The ``octeontx2 PF`` driver implements the following driver-specific parameters.
.. list-table:: Driver-specific parameters implemented
:widths: 5 5 5 85
* - Name
- Type
- Mode
- Description
* - ``unicast_filter_count``
- u8
- runtime
- Set the maximum number of unicast filters that can be programmed for
the device. This can be used to achieve better device resource
utilization, avoiding over consumption of unused MCAM table entries.

View File

@ -228,6 +228,7 @@ Userspace to kernel:
``ETHTOOL_MSG_PLCA_GET_STATUS`` get PLCA RS status
``ETHTOOL_MSG_MM_GET`` get MAC merge layer state
``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware
===================================== =================================
Kernel to userspace:
@ -274,6 +275,7 @@ Kernel to userspace:
``ETHTOOL_MSG_PLCA_GET_STATUS_REPLY`` PLCA RS status
``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters
``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status
``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates
======================================== =================================
``GET`` requests are sent by userspace applications to retrieve device
@ -1033,6 +1035,8 @@ Kernel response contents:
``ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES`` u32 max aggr size, Tx
``ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES`` u32 max aggr packets, Tx
``ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS`` u32 time (us), aggr, Tx
``ETHTOOL_A_COALESCE_RX_PROFILE`` nested profile of DIM, Rx
``ETHTOOL_A_COALESCE_TX_PROFILE`` nested profile of DIM, Tx
=========================================== ====== =======================
Attributes are only included in reply if their value is not zero or the
@ -1062,6 +1066,10 @@ block should be sent.
This feature is mainly of interest for specific USB devices which does not cope
well with frequent small-sized URBs transmissions.
``ETHTOOL_A_COALESCE_RX_PROFILE`` and ``ETHTOOL_A_COALESCE_TX_PROFILE`` refer
to DIM parameters, see `Generic Network Dynamic Interrupt Moderation (Net DIM)
<https://www.kernel.org/doc/Documentation/networking/net_dim.rst>`_.
COALESCE_SET
============
@ -1098,6 +1106,8 @@ Request contents:
``ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES`` u32 max aggr size, Tx
``ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES`` u32 max aggr packets, Tx
``ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS`` u32 time (us), aggr, Tx
``ETHTOOL_A_COALESCE_RX_PROFILE`` nested profile of DIM, Rx
``ETHTOOL_A_COALESCE_TX_PROFILE`` nested profile of DIM, Tx
=========================================== ====== =======================
Request is rejected if it attributes declared as unsupported by driver (i.e.
@ -1720,17 +1730,28 @@ Request contents:
Kernel response contents:
====================================== ====== =============================
``ETHTOOL_A_PSE_HEADER`` nested reply header
``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` u32 Operational state of the PoDL
PSE functions
``ETHTOOL_A_PODL_PSE_PW_D_STATUS`` u32 power detection status of the
PoDL PSE.
``ETHTOOL_A_C33_PSE_ADMIN_STATE`` u32 Operational state of the PoE
PSE functions.
``ETHTOOL_A_C33_PSE_PW_D_STATUS`` u32 power detection status of the
PoE PSE.
====================================== ====== =============================
========================================== ====== =============================
``ETHTOOL_A_PSE_HEADER`` nested reply header
``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` u32 Operational state of the PoDL
PSE functions
``ETHTOOL_A_PODL_PSE_PW_D_STATUS`` u32 power detection status of the
PoDL PSE.
``ETHTOOL_A_C33_PSE_ADMIN_STATE`` u32 Operational state of the PoE
PSE functions.
``ETHTOOL_A_C33_PSE_PW_D_STATUS`` u32 power detection status of the
PoE PSE.
``ETHTOOL_A_C33_PSE_PW_CLASS`` u32 power class of the PoE PSE.
``ETHTOOL_A_C33_PSE_ACTUAL_PW`` u32 actual power drawn on the
PoE PSE.
``ETHTOOL_A_C33_PSE_EXT_STATE`` u32 power extended state of the
PoE PSE.
``ETHTOOL_A_C33_PSE_EXT_SUBSTATE`` u32 power extended substatus of
the PoE PSE.
``ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT`` u32 currently configured power
limit of the PoE PSE.
``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested Supported power limit
configuration ranges.
========================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_STATE`` attribute identifies
the operational state of the PoDL PSE functions. The operational state of the
@ -1762,6 +1783,46 @@ The same goes for ``ETHTOOL_A_C33_PSE_ADMIN_PW_D_STATUS`` implementing
.. kernel-doc:: include/uapi/linux/ethtool.h
:identifiers: ethtool_c33_pse_pw_d_status
When set, the optional ``ETHTOOL_A_C33_PSE_PW_CLASS`` attribute identifies
the power class of the C33 PSE. It depends on the class negotiated between
the PSE and the PD. This option is corresponding to ``IEEE 802.3-2022``
30.9.1.1.8 aPSEPowerClassification.
When set, the optional ``ETHTOOL_A_C33_PSE_ACTUAL_PW`` attribute identifies
This option is corresponding to ``IEEE 802.3-2022`` 30.9.1.1.23 aPSEActualPower.
Actual power is reported in mW.
When set, the optional ``ETHTOOL_A_C33_PSE_EXT_STATE`` attribute identifies
the extended error state of the C33 PSE. Possible values are:
.. kernel-doc:: include/uapi/linux/ethtool.h
:identifiers: ethtool_c33_pse_ext_state
When set, the optional ``ETHTOOL_A_C33_PSE_EXT_SUBSTATE`` attribute identifies
the extended error state of the C33 PSE. Possible values are:
Possible values are:
.. kernel-doc:: include/uapi/linux/ethtool.h
:identifiers: ethtool_c33_pse_ext_substate_class_num_events
ethtool_c33_pse_ext_substate_error_condition
ethtool_c33_pse_ext_substate_mr_pse_enable
ethtool_c33_pse_ext_substate_option_detect_ted
ethtool_c33_pse_ext_substate_option_vport_lim
ethtool_c33_pse_ext_substate_ovld_detected
ethtool_c33_pse_ext_substate_pd_dll_power_type
ethtool_c33_pse_ext_substate_power_not_available
ethtool_c33_pse_ext_substate_short_detected
When set, the optional ``ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT`` attribute
identifies the C33 PSE power limit in mW.
When set the optional ``ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES`` nested attribute
identifies the C33 PSE power limit ranges through
``ETHTOOL_A_C33_PSE_PWR_VAL_LIMIT_RANGE_MIN`` and
``ETHTOOL_A_C33_PSE_PWR_VAL_LIMIT_RANGE_MAX``.
If the controller works with fixed classes, the min and max values will be
equal.
PSE_SET
=======
@ -1773,6 +1834,8 @@ Request contents:
``ETHTOOL_A_PSE_HEADER`` nested request header
``ETHTOOL_A_PODL_PSE_ADMIN_CONTROL`` u32 Control PoDL PSE Admin state
``ETHTOOL_A_C33_PSE_ADMIN_CONTROL`` u32 Control PSE Admin state
``ETHTOOL_A_C33_PSE_AVAIL_PWR_LIMIT`` u32 Control PoE PSE available
power limit
====================================== ====== =============================
When set, the optional ``ETHTOOL_A_PODL_PSE_ADMIN_CONTROL`` attribute is used
@ -1783,6 +1846,18 @@ to control PoDL PSE Admin functions. This option is implementing
The same goes for ``ETHTOOL_A_C33_PSE_ADMIN_CONTROL`` implementing
``IEEE 802.3-2022`` 30.9.1.2.1 acPSEAdminControl.
When set, the optional ``ETHTOOL_A_C33_PSE_AVAIL_PWR_LIMIT`` attribute is
used to control the available power value limit for C33 PSE in milliwatts.
This attribute corresponds to the `pse_available_power` variable described in
``IEEE 802.3-2022`` 33.2.4.4 Variables and `pse_avail_pwr` in 145.2.5.4
Variables, which are described in power classes.
It was decided to use milliwatts for this interface to unify it with other
power monitoring interfaces, which also use milliwatts, and to align with
various existing products that document power consumption in watts rather than
classes. If power limit configuration based on classes is needed, the
conversion can be done in user space, for example by ethtool.
RSS_GET
=======
@ -2033,6 +2108,73 @@ The attributes are propagated to the driver through the following structure:
.. kernel-doc:: include/linux/ethtool.h
:identifiers: ethtool_mm_cfg
MODULE_FW_FLASH_ACT
===================
Flashes transceiver module firmware.
Request contents:
======================================= ====== ===========================
``ETHTOOL_A_MODULE_FW_FLASH_HEADER`` nested request header
``ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME`` string firmware image file name
``ETHTOOL_A_MODULE_FW_FLASH_PASSWORD`` u32 transceiver module password
======================================= ====== ===========================
The firmware update process consists of three logical steps:
1. Downloading a firmware image to the transceiver module and validating it.
2. Running the firmware image.
3. Committing the firmware image so that it is run upon reset.
When flash command is given, those three steps are taken in that order.
This message merely schedules the update process and returns immediately
without blocking. The process then runs asynchronously.
Since it can take several minutes to complete, during the update process
notifications are emitted from the kernel to user space updating it about
the status and progress.
The ``ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME`` attribute encodes the firmware
image file name. The firmware image is downloaded to the transceiver module,
validated, run and committed.
The optional ``ETHTOOL_A_MODULE_FW_FLASH_PASSWORD`` attribute encodes a password
that might be required as part of the transceiver module firmware update
process.
The firmware update process can take several minutes to complete. Therefore,
during the update process notifications are emitted from the kernel to user
space updating it about the status and progress.
Notification contents:
+---------------------------------------------------+--------+----------------+
| ``ETHTOOL_A_MODULE_FW_FLASH_HEADER`` | nested | reply header |
+---------------------------------------------------+--------+----------------+
| ``ETHTOOL_A_MODULE_FW_FLASH_STATUS`` | u32 | status |
+---------------------------------------------------+--------+----------------+
| ``ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG`` | string | status message |
+---------------------------------------------------+--------+----------------+
| ``ETHTOOL_A_MODULE_FW_FLASH_DONE`` | uint | progress |
+---------------------------------------------------+--------+----------------+
| ``ETHTOOL_A_MODULE_FW_FLASH_TOTAL`` | uint | total |
+---------------------------------------------------+--------+----------------+
The ``ETHTOOL_A_MODULE_FW_FLASH_STATUS`` attribute encodes the current status
of the firmware update process. Possible values are:
.. kernel-doc:: include/uapi/linux/ethtool.h
:identifiers: ethtool_module_fw_flash_status
The ``ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG`` attribute encodes a status message
string.
The ``ETHTOOL_A_MODULE_FW_FLASH_DONE`` and ``ETHTOOL_A_MODULE_FW_FLASH_TOTAL``
attributes encode the completed and total amount of work, respectively.
Request translation
===================
@ -2139,4 +2281,5 @@ are netlink only.
n/a ``ETHTOOL_MSG_PLCA_GET_STATUS``
n/a ``ETHTOOL_MSG_MM_GET``
n/a ``ETHTOOL_MSG_MM_SET``
n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT``
=================================== =====================================

View File

@ -19,6 +19,7 @@ Contents:
caif/index
ethtool-netlink
ieee802154
iso15765-2
j1939
kapi
msg_zerocopy
@ -72,6 +73,7 @@ Contents:
mac80211-injection
mctp
mpls-sysctl
mptcp
mptcp-sysctl
multiqueue
multi-pf-netdev
@ -104,6 +106,7 @@ Contents:
seg6-sysctl
skbuff
smc-sysctl
sriov
statistics
strparser
switchdev

View File

@ -131,6 +131,20 @@ fib_multipath_hash_fields - UNSIGNED INTEGER
Default: 0x0007 (source IP, destination IP and IP protocol)
fib_multipath_hash_seed - UNSIGNED INTEGER
The seed value used when calculating hash for multipath routes. Applies
to both IPv4 and IPv6 datapath. Only present for kernels built with
CONFIG_IP_ROUTE_MULTIPATH enabled.
When set to 0, the seed value used for multipath routing defaults to an
internal random-generated one.
The actual hashing algorithm is not specified -- there is no guarantee
that a next hop distribution effected by a given seed will keep stable
across kernel versions.
Default: 0 (random)
fib_sync_mem - UNSIGNED INTEGER
Amount of dirty memory from fib entries that can be backlogged before
synchronize_rcu is forced.
@ -1196,6 +1210,19 @@ tcp_pingpong_thresh - INTEGER
Default: 1
tcp_rto_min_us - INTEGER
Minimal TCP retransmission timeout (in microseconds). Note that the
rto_min route option has the highest precedence for configuring this
setting, followed by the TCP_BPF_RTO_MIN socket option, followed by
this tcp_rto_min_us sysctl.
The recommended practice is to use a value less or equal to 200000
microseconds.
Possible Values: 1 - INT_MAX
Default: 200000
UDP variables
=============

View File

@ -0,0 +1,386 @@
.. SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
====================
ISO 15765-2 (ISO-TP)
====================
Overview
========
ISO 15765-2, also known as ISO-TP, is a transport protocol specifically defined
for diagnostic communication on CAN. It is widely used in the automotive
industry, for example as the transport protocol for UDSonCAN (ISO 14229-3) or
emission-related diagnostic services (ISO 15031-5).
ISO-TP can be used both on CAN CC (aka Classical CAN) and CAN FD (CAN with
Flexible Datarate) based networks. It is also designed to be compatible with a
CAN network using SAE J1939 as data link layer (however, this is not a
requirement).
Specifications used
-------------------
* ISO 15765-2:2024 : Road vehicles - Diagnostic communication over Controller
Area Network (DoCAN). Part 2: Transport protocol and network layer services.
Addressing
----------
In its simplest form, ISO-TP is based on two kinds of addressing modes for the
nodes connected to the same network:
* physical addressing is implemented by two node-specific addresses and is used
in 1-to-1 communication.
* functional addressing is implemented by one node-specific address and is used
in 1-to-N communication.
Three different addressing formats can be employed:
* "normal" : each address is represented simply by a CAN ID.
* "extended": each address is represented by a CAN ID plus the first byte of
the CAN payload; both the CAN ID and the byte inside the payload shall be
different between two addresses.
* "mixed": each address is represented by a CAN ID plus the first byte of
the CAN payload; the CAN ID is different between two addresses, but the
additional byte is the same.
Transport protocol and associated frame types
---------------------------------------------
When transmitting data using the ISO-TP protocol, the payload can either fit
inside one single CAN message or not, also considering the overhead the protocol
is generating and the optional extended addressing. In the first case, the data
is transmitted at once using a so-called Single Frame (SF). In the second case,
ISO-TP defines a multi-frame protocol, in which the sender provides (through a
First Frame - FF) the PDU length which is to be transmitted and also asks for a
Flow Control (FC) frame, which provides the maximum supported size of a macro
data block (``blocksize``) and the minimum time between the single CAN messages
composing such block (``stmin``). Once this information has been received, the
sender starts to send frames containing fragments of the data payload (called
Consecutive Frames - CF), stopping after every ``blocksize``-sized block to wait
confirmation from the receiver which should then send another Flow Control
frame to inform the sender about its availability to receive more data.
How to Use ISO-TP
=================
As with others CAN protocols, the ISO-TP stack support is built into the
Linux network subsystem for the CAN bus, aka. Linux-CAN or SocketCAN, and
thus follows the same socket API.
Creation and basic usage of an ISO-TP socket
--------------------------------------------
To use the ISO-TP stack, ``#include <linux/can/isotp.h>`` shall be used. A
socket can then be created using the ``PF_CAN`` protocol family, the
``SOCK_DGRAM`` type (as the underlying protocol is datagram-based by design)
and the ``CAN_ISOTP`` protocol:
.. code-block:: C
s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP);
After the socket has been successfully created, ``bind(2)`` shall be called to
bind the socket to the desired CAN interface; to do so:
* a TX CAN ID shall be specified as part of the sockaddr supplied to the call
itself.
* a RX CAN ID shall also be specified, unless broadcast flags have been set
through socket option (explained below).
Once bound to an interface, the socket can be read from and written to using
the usual ``read(2)`` and ``write(2)`` system calls, as well as ``send(2)``,
``sendmsg(2)``, ``recv(2)`` and ``recvmsg(2)``.
Unlike the CAN_RAW socket API, only the ISO-TP data field (the actual payload)
is sent and received by the userspace application using these calls. The address
information and the protocol information are automatically filled by the ISO-TP
stack using the configuration supplied during socket creation. In the same way,
the stack will use the transport mechanism when required (i.e., when the size
of the data payload exceeds the MTU of the underlying CAN bus).
The sockaddr structure used for SocketCAN has extensions for use with ISO-TP,
as specified below:
.. code-block:: C
struct sockaddr_can {
sa_family_t can_family;
int can_ifindex;
union {
struct { canid_t rx_id, tx_id; } tp;
...
} can_addr;
}
* ``can_family`` and ``can_ifindex`` serve the same purpose as for other
SocketCAN sockets.
* ``can_addr.tp.rx_id`` specifies the receive (RX) CAN ID and will be used as
a RX filter.
* ``can_addr.tp.tx_id`` specifies the transmit (TX) CAN ID
ISO-TP socket options
---------------------
When creating an ISO-TP socket, reasonable defaults are set. Some options can
be modified with ``setsockopt(2)`` and/or read back with ``getsockopt(2)``.
General options
~~~~~~~~~~~~~~~
General socket options can be passed using the ``CAN_ISOTP_OPTS`` optname:
.. code-block:: C
struct can_isotp_options opts;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts))
where the ``can_isotp_options`` structure has the following contents:
.. code-block:: C
struct can_isotp_options {
u32 flags;
u32 frame_txtime;
u8 ext_address;
u8 txpad_content;
u8 rxpad_content;
u8 rx_ext_address;
};
* ``flags``: modifiers to be applied to the default behaviour of the ISO-TP
stack. Following flags are available:
* ``CAN_ISOTP_LISTEN_MODE``: listen only (do not send FC frames); normally
used as a testing feature.
* ``CAN_ISOTP_EXTEND_ADDR``: use the byte specified in ``ext_address`` as an
additional address component. This enables the "mixed" addressing format if
used alone, or the "extended" addressing format if used in conjunction with
``CAN_ISOTP_RX_EXT_ADDR``.
* ``CAN_ISOTP_TX_PADDING``: enable padding for transmitted frames, using
``txpad_content`` as value for the padding bytes.
* ``CAN_ISOTP_RX_PADDING``: enable padding for the received frames, using
``rxpad_content`` as value for the padding bytes.
* ``CAN_ISOTP_CHK_PAD_LEN``: check for correct padding length on the received
frames.
* ``CAN_ISOTP_CHK_PAD_DATA``: check padding bytes on the received frames
against ``rxpad_content``; if ``CAN_ISOTP_RX_PADDING`` is not specified,
this flag is ignored.
* ``CAN_ISOTP_HALF_DUPLEX``: force ISO-TP socket in half duplex mode
(that is, transport mechanism can only be incoming or outgoing at the same
time, not both).
* ``CAN_ISOTP_FORCE_TXSTMIN``: ignore stmin from received FC; normally
used as a testing feature.
* ``CAN_ISOTP_FORCE_RXSTMIN``: ignore CFs depending on rx stmin; normally
used as a testing feature.
* ``CAN_ISOTP_RX_EXT_ADDR``: use ``rx_ext_address`` instead of ``ext_address``
as extended addressing byte on the reception path. If used in conjunction
with ``CAN_ISOTP_EXTEND_ADDR``, this flag effectively enables the "extended"
addressing format.
* ``CAN_ISOTP_WAIT_TX_DONE``: wait until the frame is sent before returning
from ``write(2)`` and ``send(2)`` calls (i.e., blocking write operations).
* ``CAN_ISOTP_SF_BROADCAST``: use 1-to-N functional addressing (cannot be
specified alongside ``CAN_ISOTP_CF_BROADCAST``).
* ``CAN_ISOTP_CF_BROADCAST``: use 1-to-N transmission without flow control
(cannot be specified alongside ``CAN_ISOTP_SF_BROADCAST``).
NOTE: this is not covered by the ISO 15765-2 standard.
* ``CAN_ISOTP_DYN_FC_PARMS``: enable dynamic update of flow control
parameters.
* ``frame_txtime``: frame transmission time (defined as N_As/N_Ar inside the
ISO standard); if ``0``, the default (or the last set value) is used.
To set the transmission time to ``0``, the ``CAN_ISOTP_FRAME_TXTIME_ZERO``
macro (equal to 0xFFFFFFFF) shall be used.
* ``ext_address``: extended addressing byte, used if the
``CAN_ISOTP_EXTEND_ADDR`` flag is specified.
* ``txpad_content``: byte used as padding value for transmitted frames.
* ``rxpad_content``: byte used as padding value for received frames.
* ``rx_ext_address``: extended addressing byte for the reception path, used if
the ``CAN_ISOTP_RX_EXT_ADDR`` flag is specified.
Flow Control options
~~~~~~~~~~~~~~~~~~~~
Flow Control (FC) options can be passed using the ``CAN_ISOTP_RECV_FC`` optname
to provide the communication parameters for receiving ISO-TP PDUs.
.. code-block:: C
struct can_isotp_fc_options fc_opts;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fc_opts, sizeof(fc_opts));
where the ``can_isotp_fc_options`` structure has the following contents:
.. code-block:: C
struct can_isotp_options {
u8 bs;
u8 stmin;
u8 wftmax;
};
* ``bs``: blocksize provided in flow control frames.
* ``stmin``: minimum separation time provided in flow control frames; can
have the following values (others are reserved):
* 0x00 - 0x7F : 0 - 127 ms
* 0xF1 - 0xF9 : 100 us - 900 us
* ``wftmax``: maximum number of wait frames provided in flow control frames.
Link Layer options
~~~~~~~~~~~~~~~~~~
Link Layer (LL) options can be passed using the ``CAN_ISOTP_LL_OPTS`` optname:
.. code-block:: C
struct can_isotp_ll_options ll_opts;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &ll_opts, sizeof(ll_opts));
where the ``can_isotp_ll_options`` structure has the following contents:
.. code-block:: C
struct can_isotp_ll_options {
u8 mtu;
u8 tx_dl;
u8 tx_flags;
};
* ``mtu``: generated and accepted CAN frame type, can be equal to ``CAN_MTU``
for classical CAN frames or ``CANFD_MTU`` for CAN FD frames.
* ``tx_dl``: maximum payload length for transmitted frames, can have one value
among: 8, 12, 16, 20, 24, 32, 48, 64. Values above 8 only apply to CAN FD
traffic (i.e.: ``mtu = CANFD_MTU``).
* ``tx_flags``: flags set into ``struct canfd_frame.flags`` at frame creation.
Only applies to CAN FD traffic (i.e.: ``mtu = CANFD_MTU``).
Transmission stmin
~~~~~~~~~~~~~~~~~~
The transmission minimum separation time (stmin) can be forced using the
``CAN_ISOTP_TX_STMIN`` optname and providing an stmin value in microseconds as
a 32bit unsigned integer; this will overwrite the value sent by the receiver in
flow control frames:
.. code-block:: C
uint32_t stmin;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &stmin, sizeof(stmin));
Reception stmin
~~~~~~~~~~~~~~~
The reception minimum separation time (stmin) can be forced using the
``CAN_ISOTP_RX_STMIN`` optname and providing an stmin value in microseconds as
a 32bit unsigned integer; received Consecutive Frames (CF) which timestamps
differ less than this value will be ignored:
.. code-block:: C
uint32_t stmin;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &stmin, sizeof(stmin));
Multi-frame transport support
-----------------------------
The ISO-TP stack contained inside the Linux kernel supports the multi-frame
transport mechanism defined by the standard, with the following constraints:
* the maximum size of a PDU is defined by a module parameter, with an hard
limit imposed at build time.
* when a transmission is in progress, subsequent calls to ``write(2)`` will
block, while calls to ``send(2)`` will either block or fail depending on the
presence of the ``MSG_DONTWAIT`` flag.
* no support is present for sending "wait frames": whether a PDU can be fully
received or not is decided when the First Frame is received.
Errors
------
Following errors are reported to userspace:
RX path errors
~~~~~~~~~~~~~~
============ ===============================================================
-ETIMEDOUT timeout of data reception
-EILSEQ sequence number mismatch during a multi-frame reception
-EBADMSG data reception with wrong padding
============ ===============================================================
TX path errors
~~~~~~~~~~~~~~
========== =================================================================
-ECOMM flow control reception timeout
-EMSGSIZE flow control reception overflow
-EBADMSG flow control reception with wrong layout/padding
========== =================================================================
Examples
========
Basic node example
------------------
Following example implements a node using "normal" physical addressing, with
RX ID equal to 0x18DAF142 and a TX ID equal to 0x18DA42F1. All options are left
to their default.
.. code-block:: C
int s;
struct sockaddr_can addr;
int ret;
s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP);
if (s < 0)
exit(1);
addr.can_family = AF_CAN;
addr.can_ifindex = if_nametoindex("can0");
addr.tp.tx_id = 0x18DA42F1 | CAN_EFF_FLAG;
addr.tp.rx_id = 0x18DAF142 | CAN_EFF_FLAG;
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0)
exit(1);
/* Data can now be received using read(s, ...) and sent using write(s, ...) */
Additional examples
-------------------
More complete (and complex) examples can be found inside the ``isotp*`` userland
tools, distributed as part of the ``can-utils`` utilities at:
https://github.com/linux-can/can-utils

View File

@ -7,14 +7,6 @@ MPTCP Sysfs variables
/proc/sys/net/mptcp/* Variables
===============================
enabled - BOOLEAN
Control whether MPTCP sockets can be created.
MPTCP sockets can be created if the value is 1. This is a
per-namespace sysctl.
Default: 1 (enabled)
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
@ -25,25 +17,6 @@ add_addr_timeout - INTEGER (seconds)
Default: 120
close_timeout - INTEGER (seconds)
Set the make-after-break timeout: in absence of any close or
shutdown syscall, MPTCP sockets will maintain the status
unchanged for such time, after the last subflow removal, before
moving to TCP_CLOSE.
The default value matches TCP_TIMEWAIT_LEN. This is a per-namespace
sysctl.
Default: 60
checksum_enabled - BOOLEAN
Control whether DSS checksum can be enabled.
DSS checksum can be enabled if the value is nonzero. This is a
per-namespace sysctl.
Default: 0
allow_join_initial_addr_port - BOOLEAN
Allow peers to send join requests to the IP address and port number used
by the initial subflow if the value is 1. This controls a flag that is
@ -57,6 +30,37 @@ allow_join_initial_addr_port - BOOLEAN
Default: 1
available_schedulers - STRING
Shows the available schedulers choices that are registered. More packet
schedulers may be available, but not loaded.
checksum_enabled - BOOLEAN
Control whether DSS checksum can be enabled.
DSS checksum can be enabled if the value is nonzero. This is a
per-namespace sysctl.
Default: 0
close_timeout - INTEGER (seconds)
Set the make-after-break timeout: in absence of any close or
shutdown syscall, MPTCP sockets will maintain the status
unchanged for such time, after the last subflow removal, before
moving to TCP_CLOSE.
The default value matches TCP_TIMEWAIT_LEN. This is a per-namespace
sysctl.
Default: 60
enabled - BOOLEAN
Control whether MPTCP sockets can be created.
MPTCP sockets can be created if the value is 1. This is a
per-namespace sysctl.
Default: 1 (enabled)
pm_type - INTEGER
Set the default path manager type to use for each new MPTCP
socket. In-kernel path management will control subflow
@ -74,6 +78,14 @@ pm_type - INTEGER
Default: 0
scheduler - STRING
Select the scheduler of your choice.
Support for selection of different schedulers. This is a per-namespace
sysctl.
Default: "default"
stale_loss_cnt - INTEGER
The number of MPTCP-level retransmission intervals with no traffic and
pending outstanding data on a given subflow required to declare it stale.
@ -85,11 +97,3 @@ stale_loss_cnt - INTEGER
This is a per-namespace sysctl.
Default: 4
scheduler - STRING
Select the scheduler of your choice.
Support for selection of different schedulers. This is a per-namespace
sysctl.
Default: "default"

View File

@ -0,0 +1,156 @@
.. SPDX-License-Identifier: GPL-2.0
=====================
Multipath TCP (MPTCP)
=====================
Introduction
============
Multipath TCP or MPTCP is an extension to the standard TCP and is described in
`RFC 8684 (MPTCPv1) <https://www.rfc-editor.org/rfc/rfc8684.html>`_. It allows a
device to make use of multiple interfaces at once to send and receive TCP
packets over a single MPTCP connection. MPTCP can aggregate the bandwidth of
multiple interfaces or prefer the one with the lowest latency. It also allows a
fail-over if one path is down, and the traffic is seamlessly reinjected on other
paths.
For more details about Multipath TCP in the Linux kernel, please see the
official website: `mptcp.dev <https://www.mptcp.dev>`_.
Use cases
=========
Thanks to MPTCP, being able to use multiple paths in parallel or simultaneously
brings new use-cases, compared to TCP:
- Seamless handovers: switching from one path to another while preserving
established connections, e.g. to be used in mobility use-cases, like on
smartphones.
- Best network selection: using the "best" available path depending on some
conditions, e.g. latency, losses, cost, bandwidth, etc.
- Network aggregation: using multiple paths at the same time to have a higher
throughput, e.g. to combine fixed and mobile networks to send files faster.
Concepts
========
Technically, when a new socket is created with the ``IPPROTO_MPTCP`` protocol
(Linux-specific), a *subflow* (or *path*) is created. This *subflow* consists of
a regular TCP connection that is used to transmit data through one interface.
Additional *subflows* can be negotiated later between the hosts. For the remote
host to be able to detect the use of MPTCP, a new field is added to the TCP
*option* field of the underlying TCP *subflow*. This field contains, amongst
other things, a ``MP_CAPABLE`` option that tells the other host to use MPTCP if
it is supported. If the remote host or any middlebox in between does not support
it, the returned ``SYN+ACK`` packet will not contain MPTCP options in the TCP
*option* field. In that case, the connection will be "downgraded" to plain TCP,
and it will continue with a single path.
This behavior is made possible by two internal components: the path manager, and
the packet scheduler.
Path Manager
------------
The Path Manager is in charge of *subflows*, from creation to deletion, and also
address announcements. Typically, it is the client side that initiates subflows,
and the server side that announces additional addresses via the ``ADD_ADDR`` and
``REMOVE_ADDR`` options.
Path managers are controlled by the ``net.mptcp.pm_type`` sysctl knob -- see
mptcp-sysctl.rst. There are two types: the in-kernel one (type ``0``) where the
same rules are applied for all the connections (see: ``ip mptcp``) ; and the
userspace one (type ``1``), controlled by a userspace daemon (i.e. `mptcpd
<https://mptcpd.mptcp.dev/>`_) where different rules can be applied for each
connection. The path managers can be controlled via a Netlink API; see
netlink_spec/mptcp_pm.rst.
To be able to use multiple IP addresses on a host to create multiple *subflows*
(paths), the default in-kernel MPTCP path-manager needs to know which IP
addresses can be used. This can be configured with ``ip mptcp endpoint`` for
example.
Packet Scheduler
----------------
The Packet Scheduler is in charge of selecting which available *subflow(s)* to
use to send the next data packet. It can decide to maximize the use of the
available bandwidth, only to pick the path with the lower latency, or any other
policy depending on the configuration.
Packet schedulers are controlled by the ``net.mptcp.scheduler`` sysctl knob --
see mptcp-sysctl.rst.
Sockets API
===========
Creating MPTCP sockets
----------------------
On Linux, MPTCP can be used by selecting MPTCP instead of TCP when creating the
``socket``:
.. code-block:: C
int sd = socket(AF_INET(6), SOCK_STREAM, IPPROTO_MPTCP);
Note that ``IPPROTO_MPTCP`` is defined as ``262``.
If MPTCP is not supported, ``errno`` will be set to:
- ``EINVAL``: (*Invalid argument*): MPTCP is not available, on kernels < 5.6.
- ``EPROTONOSUPPORT`` (*Protocol not supported*): MPTCP has not been compiled,
on kernels >= v5.6.
- ``ENOPROTOOPT`` (*Protocol not available*): MPTCP has been disabled using
``net.mptcp.enabled`` sysctl knob; see mptcp-sysctl.rst.
MPTCP is then opt-in: applications need to explicitly request it. Note that
applications can be forced to use MPTCP with different techniques, e.g.
``LD_PRELOAD`` (see ``mptcpize``), eBPF (see ``mptcpify``), SystemTAP,
``GODEBUG`` (``GODEBUG=multipathtcp=1``), etc.
Switching to ``IPPROTO_MPTCP`` instead of ``IPPROTO_TCP`` should be as
transparent as possible for the userspace applications.
Socket options
--------------
MPTCP supports most socket options handled by TCP. It is possible some less
common options are not supported, but contributions are welcome.
Generally, the same value is propagated to all subflows, including the ones
created after the calls to ``setsockopt()``. eBPF can be used to set different
values per subflow.
There are some MPTCP specific socket options at the ``SOL_MPTCP`` (284) level to
retrieve info. They fill the ``optval`` buffer of the ``getsockopt()`` system
call:
- ``MPTCP_INFO``: Uses ``struct mptcp_info``.
- ``MPTCP_TCPINFO``: Uses ``struct mptcp_subflow_data``, followed by an array of
``struct tcp_info``.
- ``MPTCP_SUBFLOW_ADDRS``: Uses ``struct mptcp_subflow_data``, followed by an
array of ``mptcp_subflow_addrs``.
- ``MPTCP_FULL_INFO``: Uses ``struct mptcp_full_info``, with one pointer to an
array of ``struct mptcp_subflow_info`` (including the
``struct mptcp_subflow_addrs``), and one pointer to an array of
``struct tcp_info``, followed by the content of ``struct mptcp_info``.
Note that at the TCP level, ``TCP_IS_MPTCP`` socket option can be used to know
if MPTCP is currently being used: the value will be set to 1 if it is.
Design choices
==============
A new socket type has been added for MPTCP for the userspace-facing socket. The
kernel is in charge of creating subflow sockets: they are TCP sockets where the
behavior is modified using TCP-ULP.
MPTCP listen sockets will create "plain" *accepted* TCP sockets if the
connection request from the client didn't ask for MPTCP, making the performance
impact minimal when MPTCP is enabled by default.

View File

@ -169,6 +169,48 @@ usage is not complete but it should make the outline of the usage clear.
...
}
Tuning DIM
==========
Net DIM serves a range of network devices and delivers excellent acceleration
benefits. Yet, it has been observed that some preset configurations of DIM may
not align seamlessly with the varying specifications of network devices, and
this discrepancy has been identified as a factor to the suboptimal performance
outcomes of DIM-enabled network devices, related to a mismatch in profiles.
To address this issue, Net DIM introduces a per-device control to modify and
access a device's ``rx-profile`` and ``tx-profile`` parameters:
Assume that the target network device is named ethx, and ethx only declares
support for RX profile setting and supports modification of ``usec`` field
and ``pkts`` field (See the data structure:
:c:type:`struct dim_cq_moder <dim_cq_moder>`).
You can use ethtool to modify the current RX DIM profile where all
values are 64::
$ ethtool -C ethx rx-profile 1,1,n_2,2,n_3,n,n_n,4,n_n,n,n
``n`` means do not modify this field, and ``_`` separates structure
elements of the profile array.
Querying the current profiles using::
$ ethtool -c ethx
...
rx-profile:
{.usec = 1, .pkts = 1, .comps = n/a,},
{.usec = 2, .pkts = 2, .comps = n/a,},
{.usec = 3, .pkts = 64, .comps = n/a,},
{.usec = 64, .pkts = 4, .comps = n/a,},
{.usec = 64, .pkts = 64, .comps = n/a,}
tx-profile: n/a
If the network device does not support specific fields of DIM profiles,
the corresponding ``n/a`` will display. If the ``n/a`` field is being
modified, error messages will be reported.
Dynamic Interrupt Moderation (DIM) library API
==============================================

View File

@ -327,6 +327,12 @@ Some of the interface modes are described below:
This is the Penta SGMII mode, it is similar to QSGMII but it combines 5
SGMII lines into a single link compared to 4 on QSGMII.
``PHY_INTERFACE_MODE_10G_QXGMII``
Represents the 10G-QXGMII PHY-MAC interface as defined by the Cisco USXGMII
Multiport Copper Interface document. It supports 4 ports over a 10.3125 GHz
SerDes lane, each port having speeds of 2.5G / 1G / 100M / 10M achieved
through symbol replication. The PCS expects the standard USXGMII code word.
Pause frames / flow control
===========================

View File

@ -0,0 +1,25 @@
.. SPDX-License-Identifier: GPL-2.0
===============
NIC SR-IOV APIs
===============
Modern NICs are strongly encouraged to focus on implementing the ``switchdev``
model (see :ref:`switchdev`) to configure forwarding and security of SR-IOV
functionality.
Legacy API
==========
The old SR-IOV API is implemented in ``rtnetlink`` Netlink family as part of
the ``RTM_GETLINK`` and ``RTM_SETLINK`` commands. On the driver side
it consists of a number of ``ndo_set_vf_*`` and ``ndo_get_vf_*`` callbacks.
Since the legacy APIs do not integrate well with the rest of the stack
the API is considered frozen; no new functionality or extensions
will be accepted. New drivers should not implement the uncommon callbacks;
namely the following callbacks are off limits:
- ``ndo_get_vf_port``
- ``ndo_set_vf_port``
- ``ndo_set_vf_rss_query_en``

View File

@ -337,6 +337,15 @@ TCP-AO per-socket counters are also duplicated with per-netns counters,
exposed with SNMP. Those are ``TCPAOGood``, ``TCPAOBad``, ``TCPAOKeyNotFound``,
``TCPAORequired`` and ``TCPAODroppedIcmps``.
For monitoring purposes, there are following TCP-AO trace events:
``tcp_hash_bad_header``, ``tcp_hash_ao_required``, ``tcp_ao_handshake_failure``,
``tcp_ao_wrong_maclen``, ``tcp_ao_wrong_maclen``, ``tcp_ao_key_not_found``,
``tcp_ao_rnext_request``, ``tcp_ao_synack_no_key``, ``tcp_ao_snd_sne_update``,
``tcp_ao_rcv_sne_update``. It's possible to separately enable any of them and
one can filter them by net-namespace, 4-tuple, family, L3 index, and TCP header
flags. If a segment has a TCP-AO header, the filters may also include
keyid, rnext, and maclen. SNE updates include the rolled-over numbers.
RFC 5925 very permissively specifies how TCP port matching can be done for
MKTs::

View File

@ -682,6 +682,15 @@ S: Supported
F: fs/aio.c
F: include/linux/*aio*.h
AIROHA ETHERNET DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml
F: drivers/net/ethernet/mediatek/airoha_eth.c
AIROHA SPI SNFI DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
M: Ray Liu <ray.liu@airoha.com>
@ -4896,6 +4905,7 @@ W: https://github.com/linux-can
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
F: Documentation/networking/can.rst
F: Documentation/networking/iso15765-2.rst
F: include/linux/can/can-ml.h
F: include/linux/can/core.h
F: include/linux/can/skb.h
@ -8880,14 +8890,14 @@ M: Madalin Bucur <madalin.bucur@nxp.com>
R: Sean Anderson <sean.anderson@seco.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/fsl-fman.txt
F: Documentation/devicetree/bindings/net/fsl,fman*.yaml
F: drivers/net/ethernet/freescale/fman
FREESCALE QORIQ PTP CLOCK DRIVER
M: Yangbo Lu <yangbo.lu@nxp.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
F: Documentation/devicetree/bindings/ptp/fsl,ptp.yaml
F: drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp*
F: drivers/net/ethernet/freescale/dpaa2/dprtc*
F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c
@ -11123,8 +11133,8 @@ F: include/drm/xe*
F: include/uapi/drm/xe_drm.h
INTEL ETHERNET DRIVERS
M: Jesse Brandeburg <jesse.brandeburg@intel.com>
M: Tony Nguyen <anthony.l.nguyen@intel.com>
M: Przemek Kitszel <przemyslaw.kitszel@intel.com>
L: intel-wired-lan@lists.osuosl.org (moderated for non-subscribers)
S: Supported
W: https://www.intel.com/content/www/us/en/support.html
@ -12523,6 +12533,7 @@ LANTIQ / INTEL Ethernet drivers
M: Hauke Mehrtens <hauke@hauke-m.de>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml
F: drivers/net/dsa/lantiq_gswip.c
F: drivers/net/dsa/lantiq_pce.h
F: drivers/net/ethernet/lantiq_xrx200.c
@ -14643,6 +14654,13 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml
F: drivers/staging/media/meson/vdec/
META ETHERNET DRIVERS
M: Alexander Duyck <alexanderduyck@fb.com>
M: Jakub Kicinski <kuba@kernel.org>
R: kernel-team@meta.com
S: Supported
F: drivers/net/ethernet/meta/
METHODE UDPU SUPPORT
M: Robert Marko <robert.marko@sartura.hr>
S: Maintained
@ -15847,7 +15865,7 @@ B: https://github.com/multipath-tcp/mptcp_net-next/issues
T: git https://github.com/multipath-tcp/mptcp_net-next.git export-net
T: git https://github.com/multipath-tcp/mptcp_net-next.git export
F: Documentation/netlink/specs/mptcp_pm.yaml
F: Documentation/networking/mptcp-sysctl.rst
F: Documentation/networking/mptcp*.rst
F: include/net/mptcp.h
F: include/trace/events/mptcp.h
F: include/uapi/linux/mptcp*.h
@ -15864,8 +15882,13 @@ F: include/linux/tcp.h
F: include/net/tcp.h
F: include/trace/events/tcp.h
F: include/uapi/linux/tcp.h
F: net/ipv4/inet_connection_sock.c
F: net/ipv4/inet_hashtables.c
F: net/ipv4/inet_timewait_sock.c
F: net/ipv4/syncookies.c
F: net/ipv4/tcp*.c
F: net/ipv6/inet6_connection_sock.c
F: net/ipv6/inet6_hashtables.c
F: net/ipv6/syncookies.c
F: net/ipv6/tcp*.c
@ -19154,6 +19177,14 @@ F: drivers/net/ethernet/renesas/Makefile
F: drivers/net/ethernet/renesas/rcar_gen4*
F: drivers/net/ethernet/renesas/rswitch*
RENESAS ETHERNET TSN DRIVER
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
L: netdev@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/net/renesas,ethertsn.yaml
F: drivers/net/ethernet/renesas/rtsn.*
RENESAS IDT821034 ASoC CODEC
M: Herve Codina <herve.codina@bootlin.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@ -22262,7 +22293,13 @@ TEHUTI ETHERNET DRIVER
M: Andy Gospodarek <andy@greyhouse.net>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/tehuti/*
F: drivers/net/ethernet/tehuti/tehuti.*
TEHUTI TN40XX ETHERNET DRIVER
M: FUJITA Tomonori <fujita.tomonori@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/tehuti/tn40*
TELECOM CLOCK DRIVER FOR MCPL0010
M: Mark Gross <markgross@kernel.org>

View File

@ -896,7 +896,3 @@
&wdt {
compatible = "rockchip,rk3066-wdt", "snps,dw-wdt";
};
&emac {
compatible = "rockchip,rk3066-emac";
};

View File

@ -194,17 +194,14 @@
};
emac: ethernet@10204000 {
compatible = "snps,arc-emac";
compatible = "rockchip,rk3066-emac";
reg = <0x10204000 0x3c>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
rockchip,grf = <&grf>;
clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>;
clock-names = "hclk", "macref";
max-speed = <100>;
phy-mode = "rmii";
rockchip,grf = <&grf>;
status = "disabled";
};

View File

@ -73,3 +73,15 @@
"rx0", "rx1",
"rxmgm0", "rxmgm1";
};
&icssg0_iep0 {
interrupt-parent = <&icssg0_intc>;
interrupts = <7 7 7>;
interrupt-names = "iep_cap_cmp";
};
&icssg0_iep1 {
interrupt-parent = <&icssg0_intc>;
interrupts = <56 8 8>;
interrupt-names = "iep_cap_cmp";
};

View File

@ -1244,6 +1244,13 @@ emit_cond_jmp:
break;
}
/* Implement helper call to bpf_get_current_task/_btf() inline */
if (insn->src_reg == 0 && (insn->imm == BPF_FUNC_get_current_task ||
insn->imm == BPF_FUNC_get_current_task_btf)) {
emit(A64_MRS_SP_EL0(r0), ctx);
break;
}
ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
&func_addr, &func_addr_fixed);
if (ret < 0)
@ -1829,8 +1836,7 @@ skip_init_ctx:
prog->jited_len = 0;
goto out_free_hdr;
}
if (WARN_ON(bpf_jit_binary_pack_finalize(prog, ro_header,
header))) {
if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
/* ro_header has been freed */
ro_header = NULL;
prog = orig_prog;
@ -2141,7 +2147,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
emit(A64_STR64I(A64_R(20), A64_SP, regs_off + 8), ctx);
if (flags & BPF_TRAMP_F_CALL_ORIG) {
emit_addr_mov_i64(A64_R(0), (const u64)im, ctx);
emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
emit_call((const u64)__bpf_tramp_enter, ctx);
}
@ -2185,7 +2191,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
if (flags & BPF_TRAMP_F_CALL_ORIG) {
im->ip_epilogue = ctx->ro_image + ctx->idx;
emit_addr_mov_i64(A64_R(0), (const u64)im, ctx);
emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
emit_call((const u64)__bpf_tramp_exit, ctx);
}
@ -2581,6 +2587,8 @@ bool bpf_jit_inlines_helper_call(s32 imm)
{
switch (imm) {
case BPF_FUNC_get_smp_processor_id:
case BPF_FUNC_get_current_task:
case BPF_FUNC_get_current_task_btf:
return true;
default:
return false;

View File

@ -225,7 +225,7 @@ skip_init_ctx:
fp->jited_len = proglen + FUNCTION_DESCR_SIZE;
if (!fp->is_func || extra_pass) {
if (bpf_jit_binary_pack_finalize(fp, fhdr, hdr)) {
if (bpf_jit_binary_pack_finalize(fhdr, hdr)) {
fp = org_fp;
goto out_addrs;
}
@ -348,7 +348,7 @@ void bpf_jit_free(struct bpf_prog *fp)
* before freeing it.
*/
if (jit_data) {
bpf_jit_binary_pack_finalize(fp, jit_data->fhdr, jit_data->hdr);
bpf_jit_binary_pack_finalize(jit_data->fhdr, jit_data->hdr);
kvfree(jit_data->addrs);
kfree(jit_data);
}

View File

@ -610,6 +610,18 @@ config TOOLCHAIN_HAS_VECTOR_CRYPTO
def_bool $(as-instr, .option arch$(comma) +v$(comma) +zvkb)
depends on AS_HAS_OPTION_ARCH
config RISCV_ISA_ZBA
bool "Zba extension support for bit manipulation instructions"
default y
help
Add support for enabling optimisations in the kernel when the Zba
extension is detected at boot.
The Zba extension provides instructions to accelerate the generation
of addresses that index into arrays of basic data types.
If you don't know what to do here, say Y.
config RISCV_ISA_ZBB
bool "Zbb extension support for bit manipulation instructions"
depends on TOOLCHAIN_HAS_ZBB

View File

@ -18,6 +18,11 @@ static inline bool rvc_enabled(void)
return IS_ENABLED(CONFIG_RISCV_ISA_C);
}
static inline bool rvzba_enabled(void)
{
return IS_ENABLED(CONFIG_RISCV_ISA_ZBA) && riscv_has_extension_likely(RISCV_ISA_EXT_ZBA);
}
static inline bool rvzbb_enabled(void)
{
return IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && riscv_has_extension_likely(RISCV_ISA_EXT_ZBB);
@ -737,6 +742,17 @@ static inline u16 rvc_swsp(u32 imm8, u8 rs2)
return rv_css_insn(0x6, imm, rs2, 0x2);
}
/* RVZBA instructions. */
static inline u32 rvzba_sh2add(u8 rd, u8 rs1, u8 rs2)
{
return rv_r_insn(0x10, rs2, rs1, 0x4, rd, 0x33);
}
static inline u32 rvzba_sh3add(u8 rd, u8 rs1, u8 rs2)
{
return rv_r_insn(0x10, rs2, rs1, 0x6, rd, 0x33);
}
/* RVZBB instructions. */
static inline u32 rvzbb_sextb(u8 rd, u8 rs1)
{
@ -939,6 +955,14 @@ static inline u16 rvc_sdsp(u32 imm9, u8 rs2)
return rv_css_insn(0x7, imm, rs2, 0x2);
}
/* RV64-only ZBA instructions. */
static inline u32 rvzba_zextw(u8 rd, u8 rs1)
{
/* add.uw rd, rs1, ZERO */
return rv_r_insn(0x04, RV_REG_ZERO, rs1, 0, rd, 0x3b);
}
#endif /* __riscv_xlen == 64 */
/* Helper functions that emit RVC instructions when possible. */
@ -1082,6 +1106,28 @@ static inline void emit_sw(u8 rs1, s32 off, u8 rs2, struct rv_jit_context *ctx)
emit(rv_sw(rs1, off, rs2), ctx);
}
static inline void emit_sh2add(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx)
{
if (rvzba_enabled()) {
emit(rvzba_sh2add(rd, rs1, rs2), ctx);
return;
}
emit_slli(rd, rs1, 2, ctx);
emit_add(rd, rd, rs2, ctx);
}
static inline void emit_sh3add(u8 rd, u8 rs1, u8 rs2, struct rv_jit_context *ctx)
{
if (rvzba_enabled()) {
emit(rvzba_sh3add(rd, rs1, rs2), ctx);
return;
}
emit_slli(rd, rs1, 3, ctx);
emit_add(rd, rd, rs2, ctx);
}
/* RV64-only helper functions. */
#if __riscv_xlen == 64
@ -1161,6 +1207,11 @@ static inline void emit_zexth(u8 rd, u8 rs, struct rv_jit_context *ctx)
static inline void emit_zextw(u8 rd, u8 rs, struct rv_jit_context *ctx)
{
if (rvzba_enabled()) {
emit(rvzba_zextw(rd, rs), ctx);
return;
}
emit_slli(rd, rs, 32, ctx);
emit_srli(rd, rd, 32, ctx);
}

View File

@ -811,8 +811,7 @@ static int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx)
* if (!prog)
* goto out;
*/
emit(rv_slli(RV_REG_T0, lo(idx_reg), 2), ctx);
emit(rv_add(RV_REG_T0, RV_REG_T0, lo(arr_reg)), ctx);
emit_sh2add(RV_REG_T0, lo(idx_reg), lo(arr_reg), ctx);
off = offsetof(struct bpf_array, ptrs);
if (is_12b_check(off, insn))
return -1;

View File

@ -15,7 +15,10 @@
#include <asm/percpu.h>
#include "bpf_jit.h"
#define RV_MAX_REG_ARGS 8
#define RV_FENTRY_NINSNS 2
/* imm that allows emit_imm to emit max count insns */
#define RV_MAX_COUNT_IMM 0x7FFF7FF7FF7FF7FF
#define RV_REG_TCC RV_REG_A6
#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */
@ -380,8 +383,7 @@ static int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx)
* if (!prog)
* goto out;
*/
emit_slli(RV_REG_T2, RV_REG_A2, 3, ctx);
emit_add(RV_REG_T2, RV_REG_T2, RV_REG_A1, ctx);
emit_sh3add(RV_REG_T2, RV_REG_A2, RV_REG_A1, ctx);
off = offsetof(struct bpf_array, ptrs);
if (is_12b_check(off, insn))
return -1;
@ -537,8 +539,10 @@ static void emit_atomic(u8 rd, u8 rs, s16 off, s32 imm, bool is64,
/* r0 = atomic_cmpxchg(dst_reg + off16, r0, src_reg); */
case BPF_CMPXCHG:
r0 = bpf_to_rv_reg(BPF_REG_0, ctx);
emit(is64 ? rv_addi(RV_REG_T2, r0, 0) :
rv_addiw(RV_REG_T2, r0, 0), ctx);
if (is64)
emit_mv(RV_REG_T2, r0, ctx);
else
emit_addiw(RV_REG_T2, r0, 0, ctx);
emit(is64 ? rv_lr_d(r0, 0, rd, 0, 0) :
rv_lr_w(r0, 0, rd, 0, 0), ctx);
jmp_offset = ninsns_rvoff(8);
@ -689,26 +693,45 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
return ret;
}
static void store_args(int nregs, int args_off, struct rv_jit_context *ctx)
static void store_args(int nr_arg_slots, int args_off, struct rv_jit_context *ctx)
{
int i;
for (i = 0; i < nregs; i++) {
emit_sd(RV_REG_FP, -args_off, RV_REG_A0 + i, ctx);
for (i = 0; i < nr_arg_slots; i++) {
if (i < RV_MAX_REG_ARGS) {
emit_sd(RV_REG_FP, -args_off, RV_REG_A0 + i, ctx);
} else {
/* skip slots for T0 and FP of traced function */
emit_ld(RV_REG_T1, 16 + (i - RV_MAX_REG_ARGS) * 8, RV_REG_FP, ctx);
emit_sd(RV_REG_FP, -args_off, RV_REG_T1, ctx);
}
args_off -= 8;
}
}
static void restore_args(int nregs, int args_off, struct rv_jit_context *ctx)
static void restore_args(int nr_reg_args, int args_off, struct rv_jit_context *ctx)
{
int i;
for (i = 0; i < nregs; i++) {
for (i = 0; i < nr_reg_args; i++) {
emit_ld(RV_REG_A0 + i, -args_off, RV_REG_FP, ctx);
args_off -= 8;
}
}
static void restore_stack_args(int nr_stack_args, int args_off, int stk_arg_off,
struct rv_jit_context *ctx)
{
int i;
for (i = 0; i < nr_stack_args; i++) {
emit_ld(RV_REG_T1, -(args_off - RV_MAX_REG_ARGS * 8), RV_REG_FP, ctx);
emit_sd(RV_REG_FP, -stk_arg_off, RV_REG_T1, ctx);
args_off -= 8;
stk_arg_off -= 8;
}
}
static int invoke_bpf_prog(struct bpf_tramp_link *l, int args_off, int retval_off,
int run_ctx_off, bool save_ret, struct rv_jit_context *ctx)
{
@ -781,8 +804,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
{
int i, ret, offset;
int *branches_off = NULL;
int stack_size = 0, nregs = m->nr_args;
int retval_off, args_off, nregs_off, ip_off, run_ctx_off, sreg_off;
int stack_size = 0, nr_arg_slots = 0;
int retval_off, args_off, nregs_off, ip_off, run_ctx_off, sreg_off, stk_arg_off;
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
@ -828,20 +851,21 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
* FP - sreg_off [ callee saved reg ]
*
* [ pads ] pads for 16 bytes alignment
*
* [ stack_argN ]
* [ ... ]
* FP - stk_arg_off [ stack_arg1 ] BPF_TRAMP_F_CALL_ORIG
*/
if (flags & (BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SHARE_IPMODIFY))
return -ENOTSUPP;
/* extra regiters for struct arguments */
for (i = 0; i < m->nr_args; i++)
if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG)
nregs += round_up(m->arg_size[i], 8) / 8 - 1;
/* 8 arguments passed by registers */
if (nregs > 8)
if (m->nr_args > MAX_BPF_FUNC_ARGS)
return -ENOTSUPP;
for (i = 0; i < m->nr_args; i++)
nr_arg_slots += round_up(m->arg_size[i], 8) / 8;
/* room of trampoline frame to store return address and frame pointer */
stack_size += 16;
@ -851,7 +875,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
retval_off = stack_size;
}
stack_size += nregs * 8;
stack_size += nr_arg_slots * 8;
args_off = stack_size;
stack_size += 8;
@ -868,7 +892,13 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
stack_size += 8;
sreg_off = stack_size;
stack_size = round_up(stack_size, 16);
if ((flags & BPF_TRAMP_F_CALL_ORIG) && (nr_arg_slots - RV_MAX_REG_ARGS > 0))
stack_size += (nr_arg_slots - RV_MAX_REG_ARGS) * 8;
stack_size = round_up(stack_size, STACK_ALIGN);
/* room for args on stack must be at the top of stack */
stk_arg_off = stack_size;
if (!is_struct_ops) {
/* For the trampoline called from function entry,
@ -905,17 +935,17 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
emit_sd(RV_REG_FP, -ip_off, RV_REG_T1, ctx);
}
emit_li(RV_REG_T1, nregs, ctx);
emit_li(RV_REG_T1, nr_arg_slots, ctx);
emit_sd(RV_REG_FP, -nregs_off, RV_REG_T1, ctx);
store_args(nregs, args_off, ctx);
store_args(nr_arg_slots, args_off, ctx);
/* skip to actual body of traced function */
if (flags & BPF_TRAMP_F_SKIP_FRAME)
orig_call += RV_FENTRY_NINSNS * 4;
if (flags & BPF_TRAMP_F_CALL_ORIG) {
emit_imm(RV_REG_A0, (const s64)im, ctx);
emit_imm(RV_REG_A0, ctx->insns ? (const s64)im : RV_MAX_COUNT_IMM, ctx);
ret = emit_call((const u64)__bpf_tramp_enter, true, ctx);
if (ret)
return ret;
@ -948,13 +978,14 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
}
if (flags & BPF_TRAMP_F_CALL_ORIG) {
restore_args(nregs, args_off, ctx);
restore_args(min_t(int, nr_arg_slots, RV_MAX_REG_ARGS), args_off, ctx);
restore_stack_args(nr_arg_slots - RV_MAX_REG_ARGS, args_off, stk_arg_off, ctx);
ret = emit_call((const u64)orig_call, true, ctx);
if (ret)
goto out;
emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
im->ip_after_call = ctx->insns + ctx->ninsns;
im->ip_after_call = ctx->ro_insns + ctx->ninsns;
/* 2 nops reserved for auipc+jalr pair */
emit(rv_nop(), ctx);
emit(rv_nop(), ctx);
@ -975,15 +1006,15 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
}
if (flags & BPF_TRAMP_F_CALL_ORIG) {
im->ip_epilogue = ctx->insns + ctx->ninsns;
emit_imm(RV_REG_A0, (const s64)im, ctx);
im->ip_epilogue = ctx->ro_insns + ctx->ninsns;
emit_imm(RV_REG_A0, ctx->insns ? (const s64)im : RV_MAX_COUNT_IMM, ctx);
ret = emit_call((const u64)__bpf_tramp_exit, true, ctx);
if (ret)
goto out;
}
if (flags & BPF_TRAMP_F_RESTORE_REGS)
restore_args(nregs, args_off, ctx);
restore_args(min_t(int, nr_arg_slots, RV_MAX_REG_ARGS), args_off, ctx);
if (save_ret) {
emit_ld(RV_REG_A0, -retval_off, RV_REG_FP, ctx);
@ -1038,31 +1069,52 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
return ret < 0 ? ret : ninsns_rvoff(ctx.ninsns);
}
int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
void *image_end, const struct btf_func_model *m,
void *arch_alloc_bpf_trampoline(unsigned int size)
{
return bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
}
void arch_free_bpf_trampoline(void *image, unsigned int size)
{
bpf_prog_pack_free(image, size);
}
int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
void *ro_image_end, const struct btf_func_model *m,
u32 flags, struct bpf_tramp_links *tlinks,
void *func_addr)
{
int ret;
void *image, *res;
struct rv_jit_context ctx;
u32 size = ro_image_end - ro_image;
image = kvmalloc(size, GFP_KERNEL);
if (!image)
return -ENOMEM;
ctx.ninsns = 0;
/*
* The bpf_int_jit_compile() uses a RW buffer (ctx.insns) to write the
* JITed instructions and later copies it to a RX region (ctx.ro_insns).
* It also uses ctx.ro_insns to calculate offsets for jumps etc. As the
* trampoline image uses the same memory area for writing and execution,
* both ctx.insns and ctx.ro_insns can be set to image.
*/
ctx.insns = image;
ctx.ro_insns = image;
ctx.ro_insns = ro_image;
ret = __arch_prepare_bpf_trampoline(im, m, tlinks, func_addr, flags, &ctx);
if (ret < 0)
return ret;
goto out;
bpf_flush_icache(ctx.insns, ctx.insns + ctx.ninsns);
if (WARN_ON(size < ninsns_rvoff(ctx.ninsns))) {
ret = -E2BIG;
goto out;
}
return ninsns_rvoff(ret);
res = bpf_arch_text_copy(ro_image, image, size);
if (IS_ERR(res)) {
ret = PTR_ERR(res);
goto out;
}
bpf_flush_icache(ro_image, ro_image_end);
out:
kvfree(image);
return ret < 0 ? ret : size;
}
int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
@ -1097,12 +1149,10 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
/* Load current CPU number in T1 */
emit_ld(RV_REG_T1, offsetof(struct thread_info, cpu),
RV_REG_TP, ctx);
/* << 3 because offsets are 8 bytes */
emit_slli(RV_REG_T1, RV_REG_T1, 3, ctx);
/* Load address of __per_cpu_offset array in T2 */
emit_addr(RV_REG_T2, (u64)&__per_cpu_offset, extra_pass, ctx);
/* Add offset of current CPU to __per_cpu_offset */
emit_add(RV_REG_T1, RV_REG_T2, RV_REG_T1, ctx);
/* Get address of __per_cpu_offset[cpu] in T1 */
emit_sh3add(RV_REG_T1, RV_REG_T1, RV_REG_T2, ctx);
/* Load __per_cpu_offset[cpu] in T1 */
emit_ld(RV_REG_T1, 0, RV_REG_T1, ctx);
/* Add the offset to Rd */
@ -1960,7 +2010,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
{
int i, stack_adjust = 0, store_offset, bpf_stack_adjust;
bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16);
bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, STACK_ALIGN);
if (bpf_stack_adjust)
mark_fp(ctx);
@ -1982,7 +2032,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
if (ctx->arena_vm_start)
stack_adjust += 8;
stack_adjust = round_up(stack_adjust, 16);
stack_adjust = round_up(stack_adjust, STACK_ALIGN);
stack_adjust += bpf_stack_adjust;
store_offset = stack_adjust - 8;

View File

@ -178,8 +178,7 @@ skip_init_ctx:
prog->jited_len = prog_size - cfi_get_offset();
if (!prog->is_func || extra_pass) {
if (WARN_ON(bpf_jit_binary_pack_finalize(prog, jit_data->ro_header,
jit_data->header))) {
if (WARN_ON(bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header))) {
/* ro_header has been freed */
jit_data->ro_header = NULL;
prog = orig_prog;
@ -258,7 +257,7 @@ void bpf_jit_free(struct bpf_prog *prog)
* before freeing it.
*/
if (jit_data) {
bpf_jit_binary_pack_finalize(prog, jit_data->ro_header, jit_data->header);
bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header);
kfree(jit_data);
}
hdr = bpf_jit_binary_pack_hdr(prog);

View File

@ -31,11 +31,12 @@
#include <asm/nospec-branch.h>
#include <asm/set_memory.h>
#include <asm/text-patching.h>
#include <asm/unwind.h>
#include "bpf_jit.h"
struct bpf_jit {
u32 seen; /* Flags to remember seen eBPF instructions */
u32 seen_reg[16]; /* Array to remember which registers are used */
u16 seen_regs; /* Mask to remember which registers are used */
u32 *addrs; /* Array with relative instruction addresses */
u8 *prg_buf; /* Start of program */
int size; /* Size of program and literal pool */
@ -53,6 +54,8 @@ struct bpf_jit {
int excnt; /* Number of exception table entries */
int prologue_plt_ret; /* Return address for prologue hotpatch PLT */
int prologue_plt; /* Start of prologue hotpatch PLT */
int kern_arena; /* Pool offset of kernel arena address */
u64 user_arena; /* User arena address */
};
#define SEEN_MEM BIT(0) /* use mem[] for temporary storage */
@ -60,6 +63,8 @@ struct bpf_jit {
#define SEEN_FUNC BIT(2) /* calls C functions */
#define SEEN_STACK (SEEN_FUNC | SEEN_MEM)
#define NVREGS 0xffc0 /* %r6-%r15 */
/*
* s390 registers
*/
@ -118,8 +123,8 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
{
u32 r1 = reg2hex[b1];
if (r1 >= 6 && r1 <= 15 && !jit->seen_reg[r1])
jit->seen_reg[r1] = 1;
if (r1 >= 6 && r1 <= 15)
jit->seen_regs |= (1 << r1);
}
#define REG_SET_SEEN(b1) \
@ -127,8 +132,6 @@ static inline void reg_set_seen(struct bpf_jit *jit, u32 b1)
reg_set_seen(jit, b1); \
})
#define REG_SEEN(b1) jit->seen_reg[reg2hex[(b1)]]
/*
* EMIT macros for code generation
*/
@ -436,12 +439,12 @@ static void restore_regs(struct bpf_jit *jit, u32 rs, u32 re, u32 stack_depth)
/*
* Return first seen register (from start)
*/
static int get_start(struct bpf_jit *jit, int start)
static int get_start(u16 seen_regs, int start)
{
int i;
for (i = start; i <= 15; i++) {
if (jit->seen_reg[i])
if (seen_regs & (1 << i))
return i;
}
return 0;
@ -450,15 +453,15 @@ static int get_start(struct bpf_jit *jit, int start)
/*
* Return last seen register (from start) (gap >= 2)
*/
static int get_end(struct bpf_jit *jit, int start)
static int get_end(u16 seen_regs, int start)
{
int i;
for (i = start; i < 15; i++) {
if (!jit->seen_reg[i] && !jit->seen_reg[i + 1])
if (!(seen_regs & (3 << i)))
return i - 1;
}
return jit->seen_reg[15] ? 15 : 14;
return (seen_regs & (1 << 15)) ? 15 : 14;
}
#define REGS_SAVE 1
@ -467,8 +470,10 @@ static int get_end(struct bpf_jit *jit, int start)
* Save and restore clobbered registers (6-15) on stack.
* We save/restore registers in chunks with gap >= 2 registers.
*/
static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth)
static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth,
u16 extra_regs)
{
u16 seen_regs = jit->seen_regs | extra_regs;
const int last = 15, save_restore_size = 6;
int re = 6, rs;
@ -482,10 +487,10 @@ static void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth)
}
do {
rs = get_start(jit, re);
rs = get_start(seen_regs, re);
if (!rs)
break;
re = get_end(jit, rs + 1);
re = get_end(seen_regs, rs + 1);
if (op == REGS_SAVE)
save_regs(jit, rs, re);
else
@ -570,8 +575,21 @@ static void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp,
}
/* Tail calls have to skip above initialization */
jit->tail_call_start = jit->prg;
/* Save registers */
save_restore_regs(jit, REGS_SAVE, stack_depth);
if (fp->aux->exception_cb) {
/*
* Switch stack, the new address is in the 2nd parameter.
*
* Arrange the restoration of %r6-%r15 in the epilogue.
* Do not restore them now, the prog does not need them.
*/
/* lgr %r15,%r3 */
EMIT4(0xb9040000, REG_15, REG_3);
jit->seen_regs |= NVREGS;
} else {
/* Save registers */
save_restore_regs(jit, REGS_SAVE, stack_depth,
fp->aux->exception_boundary ? NVREGS : 0);
}
/* Setup literal pool */
if (is_first_pass(jit) || (jit->seen & SEEN_LITERAL)) {
if (!is_first_pass(jit) &&
@ -647,7 +665,7 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
/* Load exit code: lgr %r2,%b0 */
EMIT4(0xb9040000, REG_2, BPF_REG_0);
/* Restore registers */
save_restore_regs(jit, REGS_RESTORE, stack_depth);
save_restore_regs(jit, REGS_RESTORE, stack_depth, 0);
if (nospec_uses_trampoline()) {
jit->r14_thunk_ip = jit->prg;
/* Generate __s390_indirect_jump_r14 thunk */
@ -667,50 +685,111 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
jit->prg += sizeof(struct bpf_plt);
}
static int get_probe_mem_regno(const u8 *insn)
{
/*
* insn must point to llgc, llgh, llgf, lg, lgb, lgh or lgf, which have
* destination register at the same position.
*/
if (insn[0] != 0xe3) /* common prefix */
return -1;
if (insn[5] != 0x90 && /* llgc */
insn[5] != 0x91 && /* llgh */
insn[5] != 0x16 && /* llgf */
insn[5] != 0x04 && /* lg */
insn[5] != 0x77 && /* lgb */
insn[5] != 0x15 && /* lgh */
insn[5] != 0x14) /* lgf */
return -1;
return insn[1] >> 4;
}
bool ex_handler_bpf(const struct exception_table_entry *x, struct pt_regs *regs)
{
regs->psw.addr = extable_fixup(x);
regs->gprs[x->data] = 0;
if (x->data != -1)
regs->gprs[x->data] = 0;
return true;
}
static int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp,
int probe_prg, int nop_prg)
/*
* A single BPF probe instruction
*/
struct bpf_jit_probe {
int prg; /* JITed instruction offset */
int nop_prg; /* JITed nop offset */
int reg; /* Register to clear on exception */
int arena_reg; /* Register to use for arena addressing */
};
static void bpf_jit_probe_init(struct bpf_jit_probe *probe)
{
probe->prg = -1;
probe->nop_prg = -1;
probe->reg = -1;
probe->arena_reg = REG_0;
}
/*
* Handlers of certain exceptions leave psw.addr pointing to the instruction
* directly after the failing one. Therefore, create two exception table
* entries and also add a nop in case two probing instructions come directly
* after each other.
*/
static void bpf_jit_probe_emit_nop(struct bpf_jit *jit,
struct bpf_jit_probe *probe)
{
if (probe->prg == -1 || probe->nop_prg != -1)
/* The probe is not armed or nop is already emitted. */
return;
probe->nop_prg = jit->prg;
/* bcr 0,%0 */
_EMIT2(0x0700);
}
static void bpf_jit_probe_load_pre(struct bpf_jit *jit, struct bpf_insn *insn,
struct bpf_jit_probe *probe)
{
if (BPF_MODE(insn->code) != BPF_PROBE_MEM &&
BPF_MODE(insn->code) != BPF_PROBE_MEMSX &&
BPF_MODE(insn->code) != BPF_PROBE_MEM32)
return;
if (BPF_MODE(insn->code) == BPF_PROBE_MEM32) {
/* lgrl %r1,kern_arena */
EMIT6_PCREL_RILB(0xc4080000, REG_W1, jit->kern_arena);
probe->arena_reg = REG_W1;
}
probe->prg = jit->prg;
probe->reg = reg2hex[insn->dst_reg];
}
static void bpf_jit_probe_store_pre(struct bpf_jit *jit, struct bpf_insn *insn,
struct bpf_jit_probe *probe)
{
if (BPF_MODE(insn->code) != BPF_PROBE_MEM32)
return;
/* lgrl %r1,kern_arena */
EMIT6_PCREL_RILB(0xc4080000, REG_W1, jit->kern_arena);
probe->arena_reg = REG_W1;
probe->prg = jit->prg;
}
static void bpf_jit_probe_atomic_pre(struct bpf_jit *jit,
struct bpf_insn *insn,
struct bpf_jit_probe *probe)
{
if (BPF_MODE(insn->code) != BPF_PROBE_ATOMIC)
return;
/* lgrl %r1,kern_arena */
EMIT6_PCREL_RILB(0xc4080000, REG_W1, jit->kern_arena);
/* agr %r1,%dst */
EMIT4(0xb9080000, REG_W1, insn->dst_reg);
probe->arena_reg = REG_W1;
probe->prg = jit->prg;
}
static int bpf_jit_probe_post(struct bpf_jit *jit, struct bpf_prog *fp,
struct bpf_jit_probe *probe)
{
struct exception_table_entry *ex;
int reg, prg;
int i, prg;
s64 delta;
u8 *insn;
int i;
if (probe->prg == -1)
/* The probe is not armed. */
return 0;
bpf_jit_probe_emit_nop(jit, probe);
if (!fp->aux->extable)
/* Do nothing during early JIT passes. */
return 0;
insn = jit->prg_buf + probe_prg;
reg = get_probe_mem_regno(insn);
if (WARN_ON_ONCE(reg < 0))
/* JIT bug - unexpected probe instruction. */
return -1;
if (WARN_ON_ONCE(probe_prg + insn_length(*insn) != nop_prg))
insn = jit->prg_buf + probe->prg;
if (WARN_ON_ONCE(probe->prg + insn_length(*insn) != probe->nop_prg))
/* JIT bug - gap between probe and nop instructions. */
return -1;
for (i = 0; i < 2; i++) {
@ -719,23 +798,24 @@ static int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp,
return -1;
ex = &fp->aux->extable[jit->excnt];
/* Add extable entries for probe and nop instructions. */
prg = i == 0 ? probe_prg : nop_prg;
prg = i == 0 ? probe->prg : probe->nop_prg;
delta = jit->prg_buf + prg - (u8 *)&ex->insn;
if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX))
/* JIT bug - code and extable must be close. */
return -1;
ex->insn = delta;
/*
* Always land on the nop. Note that extable infrastructure
* ignores fixup field, it is handled by ex_handler_bpf().
* Land on the current instruction. Note that the extable
* infrastructure ignores the fixup field; it is handled by
* ex_handler_bpf().
*/
delta = jit->prg_buf + nop_prg - (u8 *)&ex->fixup;
delta = jit->prg_buf + jit->prg - (u8 *)&ex->fixup;
if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX))
/* JIT bug - landing pad and extable must be close. */
return -1;
ex->fixup = delta;
ex->type = EX_TYPE_BPF;
ex->data = reg;
ex->data = probe->reg;
jit->excnt++;
}
return 0;
@ -782,19 +862,15 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
s32 branch_oc_off = insn->off;
u32 dst_reg = insn->dst_reg;
u32 src_reg = insn->src_reg;
struct bpf_jit_probe probe;
int last, insn_count = 1;
u32 *addrs = jit->addrs;
s32 imm = insn->imm;
s16 off = insn->off;
int probe_prg = -1;
unsigned int mask;
int nop_prg;
int err;
if (BPF_CLASS(insn->code) == BPF_LDX &&
(BPF_MODE(insn->code) == BPF_PROBE_MEM ||
BPF_MODE(insn->code) == BPF_PROBE_MEMSX))
probe_prg = jit->prg;
bpf_jit_probe_init(&probe);
switch (insn->code) {
/*
@ -823,6 +899,22 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
}
break;
case BPF_ALU64 | BPF_MOV | BPF_X:
if (insn_is_cast_user(insn)) {
int patch_brc;
/* ltgr %dst,%src */
EMIT4(0xb9020000, dst_reg, src_reg);
/* brc 8,0f */
patch_brc = jit->prg;
EMIT4_PCREL_RIC(0xa7040000, 8, 0);
/* iihf %dst,user_arena>>32 */
EMIT6_IMM(0xc0080000, dst_reg, jit->user_arena >> 32);
/* 0: */
if (jit->prg_buf)
*(u16 *)(jit->prg_buf + patch_brc + 2) =
(jit->prg - patch_brc) >> 1;
break;
}
switch (insn->off) {
case 0: /* DST = SRC */
/* lgr %dst,%src */
@ -1366,51 +1458,99 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
* BPF_ST(X)
*/
case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */
/* stcy %src,off(%dst) */
EMIT6_DISP_LH(0xe3000000, 0x0072, src_reg, dst_reg, REG_0, off);
case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
bpf_jit_probe_store_pre(jit, insn, &probe);
/* stcy %src,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0072, src_reg, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */
/* sthy %src,off(%dst) */
EMIT6_DISP_LH(0xe3000000, 0x0070, src_reg, dst_reg, REG_0, off);
case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
bpf_jit_probe_store_pre(jit, insn, &probe);
/* sthy %src,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0070, src_reg, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */
/* sty %src,off(%dst) */
EMIT6_DISP_LH(0xe3000000, 0x0050, src_reg, dst_reg, REG_0, off);
case BPF_STX | BPF_PROBE_MEM32 | BPF_W:
bpf_jit_probe_store_pre(jit, insn, &probe);
/* sty %src,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0050, src_reg, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */
/* stg %src,off(%dst) */
EMIT6_DISP_LH(0xe3000000, 0x0024, src_reg, dst_reg, REG_0, off);
case BPF_STX | BPF_PROBE_MEM32 | BPF_DW:
bpf_jit_probe_store_pre(jit, insn, &probe);
/* stg %src,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0024, src_reg, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */
case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
/* lhi %w0,imm */
EMIT4_IMM(0xa7080000, REG_W0, (u8) imm);
/* stcy %w0,off(dst) */
EMIT6_DISP_LH(0xe3000000, 0x0072, REG_W0, dst_reg, REG_0, off);
bpf_jit_probe_store_pre(jit, insn, &probe);
/* stcy %w0,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0072, REG_W0, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */
case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
/* lhi %w0,imm */
EMIT4_IMM(0xa7080000, REG_W0, (u16) imm);
/* sthy %w0,off(dst) */
EMIT6_DISP_LH(0xe3000000, 0x0070, REG_W0, dst_reg, REG_0, off);
bpf_jit_probe_store_pre(jit, insn, &probe);
/* sthy %w0,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0070, REG_W0, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */
case BPF_ST | BPF_PROBE_MEM32 | BPF_W:
/* llilf %w0,imm */
EMIT6_IMM(0xc00f0000, REG_W0, (u32) imm);
/* sty %w0,off(%dst) */
EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, dst_reg, REG_0, off);
bpf_jit_probe_store_pre(jit, insn, &probe);
/* sty %w0,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */
case BPF_ST | BPF_PROBE_MEM32 | BPF_DW:
/* lgfi %w0,imm */
EMIT6_IMM(0xc0010000, REG_W0, imm);
/* stg %w0,off(%dst) */
EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, dst_reg, REG_0, off);
bpf_jit_probe_store_pre(jit, insn, &probe);
/* stg %w0,off(%dst,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, dst_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
/*
@ -1418,15 +1558,30 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
*/
case BPF_STX | BPF_ATOMIC | BPF_DW:
case BPF_STX | BPF_ATOMIC | BPF_W:
case BPF_STX | BPF_PROBE_ATOMIC | BPF_DW:
case BPF_STX | BPF_PROBE_ATOMIC | BPF_W:
{
bool is32 = BPF_SIZE(insn->code) == BPF_W;
/*
* Unlike loads and stores, atomics have only a base register,
* but no index register. For the non-arena case, simply use
* %dst as a base. For the arena case, use the work register
* %r1: first, load the arena base into it, and then add %dst
* to it.
*/
probe.arena_reg = dst_reg;
switch (insn->imm) {
/* {op32|op64} {%w0|%src},%src,off(%dst) */
#define EMIT_ATOMIC(op32, op64) do { \
bpf_jit_probe_atomic_pre(jit, insn, &probe); \
/* {op32|op64} {%w0|%src},%src,off(%arena) */ \
EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64), \
(insn->imm & BPF_FETCH) ? src_reg : REG_W0, \
src_reg, dst_reg, off); \
src_reg, probe.arena_reg, off); \
err = bpf_jit_probe_post(jit, fp, &probe); \
if (err < 0) \
return err; \
if (insn->imm & BPF_FETCH) { \
/* bcr 14,0 - see atomic_fetch_{add,and,or,xor}() */ \
_EMIT2(0x07e0); \
@ -1455,25 +1610,50 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
EMIT_ATOMIC(0x00f7, 0x00e7);
break;
#undef EMIT_ATOMIC
case BPF_XCHG:
/* {ly|lg} %w0,off(%dst) */
case BPF_XCHG: {
struct bpf_jit_probe load_probe = probe;
int loop_start;
bpf_jit_probe_atomic_pre(jit, insn, &load_probe);
/* {ly|lg} %w0,off(%arena) */
EMIT6_DISP_LH(0xe3000000,
is32 ? 0x0058 : 0x0004, REG_W0, REG_0,
dst_reg, off);
/* 0: {csy|csg} %w0,%src,off(%dst) */
load_probe.arena_reg, off);
bpf_jit_probe_emit_nop(jit, &load_probe);
/* Reuse {ly|lg}'s arena_reg for {csy|csg}. */
if (load_probe.prg != -1) {
probe.prg = jit->prg;
probe.arena_reg = load_probe.arena_reg;
}
loop_start = jit->prg;
/* 0: {csy|csg} %w0,%src,off(%arena) */
EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030,
REG_W0, src_reg, dst_reg, off);
REG_W0, src_reg, probe.arena_reg, off);
bpf_jit_probe_emit_nop(jit, &probe);
/* brc 4,0b */
EMIT4_PCREL_RIC(0xa7040000, 4, jit->prg - 6);
EMIT4_PCREL_RIC(0xa7040000, 4, loop_start);
/* {llgfr|lgr} %src,%w0 */
EMIT4(is32 ? 0xb9160000 : 0xb9040000, src_reg, REG_W0);
/* Both probes should land here on exception. */
err = bpf_jit_probe_post(jit, fp, &load_probe);
if (err < 0)
return err;
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
if (is32 && insn_is_zext(&insn[1]))
insn_count = 2;
break;
}
case BPF_CMPXCHG:
/* 0: {csy|csg} %b0,%src,off(%dst) */
bpf_jit_probe_atomic_pre(jit, insn, &probe);
/* 0: {csy|csg} %b0,%src,off(%arena) */
EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030,
BPF_REG_0, src_reg, dst_reg, off);
BPF_REG_0, src_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
break;
default:
pr_err("Unknown atomic operation %02x\n", insn->imm);
@ -1488,51 +1668,87 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
*/
case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEM | BPF_B:
/* llgc %dst,0(off,%src) */
EMIT6_DISP_LH(0xe3000000, 0x0090, dst_reg, src_reg, REG_0, off);
case BPF_LDX | BPF_PROBE_MEM32 | BPF_B:
bpf_jit_probe_load_pre(jit, insn, &probe);
/* llgc %dst,off(%src,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0090, dst_reg, src_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
if (insn_is_zext(&insn[1]))
insn_count = 2;
break;
case BPF_LDX | BPF_MEMSX | BPF_B: /* dst = *(s8 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEMSX | BPF_B:
/* lgb %dst,0(off,%src) */
bpf_jit_probe_load_pre(jit, insn, &probe);
/* lgb %dst,off(%src) */
EMIT6_DISP_LH(0xe3000000, 0x0077, dst_reg, src_reg, REG_0, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEM | BPF_H:
/* llgh %dst,0(off,%src) */
EMIT6_DISP_LH(0xe3000000, 0x0091, dst_reg, src_reg, REG_0, off);
case BPF_LDX | BPF_PROBE_MEM32 | BPF_H:
bpf_jit_probe_load_pre(jit, insn, &probe);
/* llgh %dst,off(%src,%arena) */
EMIT6_DISP_LH(0xe3000000, 0x0091, dst_reg, src_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
if (insn_is_zext(&insn[1]))
insn_count = 2;
break;
case BPF_LDX | BPF_MEMSX | BPF_H: /* dst = *(s16 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEMSX | BPF_H:
/* lgh %dst,0(off,%src) */
bpf_jit_probe_load_pre(jit, insn, &probe);
/* lgh %dst,off(%src) */
EMIT6_DISP_LH(0xe3000000, 0x0015, dst_reg, src_reg, REG_0, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
jit->seen |= SEEN_MEM;
break;
case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEM | BPF_W:
case BPF_LDX | BPF_PROBE_MEM32 | BPF_W:
bpf_jit_probe_load_pre(jit, insn, &probe);
/* llgf %dst,off(%src) */
jit->seen |= SEEN_MEM;
EMIT6_DISP_LH(0xe3000000, 0x0016, dst_reg, src_reg, REG_0, off);
EMIT6_DISP_LH(0xe3000000, 0x0016, dst_reg, src_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
if (insn_is_zext(&insn[1]))
insn_count = 2;
break;
case BPF_LDX | BPF_MEMSX | BPF_W: /* dst = *(s32 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEMSX | BPF_W:
bpf_jit_probe_load_pre(jit, insn, &probe);
/* lgf %dst,off(%src) */
jit->seen |= SEEN_MEM;
EMIT6_DISP_LH(0xe3000000, 0x0014, dst_reg, src_reg, REG_0, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
break;
case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
/* lg %dst,0(off,%src) */
case BPF_LDX | BPF_PROBE_MEM32 | BPF_DW:
bpf_jit_probe_load_pre(jit, insn, &probe);
/* lg %dst,off(%src,%arena) */
jit->seen |= SEEN_MEM;
EMIT6_DISP_LH(0xe3000000, 0x0004, dst_reg, src_reg, REG_0, off);
EMIT6_DISP_LH(0xe3000000, 0x0004, dst_reg, src_reg,
probe.arena_reg, off);
err = bpf_jit_probe_post(jit, fp, &probe);
if (err < 0)
return err;
break;
/*
* BPF_JMP / CALL
@ -1647,7 +1863,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
/*
* Restore registers before calling function
*/
save_restore_regs(jit, REGS_RESTORE, stack_depth);
save_restore_regs(jit, REGS_RESTORE, stack_depth, 0);
/*
* goto *(prog->bpf_func + tail_call_start);
@ -1897,22 +2113,6 @@ branch_oc:
return -1;
}
if (probe_prg != -1) {
/*
* Handlers of certain exceptions leave psw.addr pointing to
* the instruction directly after the failing one. Therefore,
* create two exception table entries and also add a nop in
* case two probing instructions come directly after each
* other.
*/
nop_prg = jit->prg;
/* bcr 0,%0 */
_EMIT2(0x0700);
err = bpf_jit_probe_mem(jit, fp, probe_prg, nop_prg);
if (err < 0)
return err;
}
return insn_count;
}
@ -1958,12 +2158,18 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp,
bool extra_pass, u32 stack_depth)
{
int i, insn_count, lit32_size, lit64_size;
u64 kern_arena;
jit->lit32 = jit->lit32_start;
jit->lit64 = jit->lit64_start;
jit->prg = 0;
jit->excnt = 0;
kern_arena = bpf_arena_get_kern_vm_start(fp->aux->arena);
if (kern_arena)
jit->kern_arena = _EMIT_CONST_U64(kern_arena);
jit->user_arena = bpf_arena_get_user_vm_start(fp->aux->arena);
bpf_jit_prologue(jit, fp, stack_depth);
if (bpf_set_addr(jit, 0) < 0)
return -1;
@ -2011,9 +2217,25 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
struct bpf_prog *fp)
{
struct bpf_binary_header *header;
struct bpf_insn *insn;
u32 extable_size;
u32 code_size;
int i;
for (i = 0; i < fp->len; i++) {
insn = &fp->insnsi[i];
if (BPF_CLASS(insn->code) == BPF_STX &&
BPF_MODE(insn->code) == BPF_PROBE_ATOMIC &&
(BPF_SIZE(insn->code) == BPF_DW ||
BPF_SIZE(insn->code) == BPF_W) &&
insn->imm == BPF_XCHG)
/*
* bpf_jit_insn() emits a load and a compare-and-swap,
* both of which need to be probed.
*/
fp->aux->num_exentries += 1;
}
/* We need two entries per insn. */
fp->aux->num_exentries *= 2;
@ -2689,3 +2911,52 @@ bool bpf_jit_supports_subprog_tailcalls(void)
{
return true;
}
bool bpf_jit_supports_arena(void)
{
return true;
}
bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
{
/*
* Currently the verifier uses this function only to check which
* atomic stores to arena are supported, and they all are.
*/
return true;
}
bool bpf_jit_supports_exceptions(void)
{
/*
* Exceptions require unwinding support, which is always available,
* because the kernel is always built with backchain.
*/
return true;
}
void arch_bpf_stack_walk(bool (*consume_fn)(void *, u64, u64, u64),
void *cookie)
{
unsigned long addr, prev_addr = 0;
struct unwind_state state;
unwind_for_each_frame(&state, NULL, NULL, 0) {
addr = unwind_get_return_address(&state);
if (!addr)
break;
/*
* addr is a return address and state.sp is the value of %r15
* at this address. exception_cb needs %r15 at entry to the
* function containing addr, so take the next state.sp.
*
* There is no bp, and the exception_cb prog does not need one
* to perform a quasi-longjmp. The common code requires a
* non-zero bp, so pass sp there as well.
*/
if (prev_addr && !consume_fn(cookie, prev_addr, state.sp,
state.sp))
break;
prev_addr = addr;
}
}

View File

@ -1234,13 +1234,11 @@ bool ex_handler_bpf(const struct exception_table_entry *x, struct pt_regs *regs)
}
static void detect_reg_usage(struct bpf_insn *insn, int insn_cnt,
bool *regs_used, bool *tail_call_seen)
bool *regs_used)
{
int i;
for (i = 1; i <= insn_cnt; i++, insn++) {
if (insn->code == (BPF_JMP | BPF_TAIL_CALL))
*tail_call_seen = true;
if (insn->dst_reg == BPF_REG_6 || insn->src_reg == BPF_REG_6)
regs_used[0] = true;
if (insn->dst_reg == BPF_REG_7 || insn->src_reg == BPF_REG_7)
@ -1324,7 +1322,6 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
struct bpf_insn *insn = bpf_prog->insnsi;
bool callee_regs_used[4] = {};
int insn_cnt = bpf_prog->len;
bool tail_call_seen = false;
bool seen_exit = false;
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
u64 arena_vm_start, user_vm_start;
@ -1336,11 +1333,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
arena_vm_start = bpf_arena_get_kern_vm_start(bpf_prog->aux->arena);
user_vm_start = bpf_arena_get_user_vm_start(bpf_prog->aux->arena);
detect_reg_usage(insn, insn_cnt, callee_regs_used,
&tail_call_seen);
/* tail call's presence in current prog implies it is reachable */
tail_call_reachable |= tail_call_seen;
detect_reg_usage(insn, insn_cnt, callee_regs_used);
emit_prologue(&prog, bpf_prog->aux->stack_depth,
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
@ -3363,7 +3356,7 @@ out_image:
*
* Both cases are serious bugs and justify WARN_ON.
*/
if (WARN_ON(bpf_jit_binary_pack_finalize(prog, header, rw_header))) {
if (WARN_ON(bpf_jit_binary_pack_finalize(header, rw_header))) {
/* header has been freed */
header = NULL;
goto out_image;
@ -3442,7 +3435,7 @@ void bpf_jit_free(struct bpf_prog *prog)
* before freeing it.
*/
if (jit_data) {
bpf_jit_binary_pack_finalize(prog, jit_data->header,
bpf_jit_binary_pack_finalize(jit_data->header,
jit_data->rw_header);
kvfree(jit_data->addrs);
kfree(jit_data);

View File

@ -16,6 +16,7 @@ obj-$(CONFIG_NUMA) += node.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
ifeq ($(CONFIG_SYSFS),y)
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_AUXILIARY_BUS) += auxiliary_sysfs.o
endif
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
obj-$(CONFIG_REGMAP) += regmap/

View File

@ -287,6 +287,7 @@ int auxiliary_device_init(struct auxiliary_device *auxdev)
dev->bus = &auxiliary_bus_type;
device_initialize(&auxdev->dev);
mutex_init(&auxdev->sysfs.lock);
return 0;
}
EXPORT_SYMBOL_GPL(auxiliary_device_init);

View File

@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES
*/
#include <linux/auxiliary_bus.h>
#include <linux/slab.h>
#define AUXILIARY_MAX_IRQ_NAME 11
struct auxiliary_irq_info {
struct device_attribute sysfs_attr;
char name[AUXILIARY_MAX_IRQ_NAME];
};
static struct attribute *auxiliary_irq_attrs[] = {
NULL
};
static const struct attribute_group auxiliary_irqs_group = {
.name = "irqs",
.attrs = auxiliary_irq_attrs,
};
static int auxiliary_irq_dir_prepare(struct auxiliary_device *auxdev)
{
int ret = 0;
guard(mutex)(&auxdev->sysfs.lock);
if (auxdev->sysfs.irq_dir_exists)
return 0;
ret = devm_device_add_group(&auxdev->dev, &auxiliary_irqs_group);
if (ret)
return ret;
auxdev->sysfs.irq_dir_exists = true;
xa_init(&auxdev->sysfs.irqs);
return 0;
}
/**
* auxiliary_device_sysfs_irq_add - add a sysfs entry for the given IRQ
* @auxdev: auxiliary bus device to add the sysfs entry.
* @irq: The associated interrupt number.
*
* This function should be called after auxiliary device have successfully
* received the irq.
* The driver is responsible to add a unique irq for the auxiliary device. The
* driver can invoke this function from multiple thread context safely for
* unique irqs of the auxiliary devices. The driver must not invoke this API
* multiple times if the irq is already added previously.
*
* Return: zero on success or an error code on failure.
*/
int auxiliary_device_sysfs_irq_add(struct auxiliary_device *auxdev, int irq)
{
struct auxiliary_irq_info *info __free(kfree) = NULL;
struct device *dev = &auxdev->dev;
int ret;
ret = auxiliary_irq_dir_prepare(auxdev);
if (ret)
return ret;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
sysfs_attr_init(&info->sysfs_attr.attr);
snprintf(info->name, AUXILIARY_MAX_IRQ_NAME, "%d", irq);
ret = xa_insert(&auxdev->sysfs.irqs, irq, info, GFP_KERNEL);
if (ret)
return ret;
info->sysfs_attr.attr.name = info->name;
ret = sysfs_add_file_to_group(&dev->kobj, &info->sysfs_attr.attr,
auxiliary_irqs_group.name);
if (ret)
goto sysfs_add_err;
xa_store(&auxdev->sysfs.irqs, irq, no_free_ptr(info), GFP_KERNEL);
return 0;
sysfs_add_err:
xa_erase(&auxdev->sysfs.irqs, irq);
return ret;
}
EXPORT_SYMBOL_GPL(auxiliary_device_sysfs_irq_add);
/**
* auxiliary_device_sysfs_irq_remove - remove a sysfs entry for the given IRQ
* @auxdev: auxiliary bus device to add the sysfs entry.
* @irq: the IRQ to remove.
*
* This function should be called to remove an IRQ sysfs entry.
* The driver must invoke this API when IRQ is released by the device.
*/
void auxiliary_device_sysfs_irq_remove(struct auxiliary_device *auxdev, int irq)
{
struct auxiliary_irq_info *info __free(kfree) = xa_load(&auxdev->sysfs.irqs, irq);
struct device *dev = &auxdev->dev;
if (!info) {
dev_err(&auxdev->dev, "IRQ %d doesn't exist\n", irq);
return;
}
sysfs_remove_file_from_group(&dev->kobj, &info->sysfs_attr.attr,
auxiliary_irqs_group.name);
xa_erase(&auxdev->sysfs.irqs, irq);
}
EXPORT_SYMBOL_GPL(auxiliary_device_sysfs_irq_remove);

View File

@ -105,6 +105,7 @@ config BT_HCIUART
tristate "HCI UART driver"
depends on SERIAL_DEV_BUS || !SERIAL_DEV_BUS
depends on NVMEM || !NVMEM
depends on POWER_SEQUENCING || !POWER_SEQUENCING
depends on TTY
help
Bluetooth HCI UART driver.
@ -287,12 +288,12 @@ config BT_HCIBCM203X
config BT_HCIBCM4377
tristate "HCI BCM4377/4378/4387 PCIe driver"
tristate "HCI BCM4377/4378/4387/4388 PCIe driver"
depends on PCI
select FW_LOADER
help
Support for Broadcom BCM4377/4378/4387 Bluetooth chipsets attached via
PCIe. These are usually found in Apple machines.
Support for Broadcom BCM4377/4378/4387/4388 Bluetooth chipsets
attached via PCIe. These are usually found in Apple machines.
Say Y here to compile support for HCI BCM4377 family devices into the
kernel or say M to compile it as module (hci_bcm4377).

View File

@ -26,21 +26,11 @@
#define ECDSA_OFFSET 644
#define ECDSA_HEADER_LEN 320
#define BTINTEL_PPAG_NAME "PPAG"
enum {
DSM_SET_WDISABLE2_DELAY = 1,
DSM_SET_RESET_METHOD = 3,
};
/* structure to store the PPAG data read from ACPI table */
struct btintel_ppag {
u32 domain;
u32 mode;
acpi_status status;
struct hci_dev *hdev;
};
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
struct cmd_write_boot_params {
__le32 boot_addr;
@ -482,6 +472,7 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
case 0x19: /* Slr-F */
case 0x1b: /* Mgr */
case 0x1c: /* Gale Peak (GaP) */
case 0x1d: /* BlazarU (BzrU) */
case 0x1e: /* BlazarI (Bzr) */
break;
default:
@ -641,6 +632,10 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
case INTEL_TLV_GIT_SHA1:
version->git_sha1 = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_FW_ID:
snprintf(version->fw_id, sizeof(version->fw_id),
"%s", tlv->val);
break;
default:
/* Ignore rest of information */
break;
@ -1324,65 +1319,6 @@ static int btintel_read_debug_features(struct hci_dev *hdev,
return 0;
}
static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data,
void **ret)
{
acpi_status status;
size_t len;
struct btintel_ppag *ppag = data;
union acpi_object *p, *elements;
struct acpi_buffer string = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
struct hci_dev *hdev = ppag->hdev;
status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
if (ACPI_FAILURE(status)) {
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
return status;
}
len = strlen(string.pointer);
if (len < strlen(BTINTEL_PPAG_NAME)) {
kfree(string.pointer);
return AE_OK;
}
if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) {
kfree(string.pointer);
return AE_OK;
}
kfree(string.pointer);
status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
if (ACPI_FAILURE(status)) {
ppag->status = status;
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
return status;
}
p = buffer.pointer;
ppag = (struct btintel_ppag *)data;
if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
kfree(buffer.pointer);
bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
p->type, p->package.count);
ppag->status = AE_ERROR;
return AE_ERROR;
}
elements = p->package.elements;
/* PPAG table is located at element[1] */
p = &elements[1];
ppag->domain = (u32)p->package.elements[0].integer.value;
ppag->mode = (u32)p->package.elements[1].integer.value;
ppag->status = AE_OK;
kfree(buffer.pointer);
return AE_CTRL_TERMINATE;
}
static int btintel_set_debug_features(struct hci_dev *hdev,
const struct intel_debug_features *features)
{
@ -2202,30 +2138,61 @@ static void btintel_get_fw_name_tlv(const struct intel_version_tlv *ver,
const char *suffix)
{
const char *format;
/* The firmware file name for new generation controllers will be
* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
*/
switch (ver->cnvi_top & 0xfff) {
u32 cnvi, cnvr;
cnvi = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
INTEL_CNVX_TOP_STEP(ver->cnvi_top));
cnvr = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
INTEL_CNVX_TOP_STEP(ver->cnvr_top));
/* Only Blazar product supports downloading of intermediate loader
* image
*/
case BTINTEL_CNVI_BLAZARI:
if (ver->img_type == BTINTEL_IMG_BOOTLOADER)
format = "intel/ibt-%04x-%04x-iml.%s";
else
format = "intel/ibt-%04x-%04x.%s";
break;
default:
format = "intel/ibt-%04x-%04x.%s";
break;
}
if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e) {
u8 zero[BTINTEL_FWID_MAXLEN];
snprintf(fw_name, len, format,
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
INTEL_CNVX_TOP_STEP(ver->cnvi_top)),
INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
INTEL_CNVX_TOP_STEP(ver->cnvr_top)),
suffix);
if (ver->img_type == BTINTEL_IMG_BOOTLOADER) {
format = "intel/ibt-%04x-%04x-iml.%s";
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
return;
}
memset(zero, 0, sizeof(zero));
/* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step-fw_id> */
if (memcmp(ver->fw_id, zero, sizeof(zero))) {
format = "intel/ibt-%04x-%04x-%s.%s";
snprintf(fw_name, len, format, cnvi, cnvr,
ver->fw_id, suffix);
return;
}
/* If firmware id is not present, fallback to legacy naming
* convention
*/
}
/* Fallback to legacy naming convention for other controllers
* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
*/
format = "intel/ibt-%04x-%04x.%s";
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
}
static void btintel_get_iml_tlv(const struct intel_version_tlv *ver,
char *fw_name, size_t len,
const char *suffix)
{
const char *format;
u32 cnvi, cnvr;
cnvi = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
INTEL_CNVX_TOP_STEP(ver->cnvi_top));
cnvr = INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
INTEL_CNVX_TOP_STEP(ver->cnvr_top));
format = "intel/ibt-%04x-%04x-iml.%s";
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
}
static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
@ -2233,7 +2200,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
u32 *boot_param)
{
const struct firmware *fw;
char fwname[64];
char fwname[128];
int err;
ktime_t calltime;
@ -2268,7 +2235,20 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
}
}
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
if (ver->img_type == BTINTEL_IMG_OP) {
/* Controller running OP image. In case of FW downgrade,
* FWID TLV may not be present and driver may attempt to load
* firmware image which doesn't exist. Lets compare the version
* of IML image
*/
if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e)
btintel_get_iml_tlv(ver, fwname, sizeof(fwname), "sfi");
else
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
} else {
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
}
err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
if (err < 0) {
if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
@ -2427,10 +2407,13 @@ error:
static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver)
{
struct btintel_ppag ppag;
struct sk_buff *skb;
struct hci_ppag_enable_cmd ppag_cmd;
acpi_handle handle;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *p, *elements;
u32 domain, mode;
acpi_status status;
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
switch (ver->cnvr_top & 0xFFF) {
@ -2448,22 +2431,34 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
return;
}
memset(&ppag, 0, sizeof(ppag));
ppag.hdev = hdev;
ppag.status = AE_NOT_FOUND;
acpi_walk_namespace(ACPI_TYPE_PACKAGE, handle, 1, NULL,
btintel_ppag_callback, &ppag, NULL);
if (ACPI_FAILURE(ppag.status)) {
if (ppag.status == AE_NOT_FOUND) {
status = acpi_evaluate_object(handle, "PPAG", NULL, &buffer);
if (ACPI_FAILURE(status)) {
if (status == AE_NOT_FOUND) {
bt_dev_dbg(hdev, "PPAG-BT: ACPI entry not found");
return;
}
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
return;
}
if (ppag.domain != 0x12) {
p = buffer.pointer;
if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
p->type, p->package.count);
kfree(buffer.pointer);
return;
}
elements = p->package.elements;
/* PPAG table is located at element[1] */
p = &elements[1];
domain = (u32)p->package.elements[0].integer.value;
mode = (u32)p->package.elements[1].integer.value;
kfree(buffer.pointer);
if (domain != 0x12) {
bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
return;
}
@ -2474,19 +2469,22 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
* BIT 1 : 0 Disabled in China
* 1 Enabled in China
*/
if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) {
bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS");
mode &= 0x03;
if (!mode) {
bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in BIOS");
return;
}
ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);
ppag_cmd.ppag_enable_flags = cpu_to_le32(mode);
skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd),
&ppag_cmd, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb));
return;
}
bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode);
bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", mode);
kfree_skb(skb);
}
@ -2600,6 +2598,24 @@ static void btintel_set_dsm_reset_method(struct hci_dev *hdev,
data->acpi_reset_method = btintel_acpi_reset_method;
}
#define BTINTEL_ISODATA_HANDLE_BASE 0x900
static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
{
/*
* Distinguish ISO data packets form ACL data packets
* based on their connection handle value range.
*/
if (hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) {
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
if (hci_handle(handle) >= BTINTEL_ISODATA_HANDLE_BASE)
return HCI_ISODATA_PKT;
}
return hci_skb_pkt_type(skb);
}
int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
struct intel_version_tlv *ver)
{
@ -2635,7 +2651,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
return err;
/* If image type returned is BTINTEL_IMG_IML, then controller supports
* intermediae loader image
* intermediate loader image
*/
if (ver->img_type == BTINTEL_IMG_IML) {
err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
@ -2703,6 +2719,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
case 0x19:
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
hci_set_msft_opcode(hdev, 0xFC1E);
break;
@ -2713,7 +2730,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
}
EXPORT_SYMBOL_GPL(btintel_set_msft_opcode);
static void btintel_print_fseq_info(struct hci_dev *hdev)
void btintel_print_fseq_info(struct hci_dev *hdev)
{
struct sk_buff *skb;
u8 *p;
@ -2825,6 +2842,7 @@ static void btintel_print_fseq_info(struct hci_dev *hdev)
kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(btintel_print_fseq_info);
static int btintel_setup_combined(struct hci_dev *hdev)
{
@ -3039,11 +3057,15 @@ static int btintel_setup_combined(struct hci_dev *hdev)
err = btintel_bootloader_setup(hdev, &ver);
btintel_register_devcoredump_support(hdev);
break;
case 0x18: /* GfP2 */
case 0x1c: /* GaP */
/* Re-classify packet type for controllers with LE audio */
hdev->classify_pkt_type = btintel_classify_pkt_type;
fallthrough;
case 0x17:
case 0x18:
case 0x19:
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
/* Display version information of TLV type */
btintel_version_info_tlv(hdev, &ver_tlv);

View File

@ -42,7 +42,8 @@ enum {
INTEL_TLV_SBE_TYPE,
INTEL_TLV_OTP_BDADDR,
INTEL_TLV_UNLOCKED_STATE,
INTEL_TLV_GIT_SHA1
INTEL_TLV_GIT_SHA1,
INTEL_TLV_FW_ID = 0x50
};
struct intel_tlv {
@ -57,6 +58,8 @@ struct intel_tlv {
#define BTINTEL_IMG_IML 0x02 /* Intermediate image */
#define BTINTEL_IMG_OP 0x03 /* Operational image */
#define BTINTEL_FWID_MAXLEN 64
struct intel_version_tlv {
u32 cnvi_top;
u32 cnvr_top;
@ -77,6 +80,7 @@ struct intel_version_tlv {
u8 limited_cce;
u8 sbe_type;
u32 git_sha1;
u8 fw_id[BTINTEL_FWID_MAXLEN];
bdaddr_t otp_bd_addr;
};
@ -244,6 +248,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
struct intel_version_tlv *ver);
int btintel_shutdown_combined(struct hci_dev *hdev);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_print_fseq_info(struct hci_dev *hdev);
#else
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
@ -373,4 +378,8 @@ static inline int btintel_shutdown_combined(struct hci_dev *hdev)
static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
{
}
static inline void btintel_print_fseq_info(struct hci_dev *hdev)
{
}
#endif

View File

@ -797,7 +797,6 @@ static int btintel_pcie_setup_txq_bufs(struct btintel_pcie_data *data,
kfree(txq->bufs);
return -ENOMEM;
}
memset(txq->buf_v_addr, 0, txq->count * BTINTEL_PCIE_BUFFER_SIZE);
/* Setup the allocated DMA buffer to bufs. Each data_buf should
* have virtual address and physical address
@ -842,7 +841,6 @@ static int btintel_pcie_setup_rxq_bufs(struct btintel_pcie_data *data,
kfree(rxq->bufs);
return -ENOMEM;
}
memset(rxq->buf_v_addr, 0, rxq->count * BTINTEL_PCIE_BUFFER_SIZE);
/* Setup the allocated DMA buffer to bufs. Each data_buf should
* have virtual address and physical address
@ -1197,9 +1195,11 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
err = -EINVAL;
goto exit_error;
break;
}
btintel_print_fseq_info(hdev);
exit_error:
kfree_skb(skb);
@ -1327,6 +1327,12 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
data = pci_get_drvdata(pdev);
btintel_pcie_reset_bt(data);
for (int i = 0; i < data->alloc_vecs; i++) {
struct msix_entry *msix_entry;
msix_entry = &data->msix_entries[i];
free_irq(msix_entry->vector, msix_entry);
}
pci_free_irq_vectors(pdev);

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,21 @@
#define MTK_COREDUMP_END_LEN (sizeof(MTK_COREDUMP_END))
#define MTK_COREDUMP_NUM 255
/* UHW CR mapping */
#define MTK_BT_MISC 0x70002510
#define MTK_BT_SUBSYS_RST 0x70002610
#define MTK_UDMA_INT_STA_BT 0x74000024
#define MTK_UDMA_INT_STA_BT1 0x74000308
#define MTK_BT_WDT_STATUS 0x740003A0
#define MTK_EP_RST_OPT 0x74011890
#define MTK_EP_RST_IN_OUT_OPT 0x00010001
#define MTK_BT_RST_DONE 0x00000100
#define MTK_BT_RESET_REG_CONNV3 0x70028610
#define MTK_BT_READ_DEV_ID 0x70010200
/* MediaTek ISO Interface */
#define MTK_ISO_IFNUM 2
enum {
BTMTK_WMT_PATCH_DWNLD = 0x1,
BTMTK_WMT_TEST = 0x2,
@ -126,6 +141,14 @@ struct btmtk_hci_wmt_params {
u32 *status;
};
enum {
BTMTK_TX_WAIT_VND_EVT,
BTMTK_FIRMWARE_LOADED,
BTMTK_HW_RESET_ACTIVE,
BTMTK_ISOPKT_OVER_INTR,
BTMTK_ISOPKT_RUNNING,
};
typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
struct btmtk_coredump_info {
@ -135,10 +158,25 @@ struct btmtk_coredump_info {
int state;
};
struct btmediatek_data {
struct btmtk_data {
const char *drv_name;
unsigned long flags;
u32 dev_id;
btmtk_reset_sync_func_t reset_sync;
struct btmtk_coredump_info cd_info;
struct usb_device *udev;
struct usb_interface *intf;
struct usb_anchor *ctrl_anchor;
struct sk_buff *evt_skb;
struct usb_endpoint_descriptor *isopkt_tx_ep;
struct usb_endpoint_descriptor *isopkt_rx_ep;
struct usb_interface *isopkt_intf;
struct usb_anchor isopkt_anchor;
struct sk_buff *isopkt_skb;
/* spinlock for ISO data transmission */
spinlock_t isorxlock;
};
typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
@ -160,6 +198,24 @@ int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
u32 fw_version);
int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
u32 fw_flavor);
int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id);
int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb);
struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb,
usb_complete_t tx_complete);
int btmtk_usb_resume(struct hci_dev *hdev);
int btmtk_usb_suspend(struct hci_dev *hdev);
int btmtk_usb_setup(struct hci_dev *hdev);
int btmtk_usb_shutdown(struct hci_dev *hdev);
#else
static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
@ -168,29 +224,73 @@ static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
return -EOPNOTSUPP;
}
static int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
static inline int btmtk_setup_firmware_79xx(struct hci_dev *hdev,
const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
return -EOPNOTSUPP;
}
static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
static inline int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
return -EOPNOTSUPP;
}
static void btmtk_reset_sync(struct hci_dev *hdev)
static inline void btmtk_reset_sync(struct hci_dev *hdev)
{
}
static int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
u32 fw_version)
static inline int btmtk_register_coredump(struct hci_dev *hdev,
const char *name, u32 fw_version)
{
return -EOPNOTSUPP;
}
static int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
static inline int btmtk_process_coredump(struct hci_dev *hdev,
struct sk_buff *skb)
{
return -EOPNOTSUPP;
}
static inline void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id,
u32 fw_ver, u32 fw_flavor)
{
}
static inline int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
{
return -EOPNOTSUPP;
}
static inline int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
{
return -EOPNOTSUPP;
}
static inline struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev,
struct sk_buff *skb,
usb_complete_t tx_complete)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline int btmtk_usb_resume(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btmtk_usb_suspend(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btmtk_usb_setup(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btmtk_usb_shutdown(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}

View File

@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_ids.h>
@ -1117,6 +1118,9 @@ static int btmtksdio_setup(struct hci_dev *hdev)
return err;
}
btmtk_fw_get_filename(fwname, sizeof(fwname), dev_id,
fw_version, 0);
snprintf(fwname, sizeof(fwname),
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, (fw_version & 0xff) + 1);

View File

@ -22,6 +22,7 @@
#include <linux/regulator/consumer.h>
#include <linux/serdev.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

View File

@ -29,27 +29,38 @@
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
#define BTNXPUART_SERDEV_OPEN 4
#define BTNXPUART_IR_IN_PROGRESS 5
#define BTNXPUART_FW_DOWNLOAD_ABORT 6
/* NXP HW err codes */
#define BTNXPUART_IR_HW_ERR 0xb0
#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin"
#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin"
#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se"
#define FIRMWARE_IW624 "nxp/uartiw624_bt.bin"
#define FIRMWARE_SECURE_IW624 "nxp/uartiw624_bt.bin.se"
#define FIRMWARE_AW693 "nxp/uartaw693_bt.bin"
#define FIRMWARE_SECURE_AW693 "nxp/uartaw693_bt.bin.se"
#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin"
#define FIRMWARE_W8987 "uart8987_bt_v0.bin"
#define FIRMWARE_W8987_OLD "uartuart8987_bt.bin"
#define FIRMWARE_W8997 "uart8997_bt_v4.bin"
#define FIRMWARE_W8997_OLD "uartuart8997_bt_v4.bin"
#define FIRMWARE_W9098 "uart9098_bt_v1.bin"
#define FIRMWARE_W9098_OLD "uartuart9098_bt_v1.bin"
#define FIRMWARE_IW416 "uartiw416_bt_v0.bin"
#define FIRMWARE_IW612 "uartspi_n61x_v1.bin.se"
#define FIRMWARE_IW615 "uartspi_iw610_v0.bin"
#define FIRMWARE_SECURE_IW615 "uartspi_iw610_v0.bin.se"
#define FIRMWARE_IW624 "uartiw624_bt.bin"
#define FIRMWARE_SECURE_IW624 "uartiw624_bt.bin.se"
#define FIRMWARE_AW693 "uartaw693_bt.bin"
#define FIRMWARE_SECURE_AW693 "uartaw693_bt.bin.se"
#define FIRMWARE_AW693_A1 "uartaw693_bt_v1.bin"
#define FIRMWARE_SECURE_AW693_A1 "uartaw693_bt_v1.bin.se"
#define FIRMWARE_HELPER "helper_uart_3000000.bin"
#define CHIP_ID_W9098 0x5c03
#define CHIP_ID_IW416 0x7201
#define CHIP_ID_IW612 0x7601
#define CHIP_ID_IW624a 0x8000
#define CHIP_ID_IW624c 0x8001
#define CHIP_ID_AW693 0x8200
#define CHIP_ID_AW693a0 0x8200
#define CHIP_ID_AW693a1 0x8201
#define CHIP_ID_IW615a0 0x8800
#define CHIP_ID_IW615a1 0x8801
#define FW_SECURE_MASK 0xc0
#define FW_OPEN 0x00
@ -144,6 +155,7 @@ struct psmode_cmd_payload {
struct btnxpuart_data {
const char *helper_fw_name;
const char *fw_name;
const char *fw_name_old;
};
struct btnxpuart_dev {
@ -159,6 +171,7 @@ struct btnxpuart_dev {
u8 fw_name[MAX_FW_FILE_NAME_LEN];
u32 fw_dnld_v1_offset;
u32 fw_v1_sent_bytes;
u32 fw_dnld_v3_offset;
u32 fw_v3_offset_correction;
u32 fw_v1_expected_len;
u32 boot_reg_offset;
@ -187,6 +200,11 @@ struct btnxpuart_dev {
#define NXP_NAK_V3 0x7b
#define NXP_CRC_ERROR_V3 0x7c
/* Bootloader signature error codes */
#define NXP_ACK_RX_TIMEOUT 0x0002 /* ACK not received from host */
#define NXP_HDR_RX_TIMEOUT 0x0003 /* FW Header chunk not received */
#define NXP_DATA_RX_TIMEOUT 0x0004 /* FW Data chunk not received */
#define HDR_LEN 16
#define NXP_RECV_CHIP_VER_V1 \
@ -277,6 +295,17 @@ struct nxp_bootloader_cmd {
__be32 crc;
} __packed;
struct nxp_v3_rx_timeout_nak {
u8 nak;
__le32 offset;
u8 crc;
} __packed;
union nxp_v3_rx_timeout_nak_u {
struct nxp_v3_rx_timeout_nak pkt;
u8 buf[6];
};
static u8 crc8_table[CRC8_TABLE_SIZE];
/* Default configurations */
@ -328,7 +357,7 @@ static void ps_cancel_timer(struct btnxpuart_dev *nxpdev)
struct ps_data *psdata = &nxpdev->psdata;
flush_work(&psdata->work);
del_timer_sync(&psdata->ps_timer);
timer_shutdown_sync(&psdata->ps_timer);
}
static void ps_control(struct hci_dev *hdev, u8 ps_state)
@ -550,6 +579,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
nxpdev->fw_v1_sent_bytes = 0;
nxpdev->fw_v1_expected_len = HDR_LEN;
nxpdev->boot_reg_offset = 0;
nxpdev->fw_dnld_v3_offset = 0;
nxpdev->fw_v3_offset_correction = 0;
nxpdev->baudrate_changed = false;
nxpdev->timeout_changed = false;
@ -564,14 +594,23 @@ static int nxp_download_firmware(struct hci_dev *hdev)
!test_bit(BTNXPUART_FW_DOWNLOADING,
&nxpdev->tx_state),
msecs_to_jiffies(60000));
release_firmware(nxpdev->fw);
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
if (err == 0) {
bt_dev_err(hdev, "FW Download Timeout.");
bt_dev_err(hdev, "FW Download Timeout. offset: %d",
nxpdev->fw_dnld_v1_offset ?
nxpdev->fw_dnld_v1_offset :
nxpdev->fw_dnld_v3_offset);
return -ETIMEDOUT;
}
if (test_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state)) {
bt_dev_err(hdev, "FW Download Aborted");
return -EINTR;
}
serdev_device_set_flow_control(nxpdev->serdev, true);
release_firmware(nxpdev->fw);
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
/* Allow the downloaded FW to initialize */
msleep(1200);
@ -682,19 +721,30 @@ static bool process_boot_signature(struct btnxpuart_dev *nxpdev)
return is_fw_downloading(nxpdev);
}
static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name)
static int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name,
const char *fw_name_old)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
const char *fw_name_dt;
int err = 0;
if (!fw_name)
return -ENOENT;
if (!strlen(nxpdev->fw_name)) {
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "%s", fw_name);
if (strcmp(fw_name, FIRMWARE_HELPER) &&
!device_property_read_string(&nxpdev->serdev->dev,
"firmware-name",
&fw_name_dt))
fw_name = fw_name_dt;
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "nxp/%s", fw_name);
err = request_firmware_direct(&nxpdev->fw, nxpdev->fw_name, &hdev->dev);
if (err < 0 && fw_name_old) {
snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "nxp/%s", fw_name_old);
err = request_firmware_direct(&nxpdev->fw, nxpdev->fw_name, &hdev->dev);
}
bt_dev_dbg(hdev, "Request Firmware: %s", nxpdev->fw_name);
err = request_firmware(&nxpdev->fw, nxpdev->fw_name, &hdev->dev);
bt_dev_info(hdev, "Request Firmware: %s", nxpdev->fw_name);
if (err < 0) {
bt_dev_err(hdev, "Firmware file %s not found", nxpdev->fw_name);
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
@ -773,15 +823,15 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb)
}
if (!nxp_data->helper_fw_name || nxpdev->helper_downloaded) {
if (nxp_request_firmware(hdev, nxp_data->fw_name))
if (nxp_request_firmware(hdev, nxp_data->fw_name, nxp_data->fw_name_old))
goto free_skb;
} else if (nxp_data->helper_fw_name && !nxpdev->helper_downloaded) {
if (nxp_request_firmware(hdev, nxp_data->helper_fw_name))
if (nxp_request_firmware(hdev, nxp_data->helper_fw_name, NULL))
goto free_skb;
}
if (!len) {
bt_dev_dbg(hdev, "FW Downloaded Successfully: %zu bytes",
bt_dev_info(hdev, "FW Download Complete: %zu bytes",
nxpdev->fw->size);
if (nxp_data->helper_fw_name && !nxpdev->helper_downloaded) {
nxpdev->helper_downloaded = true;
@ -863,7 +913,7 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
else
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
break;
case CHIP_ID_AW693:
case CHIP_ID_AW693a0:
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
fw_name = FIRMWARE_AW693;
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
@ -871,6 +921,23 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
else
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
break;
case CHIP_ID_AW693a1:
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
fw_name = FIRMWARE_AW693_A1;
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
fw_name = FIRMWARE_SECURE_AW693_A1;
else
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
break;
case CHIP_ID_IW615a0:
case CHIP_ID_IW615a1:
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
fw_name = FIRMWARE_IW615;
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
fw_name = FIRMWARE_SECURE_IW615;
else
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
break;
default:
bt_dev_err(hdev, "Unknown chip signature %04x", chipid);
break;
@ -878,10 +945,25 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
return fw_name;
}
static char *nxp_get_old_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
u8 loader_ver)
{
char *fw_name_old = NULL;
switch (chipid) {
case CHIP_ID_W9098:
fw_name_old = FIRMWARE_W9098_OLD;
break;
}
return fw_name_old;
}
static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb)
{
struct v3_start_ind *req = skb_pull_data(skb, sizeof(*req));
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
const char *fw_name;
const char *fw_name_old;
u16 chip_id;
u8 loader_ver;
@ -890,8 +972,10 @@ static int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb)
chip_id = le16_to_cpu(req->chip_id);
loader_ver = req->loader_ver;
if (!nxp_request_firmware(hdev, nxp_get_fw_name_from_chipid(hdev,
chip_id, loader_ver)))
bt_dev_info(hdev, "ChipID: %04x, Version: %d", chip_id, loader_ver);
fw_name = nxp_get_fw_name_from_chipid(hdev, chip_id, loader_ver);
fw_name_old = nxp_get_old_fw_name_from_chipid(hdev, chip_id, loader_ver);
if (!nxp_request_firmware(hdev, fw_name, fw_name_old))
nxp_send_ack(NXP_ACK_V3, hdev);
free_skb:
@ -899,6 +983,32 @@ free_skb:
return 0;
}
static void nxp_handle_fw_download_error(struct hci_dev *hdev, struct v3_data_req *req)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
__u32 offset = __le32_to_cpu(req->offset);
__u16 err = __le16_to_cpu(req->error);
union nxp_v3_rx_timeout_nak_u nak_tx_buf;
switch (err) {
case NXP_ACK_RX_TIMEOUT:
case NXP_HDR_RX_TIMEOUT:
case NXP_DATA_RX_TIMEOUT:
nak_tx_buf.pkt.nak = NXP_NAK_V3;
nak_tx_buf.pkt.offset = __cpu_to_le32(offset);
nak_tx_buf.pkt.crc = crc8(crc8_table, nak_tx_buf.buf,
sizeof(nak_tx_buf) - 1, 0xff);
serdev_device_write_buf(nxpdev->serdev, nak_tx_buf.buf,
sizeof(nak_tx_buf));
break;
default:
bt_dev_dbg(hdev, "Unknown bootloader error code: %d", err);
break;
}
}
static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
@ -913,7 +1023,12 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
if (!req || !nxpdev->fw)
goto free_skb;
nxp_send_ack(NXP_ACK_V3, hdev);
if (!req->error) {
nxp_send_ack(NXP_ACK_V3, hdev);
} else {
nxp_handle_fw_download_error(hdev, req);
goto free_skb;
}
len = __le16_to_cpu(req->len);
@ -934,15 +1049,12 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
}
if (req->len == 0) {
bt_dev_dbg(hdev, "FW Downloaded Successfully: %zu bytes",
bt_dev_info(hdev, "FW Download Complete: %zu bytes",
nxpdev->fw->size);
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
goto free_skb;
}
if (req->error)
bt_dev_dbg(hdev, "FW Download received err 0x%02x from chip",
req->error);
offset = __le32_to_cpu(req->offset);
if (offset < nxpdev->fw_v3_offset_correction) {
@ -954,8 +1066,9 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
goto free_skb;
}
serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset -
nxpdev->fw_v3_offset_correction, len);
nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction;
serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data +
nxpdev->fw_dnld_v3_offset, len);
free_skb:
kfree_skb(skb);
@ -1037,7 +1150,7 @@ static int nxp_setup(struct hci_dev *hdev)
if (err < 0)
return err;
} else {
bt_dev_dbg(hdev, "FW already running.");
bt_dev_info(hdev, "FW already running.");
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
}
@ -1253,8 +1366,10 @@ static int btnxpuart_close(struct hci_dev *hdev)
ps_wakeup(nxpdev);
serdev_device_close(nxpdev->serdev);
skb_queue_purge(&nxpdev->txq);
kfree_skb(nxpdev->rx_skb);
nxpdev->rx_skb = NULL;
if (!IS_ERR_OR_NULL(nxpdev->rx_skb)) {
kfree_skb(nxpdev->rx_skb);
nxpdev->rx_skb = NULL;
}
clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state);
return 0;
}
@ -1269,8 +1384,10 @@ static int btnxpuart_flush(struct hci_dev *hdev)
cancel_work_sync(&nxpdev->tx_work);
kfree_skb(nxpdev->rx_skb);
nxpdev->rx_skb = NULL;
if (!IS_ERR_OR_NULL(nxpdev->rx_skb)) {
kfree_skb(nxpdev->rx_skb);
nxpdev->rx_skb = NULL;
}
return 0;
}
@ -1385,28 +1502,56 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
struct hci_dev *hdev = nxpdev->hdev;
/* Restore FW baudrate to fw_init_baudrate if changed.
* This will ensure FW baudrate is in sync with
* driver baudrate in case this driver is re-inserted.
*/
if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
nxp_set_baudrate_cmd(hdev, NULL);
if (is_fw_downloading(nxpdev)) {
set_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state);
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
wake_up_interruptible(&nxpdev->check_boot_sign_wait_q);
wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
} else {
/* Restore FW baudrate to fw_init_baudrate if changed.
* This will ensure FW baudrate is in sync with
* driver baudrate in case this driver is re-inserted.
*/
if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
nxp_set_baudrate_cmd(hdev, NULL);
}
ps_cancel_timer(nxpdev);
}
ps_cancel_timer(nxpdev);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
}
#ifdef CONFIG_PM_SLEEP
static int nxp_serdev_suspend(struct device *dev)
{
struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev);
struct ps_data *psdata = &nxpdev->psdata;
ps_control(psdata->hdev, PS_STATE_SLEEP);
return 0;
}
static int nxp_serdev_resume(struct device *dev)
{
struct btnxpuart_dev *nxpdev = dev_get_drvdata(dev);
struct ps_data *psdata = &nxpdev->psdata;
ps_control(psdata->hdev, PS_STATE_AWAKE);
return 0;
}
#endif
static struct btnxpuart_data w8987_data __maybe_unused = {
.helper_fw_name = NULL,
.fw_name = FIRMWARE_W8987,
.fw_name_old = FIRMWARE_W8987_OLD,
};
static struct btnxpuart_data w8997_data __maybe_unused = {
.helper_fw_name = FIRMWARE_HELPER,
.fw_name = FIRMWARE_W8997,
.fw_name_old = FIRMWARE_W8997_OLD,
};
static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = {
@ -1416,12 +1561,17 @@ static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = {
};
MODULE_DEVICE_TABLE(of, nxpuart_of_match_table);
static const struct dev_pm_ops nxp_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(nxp_serdev_suspend, nxp_serdev_resume)
};
static struct serdev_device_driver nxp_serdev_driver = {
.probe = nxp_serdev_probe,
.remove = nxp_serdev_remove,
.driver = {
.name = "btnxpuart",
.of_match_table = of_match_ptr(nxpuart_of_match_table),
.pm = &nxp_pm_ops,
},
};

View File

@ -811,7 +811,7 @@ static int rtl_download_firmware(struct hci_dev *hdev,
struct sk_buff *skb;
struct hci_rp_read_local_version *rp;
dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL);
dl_cmd = kmalloc(sizeof(*dl_cmd), GFP_KERNEL);
if (!dl_cmd)
return -ENOMEM;

View File

@ -479,6 +479,7 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0037), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0038), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0039), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
BTUSB_INTEL_NO_WBS_SUPPORT |
@ -555,6 +556,10 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3572), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek 8852BT/8852BE-VT Bluetooth devices */
{ USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK |
@ -891,6 +896,9 @@ struct btusb_data {
int (*setup_on_usb)(struct hci_dev *hdev);
int (*suspend)(struct hci_dev *hdev);
int (*resume)(struct hci_dev *hdev);
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
unsigned cmd_timeout_cnt;
@ -2638,410 +2646,48 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
return hci_recv_frame(hdev, skb);
}
/* UHW CR mapping */
#define MTK_BT_MISC 0x70002510
#define MTK_BT_SUBSYS_RST 0x70002610
#define MTK_UDMA_INT_STA_BT 0x74000024
#define MTK_UDMA_INT_STA_BT1 0x74000308
#define MTK_BT_WDT_STATUS 0x740003A0
#define MTK_EP_RST_OPT 0x74011890
#define MTK_EP_RST_IN_OUT_OPT 0x00010001
#define MTK_BT_RST_DONE 0x00000100
#define MTK_BT_RESET_REG_CONNV3 0x70028610
#define MTK_BT_READ_DEV_ID 0x70010200
static void btusb_mtk_wmt_recv(struct urb *urb)
static void btusb_mtk_claim_iso_intf(struct btusb_data *data)
{
struct hci_dev *hdev = urb->context;
struct btusb_data *data = hci_get_drvdata(hdev);
struct sk_buff *skb;
struct btmtk_data *btmtk_data = hci_get_priv(data->hdev);
int err;
if (urb->status == 0 && urb->actual_length > 0) {
hdev->stat.byte_rx += urb->actual_length;
/* WMT event shouldn't be fragmented and the size should be
* less than HCI_WMT_MAX_EVENT_SIZE.
*/
skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC);
if (!skb) {
hdev->stat.err_rx++;
kfree(urb->setup_packet);
return;
}
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
skb_put_data(skb, urb->transfer_buffer, urb->actual_length);
/* When someone waits for the WMT event, the skb is being cloned
* and being processed the events from there then.
*/
if (test_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags)) {
data->evt_skb = skb_clone(skb, GFP_ATOMIC);
if (!data->evt_skb) {
kfree_skb(skb);
kfree(urb->setup_packet);
return;
}
}
err = hci_recv_frame(hdev, skb);
if (err < 0) {
kfree_skb(data->evt_skb);
data->evt_skb = NULL;
kfree(urb->setup_packet);
return;
}
if (test_and_clear_bit(BTUSB_TX_WAIT_VND_EVT,
&data->flags)) {
/* Barrier to sync with other CPUs */
smp_mb__after_atomic();
wake_up_bit(&data->flags,
BTUSB_TX_WAIT_VND_EVT);
}
kfree(urb->setup_packet);
return;
} else if (urb->status == -ENOENT) {
/* Avoid suspend failed when usb_kill_urb */
err = usb_driver_claim_interface(&btusb_driver,
btmtk_data->isopkt_intf, data);
if (err < 0) {
btmtk_data->isopkt_intf = NULL;
bt_dev_err(data->hdev, "Failed to claim iso interface");
return;
}
usb_mark_last_busy(data->udev);
/* The URB complete handler is still called with urb->actual_length = 0
* when the event is not available, so we should keep re-submitting
* URB until WMT event returns, Also, It's necessary to wait some time
* between the two consecutive control URBs to relax the target device
* to generate the event. Otherwise, the WMT event cannot return from
* the device successfully.
*/
udelay(500);
usb_anchor_urb(urb, &data->ctrl_anchor);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
kfree(urb->setup_packet);
/* -EPERM: urb is being killed;
* -ENODEV: device got disconnected
*/
if (err != -EPERM && err != -ENODEV)
bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
urb, -err);
usb_unanchor_urb(urb);
}
set_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
}
static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev)
static void btusb_mtk_release_iso_intf(struct btusb_data *data)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct usb_ctrlrequest *dr;
unsigned char *buf;
int err, size = 64;
unsigned int pipe;
struct urb *urb;
struct btmtk_data *btmtk_data = hci_get_priv(data->hdev);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
if (btmtk_data->isopkt_intf) {
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags);
dr = kmalloc(sizeof(*dr), GFP_KERNEL);
if (!dr) {
usb_free_urb(urb);
return -ENOMEM;
dev_kfree_skb_irq(btmtk_data->isopkt_skb);
btmtk_data->isopkt_skb = NULL;
usb_set_intfdata(btmtk_data->isopkt_intf, NULL);
usb_driver_release_interface(&btusb_driver,
btmtk_data->isopkt_intf);
}
dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
dr->bRequest = 1;
dr->wIndex = cpu_to_le16(0);
dr->wValue = cpu_to_le16(48);
dr->wLength = cpu_to_le16(size);
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
kfree(dr);
usb_free_urb(urb);
return -ENOMEM;
}
pipe = usb_rcvctrlpipe(data->udev, 0);
usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
buf, size, btusb_mtk_wmt_recv, hdev);
urb->transfer_flags |= URB_FREE_BUFFER;
usb_anchor_urb(urb, &data->ctrl_anchor);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
bt_dev_err(hdev, "urb %p submission failed (%d)",
urb, -err);
usb_unanchor_urb(urb);
}
usb_free_urb(urb);
return err;
}
static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
struct btmtk_hci_wmt_params *wmt_params)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
u32 hlen, status = BTMTK_WMT_INVALID;
struct btmtk_hci_wmt_evt *wmt_evt;
struct btmtk_hci_wmt_cmd *wc;
struct btmtk_wmt_hdr *hdr;
int err;
/* Send the WMT command and wait until the WMT event returns */
hlen = sizeof(*hdr) + wmt_params->dlen;
if (hlen > 255)
return -EINVAL;
wc = kzalloc(hlen, GFP_KERNEL);
if (!wc)
return -ENOMEM;
hdr = &wc->hdr;
hdr->dir = 1;
hdr->op = wmt_params->op;
hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
hdr->flag = wmt_params->flag;
memcpy(wc->data, wmt_params->data, wmt_params->dlen);
set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
/* WMT cmd/event doesn't follow up the generic HCI cmd/event handling,
* it needs constantly polling control pipe until the host received the
* WMT event, thus, we should require to specifically acquire PM counter
* on the USB to prevent the interface from entering auto suspended
* while WMT cmd/event in progress.
*/
err = usb_autopm_get_interface(data->intf);
if (err < 0)
goto err_free_wc;
err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
if (err < 0) {
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
usb_autopm_put_interface(data->intf);
goto err_free_wc;
}
/* Submit control IN URB on demand to process the WMT event */
err = btusb_mtk_submit_wmt_recv_urb(hdev);
usb_autopm_put_interface(data->intf);
if (err < 0)
goto err_free_wc;
/* The vendor specific WMT commands are all answered by a vendor
* specific event and will have the Command Status or Command
* Complete as with usual HCI command flow control.
*
* After sending the command, wait for BTUSB_TX_WAIT_VND_EVT
* state to be cleared. The driver specific event receive routine
* will clear that state and with that indicate completion of the
* WMT command.
*/
err = wait_on_bit_timeout(&data->flags, BTUSB_TX_WAIT_VND_EVT,
TASK_INTERRUPTIBLE, HCI_INIT_TIMEOUT);
if (err == -EINTR) {
bt_dev_err(hdev, "Execution of wmt command interrupted");
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
goto err_free_wc;
}
if (err) {
bt_dev_err(hdev, "Execution of wmt command timed out");
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
err = -ETIMEDOUT;
goto err_free_wc;
}
if (data->evt_skb == NULL)
goto err_free_wc;
/* Parse and handle the return WMT event */
wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data;
if (wmt_evt->whdr.op != hdr->op) {
bt_dev_err(hdev, "Wrong op received %d expected %d",
wmt_evt->whdr.op, hdr->op);
err = -EIO;
goto err_free_skb;
}
switch (wmt_evt->whdr.op) {
case BTMTK_WMT_SEMAPHORE:
if (wmt_evt->whdr.flag == 2)
status = BTMTK_WMT_PATCH_UNDONE;
else
status = BTMTK_WMT_PATCH_DONE;
break;
case BTMTK_WMT_FUNC_CTRL:
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
status = BTMTK_WMT_ON_DONE;
else if (be16_to_cpu(wmt_evt_funcc->status) == 0x420)
status = BTMTK_WMT_ON_PROGRESS;
else
status = BTMTK_WMT_ON_UNDONE;
break;
case BTMTK_WMT_PATCH_DWNLD:
if (wmt_evt->whdr.flag == 2)
status = BTMTK_WMT_PATCH_DONE;
else if (wmt_evt->whdr.flag == 1)
status = BTMTK_WMT_PATCH_PROGRESS;
else
status = BTMTK_WMT_PATCH_UNDONE;
break;
}
if (wmt_params->status)
*wmt_params->status = status;
err_free_skb:
kfree_skb(data->evt_skb);
data->evt_skb = NULL;
err_free_wc:
kfree(wc);
return err;
}
static int btusb_mtk_func_query(struct hci_dev *hdev)
{
struct btmtk_hci_wmt_params wmt_params;
int status, err;
u8 param = 0;
/* Query whether the function is enabled */
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
wmt_params.flag = 4;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
wmt_params.status = &status;
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to query function status (%d)", err);
return err;
}
return status;
}
static int btusb_mtk_uhw_reg_write(struct btusb_data *data, u32 reg, u32 val)
{
struct hci_dev *hdev = data->hdev;
int pipe, err;
void *buf;
buf = kzalloc(4, GFP_KERNEL);
if (!buf)
return -ENOMEM;
put_unaligned_le32(val, buf);
pipe = usb_sndctrlpipe(data->udev, 0);
err = usb_control_msg(data->udev, pipe, 0x02,
0x5E,
reg >> 16, reg & 0xffff,
buf, 4, USB_CTRL_SET_TIMEOUT);
if (err < 0) {
bt_dev_err(hdev, "Failed to write uhw reg(%d)", err);
goto err_free_buf;
}
err_free_buf:
kfree(buf);
return err;
}
static int btusb_mtk_uhw_reg_read(struct btusb_data *data, u32 reg, u32 *val)
{
struct hci_dev *hdev = data->hdev;
int pipe, err;
void *buf;
buf = kzalloc(4, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pipe = usb_rcvctrlpipe(data->udev, 0);
err = usb_control_msg(data->udev, pipe, 0x01,
0xDE,
reg >> 16, reg & 0xffff,
buf, 4, USB_CTRL_GET_TIMEOUT);
if (err < 0) {
bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
goto err_free_buf;
}
*val = get_unaligned_le32(buf);
bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
err_free_buf:
kfree(buf);
return err;
}
static int btusb_mtk_reg_read(struct btusb_data *data, u32 reg, u32 *val)
{
int pipe, err, size = sizeof(u32);
void *buf;
buf = kzalloc(size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
pipe = usb_rcvctrlpipe(data->udev, 0);
err = usb_control_msg(data->udev, pipe, 0x63,
USB_TYPE_VENDOR | USB_DIR_IN,
reg >> 16, reg & 0xffff,
buf, size, USB_CTRL_GET_TIMEOUT);
if (err < 0)
goto err_free_buf;
*val = get_unaligned_le32(buf);
err_free_buf:
kfree(buf);
return err;
}
static int btusb_mtk_id_get(struct btusb_data *data, u32 reg, u32 *id)
{
return btusb_mtk_reg_read(data, reg, id);
}
static u32 btusb_mtk_reset_done(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
u32 val = 0;
btusb_mtk_uhw_reg_read(data, MTK_BT_MISC, &val);
return val & MTK_BT_RST_DONE;
clear_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
}
static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct btmediatek_data *mediatek;
u32 val;
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
int err;
/* It's MediaTek specific bluetooth reset mechanism via USB */
if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
if (test_and_set_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags)) {
bt_dev_err(hdev, "last reset failed? Not resetting again");
return -EBUSY;
}
@ -3050,302 +2696,68 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
if (err < 0)
return err;
if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags))
btusb_mtk_release_iso_intf(data);
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
mediatek = hci_get_priv(hdev);
if (mediatek->dev_id == 0x7925) {
btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
val |= (1 << 5);
btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
val &= 0xFFFF00FF;
val |= (1 << 13);
btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, 0x00010001);
btusb_mtk_uhw_reg_read(data, MTK_BT_RESET_REG_CONNV3, &val);
val |= (1 << 0);
btusb_mtk_uhw_reg_write(data, MTK_BT_RESET_REG_CONNV3, val);
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
msleep(100);
} else {
/* It's Device EndPoint Reset Option Register */
bt_dev_dbg(hdev, "Initiating reset mechanism via uhw");
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
btusb_mtk_uhw_reg_read(data, MTK_BT_WDT_STATUS, &val);
/* Reset the bluetooth chip via USB interface. */
btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 1);
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT, 0x000000FF);
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT, &val);
btusb_mtk_uhw_reg_write(data, MTK_UDMA_INT_STA_BT1, 0x000000FF);
btusb_mtk_uhw_reg_read(data, MTK_UDMA_INT_STA_BT1, &val);
/* MT7921 need to delay 20ms between toggle reset bit */
msleep(20);
btusb_mtk_uhw_reg_write(data, MTK_BT_SUBSYS_RST, 0);
btusb_mtk_uhw_reg_read(data, MTK_BT_SUBSYS_RST, &val);
}
err = readx_poll_timeout(btusb_mtk_reset_done, hdev, val,
val & MTK_BT_RST_DONE, 20000, 1000000);
if (err < 0)
bt_dev_err(hdev, "Reset timeout");
btusb_mtk_id_get(data, 0x70010200, &val);
if (!val)
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
err = btmtk_usb_subsys_reset(hdev, btmtk_data->dev_id);
usb_queue_reset_device(data->intf);
clear_bit(BTUSB_HW_RESET_ACTIVE, &data->flags);
clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
return err;
}
static int btusb_send_frame_mtk(struct hci_dev *hdev, struct sk_buff *skb)
{
struct urb *urb;
BT_DBG("%s", hdev->name);
if (hci_skb_pkt_type(skb) == HCI_ISODATA_PKT) {
urb = alloc_mtk_intr_urb(hdev, skb, btusb_tx_complete);
if (IS_ERR(urb))
return PTR_ERR(urb);
return submit_or_queue_tx_urb(hdev, urb);
} else {
return btusb_send_frame(hdev, skb);
}
}
static int btusb_mtk_setup(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct btmtk_hci_wmt_params wmt_params;
ktime_t calltime, delta, rettime;
struct btmtk_tci_sleep tci_sleep;
unsigned long long duration;
struct sk_buff *skb;
const char *fwname;
int err, status;
u32 dev_id = 0;
char fw_bin_name[64];
u32 fw_version = 0, fw_flavor = 0;
u8 param;
struct btmediatek_data *mediatek;
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
calltime = ktime_get();
/* MediaTek WMT vendor cmd requiring below USB resources to
* complete the handshake.
*/
btmtk_data->drv_name = btusb_driver.name;
btmtk_data->intf = data->intf;
btmtk_data->udev = data->udev;
btmtk_data->ctrl_anchor = &data->ctrl_anchor;
btmtk_data->reset_sync = btusb_mtk_reset;
err = btusb_mtk_id_get(data, 0x80000008, &dev_id);
if (err < 0) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
/* Claim ISO data interface and endpoint */
btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM);
if (btmtk_data->isopkt_intf)
btusb_mtk_claim_iso_intf(data);
if (!dev_id || dev_id != 0x7663) {
err = btusb_mtk_id_get(data, 0x70010200, &dev_id);
if (err < 0) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
err = btusb_mtk_id_get(data, 0x80021004, &fw_version);
if (err < 0) {
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
return err;
}
err = btusb_mtk_id_get(data, 0x70010020, &fw_flavor);
if (err < 0) {
bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
return err;
}
fw_flavor = (fw_flavor & 0x00000080) >> 7;
}
mediatek = hci_get_priv(hdev);
mediatek->dev_id = dev_id;
mediatek->reset_sync = btusb_mtk_reset;
err = btmtk_register_coredump(hdev, btusb_driver.name, fw_version);
if (err < 0)
bt_dev_err(hdev, "Failed to register coredump (%d)", err);
switch (dev_id) {
case 0x7663:
fwname = FIRMWARE_MT7663;
break;
case 0x7668:
fwname = FIRMWARE_MT7668;
break;
case 0x7922:
case 0x7961:
case 0x7925:
if (dev_id == 0x7925)
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1);
else if (dev_id == 0x7961 && fw_flavor)
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin",
dev_id & 0xffff, (fw_version & 0xff) + 1);
else
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, (fw_version & 0xff) + 1);
err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
btusb_mtk_hci_wmt_sync);
if (err < 0) {
bt_dev_err(hdev, "Failed to set up firmware (%d)", err);
return err;
}
/* It's Device EndPoint Reset Option Register */
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
/* Enable Bluetooth protocol */
param = 1;
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
wmt_params.flag = 0;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
wmt_params.status = NULL;
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
return err;
}
hci_set_msft_opcode(hdev, 0xFD30);
hci_set_aosp_capable(hdev);
goto done;
default:
bt_dev_err(hdev, "Unsupported hardware variant (%08x)",
dev_id);
return -ENODEV;
}
/* Query whether the firmware is already download */
wmt_params.op = BTMTK_WMT_SEMAPHORE;
wmt_params.flag = 1;
wmt_params.dlen = 0;
wmt_params.data = NULL;
wmt_params.status = &status;
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to query firmware status (%d)", err);
return err;
}
if (status == BTMTK_WMT_PATCH_DONE) {
bt_dev_info(hdev, "firmware already downloaded");
goto ignore_setup_fw;
}
/* Setup a firmware which the device definitely requires */
err = btmtk_setup_firmware(hdev, fwname,
btusb_mtk_hci_wmt_sync);
if (err < 0)
return err;
ignore_setup_fw:
err = readx_poll_timeout(btusb_mtk_func_query, hdev, status,
status < 0 || status != BTMTK_WMT_ON_PROGRESS,
2000, 5000000);
/* -ETIMEDOUT happens */
if (err < 0)
return err;
/* The other errors happen in btusb_mtk_func_query */
if (status < 0)
return status;
if (status == BTMTK_WMT_ON_DONE) {
bt_dev_info(hdev, "function already on");
goto ignore_func_on;
}
/* Enable Bluetooth protocol */
param = 1;
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
wmt_params.flag = 0;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
wmt_params.status = NULL;
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
return err;
}
ignore_func_on:
/* Apply the low power environment setup */
tci_sleep.mode = 0x5;
tci_sleep.duration = cpu_to_le16(0x640);
tci_sleep.host_duration = cpu_to_le16(0x640);
tci_sleep.host_wakeup_pin = 0;
tci_sleep.time_compensation = 0;
skb = __hci_cmd_sync(hdev, 0xfc7a, sizeof(tci_sleep), &tci_sleep,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Failed to apply low power setting (%d)", err);
return err;
}
kfree_skb(skb);
done:
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
bt_dev_info(hdev, "Device setup in %llu usecs", duration);
return 0;
return btmtk_usb_setup(hdev);
}
static int btusb_mtk_shutdown(struct hci_dev *hdev)
{
struct btmtk_hci_wmt_params wmt_params;
u8 param = 0;
int err;
/* Disable the device */
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
wmt_params.flag = 0;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
wmt_params.status = NULL;
err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
return err;
}
return 0;
}
static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
switch (handle) {
case 0xfc6f: /* Firmware dump from device */
/* When the firmware hangs, the device can no longer
* suspend and thus disable auto-suspend.
*/
usb_disable_autosuspend(data->udev);
if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags))
btusb_mtk_release_iso_intf(data);
/* We need to forward the diagnostic packet to userspace daemon
* for backward compatibility, so we have to clone the packet
* extraly for the in-kernel coredump support.
*/
if (IS_ENABLED(CONFIG_DEV_COREDUMP)) {
struct sk_buff *skb_cd = skb_clone(skb, GFP_ATOMIC);
if (skb_cd)
btmtk_process_coredump(hdev, skb_cd);
}
fallthrough;
case 0x05ff: /* Firmware debug logging 1 */
case 0x05fe: /* Firmware debug logging 2 */
return hci_recv_diag(hdev, skb);
}
return hci_recv_frame(hdev, skb);
return btmtk_usb_shutdown(hdev);
}
#ifdef CONFIG_PM
@ -4347,7 +3759,7 @@ static int btusb_probe(struct usb_interface *intf,
data->recv_event = btusb_recv_event_realtek;
} else if (id->driver_info & BTUSB_MEDIATEK) {
/* Allocate extra space for Mediatek device */
priv_size += sizeof(struct btmediatek_data);
priv_size += sizeof(struct btmtk_data);
}
data->recv_acl = hci_recv_frame;
@ -4451,9 +3863,12 @@ static int btusb_probe(struct usb_interface *intf,
hdev->manufacturer = 70;
hdev->cmd_timeout = btmtk_reset_sync;
hdev->set_bdaddr = btmtk_set_bdaddr;
hdev->send = btusb_send_frame_mtk;
set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
data->recv_acl = btusb_recv_acl_mtk;
data->recv_acl = btmtk_usb_recv_acl;
data->suspend = btmtk_usb_suspend;
data->resume = btmtk_usb_resume;
}
if (id->driver_info & BTUSB_SWAVE) {
@ -4694,6 +4109,9 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
cancel_work_sync(&data->work);
if (data->suspend)
data->suspend(data->hdev);
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
@ -4797,6 +4215,9 @@ static int btusb_resume(struct usb_interface *intf)
btusb_submit_isoc_urb(hdev, GFP_NOIO);
}
if (data->resume)
data->resume(hdev);
spin_lock_irq(&data->txlock);
play_deferred(data);
clear_bit(BTUSB_SUSPENDING, &data->flags);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/*
* Bluetooth HCI driver for Broadcom 4377/4378/4387 devices attached via PCIe
* Bluetooth HCI driver for Broadcom 4377/4378/4387/4388 devices attached via PCIe
*
* Copyright (C) The Asahi Linux Contributors
*/
@ -26,13 +26,16 @@ enum bcm4377_chip {
BCM4377 = 0,
BCM4378,
BCM4387,
BCM4388,
};
#define BCM4377_DEVICE_ID 0x5fa0
#define BCM4378_DEVICE_ID 0x5f69
#define BCM4387_DEVICE_ID 0x5f71
#define BCM4388_DEVICE_ID 0x5f72
#define BCM4377_TIMEOUT 1000
#define BCM4377_TIMEOUT msecs_to_jiffies(1000)
#define BCM4377_BOOT_TIMEOUT msecs_to_jiffies(5000)
/*
* These devices only support DMA transactions inside a 32bit window
@ -487,6 +490,7 @@ struct bcm4377_data;
* second window in BAR0
* has_bar0_core2_window2: Set to true if this chip requires the second core's
* second window to be configured
* bar2_offset: Offset to the start of the variables in BAR2
* clear_pciecfg_subsystem_ctrl_bit19: Set to true if bit 19 in the
* vendor-specific subsystem control
* register has to be cleared
@ -510,6 +514,7 @@ struct bcm4377_hw {
u32 bar0_window1;
u32 bar0_window2;
u32 bar0_core2_window2;
u32 bar2_offset;
unsigned long has_bar0_core2_window2 : 1;
unsigned long clear_pciecfg_subsystem_ctrl_bit19 : 1;
@ -835,8 +840,8 @@ static irqreturn_t bcm4377_irq(int irq, void *data)
struct bcm4377_data *bcm4377 = data;
u32 bootstage, rti_status;
bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE);
rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS);
bootstage = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_BOOTSTAGE);
rti_status = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_STATUS);
if (bootstage != bcm4377->bootstage ||
rti_status != bcm4377->rti_status) {
@ -1196,6 +1201,14 @@ static int bcm4387_send_calibration(struct bcm4377_data *bcm4377)
bcm4377->taurus_cal_size);
}
static int bcm4388_send_calibration(struct bcm4377_data *bcm4377)
{
/* BCM4388 always uses beamforming */
return __bcm4378_send_calibration(
bcm4377, bcm4377->taurus_beamforming_cal_blob,
bcm4377->taurus_beamforming_cal_size);
}
static const struct firmware *bcm4377_request_blob(struct bcm4377_data *bcm4377,
const char *suffix)
{
@ -1819,8 +1832,8 @@ static int bcm4377_boot(struct bcm4377_data *bcm4377)
int ret = 0;
u32 bootstage, rti_status;
bootstage = ioread32(bcm4377->bar2 + BCM4377_BAR2_BOOTSTAGE);
rti_status = ioread32(bcm4377->bar2 + BCM4377_BAR2_RTI_STATUS);
bootstage = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_BOOTSTAGE);
rti_status = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_STATUS);
if (bootstage != 0) {
dev_err(&bcm4377->pdev->dev, "bootstage is %d and not 0\n",
@ -1854,15 +1867,18 @@ static int bcm4377_boot(struct bcm4377_data *bcm4377)
iowrite32(BCM4377_DMA_MASK,
bcm4377->bar0 + BCM4377_BAR0_HOST_WINDOW_SIZE);
iowrite32(lower_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_LO);
iowrite32(upper_32_bits(fw_dma), bcm4377->bar2 + BCM4377_BAR2_FW_HI);
iowrite32(fw->size, bcm4377->bar2 + BCM4377_BAR2_FW_SIZE);
iowrite32(lower_32_bits(fw_dma),
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_FW_LO);
iowrite32(upper_32_bits(fw_dma),
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_FW_HI);
iowrite32(fw->size,
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_FW_SIZE);
iowrite32(0, bcm4377->bar0 + BCM4377_BAR0_FW_DOORBELL);
dev_dbg(&bcm4377->pdev->dev, "waiting for firmware to boot\n");
ret = wait_for_completion_interruptible_timeout(&bcm4377->event,
BCM4377_TIMEOUT);
BCM4377_BOOT_TIMEOUT);
if (ret == 0) {
ret = -ETIMEDOUT;
goto out_dma_free;
@ -1913,16 +1929,16 @@ static int bcm4377_setup_rti(struct bcm4377_data *bcm4377)
dev_dbg(&bcm4377->pdev->dev, "RTI is in state 1\n");
/* allow access to the entire IOVA space again */
iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_LO);
iowrite32(0, bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_HI);
iowrite32(0, bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_WINDOW_LO);
iowrite32(0, bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_WINDOW_HI);
iowrite32(BCM4377_DMA_MASK,
bcm4377->bar2 + BCM4377_BAR2_RTI_WINDOW_SIZE);
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_WINDOW_SIZE);
/* setup "Converged IPC" context */
iowrite32(lower_32_bits(bcm4377->ctx_dma),
bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_LO);
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_CONTEXT_ADDR_LO);
iowrite32(upper_32_bits(bcm4377->ctx_dma),
bcm4377->bar2 + BCM4377_BAR2_CONTEXT_ADDR_HI);
bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_CONTEXT_ADDR_HI);
iowrite32(2, bcm4377->bar0 + BCM4377_BAR0_RTI_CONTROL);
ret = wait_for_completion_interruptible_timeout(&bcm4377->event,
@ -2488,6 +2504,21 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
.send_calibration = bcm4387_send_calibration,
.send_ptb = bcm4378_send_ptb,
},
[BCM4388] = {
.id = 0x4388,
.otp_offset = 0x415c,
.bar2_offset = 0x200000,
.bar0_window1 = 0x18002000,
.bar0_window2 = 0x18109000,
.bar0_core2_window2 = 0x18106000,
.has_bar0_core2_window2 = true,
.broken_mws_transport_config = true,
.broken_le_coded = true,
.broken_le_ext_adv_report_phy = true,
.send_calibration = bcm4388_send_calibration,
.send_ptb = bcm4378_send_ptb,
},
};
#define BCM4377_DEVID_ENTRY(id) \
@ -2501,6 +2532,7 @@ static const struct pci_device_id bcm4377_devid_table[] = {
BCM4377_DEVID_ENTRY(4377),
BCM4377_DEVID_ENTRY(4378),
BCM4377_DEVID_ENTRY(4387),
BCM4377_DEVID_ENTRY(4388),
{},
};
MODULE_DEVICE_TABLE(pci, bcm4377_devid_table);
@ -2515,7 +2547,7 @@ static struct pci_driver bcm4377_pci_driver = {
module_pci_driver(bcm4377_pci_driver);
MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
MODULE_DESCRIPTION("Bluetooth support for Broadcom 4377/4378/4387 devices");
MODULE_DESCRIPTION("Bluetooth support for Broadcom 4377/4378/4387/4388 devices");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_FIRMWARE("brcm/brcmbt4377*.bin");
MODULE_FIRMWARE("brcm/brcmbt4377*.ptb");
@ -2523,3 +2555,5 @@ MODULE_FIRMWARE("brcm/brcmbt4378*.bin");
MODULE_FIRMWARE("brcm/brcmbt4378*.ptb");
MODULE_FIRMWARE("brcm/brcmbt4387*.bin");
MODULE_FIRMWARE("brcm/brcmbt4387*.ptb");
MODULE_FIRMWARE("brcm/brcmbt4388*.bin");
MODULE_FIRMWARE("brcm/brcmbt4388*.ptb");

View File

@ -488,7 +488,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL);
hu = kzalloc(sizeof(*hu), GFP_KERNEL);
if (!hu) {
BT_ERR("Can't allocate control structure");
return -ENFILE;

View File

@ -116,11 +116,6 @@ struct hci_nokia_neg_evt {
#define SETUP_BAUD_RATE 921600
#define INIT_BAUD_RATE 120000
struct hci_nokia_radio_hdr {
u8 evt;
u8 dlen;
} __packed;
struct nokia_bt_dev {
struct hci_uart hu;
struct serdev_device *serdev;

View File

@ -28,6 +28,7 @@
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/pwrseq/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/serdev.h>
#include <linux/mutex.h>
@ -214,6 +215,7 @@ struct qca_power {
struct regulator_bulk_data *vreg_bulk;
int num_vregs;
bool vregs_on;
struct pwrseq_desc *pwrseq;
};
struct qca_serdev {
@ -569,7 +571,7 @@ static int qca_open(struct hci_uart *hu)
if (!hci_uart_has_flow_control(hu))
return -EOPNOTSUPP;
qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL);
qca = kzalloc(sizeof(*qca), GFP_KERNEL);
if (!qca)
return -ENOMEM;
@ -1040,8 +1042,7 @@ static void qca_controller_memdump(struct work_struct *work)
}
if (!qca_memdump) {
qca_memdump = kzalloc(sizeof(struct qca_memdump_info),
GFP_ATOMIC);
qca_memdump = kzalloc(sizeof(*qca_memdump), GFP_ATOMIC);
if (!qca_memdump) {
mutex_unlock(&qca->hci_memdump_lock);
return;
@ -1685,6 +1686,27 @@ static bool qca_wakeup(struct hci_dev *hdev)
return wakeup;
}
static int qca_port_reopen(struct hci_uart *hu)
{
int ret;
/* Now the device is in ready state to communicate with host.
* To sync host with device we need to reopen port.
* Without this, we will have RTS and CTS synchronization
* issues.
*/
serdev_device_close(hu->serdev);
ret = serdev_device_open(hu->serdev);
if (ret) {
bt_dev_err(hu->hdev, "failed to open port");
return ret;
}
hci_uart_set_flow_control(hu, false);
return 0;
}
static int qca_regulator_init(struct hci_uart *hu)
{
enum qca_btsoc_type soc_type = qca_soc_type(hu);
@ -1696,6 +1718,7 @@ static int qca_regulator_init(struct hci_uart *hu)
* off the voltage regulator.
*/
qcadev = serdev_device_get_drvdata(hu->serdev);
if (!qcadev->bt_power->vregs_on) {
serdev_device_close(hu->serdev);
ret = qca_regulator_enable(qcadev);
@ -1753,21 +1776,7 @@ static int qca_regulator_init(struct hci_uart *hu)
break;
}
/* Now the device is in ready state to communicate with host.
* To sync host with device we need to reopen port.
* Without this, we will have RTS and CTS synchronization
* issues.
*/
serdev_device_close(hu->serdev);
ret = serdev_device_open(hu->serdev);
if (ret) {
bt_dev_err(hu->hdev, "failed to open port");
return ret;
}
hci_uart_set_flow_control(hu, false);
return 0;
return qca_port_reopen(hu);
}
static int qca_power_on(struct hci_dev *hdev)
@ -1792,6 +1801,7 @@ static int qca_power_on(struct hci_dev *hdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
case QCA_QCA6390:
ret = qca_regulator_init(hu);
break;
@ -2130,6 +2140,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
unsigned long flags;
enum qca_btsoc_type soc_type = qca_soc_type(hu);
bool sw_ctrl_state;
struct qca_power *power;
/* From this point we go into power off state. But serial port is
* still open, stop queueing the IBS data and flush all the buffered
@ -2147,6 +2158,13 @@ static void qca_power_shutdown(struct hci_uart *hu)
return;
qcadev = serdev_device_get_drvdata(hu->serdev);
power = qcadev->bt_power;
if (power->pwrseq) {
pwrseq_power_off(power->pwrseq);
set_bit(QCA_BT_OFF, &qca->flags);
return;
}
switch (soc_type) {
case QCA_WCN3988:
@ -2169,6 +2187,10 @@ static void qca_power_shutdown(struct hci_uart *hu)
}
break;
case QCA_QCA6390:
pwrseq_power_off(qcadev->bt_power->pwrseq);
break;
default:
gpiod_set_value_cansleep(qcadev->bt_en, 0);
}
@ -2204,6 +2226,9 @@ static int qca_regulator_enable(struct qca_serdev *qcadev)
struct qca_power *power = qcadev->bt_power;
int ret;
if (power->pwrseq)
return pwrseq_power_on(power->pwrseq);
/* Already enabled */
if (power->vregs_on)
return 0;
@ -2272,6 +2297,13 @@ static int qca_init_regulators(struct qca_power *qca,
return 0;
}
static void qca_clk_disable_unprepare(void *data)
{
struct clk *clk = data;
clk_disable_unprepare(clk);
}
static int qca_serdev_probe(struct serdev_device *serdev)
{
struct qca_serdev *qcadev;
@ -2310,12 +2342,40 @@ static int qca_serdev_probe(struct serdev_device *serdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
case QCA_QCA6390:
qcadev->bt_power = devm_kzalloc(&serdev->dev,
sizeof(struct qca_power),
GFP_KERNEL);
if (!qcadev->bt_power)
return -ENOMEM;
break;
default:
break;
}
switch (qcadev->btsoc_type) {
case QCA_WCN6855:
case QCA_WCN7850:
if (!device_property_present(&serdev->dev, "enable-gpios")) {
/*
* Backward compatibility with old DT sources. If the
* node doesn't have the 'enable-gpios' property then
* let's use the power sequencer. Otherwise, let's
* drive everything outselves.
*/
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
"bluetooth");
if (IS_ERR(qcadev->bt_power->pwrseq))
return PTR_ERR(qcadev->bt_power->pwrseq);
break;
}
fallthrough;
case QCA_WCN3988:
case QCA_WCN3990:
case QCA_WCN3991:
case QCA_WCN3998:
case QCA_WCN6750:
qcadev->bt_power->dev = &serdev->dev;
err = qca_init_regulators(qcadev->bt_power, data->vregs,
data->num_vregs);
@ -2353,12 +2413,13 @@ static int qca_serdev_probe(struct serdev_device *serdev)
dev_err(&serdev->dev, "failed to acquire clk\n");
return PTR_ERR(qcadev->susclk);
}
break;
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
if (err) {
BT_ERR("wcn3990 serdev registration failed");
return err;
}
case QCA_QCA6390:
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
"bluetooth");
if (IS_ERR(qcadev->bt_power->pwrseq))
return PTR_ERR(qcadev->bt_power->pwrseq);
break;
default:
@ -2385,12 +2446,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (err)
return err;
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
if (err) {
BT_ERR("Rome serdev registration failed");
clk_disable_unprepare(qcadev->susclk);
err = devm_add_action_or_reset(&serdev->dev,
qca_clk_disable_unprepare,
qcadev->susclk);
if (err)
return err;
}
}
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
if (err) {
BT_ERR("serdev registration failed");
return err;
}
hdev = qcadev->serdev_hu.hdev;
@ -2428,15 +2495,11 @@ static void qca_serdev_remove(struct serdev_device *serdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
if (power->vregs_on) {
if (power->vregs_on)
qca_power_shutdown(&qcadev->serdev_hu);
break;
}
fallthrough;
break;
default:
if (qcadev->susclk)
clk_disable_unprepare(qcadev->susclk);
break;
}
hci_uart_unregister_device(&qcadev->serdev_hu);

View File

@ -633,7 +633,7 @@ static int vhci_open(struct inode *inode, struct file *file)
{
struct vhci_data *data;
data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;

View File

@ -10,7 +10,7 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
config CRYPTO_DEV_FSL_CAAM
tristate "Freescale CAAM-Multicore platform driver backend"
depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE
depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST
select SOC_BUS
select CRYPTO_DEV_FSL_CAAM_COMMON
imply FSL_MC_BUS

View File

@ -4990,11 +4990,23 @@ err_dma_map:
return err;
}
static void free_dpaa2_pcpu_netdev(struct dpaa2_caam_priv *priv, const cpumask_t *cpus)
{
struct dpaa2_caam_priv_per_cpu *ppriv;
int i;
for_each_cpu(i, cpus) {
ppriv = per_cpu_ptr(priv->ppriv, i);
free_netdev(ppriv->net_dev);
}
}
static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
{
struct device *dev = &ls_dev->dev;
struct dpaa2_caam_priv *priv;
struct dpaa2_caam_priv_per_cpu *ppriv;
cpumask_t clean_mask;
int err, cpu;
u8 i;
@ -5073,6 +5085,7 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
}
}
cpumask_clear(&clean_mask);
i = 0;
for_each_online_cpu(cpu) {
u8 j;
@ -5096,15 +5109,23 @@ static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
priv->rx_queue_attr[j].fqid,
priv->tx_queue_attr[j].fqid);
ppriv->net_dev.dev = *dev;
INIT_LIST_HEAD(&ppriv->net_dev.napi_list);
netif_napi_add_tx_weight(&ppriv->net_dev, &ppriv->napi,
ppriv->net_dev = alloc_netdev_dummy(0);
if (!ppriv->net_dev) {
err = -ENOMEM;
goto err_alloc_netdev;
}
cpumask_set_cpu(cpu, &clean_mask);
ppriv->net_dev->dev = *dev;
netif_napi_add_tx_weight(ppriv->net_dev, &ppriv->napi,
dpaa2_dpseci_poll,
DPAA2_CAAM_NAPI_WEIGHT);
}
return 0;
err_alloc_netdev:
free_dpaa2_pcpu_netdev(priv, &clean_mask);
err_get_rx_queue:
dpaa2_dpseci_congestion_free(priv);
err_get_vers:
@ -5153,6 +5174,7 @@ static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv)
ppriv = per_cpu_ptr(priv->ppriv, i);
napi_disable(&ppriv->napi);
netif_napi_del(&ppriv->napi);
free_netdev(ppriv->net_dev);
}
return 0;

View File

@ -81,7 +81,7 @@ struct dpaa2_caam_priv {
*/
struct dpaa2_caam_priv_per_cpu {
struct napi_struct napi;
struct net_device net_dev;
struct net_device *net_dev;
int req_fqid;
int rsp_fqid;
int prio;

View File

@ -80,6 +80,7 @@ static void build_deinstantiation_desc(u32 *desc, int handle)
append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
}
#ifdef CONFIG_OF
static const struct of_device_id imx8m_machine_match[] = {
{ .compatible = "fsl,imx8mm", },
{ .compatible = "fsl,imx8mn", },
@ -88,6 +89,7 @@ static const struct of_device_id imx8m_machine_match[] = {
{ .compatible = "fsl,imx8ulp", },
{ }
};
#endif
/*
* run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of

View File

@ -57,7 +57,7 @@ struct caam_napi {
*/
struct caam_qi_pcpu_priv {
struct caam_napi caam_napi;
struct net_device net_dev;
struct net_device *net_dev;
struct qman_fq *rsp_fq;
} ____cacheline_aligned;
@ -144,7 +144,7 @@ static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq,
{
const struct qm_fd *fd;
struct caam_drv_req *drv_req;
struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev->dev);
struct caam_drv_private *priv = dev_get_drvdata(qidev);
fd = &msg->ern.fd;
@ -530,6 +530,7 @@ static void caam_qi_shutdown(void *data)
if (kill_fq(qidev, per_cpu(pcpu_qipriv.rsp_fq, i)))
dev_err(qidev, "Rsp FQ kill failed, cpu: %d\n", i);
free_netdev(per_cpu(pcpu_qipriv.net_dev, i));
}
qman_delete_cgr_safe(&priv->cgr);
@ -573,7 +574,7 @@ static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
struct caam_napi *caam_napi = raw_cpu_ptr(&pcpu_qipriv.caam_napi);
struct caam_drv_req *drv_req;
const struct qm_fd *fd;
struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev->dev);
struct caam_drv_private *priv = dev_get_drvdata(qidev);
u32 status;
@ -718,12 +719,24 @@ static void free_rsp_fqs(void)
kfree(per_cpu(pcpu_qipriv.rsp_fq, i));
}
static void free_caam_qi_pcpu_netdev(const cpumask_t *cpus)
{
struct caam_qi_pcpu_priv *priv;
int i;
for_each_cpu(i, cpus) {
priv = per_cpu_ptr(&pcpu_qipriv, i);
free_netdev(priv->net_dev);
}
}
int caam_qi_init(struct platform_device *caam_pdev)
{
int err, i;
struct device *ctrldev = &caam_pdev->dev, *qidev;
struct caam_drv_private *ctrlpriv;
const cpumask_t *cpus = qman_affine_cpus();
cpumask_t clean_mask;
ctrlpriv = dev_get_drvdata(ctrldev);
qidev = ctrldev;
@ -743,6 +756,8 @@ int caam_qi_init(struct platform_device *caam_pdev)
return err;
}
cpumask_clear(&clean_mask);
/*
* Enable the NAPI contexts on each of the core which has an affine
* portal.
@ -751,10 +766,16 @@ int caam_qi_init(struct platform_device *caam_pdev)
struct caam_qi_pcpu_priv *priv = per_cpu_ptr(&pcpu_qipriv, i);
struct caam_napi *caam_napi = &priv->caam_napi;
struct napi_struct *irqtask = &caam_napi->irqtask;
struct net_device *net_dev = &priv->net_dev;
struct net_device *net_dev;
net_dev = alloc_netdev_dummy(0);
if (!net_dev) {
err = -ENOMEM;
goto fail;
}
cpumask_set_cpu(i, &clean_mask);
priv->net_dev = net_dev;
net_dev->dev = *qidev;
INIT_LIST_HEAD(&net_dev->napi_list);
netif_napi_add_tx_weight(net_dev, irqtask, caam_qi_poll,
CAAM_NAPI_WEIGHT);
@ -766,16 +787,22 @@ int caam_qi_init(struct platform_device *caam_pdev)
dma_get_cache_alignment(), 0, NULL);
if (!qi_cache) {
dev_err(qidev, "Can't allocate CAAM cache\n");
free_rsp_fqs();
return -ENOMEM;
err = -ENOMEM;
goto fail2;
}
caam_debugfs_qi_init(ctrlpriv);
err = devm_add_action_or_reset(qidev, caam_qi_shutdown, ctrlpriv);
if (err)
return err;
goto fail2;
dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n");
return 0;
fail2:
free_rsp_fqs();
fail:
free_caam_qi_pcpu_netdev(&clean_mask);
return err;
}

View File

@ -1528,6 +1528,9 @@ int k3_udma_glue_rx_get_irq(struct k3_udma_glue_rx_channel *rx_chn,
flow->virq = k3_ringacc_get_ring_irq_num(flow->ringrx);
}
if (!flow->virq)
return -ENXIO;
return flow->virq;
}
EXPORT_SYMBOL_GPL(k3_udma_glue_rx_get_irq);

Some files were not shown because too many files have changed in this diff Show More