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:
commit
51835949dd
9
Documentation/ABI/testing/sysfs-bus-auxiliary
Normal file
9
Documentation/ABI/testing/sysfs-bus-auxiliary
Normal 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.
|
@ -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
|
||||
========================
|
||||
|
||||
|
@ -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``.
|
||||
|
@ -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.
|
||||
|
143
Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml
Normal file
143
Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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";
|
||||
};
|
||||
};
|
@ -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";
|
||||
};
|
||||
};
|
||||
|
@ -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:
|
||||
- |
|
||||
|
@ -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>
|
||||
|
@ -146,6 +146,7 @@ patternProperties:
|
||||
|
||||
magic-packet:
|
||||
type: boolean
|
||||
deprecated: true
|
||||
description:
|
||||
Indicates that the hardware supports waking up via magic packet.
|
||||
|
||||
|
202
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml
Normal file
202
Documentation/devicetree/bindings/net/dsa/lantiq,gswip.yaml
Normal 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 = <ð0>;
|
||||
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
@ -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 = <ð0>;
|
||||
};
|
||||
};
|
||||
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
162
Documentation/devicetree/bindings/net/dsa/vitesse,vsc73xx.yaml
Normal file
162
Documentation/devicetree/bindings/net/dsa/vitesse,vsc73xx.yaml
Normal 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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -103,6 +103,7 @@ properties:
|
||||
- usxgmii
|
||||
- 10gbase-r
|
||||
- 25gbase-r
|
||||
- 10g-qxgmii
|
||||
|
||||
phy-mode:
|
||||
$ref: "#/properties/phy-connection-type"
|
||||
|
@ -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:
|
||||
|
38
Documentation/devicetree/bindings/net/fsl,enetc-ierb.yaml
Normal file
38
Documentation/devicetree/bindings/net/fsl,enetc-ierb.yaml
Normal 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>;
|
||||
};
|
57
Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml
Normal file
57
Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
66
Documentation/devicetree/bindings/net/fsl,enetc.yaml
Normal file
66
Documentation/devicetree/bindings/net/fsl,enetc.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
123
Documentation/devicetree/bindings/net/fsl,fman-mdio.yaml
Normal file
123
Documentation/devicetree/bindings/net/fsl,fman-mdio.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
|
40
Documentation/devicetree/bindings/net/fsl,fman-muram.yaml
Normal file
40
Documentation/devicetree/bindings/net/fsl,fman-muram.yaml
Normal 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>;
|
||||
};
|
75
Documentation/devicetree/bindings/net/fsl,fman-port.yaml
Normal file
75
Documentation/devicetree/bindings/net/fsl,fman-port.yaml
Normal 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>;
|
||||
};
|
||||
|
210
Documentation/devicetree/bindings/net/fsl,fman.yaml
Normal file
210
Documentation/devicetree/bindings/net/fsl,fman.yaml
Normal 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>;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
==================================
|
||||
|
||||
|
@ -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
|
||||
|
136
Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml
Normal file
136
Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml
Normal 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";
|
||||
};
|
||||
};
|
||||
...
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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>;
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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>;
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
144
Documentation/devicetree/bindings/ptp/fsl,ptp.yaml
Normal file
144
Documentation/devicetree/bindings/ptp/fsl,ptp.yaml
Normal 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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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-
|
||||
|
@ -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:
|
||||
|
169
Documentation/netlink/specs/tcp_metrics.yaml
Normal file
169
Documentation/netlink/specs/tcp_metrics.yaml
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
=============
|
||||
|
@ -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.
|
||||
|
@ -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``
|
||||
=================================== =====================================
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
=============
|
||||
|
||||
|
386
Documentation/networking/iso15765-2.rst
Normal file
386
Documentation/networking/iso15765-2.rst
Normal 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
|
@ -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"
|
||||
|
156
Documentation/networking/mptcp.rst
Normal file
156
Documentation/networking/mptcp.rst
Normal 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.
|
@ -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
|
||||
==============================================
|
||||
|
||||
|
@ -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
|
||||
===========================
|
||||
|
||||
|
25
Documentation/networking/sriov.rst
Normal file
25
Documentation/networking/sriov.rst
Normal 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``
|
@ -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::
|
||||
|
||||
|
47
MAINTAINERS
47
MAINTAINERS
@ -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>
|
||||
|
@ -896,7 +896,3 @@
|
||||
&wdt {
|
||||
compatible = "rockchip,rk3066-wdt", "snps,dw-wdt";
|
||||
};
|
||||
|
||||
&emac {
|
||||
compatible = "rockchip,rk3066-emac";
|
||||
};
|
||||
|
@ -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";
|
||||
};
|
||||
|
||||
|
@ -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";
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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/
|
||||
|
@ -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);
|
||||
|
113
drivers/base/auxiliary_sysfs.c
Normal file
113
drivers/base/auxiliary_sysfs.c
Normal 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);
|
@ -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).
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = ¶m;
|
||||
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 = ¶m;
|
||||
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 = ¶m;
|
||||
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 = ¶m;
|
||||
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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user