mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Networking changes for 6.7.
Core & protocols ---------------- - Support usec resolution of TCP timestamps, enabled selectively by a route attribute. - Defer regular TCP ACK while processing socket backlog, try to send a cumulative ACK at the end. Increase single TCP flow performance on a 200Gbit NIC by 20% (100Gbit -> 120Gbit). - The Fair Queuing (FQ) packet scheduler: - add built-in 3 band prio / WRR scheduling - support bypass if the qdisc is mostly idle (5% speed up for TCP RR) - improve inactive flow reporting - optimize the layout of structures for better cache locality - Support TCP Authentication Option (RFC 5925, TCP-AO), a more modern replacement for the old MD5 option. - Add more retransmission timeout (RTO) related statistics to TCP_INFO. - Support sending fragmented skbs over vsock sockets. - Make sure we send SIGPIPE for vsock sockets if socket was shutdown(). - Add sysctl for ignoring lower limit on lifetime in Router Advertisement PIO, based on an in-progress IETF draft. - Add sysctl to control activation of TCP ping-pong mode. - Add sysctl to make connection timeout in MPTCP configurable. - Support rcvlowat and notsent_lowat on MPTCP sockets, to help apps limit the number of wakeups. - Support netlink GET for MDB (multicast forwarding), allowing user space to request a single MDB entry instead of dumping the entire table. - Support selective FDB flushing in the VXLAN tunnel driver. - Allow limiting learned FDB entries in bridges, prevent OOM attacks. - Allow controlling via configfs netconsole targets which were created via the kernel cmdline at boot, rather than via configfs at runtime. - Support multiple PTP timestamp event queue readers with different filters. - MCTP over I3C. BPF --- - Add new veth-like netdevice where BPF program defines the logic of the xmit routine. It can operate in L3 and L2 mode. - Support exceptions - allow asserting conditions which should never be true but are hard for the verifier to infer. With some extra flexibility around handling of the exit / failure. https://lwn.net/Articles/938435/ - Add support for local per-cpu kptr, allow allocating and storing per-cpu objects in maps. Access to those objects operates on the value for the current CPU. This allows to deprecate local one-off implementations of per-CPU storage like BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE maps. - Extend cgroup BPF sockaddr hooks for UNIX sockets. The use case is for systemd to re-implement the LogNamespace feature which allows running multiple instances of systemd-journald to process the logs of different services. - Enable open-coded task_vma iteration, after maple tree conversion made it hard to directly walk VMAs in tracing programs. - Add open-coded task, css_task and css iterator support. One of the use cases is customizable OOM victim selection via BPF. - Allow source address selection with bpf_*_fib_lookup(). - Add ability to pin BPF timer to the current CPU. - Prevent creation of infinite loops by combining tail calls and fentry/fexit programs. - Add missed stats for kprobes to retrieve the number of missed kprobe executions and subsequent executions of BPF programs. - Inherit system settings for CPU security mitigations. - Add BPF v4 CPU instruction support for arm32 and s390x. Changes to common code ---------------------- - overflow: add DEFINE_FLEX() for on-stack definition of structs with flexible array members. - Process doc update with more guidance for reviewers. Driver API ---------- - Simplify locking in WiFi (cfg80211 and mac80211 layers), use wiphy mutex in most places and remove a lot of smaller locks. - Create a common DPLL configuration API. Allow configuring and querying state of PLL circuits used for clock syntonization, in network time distribution. - Unify fragmented and full page allocation APIs in page pool code. Let drivers be ignorant of PAGE_SIZE. - Rework PHY state machine to avoid races with calls to phy_stop(). - Notify DSA drivers of MAC address changes on user ports, improve correctness of offloads which depend on matching port MAC addresses. - Allow antenna control on injected WiFi frames. - Reduce the number of variants of napi_schedule(). - Simplify error handling when composing devlink health messages. Misc ---- - A lot of KCSAN data race "fixes", from Eric. - A lot of __counted_by() annotations, from Kees. - A lot of strncpy -> strscpy and printf format fixes. - Replace master/slave terminology with conduit/user in DSA drivers. - Handful of KUnit tests for netdev and WiFi core. Removed ------- - AppleTalk COPS. - AppleTalk ipddp. - TI AR7 CPMAC Ethernet driver. Drivers ------- - Ethernet high-speed NICs: - Intel (100G, ice, idpf): - add a driver for the Intel E2000 IPUs - make CRC/FCS stripping configurable - cross-timestamping for E823 devices - basic support for E830 devices - use aux-bus for managing client drivers - i40e: report firmware versions via devlink - nVidia/Mellanox: - support 4-port NICs - increase max number of channels to 256 - optimize / parallelize SF creation flow - Broadcom (bnxt): - enhance NIC temperature reporting - support PAM4 speeds and lane configuration - Marvell OcteonTX2: - PTP pulse-per-second output support - enable hardware timestamping for VFs - Solarflare/AMD: - conntrack NAT offload and offload for tunnels - Wangxun (ngbe/txgbe): - expose HW statistics - Pensando/AMD: - support PCI level reset - narrow down the condition under which skbs are linearized - Netronome/Corigine (nfp): - support CHACHA20-POLY1305 crypto in IPsec offload - Ethernet NICs embedded, slower, virtual: - Synopsys (stmmac): - add Loongson-1 SoC support - enable use of HW queues with no offload capabilities - enable PPS input support on all 5 channels - increase TX coalesce timer to 5ms - RealTek USB (r8152): improve efficiency of Rx by using GRO frags - xen: support SW packet timestamping - add drivers for implementations based on TI's PRUSS (AM64x EVM) - nVidia/Mellanox Ethernet datacenter switches: - avoid poor HW resource use on Spectrum-4 by better block selection for IPv6 multicast forwarding and ordering of blocks in ACL region - Ethernet embedded switches: - Microchip: - support configuring the drive strength for EMI compliance - ksz9477: partial ACL support - ksz9477: HSR offload - ksz9477: Wake on LAN - Realtek: - rtl8366rb: respect device tree config of the CPU port - Ethernet PHYs: - support Broadcom BCM5221 PHYs - TI dp83867: support hardware LED blinking - CAN: - add support for Linux-PHY based CAN transceivers - at91_can: clean up and use rx-offload helpers - WiFi: - MediaTek (mt76): - new sub-driver for mt7925 USB/PCIe devices - HW wireless <> Ethernet bridging in MT7988 chips - mt7603/mt7628 stability improvements - Qualcomm (ath12k): - WCN7850: - enable 320 MHz channels in 6 GHz band - hardware rfkill support - enable IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS to make scan faster - read board data variant name from SMBIOS - QCN9274: mesh support - RealTek (rtw89): - TDMA-based multi-channel concurrency (MCC) - Silicon Labs (wfx): - Remain-On-Channel (ROC) support - Bluetooth: - ISO: many improvements for broadcast support - mark BCM4378/BCM4387 as BROKEN_LE_CODED - add support for QCA2066 - btmtksdio: enable Bluetooth wakeup from suspend Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmU8XsYACgkQMUZtbf5S Irv19RAAnud/24OOF5XMEJkIcYlnfqximh4XO6PujRSYkSkOUJdZTF6iJPgf3pSP YpwoHYbYKHYfeOf8+3bTNESiQNSnoVmvmvwiS6/7lZ3behHUrGLQzW9Htc3EZyWH 2h6QkDZ5OOjfg0bwYSfp3vXkmMH2k8WE9Y0NvCkhcohqZi13Rmp14RnyPmNb2d1V yZRYDMSM133KqE6gnBr1Ct65IEvnKeGlCUN2mTGqOJgdn6DZMsyxvtt0y4rmN7Ab 41+CgPU5SfxfbYpW+Dl2HJpgfte3WrC57KC6AM0PAPJzPmQWgeB/m9mjz/apj6Bg bhsEIo7FdvbCnQm3yWPhK2OgCAcSwLr8jfGMU+Q+W4VnL5SRRR3Rm0zjsze+kHNP OfqJgxzl3DpvoJqVBy1h5FGcZt0XHwhksm4cTxWqIahsF+veY0ECBXbuBBQx9XTF Y7INfI8ulg7wISJs+CJfIClYkgOibTw2u8taBS5ikbtgxNqp5D4QqODn7UefQap1 PR/IDYODF+zRgmMJLeBqSa6fij6BkfOEDiOWak5kggBoZdtbtmeKI6tzze06CNdW lWv1WEhRufxnwK+IuWsEkjhiMbs2WGLvkJ5JbgQV9BfqHfIfiqBCrcWtT/WbQnGt lmU46CXh1t/FZEqbmK9h+8vsIIfrcDl6jb5npEiKPRG00vDKRTM= =46nS -----END PGP SIGNATURE----- Merge tag 'net-next-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core & protocols: - Support usec resolution of TCP timestamps, enabled selectively by a route attribute. - Defer regular TCP ACK while processing socket backlog, try to send a cumulative ACK at the end. Increase single TCP flow performance on a 200Gbit NIC by 20% (100Gbit -> 120Gbit). - The Fair Queuing (FQ) packet scheduler: - add built-in 3 band prio / WRR scheduling - support bypass if the qdisc is mostly idle (5% speed up for TCP RR) - improve inactive flow reporting - optimize the layout of structures for better cache locality - Support TCP Authentication Option (RFC 5925, TCP-AO), a more modern replacement for the old MD5 option. - Add more retransmission timeout (RTO) related statistics to TCP_INFO. - Support sending fragmented skbs over vsock sockets. - Make sure we send SIGPIPE for vsock sockets if socket was shutdown(). - Add sysctl for ignoring lower limit on lifetime in Router Advertisement PIO, based on an in-progress IETF draft. - Add sysctl to control activation of TCP ping-pong mode. - Add sysctl to make connection timeout in MPTCP configurable. - Support rcvlowat and notsent_lowat on MPTCP sockets, to help apps limit the number of wakeups. - Support netlink GET for MDB (multicast forwarding), allowing user space to request a single MDB entry instead of dumping the entire table. - Support selective FDB flushing in the VXLAN tunnel driver. - Allow limiting learned FDB entries in bridges, prevent OOM attacks. - Allow controlling via configfs netconsole targets which were created via the kernel cmdline at boot, rather than via configfs at runtime. - Support multiple PTP timestamp event queue readers with different filters. - MCTP over I3C. BPF: - Add new veth-like netdevice where BPF program defines the logic of the xmit routine. It can operate in L3 and L2 mode. - Support exceptions - allow asserting conditions which should never be true but are hard for the verifier to infer. With some extra flexibility around handling of the exit / failure: https://lwn.net/Articles/938435/ - Add support for local per-cpu kptr, allow allocating and storing per-cpu objects in maps. Access to those objects operates on the value for the current CPU. This allows to deprecate local one-off implementations of per-CPU storage like BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE maps. - Extend cgroup BPF sockaddr hooks for UNIX sockets. The use case is for systemd to re-implement the LogNamespace feature which allows running multiple instances of systemd-journald to process the logs of different services. - Enable open-coded task_vma iteration, after maple tree conversion made it hard to directly walk VMAs in tracing programs. - Add open-coded task, css_task and css iterator support. One of the use cases is customizable OOM victim selection via BPF. - Allow source address selection with bpf_*_fib_lookup(). - Add ability to pin BPF timer to the current CPU. - Prevent creation of infinite loops by combining tail calls and fentry/fexit programs. - Add missed stats for kprobes to retrieve the number of missed kprobe executions and subsequent executions of BPF programs. - Inherit system settings for CPU security mitigations. - Add BPF v4 CPU instruction support for arm32 and s390x. Changes to common code: - overflow: add DEFINE_FLEX() for on-stack definition of structs with flexible array members. - Process doc update with more guidance for reviewers. Driver API: - Simplify locking in WiFi (cfg80211 and mac80211 layers), use wiphy mutex in most places and remove a lot of smaller locks. - Create a common DPLL configuration API. Allow configuring and querying state of PLL circuits used for clock syntonization, in network time distribution. - Unify fragmented and full page allocation APIs in page pool code. Let drivers be ignorant of PAGE_SIZE. - Rework PHY state machine to avoid races with calls to phy_stop(). - Notify DSA drivers of MAC address changes on user ports, improve correctness of offloads which depend on matching port MAC addresses. - Allow antenna control on injected WiFi frames. - Reduce the number of variants of napi_schedule(). - Simplify error handling when composing devlink health messages. Misc: - A lot of KCSAN data race "fixes", from Eric. - A lot of __counted_by() annotations, from Kees. - A lot of strncpy -> strscpy and printf format fixes. - Replace master/slave terminology with conduit/user in DSA drivers. - Handful of KUnit tests for netdev and WiFi core. Removed: - AppleTalk COPS. - AppleTalk ipddp. - TI AR7 CPMAC Ethernet driver. Drivers: - Ethernet high-speed NICs: - Intel (100G, ice, idpf): - add a driver for the Intel E2000 IPUs - make CRC/FCS stripping configurable - cross-timestamping for E823 devices - basic support for E830 devices - use aux-bus for managing client drivers - i40e: report firmware versions via devlink - nVidia/Mellanox: - support 4-port NICs - increase max number of channels to 256 - optimize / parallelize SF creation flow - Broadcom (bnxt): - enhance NIC temperature reporting - support PAM4 speeds and lane configuration - Marvell OcteonTX2: - PTP pulse-per-second output support - enable hardware timestamping for VFs - Solarflare/AMD: - conntrack NAT offload and offload for tunnels - Wangxun (ngbe/txgbe): - expose HW statistics - Pensando/AMD: - support PCI level reset - narrow down the condition under which skbs are linearized - Netronome/Corigine (nfp): - support CHACHA20-POLY1305 crypto in IPsec offload - Ethernet NICs embedded, slower, virtual: - Synopsys (stmmac): - add Loongson-1 SoC support - enable use of HW queues with no offload capabilities - enable PPS input support on all 5 channels - increase TX coalesce timer to 5ms - RealTek USB (r8152): improve efficiency of Rx by using GRO frags - xen: support SW packet timestamping - add drivers for implementations based on TI's PRUSS (AM64x EVM) - nVidia/Mellanox Ethernet datacenter switches: - avoid poor HW resource use on Spectrum-4 by better block selection for IPv6 multicast forwarding and ordering of blocks in ACL region - Ethernet embedded switches: - Microchip: - support configuring the drive strength for EMI compliance - ksz9477: partial ACL support - ksz9477: HSR offload - ksz9477: Wake on LAN - Realtek: - rtl8366rb: respect device tree config of the CPU port - Ethernet PHYs: - support Broadcom BCM5221 PHYs - TI dp83867: support hardware LED blinking - CAN: - add support for Linux-PHY based CAN transceivers - at91_can: clean up and use rx-offload helpers - WiFi: - MediaTek (mt76): - new sub-driver for mt7925 USB/PCIe devices - HW wireless <> Ethernet bridging in MT7988 chips - mt7603/mt7628 stability improvements - Qualcomm (ath12k): - WCN7850: - enable 320 MHz channels in 6 GHz band - hardware rfkill support - enable IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS to make scan faster - read board data variant name from SMBIOS - QCN9274: mesh support - RealTek (rtw89): - TDMA-based multi-channel concurrency (MCC) - Silicon Labs (wfx): - Remain-On-Channel (ROC) support - Bluetooth: - ISO: many improvements for broadcast support - mark BCM4378/BCM4387 as BROKEN_LE_CODED - add support for QCA2066 - btmtksdio: enable Bluetooth wakeup from suspend" * tag 'net-next-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1816 commits) net: pcs: xpcs: Add 2500BASE-X case in get state for XPCS drivers net: bpf: Use sockopt_lock_sock() in ip_sock_set_tos() net: mana: Use xdp_set_features_flag instead of direct assignment vxlan: Cleanup IFLA_VXLAN_PORT_RANGE entry in vxlan_get_size() iavf: delete the iavf client interface iavf: add a common function for undoing the interrupt scheme iavf: use unregister_netdev iavf: rely on netdev's own registered state iavf: fix the waiting time for initial reset iavf: in iavf_down, don't queue watchdog_task if comms failed iavf: simplify mutex_trylock+sleep loops iavf: fix comments about old bit locks doc/netlink: Update schema to support cmd-cnt-name and cmd-max-name tools: ynl: introduce option to process unknown attributes or types ipvlan: properly track tx_errors netdevsim: Block until all devices are released nfp: using napi_build_skb() to replace build_skb() net: dsa: microchip: ksz9477: Fix spelling mistake "Enery" -> "Energy" net: dsa: microchip: Ensure Stable PME Pin State for Wake-on-LAN net: dsa: microchip: Refactor switch shutdown routine for WoL preparation ...
This commit is contained in:
commit
89ed67ef12
@ -71,6 +71,7 @@ two flavors of JITs, the newer eBPF JIT currently supported on:
|
||||
- s390x
|
||||
- riscv64
|
||||
- riscv32
|
||||
- loongarch64
|
||||
|
||||
And the older cBPF JIT supported on the following archs:
|
||||
|
||||
|
@ -56,6 +56,16 @@ described in more detail in the footnotes.
|
||||
| | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_CONNECT`` | ``cgroup/connect_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_SENDMSG`` | ``cgroup/sendmsg_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_RECVMSG`` | ``cgroup/recvmsg_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_GETPEERNAME`` | ``cgroup/getpeername_unix`` | |
|
||||
| +----------------------------------------+----------------------------------+-----------+
|
||||
| | ``BPF_CGROUP_UNIX_GETSOCKNAME`` | ``cgroup/getsockname_unix`` | |
|
||||
+-------------------------------------------+----------------------------------------+----------------------------------+-----------+
|
||||
| ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | |
|
||||
+ +----------------------------------------+----------------------------------+-----------+
|
||||
|
@ -113,7 +113,7 @@ Flags
|
||||
used by ``eth_get_headlen`` to estimate length of all headers for GRO.
|
||||
* ``BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL`` - tells BPF flow dissector to
|
||||
stop parsing as soon as it reaches IPv6 flow label; used by
|
||||
``___skb_get_hash`` and ``__skb_get_hash_symmetric`` to get flow hash.
|
||||
``___skb_get_hash`` to get flow hash.
|
||||
* ``BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP`` - tells BPF flow dissector to stop
|
||||
parsing as soon as it reaches encapsulated headers; used by routing
|
||||
infrastructure.
|
||||
|
@ -283,6 +283,14 @@ For signed operations (``BPF_SDIV`` and ``BPF_SMOD``), for ``BPF_ALU``,
|
||||
is first :term:`sign extended<Sign Extend>` from 32 to 64 bits, and then
|
||||
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
|
||||
(where -13 % 3 == -1) as implemented in C, Go, etc.:
|
||||
|
||||
a % n = a - n * trunc(a / n)
|
||||
|
||||
The ``BPF_MOVSX`` instruction does a move operation with sign extension.
|
||||
``BPF_ALU | BPF_MOVSX`` :term:`sign extends<Sign Extend>` 8-bit and 16-bit operands into 32
|
||||
bit operands, and zeroes the remaining upper 32 bits.
|
||||
|
@ -22,6 +22,7 @@ properties:
|
||||
- mediatek,mt7622-wed
|
||||
- mediatek,mt7981-wed
|
||||
- mediatek,mt7986-wed
|
||||
- mediatek,mt7988-wed
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
|
@ -55,6 +55,12 @@ properties:
|
||||
|
||||
May not be supported by all controllers.
|
||||
|
||||
mctp-controller:
|
||||
type: boolean
|
||||
description: |
|
||||
Indicates that the system is accessible via this bus as an endpoint for
|
||||
MCTP over I3C transport.
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
@ -49,6 +49,8 @@ properties:
|
||||
- hisilicon,peri-subctrl
|
||||
- hpe,gxp-sysreg
|
||||
- intel,lgm-syscon
|
||||
- loongson,ls1b-syscon
|
||||
- loongson,ls1c-syscon
|
||||
- marvell,armada-3700-usb2-host-misc
|
||||
- mediatek,mt8135-pctl-a-syscfg
|
||||
- mediatek,mt8135-pctl-b-syscfg
|
||||
|
@ -158,6 +158,8 @@ allOf:
|
||||
patternProperties:
|
||||
"^ethernet-phy@[0-9a-f]$":
|
||||
type: object
|
||||
$ref: ethernet-phy.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Integrated PHY node
|
||||
|
||||
|
@ -53,7 +53,7 @@ properties:
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^port@[0-9]+$":
|
||||
"^port@[0-9a-f]+$":
|
||||
type: object
|
||||
|
||||
$ref: ethernet-controller.yaml#
|
||||
|
@ -78,6 +78,7 @@ properties:
|
||||
|
||||
ports:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
patternProperties:
|
||||
'^port@[0-9a-f]$':
|
||||
|
@ -40,17 +40,8 @@ $defs:
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#address-cells':
|
||||
const: 1
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-9a-f]+$":
|
||||
description: Ethernet switch ports
|
||||
$ref: dsa-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
@ -60,7 +60,7 @@ description: |
|
||||
|
||||
Check out example 6.
|
||||
|
||||
- Port 5 can be wired to an external phy. Port 5 becomes a DSA slave.
|
||||
- Port 5 can be wired to an external phy. Port 5 becomes a DSA user port.
|
||||
|
||||
For the multi-chip module MT7530, the external phy must be wired TX to TX
|
||||
to gmac1 of the SoC for this to work. Ubiquiti EdgeRouter X SFP is wired
|
||||
@ -154,10 +154,12 @@ properties:
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-6]$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
properties:
|
||||
reg:
|
||||
@ -184,7 +186,7 @@ $defs:
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-6]$":
|
||||
if:
|
||||
required: [ ethernet ]
|
||||
then:
|
||||
@ -210,7 +212,7 @@ $defs:
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-6]$":
|
||||
if:
|
||||
required: [ ethernet ]
|
||||
then:
|
||||
|
@ -38,6 +38,8 @@ properties:
|
||||
Should be a gpio specifier for a reset line.
|
||||
maxItems: 1
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
microchip,synclko-125:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
@ -49,6 +51,26 @@ properties:
|
||||
Set if the output SYNCLKO clock should be disabled. Do not mix with
|
||||
microchip,synclko-125.
|
||||
|
||||
microchip,io-drive-strength-microamp:
|
||||
description:
|
||||
IO Pad Drive Strength
|
||||
enum: [8000, 16000]
|
||||
default: 16000
|
||||
|
||||
microchip,hi-drive-strength-microamp:
|
||||
description:
|
||||
High Speed Drive Strength. Controls drive strength of GMII / RGMII /
|
||||
MII / RMII (except TX_CLK/REFCLKI, COL and CRS) and CLKO_25_125 lines.
|
||||
enum: [2000, 4000, 8000, 12000, 16000, 20000, 24000, 28000]
|
||||
default: 24000
|
||||
|
||||
microchip,lo-drive-strength-microamp:
|
||||
description:
|
||||
Low Speed Drive Strength. Controls drive strength of TX_CLK / REFCLKI,
|
||||
COL, CRS, LEDs, PME_N, NTRP_N, SDO and SDI/SDA/MDIO lines.
|
||||
enum: [2000, 4000, 8000, 12000, 16000, 20000, 24000, 28000]
|
||||
default: 8000
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -37,8 +37,9 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
additionalProperties: true
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-7]$":
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
|
@ -43,6 +43,7 @@ properties:
|
||||
# PHY 1.
|
||||
mdios:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#address-cells':
|
||||
@ -74,8 +75,9 @@ properties:
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
additionalProperties: true
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-9]$":
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
|
@ -73,6 +73,7 @@ $ref: dsa.yaml#
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-6]$":
|
||||
type: object
|
||||
|
@ -68,6 +68,8 @@ properties:
|
||||
|
||||
interrupt-controller:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
description: |
|
||||
This defines an interrupt controller with an IRQ line (typically
|
||||
a GPIO) that will demultiplex and handle the interrupt from the single
|
||||
|
@ -61,17 +61,11 @@ properties:
|
||||
|
||||
ethernet-ports:
|
||||
type: object
|
||||
properties:
|
||||
'#address-cells':
|
||||
const: 1
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
additionalProperties: true
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-4]$":
|
||||
type: object
|
||||
description: Ethernet switch ports
|
||||
|
||||
additionalProperties: true
|
||||
properties:
|
||||
pcs-handle:
|
||||
maxItems: 1
|
||||
|
@ -63,6 +63,7 @@ properties:
|
||||
mdio:
|
||||
type: object
|
||||
$ref: mdio.yaml#
|
||||
unevaluatedProperties: false
|
||||
description: optional node for embedded MDIO controller
|
||||
|
||||
required:
|
||||
|
@ -36,7 +36,7 @@ patternProperties:
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
"^(ethernet-)?port@[0-9a-f]+$":
|
||||
type: object
|
||||
description: Ethernet switch ports
|
||||
|
||||
@ -53,14 +53,16 @@ oneOf:
|
||||
additionalProperties: true
|
||||
|
||||
$defs:
|
||||
base:
|
||||
ethernet-ports:
|
||||
description: An ethernet switch without any extra port properties
|
||||
$ref: '#'
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
description: Ethernet switch ports
|
||||
$ref: ethernet-switch-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
"^(ethernet-)?ports$":
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9a-f]+$":
|
||||
description: Ethernet switch ports
|
||||
$ref: ethernet-switch-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
...
|
||||
|
@ -59,6 +59,7 @@ properties:
|
||||
- const: fsl,imx6sx-fec
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8dxl-fec
|
||||
- fsl,imx8qxp-fec
|
||||
- const: fsl,imx8qm-fec
|
||||
- const: fsl,imx6sx-fec
|
||||
|
114
Documentation/devicetree/bindings/net/loongson,ls1b-gmac.yaml
Normal file
114
Documentation/devicetree/bindings/net/loongson,ls1b-gmac.yaml
Normal file
@ -0,0 +1,114 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/loongson,ls1b-gmac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Loongson-1B Gigabit Ethernet MAC Controller
|
||||
|
||||
maintainers:
|
||||
- Keguang Zhang <keguang.zhang@gmail.com>
|
||||
|
||||
description: |
|
||||
Loongson-1B Gigabit Ethernet MAC Controller is based on
|
||||
Synopsys DesignWare MAC (version 3.50a).
|
||||
|
||||
Main features
|
||||
- Dual 10/100/1000Mbps GMAC controllers
|
||||
- Full-duplex operation (IEEE 802.3x flow control automatic transmission)
|
||||
- Half-duplex operation (CSMA/CD Protocol and back-pressure support)
|
||||
- RX Checksum Offload
|
||||
- TX Checksum insertion
|
||||
- MII interface
|
||||
- RGMII interface
|
||||
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- loongson,ls1b-gmac
|
||||
required:
|
||||
- compatible
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- loongson,ls1b-gmac
|
||||
- const: snps,dwmac-3.50a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: stmmaceth
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: macirq
|
||||
|
||||
loongson,ls1-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon containing some extra configurations
|
||||
including PHY interface mode.
|
||||
|
||||
phy-mode:
|
||||
enum:
|
||||
- mii
|
||||
- rgmii-id
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- loongson,ls1-syscon
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwmac.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/loongson,ls1x-clk.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
gmac0: ethernet@1fe10000 {
|
||||
compatible = "loongson,ls1b-gmac", "snps,dwmac-3.50a";
|
||||
reg = <0x1fe10000 0x10000>;
|
||||
|
||||
clocks = <&clkc LS1X_CLKID_AHB>;
|
||||
clock-names = "stmmaceth";
|
||||
|
||||
interrupt-parent = <&intc1>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq";
|
||||
|
||||
loongson,ls1-syscon = <&syscon>;
|
||||
|
||||
phy-handle = <&phy0>;
|
||||
phy-mode = "mii";
|
||||
snps,pbl = <1>;
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "snps,dwmac-mdio";
|
||||
|
||||
phy0: ethernet-phy@0 {
|
||||
reg = <0x0>;
|
||||
};
|
||||
};
|
||||
};
|
113
Documentation/devicetree/bindings/net/loongson,ls1c-emac.yaml
Normal file
113
Documentation/devicetree/bindings/net/loongson,ls1c-emac.yaml
Normal file
@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/loongson,ls1c-emac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Loongson-1C Ethernet MAC Controller
|
||||
|
||||
maintainers:
|
||||
- Keguang Zhang <keguang.zhang@gmail.com>
|
||||
|
||||
description: |
|
||||
Loongson-1C Ethernet MAC Controller is based on
|
||||
Synopsys DesignWare MAC (version 3.50a).
|
||||
|
||||
Main features
|
||||
- 10/100Mbps
|
||||
- Full-duplex operation (IEEE 802.3x flow control automatic transmission)
|
||||
- Half-duplex operation (CSMA/CD Protocol and back-pressure support)
|
||||
- IEEE 802.1Q VLAN tag detection for reception frames
|
||||
- MII interface
|
||||
- RMII interface
|
||||
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- loongson,ls1c-emac
|
||||
required:
|
||||
- compatible
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- loongson,ls1c-emac
|
||||
- const: snps,dwmac-3.50a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: stmmaceth
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: macirq
|
||||
|
||||
loongson,ls1-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon containing some extra configurations
|
||||
including PHY interface mode.
|
||||
|
||||
phy-mode:
|
||||
enum:
|
||||
- mii
|
||||
- rmii
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- loongson,ls1-syscon
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwmac.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/loongson,ls1x-clk.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
emac: ethernet@1fe10000 {
|
||||
compatible = "loongson,ls1c-emac", "snps,dwmac-3.50a";
|
||||
reg = <0x1fe10000 0x10000>;
|
||||
|
||||
clocks = <&clkc LS1X_CLKID_AHB>;
|
||||
clock-names = "stmmaceth";
|
||||
|
||||
interrupt-parent = <&intc1>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq";
|
||||
|
||||
loongson,ls1-syscon = <&syscon>;
|
||||
|
||||
phy-handle = <&phy0>;
|
||||
phy-mode = "mii";
|
||||
snps,pbl = <1>;
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "snps,dwmac-mdio";
|
||||
|
||||
phy0: ethernet-phy@13 {
|
||||
reg = <0x13>;
|
||||
};
|
||||
};
|
||||
};
|
@ -24,7 +24,7 @@ allOf:
|
||||
compatible:
|
||||
const: mscc,vsc7514-switch
|
||||
then:
|
||||
$ref: ethernet-switch.yaml#
|
||||
$ref: ethernet-switch.yaml#/$defs/ethernet-ports
|
||||
required:
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
@ -33,28 +33,18 @@ allOf:
|
||||
minItems: 21
|
||||
reg-names:
|
||||
minItems: 21
|
||||
ethernet-ports:
|
||||
patternProperties:
|
||||
"^port@[0-9a-f]+$":
|
||||
$ref: ethernet-switch-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
const: mscc,vsc7512-switch
|
||||
then:
|
||||
$ref: /schemas/net/dsa/dsa.yaml#
|
||||
$ref: /schemas/net/dsa/dsa.yaml#/$defs/ethernet-ports
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 20
|
||||
reg-names:
|
||||
maxItems: 20
|
||||
ethernet-ports:
|
||||
patternProperties:
|
||||
"^port@[0-9a-f]+$":
|
||||
$ref: /schemas/net/dsa/dsa-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -185,7 +175,7 @@ examples:
|
||||
};
|
||||
# VSC7512 (DSA)
|
||||
- |
|
||||
ethernet-switch@1{
|
||||
ethernet-switch@1 {
|
||||
compatible = "mscc,vsc7512-switch";
|
||||
reg = <0x71010000 0x10000>,
|
||||
<0x71030000 0x10000>,
|
||||
@ -212,22 +202,22 @@ examples:
|
||||
"port7", "port8", "port9", "port10", "qsys",
|
||||
"ana", "s0", "s1", "s2";
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ethernet = <&mac_sw>;
|
||||
phy-handle = <&phy0>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
phy-handle = <&phy1>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
ethernet = <&mac_sw>;
|
||||
phy-handle = <&phy0>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
phy-handle = <&phy1>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
@ -20,6 +20,7 @@ allOf:
|
||||
patternProperties:
|
||||
"^ethernet-phy@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
description: |
|
||||
Some packages have multiple PHYs. Secondary PHY should be defines as
|
||||
subnode of the first (parent) PHY.
|
||||
|
@ -81,9 +81,8 @@ properties:
|
||||
active-high
|
||||
|
||||
patternProperties:
|
||||
"^ethernet-phy@[0-9a-f]$":
|
||||
"@[0-9a-f]$":
|
||||
type: object
|
||||
$ref: ethernet-phy.yaml#
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -109,9 +109,8 @@ properties:
|
||||
enum: [0, 2000]
|
||||
|
||||
patternProperties:
|
||||
"^ethernet-phy@[0-9a-f]$":
|
||||
"@[0-9a-f]$":
|
||||
type: object
|
||||
$ref: ethernet-phy.yaml#
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -394,6 +394,11 @@ properties:
|
||||
When a PFC frame is received with priorities matching the bitmask,
|
||||
the queue is blocked from transmitting for the pause time specified
|
||||
in the PFC frame.
|
||||
|
||||
snps,coe-unsupported:
|
||||
type: boolean
|
||||
description: TX checksum offload is unsupported by the TX queue.
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
required:
|
||||
|
@ -86,7 +86,7 @@ properties:
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^port@[0-9]+$":
|
||||
"^port@[12]$":
|
||||
type: object
|
||||
description: CPSW external ports
|
||||
|
||||
|
@ -19,6 +19,7 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,am642-icssg-prueth # for AM64x SoC family
|
||||
- ti,am654-icssg-prueth # for AM65x SoC family
|
||||
|
||||
sram:
|
||||
@ -106,6 +107,13 @@ properties:
|
||||
phandle to system controller node and register offset
|
||||
to ICSSG control register for RGMII transmit delay
|
||||
|
||||
ti,half-duplex-capable:
|
||||
type: boolean
|
||||
description:
|
||||
Indicates that the PHY output pin COL is routed to ICSSG GPIO pin
|
||||
(PRGx_PRU0/1_GPIO10) as input so that the ICSSG MII port is
|
||||
capable of half duplex operations.
|
||||
|
||||
required:
|
||||
- reg
|
||||
anyOf:
|
||||
|
@ -20,6 +20,7 @@ properties:
|
||||
items:
|
||||
- enum:
|
||||
- mediatek,mt7986-wo-ccif
|
||||
- mediatek,mt7988-wo-ccif
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
|
@ -120,7 +120,7 @@ functions/definitions
|
||||
ieee80211_rx
|
||||
ieee80211_rx_ni
|
||||
ieee80211_rx_irqsafe
|
||||
ieee80211_tx_status
|
||||
ieee80211_tx_status_skb
|
||||
ieee80211_tx_status_ni
|
||||
ieee80211_tx_status_irqsafe
|
||||
ieee80211_rts_get
|
||||
|
551
Documentation/driver-api/dpll.rst
Normal file
551
Documentation/driver-api/dpll.rst
Normal file
@ -0,0 +1,551 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============================
|
||||
The Linux kernel dpll subsystem
|
||||
===============================
|
||||
|
||||
DPLL
|
||||
====
|
||||
|
||||
PLL - Phase Locked Loop is an electronic circuit which syntonizes clock
|
||||
signal of a device with an external clock signal. Effectively enabling
|
||||
device to run on the same clock signal beat as provided on a PLL input.
|
||||
|
||||
DPLL - Digital Phase Locked Loop is an integrated circuit which in
|
||||
addition to plain PLL behavior incorporates a digital phase detector
|
||||
and may have digital divider in the loop. As a result, the frequency on
|
||||
DPLL's input and output may be configurable.
|
||||
|
||||
Subsystem
|
||||
=========
|
||||
|
||||
The main purpose of dpll subsystem is to provide general interface
|
||||
to configure devices that use any kind of Digital PLL and could use
|
||||
different sources of input signal to synchronize to, as well as
|
||||
different types of outputs.
|
||||
The main interface is NETLINK_GENERIC based protocol with an event
|
||||
monitoring multicast group defined.
|
||||
|
||||
Device object
|
||||
=============
|
||||
|
||||
Single dpll device object means single Digital PLL circuit and bunch of
|
||||
connected pins.
|
||||
It reports the supported modes of operation and current status to the
|
||||
user in response to the `do` request of netlink command
|
||||
``DPLL_CMD_DEVICE_GET`` and list of dplls registered in the subsystem
|
||||
with `dump` netlink request of the same command.
|
||||
Changing the configuration of dpll device is done with `do` request of
|
||||
netlink ``DPLL_CMD_DEVICE_SET`` command.
|
||||
A device handle is ``DPLL_A_ID``, it shall be provided to get or set
|
||||
configuration of particular device in the system. It can be obtained
|
||||
with a ``DPLL_CMD_DEVICE_GET`` `dump` request or
|
||||
a ``DPLL_CMD_DEVICE_ID_GET`` `do` request, where the one must provide
|
||||
attributes that result in single device match.
|
||||
|
||||
Pin object
|
||||
==========
|
||||
|
||||
A pin is amorphic object which represents either input or output, it
|
||||
could be internal component of the device, as well as externally
|
||||
connected.
|
||||
The number of pins per dpll vary, but usually multiple pins shall be
|
||||
provided for a single dpll device.
|
||||
Pin's properties, capabilities and status is provided to the user in
|
||||
response to `do` request of netlink ``DPLL_CMD_PIN_GET`` command.
|
||||
It is also possible to list all the pins that were registered in the
|
||||
system with `dump` request of ``DPLL_CMD_PIN_GET`` command.
|
||||
Configuration of a pin can be changed by `do` request of netlink
|
||||
``DPLL_CMD_PIN_SET`` command.
|
||||
Pin handle is a ``DPLL_A_PIN_ID``, it shall be provided to get or set
|
||||
configuration of particular pin in the system. It can be obtained with
|
||||
``DPLL_CMD_PIN_GET`` `dump` request or ``DPLL_CMD_PIN_ID_GET`` `do`
|
||||
request, where user provides attributes that result in single pin match.
|
||||
|
||||
Pin selection
|
||||
=============
|
||||
|
||||
In general, selected pin (the one which signal is driving the dpll
|
||||
device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only
|
||||
one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll
|
||||
device.
|
||||
|
||||
Pin selection can be done either manually or automatically, depending
|
||||
on hardware capabilities and active dpll device work mode
|
||||
(``DPLL_A_MODE`` attribute). The consequence is that there are
|
||||
differences for each mode in terms of available pin states, as well as
|
||||
for the states the user can request for a dpll device.
|
||||
|
||||
In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive
|
||||
one of following pin states:
|
||||
|
||||
- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device
|
||||
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll
|
||||
device
|
||||
|
||||
In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or
|
||||
receive one of following pin states:
|
||||
|
||||
- ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid
|
||||
input for automatic selection algorithm
|
||||
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as
|
||||
a valid input for automatic selection algorithm
|
||||
|
||||
In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive
|
||||
pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection
|
||||
algorithm locks a dpll device with one of the inputs.
|
||||
|
||||
Shared pins
|
||||
===========
|
||||
|
||||
A single pin object can be attached to multiple dpll devices.
|
||||
Then there are two groups of configuration knobs:
|
||||
|
||||
1) Set on a pin - the configuration affects all dpll devices pin is
|
||||
registered to (i.e., ``DPLL_A_PIN_FREQUENCY``),
|
||||
2) Set on a pin-dpll tuple - the configuration affects only selected
|
||||
dpll device (i.e., ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE``,
|
||||
``DPLL_A_PIN_DIRECTION``).
|
||||
|
||||
MUX-type pins
|
||||
=============
|
||||
|
||||
A pin can be MUX-type, it aggregates child pins and serves as a pin
|
||||
multiplexer. One or more pins are registered with MUX-type instead of
|
||||
being directly registered to a dpll device.
|
||||
Pins registered with a MUX-type pin provide user with additional nested
|
||||
attribute ``DPLL_A_PIN_PARENT_PIN`` for each parent they were registered
|
||||
with.
|
||||
If a pin was registered with multiple parent pins, they behave like a
|
||||
multiple output multiplexer. In this case output of a
|
||||
``DPLL_CMD_PIN_GET`` would contain multiple pin-parent nested
|
||||
attributes with current state related to each parent, like::
|
||||
|
||||
'pin': [{{
|
||||
'clock-id': 282574471561216,
|
||||
'module-name': 'ice',
|
||||
'capabilities': 4,
|
||||
'id': 13,
|
||||
'parent-pin': [
|
||||
{'parent-id': 2, 'state': 'connected'},
|
||||
{'parent-id': 3, 'state': 'disconnected'}
|
||||
],
|
||||
'type': 'synce-eth-port'
|
||||
}}]
|
||||
|
||||
Only one child pin can provide its signal to the parent MUX-type pin at
|
||||
a time, the selection is done by requesting change of a child pin state
|
||||
on desired parent, with the use of ``DPLL_A_PIN_PARENT`` nested
|
||||
attribute. Example of netlink `set state on parent pin` message format:
|
||||
|
||||
========================== =============================================
|
||||
``DPLL_A_PIN_ID`` child pin id
|
||||
``DPLL_A_PIN_PARENT_PIN`` nested attribute for requesting configuration
|
||||
related to parent pin
|
||||
``DPLL_A_PIN_PARENT_ID`` parent pin id
|
||||
``DPLL_A_PIN_STATE`` requested pin state on parent
|
||||
========================== =============================================
|
||||
|
||||
Pin priority
|
||||
============
|
||||
|
||||
Some devices might offer a capability of automatic pin selection mode
|
||||
(enum value ``DPLL_MODE_AUTOMATIC`` of ``DPLL_A_MODE`` attribute).
|
||||
Usually, automatic selection is performed on the hardware level, which
|
||||
means only pins directly connected to the dpll can be used for automatic
|
||||
input pin selection.
|
||||
In automatic selection mode, the user cannot manually select a input
|
||||
pin for the device, instead the user shall provide all directly
|
||||
connected pins with a priority ``DPLL_A_PIN_PRIO``, the device would
|
||||
pick a highest priority valid signal and use it to control the DPLL
|
||||
device. Example of netlink `set priority on parent pin` message format:
|
||||
|
||||
============================ =============================================
|
||||
``DPLL_A_PIN_ID`` configured pin id
|
||||
``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting configuration
|
||||
related to parent dpll device
|
||||
``DPLL_A_PIN_PARENT_ID`` parent dpll device id
|
||||
``DPLL_A_PIN_PRIO`` requested pin prio on parent dpll
|
||||
============================ =============================================
|
||||
|
||||
Child pin of MUX-type pin is not capable of automatic input pin selection,
|
||||
in order to configure active input of a MUX-type pin, the user needs to
|
||||
request desired pin state of the child pin on the parent pin,
|
||||
as described in the ``MUX-type pins`` chapter.
|
||||
|
||||
Phase offset measurement and adjustment
|
||||
========================================
|
||||
|
||||
Device may provide ability to measure a phase difference between signals
|
||||
on a pin and its parent dpll device. If pin-dpll phase offset measurement
|
||||
is supported, it shall be provided with ``DPLL_A_PIN_PHASE_OFFSET``
|
||||
attribute for each parent dpll device.
|
||||
|
||||
Device may also provide ability to adjust a signal phase on a pin.
|
||||
If pin phase adjustment is supported, minimal and maximal values that pin
|
||||
handle shall be provide to the user on ``DPLL_CMD_PIN_GET`` respond
|
||||
with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and ``DPLL_A_PIN_PHASE_ADJUST_MAX``
|
||||
attributes. Configured phase adjust value is provided with
|
||||
``DPLL_A_PIN_PHASE_ADJUST`` attribute of a pin, and value change can be
|
||||
requested with the same attribute with ``DPLL_CMD_PIN_SET`` command.
|
||||
|
||||
=============================== ======================================
|
||||
``DPLL_A_PIN_ID`` configured pin id
|
||||
``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment
|
||||
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment
|
||||
``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
|
||||
adjustment on parent dpll device
|
||||
``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting
|
||||
configuration on given parent dpll
|
||||
device
|
||||
``DPLL_A_PIN_PARENT_ID`` parent dpll device id
|
||||
``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
|
||||
between a pin and parent dpll device
|
||||
=============================== ======================================
|
||||
|
||||
All phase related values are provided in pico seconds, which represents
|
||||
time difference between signals phase. The negative value means that
|
||||
phase of signal on pin is earlier in time than dpll's signal. Positive
|
||||
value means that phase of signal on pin is later in time than signal of
|
||||
a dpll.
|
||||
|
||||
Phase adjust (also min and max) values are integers, but measured phase
|
||||
offset values are fractional with 3-digit decimal places and shell be
|
||||
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
|
||||
modulo divided to get fractional part.
|
||||
|
||||
Configuration commands group
|
||||
============================
|
||||
|
||||
Configuration commands are used to get information about registered
|
||||
dpll devices (and pins), as well as set configuration of device or pins.
|
||||
As dpll devices must be abstracted and reflect real hardware,
|
||||
there is no way to add new dpll device via netlink from user space and
|
||||
each device should be registered by its driver.
|
||||
|
||||
All netlink commands require ``GENL_ADMIN_PERM``. This is to prevent
|
||||
any spamming/DoS from unauthorized userspace applications.
|
||||
|
||||
List of netlink commands with possible attributes
|
||||
=================================================
|
||||
|
||||
Constants identifying command types for dpll device uses a
|
||||
``DPLL_CMD_`` prefix and suffix according to command purpose.
|
||||
The dpll device related attributes use a ``DPLL_A_`` prefix and
|
||||
suffix according to attribute purpose.
|
||||
|
||||
==================================== =================================
|
||||
``DPLL_CMD_DEVICE_ID_GET`` command to get device ID
|
||||
``DPLL_A_MODULE_NAME`` attr module name of registerer
|
||||
``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier
|
||||
(EUI-64), as defined by the
|
||||
IEEE 1588 standard
|
||||
``DPLL_A_TYPE`` attr type of dpll device
|
||||
==================================== =================================
|
||||
|
||||
==================================== =================================
|
||||
``DPLL_CMD_DEVICE_GET`` command to get device info or
|
||||
dump list of available devices
|
||||
``DPLL_A_ID`` attr unique dpll device ID
|
||||
``DPLL_A_MODULE_NAME`` attr module name of registerer
|
||||
``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier
|
||||
(EUI-64), as defined by the
|
||||
IEEE 1588 standard
|
||||
``DPLL_A_MODE`` attr selection mode
|
||||
``DPLL_A_MODE_SUPPORTED`` attr available selection modes
|
||||
``DPLL_A_LOCK_STATUS`` attr dpll device lock status
|
||||
``DPLL_A_TEMP`` attr device temperature info
|
||||
``DPLL_A_TYPE`` attr type of dpll device
|
||||
==================================== =================================
|
||||
|
||||
==================================== =================================
|
||||
``DPLL_CMD_DEVICE_SET`` command to set dpll device config
|
||||
``DPLL_A_ID`` attr internal dpll device index
|
||||
``DPLL_A_MODE`` attr selection mode to configure
|
||||
==================================== =================================
|
||||
|
||||
Constants identifying command types for pins uses a
|
||||
``DPLL_CMD_PIN_`` prefix and suffix according to command purpose.
|
||||
The pin related attributes use a ``DPLL_A_PIN_`` prefix and suffix
|
||||
according to attribute purpose.
|
||||
|
||||
==================================== =================================
|
||||
``DPLL_CMD_PIN_ID_GET`` command to get pin ID
|
||||
``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer
|
||||
``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier
|
||||
(EUI-64), as defined by the
|
||||
IEEE 1588 standard
|
||||
``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided
|
||||
by registerer
|
||||
``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided
|
||||
by registerer
|
||||
``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided
|
||||
by registerer
|
||||
``DPLL_A_PIN_TYPE`` attr type of a pin
|
||||
==================================== =================================
|
||||
|
||||
==================================== ==================================
|
||||
``DPLL_CMD_PIN_GET`` command to get pin info or dump
|
||||
list of available pins
|
||||
``DPLL_A_PIN_ID`` attr unique a pin ID
|
||||
``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer
|
||||
``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier
|
||||
(EUI-64), as defined by the
|
||||
IEEE 1588 standard
|
||||
``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided
|
||||
by registerer
|
||||
``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided
|
||||
by registerer
|
||||
``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided
|
||||
by registerer
|
||||
``DPLL_A_PIN_TYPE`` attr type of a pin
|
||||
``DPLL_A_PIN_FREQUENCY`` attr current frequency of a pin
|
||||
``DPLL_A_PIN_FREQUENCY_SUPPORTED`` nested attr provides supported
|
||||
frequencies
|
||||
``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency
|
||||
``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency
|
||||
``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase
|
||||
adjustment
|
||||
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase
|
||||
adjustment
|
||||
``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
|
||||
adjustment on parent device
|
||||
``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device
|
||||
the pin is connected with
|
||||
``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id
|
||||
``DPLL_A_PIN_PRIO`` attr priority of pin on the
|
||||
dpll device
|
||||
``DPLL_A_PIN_STATE`` attr state of pin on the parent
|
||||
dpll device
|
||||
``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the
|
||||
parent dpll device
|
||||
``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
|
||||
between a pin and parent dpll
|
||||
``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
|
||||
the pin is connected with
|
||||
``DPLL_A_PIN_PARENT_ID`` attr parent pin id
|
||||
``DPLL_A_PIN_STATE`` attr state of pin on the parent
|
||||
pin
|
||||
``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities
|
||||
==================================== ==================================
|
||||
|
||||
==================================== =================================
|
||||
``DPLL_CMD_PIN_SET`` command to set pins configuration
|
||||
``DPLL_A_PIN_ID`` attr unique a pin ID
|
||||
``DPLL_A_PIN_FREQUENCY`` attr requested frequency of a pin
|
||||
``DPLL_A_PIN_PHASE_ADJUST`` attr requested value of phase
|
||||
adjustment on parent device
|
||||
``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent dpll
|
||||
device configuration request
|
||||
``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id
|
||||
``DPLL_A_PIN_DIRECTION`` attr requested direction of a pin
|
||||
``DPLL_A_PIN_PRIO`` attr requested priority of pin on
|
||||
the dpll device
|
||||
``DPLL_A_PIN_STATE`` attr requested state of pin on
|
||||
the dpll device
|
||||
``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
|
||||
configuration request
|
||||
``DPLL_A_PIN_PARENT_ID`` attr parent pin id
|
||||
``DPLL_A_PIN_STATE`` attr requested state of pin on
|
||||
parent pin
|
||||
==================================== =================================
|
||||
|
||||
Netlink dump requests
|
||||
=====================
|
||||
|
||||
The ``DPLL_CMD_DEVICE_GET`` and ``DPLL_CMD_PIN_GET`` commands are
|
||||
capable of dump type netlink requests, in which case the response is in
|
||||
the same format as for their ``do`` request, but every device or pin
|
||||
registered in the system is returned.
|
||||
|
||||
SET commands format
|
||||
===================
|
||||
|
||||
``DPLL_CMD_DEVICE_SET`` - to target a dpll device, the user provides
|
||||
``DPLL_A_ID``, which is unique identifier of dpll device in the system,
|
||||
as well as parameter being configured (``DPLL_A_MODE``).
|
||||
|
||||
``DPLL_CMD_PIN_SET`` - to target a pin user must provide a
|
||||
``DPLL_A_PIN_ID``, which is unique identifier of a pin in the system.
|
||||
Also configured pin parameters must be added.
|
||||
If ``DPLL_A_PIN_FREQUENCY`` is configured, this affects all the dpll
|
||||
devices that are connected with the pin, that is why frequency attribute
|
||||
shall not be enclosed in ``DPLL_A_PIN_PARENT_DEVICE``.
|
||||
Other attributes: ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE`` or
|
||||
``DPLL_A_PIN_DIRECTION`` must be enclosed in
|
||||
``DPLL_A_PIN_PARENT_DEVICE`` as their configuration relates to only one
|
||||
of parent dplls, targeted by ``DPLL_A_PIN_PARENT_ID`` attribute which is
|
||||
also required inside that nest.
|
||||
For MUX-type pins the ``DPLL_A_PIN_STATE`` attribute is configured in
|
||||
similar way, by enclosing required state in ``DPLL_A_PIN_PARENT_PIN``
|
||||
nested attribute and targeted parent pin id in ``DPLL_A_PIN_PARENT_ID``.
|
||||
|
||||
In general, it is possible to configure multiple parameters at once, but
|
||||
internally each parameter change will be invoked separately, where order
|
||||
of configuration is not guaranteed by any means.
|
||||
|
||||
Configuration pre-defined enums
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/dpll.h
|
||||
|
||||
Notifications
|
||||
=============
|
||||
|
||||
dpll device can provide notifications regarding status changes of the
|
||||
device, i.e. lock status changes, input/output changes or other alarms.
|
||||
There is one multicast group that is used to notify user-space apps via
|
||||
netlink socket: ``DPLL_MCGRP_MONITOR``
|
||||
|
||||
Notifications messages:
|
||||
|
||||
============================== =====================================
|
||||
``DPLL_CMD_DEVICE_CREATE_NTF`` dpll device was created
|
||||
``DPLL_CMD_DEVICE_DELETE_NTF`` dpll device was deleted
|
||||
``DPLL_CMD_DEVICE_CHANGE_NTF`` dpll device has changed
|
||||
``DPLL_CMD_PIN_CREATE_NTF`` dpll pin was created
|
||||
``DPLL_CMD_PIN_DELETE_NTF`` dpll pin was deleted
|
||||
``DPLL_CMD_PIN_CHANGE_NTF`` dpll pin has changed
|
||||
============================== =====================================
|
||||
|
||||
Events format is the same as for the corresponding get command.
|
||||
Format of ``DPLL_CMD_DEVICE_`` events is the same as response of
|
||||
``DPLL_CMD_DEVICE_GET``.
|
||||
Format of ``DPLL_CMD_PIN_`` events is same as response of
|
||||
``DPLL_CMD_PIN_GET``.
|
||||
|
||||
Device driver implementation
|
||||
============================
|
||||
|
||||
Device is allocated by dpll_device_get() call. Second call with the
|
||||
same arguments will not create new object but provides pointer to
|
||||
previously created device for given arguments, it also increases
|
||||
refcount of that object.
|
||||
Device is deallocated by dpll_device_put() call, which first
|
||||
decreases the refcount, once refcount is cleared the object is
|
||||
destroyed.
|
||||
|
||||
Device should implement set of operations and register device via
|
||||
dpll_device_register() at which point it becomes available to the
|
||||
users. Multiple driver instances can obtain reference to it with
|
||||
dpll_device_get(), as well as register dpll device with their own
|
||||
ops and priv.
|
||||
|
||||
The pins are allocated separately with dpll_pin_get(), it works
|
||||
similarly to dpll_device_get(). Function first creates object and then
|
||||
for each call with the same arguments only the object refcount
|
||||
increases. Also dpll_pin_put() works similarly to dpll_device_put().
|
||||
|
||||
A pin can be registered with parent dpll device or parent pin, depending
|
||||
on hardware needs. Each registration requires registerer to provide set
|
||||
of pin callbacks, and private data pointer for calling them:
|
||||
|
||||
- dpll_pin_register() - register pin with a dpll device,
|
||||
- dpll_pin_on_pin_register() - register pin with another MUX type pin.
|
||||
|
||||
Notifications of adding or removing dpll devices are created within
|
||||
subsystem itself.
|
||||
Notifications about registering/deregistering pins are also invoked by
|
||||
the subsystem.
|
||||
Notifications about status changes either of dpll device or a pin are
|
||||
invoked in two ways:
|
||||
|
||||
- after successful change was requested on dpll subsystem, the subsystem
|
||||
calls corresponding notification,
|
||||
- requested by device driver with dpll_device_change_ntf() or
|
||||
dpll_pin_change_ntf() when driver informs about the status change.
|
||||
|
||||
The device driver using dpll interface is not required to implement all
|
||||
the callback operation. Nevertheless, there are few required to be
|
||||
implemented.
|
||||
Required dpll device level callback operations:
|
||||
|
||||
- ``.mode_get``,
|
||||
- ``.lock_status_get``.
|
||||
|
||||
Required pin level callback operations:
|
||||
|
||||
- ``.state_on_dpll_get`` (pins registered with dpll device),
|
||||
- ``.state_on_pin_get`` (pins registered with parent pin),
|
||||
- ``.direction_get``.
|
||||
|
||||
Every other operation handler is checked for existence and
|
||||
``-EOPNOTSUPP`` is returned in case of absence of specific handler.
|
||||
|
||||
The simplest implementation is in the OCP TimeCard driver. The ops
|
||||
structures are defined like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const struct dpll_device_ops dpll_ops = {
|
||||
.lock_status_get = ptp_ocp_dpll_lock_status_get,
|
||||
.mode_get = ptp_ocp_dpll_mode_get,
|
||||
.mode_supported = ptp_ocp_dpll_mode_supported,
|
||||
};
|
||||
|
||||
static const struct dpll_pin_ops dpll_pins_ops = {
|
||||
.frequency_get = ptp_ocp_dpll_frequency_get,
|
||||
.frequency_set = ptp_ocp_dpll_frequency_set,
|
||||
.direction_get = ptp_ocp_dpll_direction_get,
|
||||
.direction_set = ptp_ocp_dpll_direction_set,
|
||||
.state_on_dpll_get = ptp_ocp_dpll_state_get,
|
||||
};
|
||||
|
||||
The registration part is then looks like this part:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
clkid = pci_get_dsn(pdev);
|
||||
bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE);
|
||||
if (IS_ERR(bp->dpll)) {
|
||||
err = PTR_ERR(bp->dpll);
|
||||
dev_err(&pdev->dev, "dpll_device_alloc failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < OCP_SMA_NUM; i++) {
|
||||
bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop);
|
||||
if (IS_ERR(bp->sma[i].dpll_pin)) {
|
||||
err = PTR_ERR(bp->dpll);
|
||||
goto out_dpll;
|
||||
}
|
||||
|
||||
err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops,
|
||||
&bp->sma[i]);
|
||||
if (err) {
|
||||
dpll_pin_put(bp->sma[i].dpll_pin);
|
||||
goto out_dpll;
|
||||
}
|
||||
}
|
||||
|
||||
In the error path we have to rewind every allocation in the reverse order:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
while (i) {
|
||||
--i;
|
||||
dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
|
||||
dpll_pin_put(bp->sma[i].dpll_pin);
|
||||
}
|
||||
dpll_device_put(bp->dpll);
|
||||
|
||||
More complex example can be found in Intel's ICE driver or nVidia's mlx5 driver.
|
||||
|
||||
SyncE enablement
|
||||
================
|
||||
For SyncE enablement it is required to allow control over dpll device
|
||||
for a software application which monitors and configures the inputs of
|
||||
dpll device in response to current state of a dpll device and its
|
||||
inputs.
|
||||
In such scenario, dpll device input signal shall be also configurable
|
||||
to drive dpll with signal recovered from the PHY netdevice.
|
||||
This is done by exposing a pin to the netdevice - attaching pin to the
|
||||
netdevice itself with
|
||||
``netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)``.
|
||||
Exposed pin id handle ``DPLL_A_PIN_ID`` is then identifiable by the user
|
||||
as it is attached to rtnetlink respond to get ``RTM_NEWLINK`` command in
|
||||
nested attribute ``IFLA_DPLL_PIN``.
|
@ -114,6 +114,7 @@ available subsections can be seen below.
|
||||
zorro
|
||||
hte/index
|
||||
wmi
|
||||
dpll
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
@ -13,6 +13,11 @@ $defs:
|
||||
type: [ string, integer ]
|
||||
pattern: ^[0-9A-Za-z_]+( - 1)?$
|
||||
minimum: 0
|
||||
len-or-limit:
|
||||
# literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc.
|
||||
type: [ string, integer ]
|
||||
pattern: ^[su](8|16|32|64)-(min|max)$
|
||||
minimum: 0
|
||||
|
||||
# Schema for specs
|
||||
title: Protocol
|
||||
@ -26,10 +31,6 @@ properties:
|
||||
type: string
|
||||
doc:
|
||||
type: string
|
||||
version:
|
||||
description: Generic Netlink family version. Default is 1.
|
||||
type: integer
|
||||
minimum: 1
|
||||
protocol:
|
||||
description: Schema compatibility level. Default is "genetlink".
|
||||
enum: [ genetlink, genetlink-c ]
|
||||
@ -46,6 +47,12 @@ properties:
|
||||
max-by-define:
|
||||
description: Makes the number of attributes and commands be specified by a define, not an enum value.
|
||||
type: boolean
|
||||
cmd-max-name:
|
||||
description: Name of the define for the last operation in the list.
|
||||
type: string
|
||||
cmd-cnt-name:
|
||||
description: The explicit name for constant holding the count of operations (last operation + 1).
|
||||
type: string
|
||||
# End genetlink-c
|
||||
|
||||
definitions:
|
||||
@ -142,13 +149,14 @@ properties:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name, type ]
|
||||
required: [ name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type: &attr-type
|
||||
enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
|
||||
enum: [ unused, pad, flag, binary,
|
||||
uint, sint, u8, u16, u32, u64, s32, s64,
|
||||
string, nest, array-nest, nest-type-value ]
|
||||
doc:
|
||||
description: Documentation of the attribute.
|
||||
@ -187,13 +195,19 @@ properties:
|
||||
type: string
|
||||
min:
|
||||
description: Min value for an integer attribute.
|
||||
type: integer
|
||||
$ref: '#/$defs/len-or-limit'
|
||||
max:
|
||||
description: Max value for an integer attribute.
|
||||
$ref: '#/$defs/len-or-limit'
|
||||
min-len:
|
||||
description: Min length for a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
max-len:
|
||||
description: Max length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
exact-len:
|
||||
description: Exact length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
sub-type: *attr-type
|
||||
display-hint: &display-hint
|
||||
description: |
|
||||
@ -215,6 +229,18 @@ properties:
|
||||
not:
|
||||
required: [ name-prefix ]
|
||||
|
||||
# type property is only required if not in subset definition
|
||||
if:
|
||||
properties:
|
||||
subset-of:
|
||||
not:
|
||||
type: string
|
||||
then:
|
||||
properties:
|
||||
attributes:
|
||||
items:
|
||||
required: [ type ]
|
||||
|
||||
operations:
|
||||
description: Operations supported by the protocol.
|
||||
type: object
|
||||
@ -275,6 +301,11 @@ properties:
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump, dump-strict ]
|
||||
config-cond:
|
||||
description: |
|
||||
Name of the kernel config option gating the presence of
|
||||
the operation, without the 'CONFIG_' prefix.
|
||||
type: string
|
||||
do: &subop-type
|
||||
description: Main command handler.
|
||||
type: object
|
||||
|
@ -13,6 +13,11 @@ $defs:
|
||||
type: [ string, integer ]
|
||||
pattern: ^[0-9A-Za-z_]+( - 1)?$
|
||||
minimum: 0
|
||||
len-or-limit:
|
||||
# literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc.
|
||||
type: [ string, integer ]
|
||||
pattern: ^[su](8|16|32|64)-(min|max)$
|
||||
minimum: 0
|
||||
|
||||
# Schema for specs
|
||||
title: Protocol
|
||||
@ -26,10 +31,6 @@ properties:
|
||||
type: string
|
||||
doc:
|
||||
type: string
|
||||
version:
|
||||
description: Generic Netlink family version. Default is 1.
|
||||
type: integer
|
||||
minimum: 1
|
||||
protocol:
|
||||
description: Schema compatibility level. Default is "genetlink".
|
||||
enum: [ genetlink, genetlink-c, genetlink-legacy ] # Trim
|
||||
@ -46,6 +47,12 @@ properties:
|
||||
max-by-define:
|
||||
description: Makes the number of attributes and commands be specified by a define, not an enum value.
|
||||
type: boolean
|
||||
cmd-max-name:
|
||||
description: Name of the define for the last operation in the list.
|
||||
type: string
|
||||
cmd-cnt-name:
|
||||
description: The explicit name for constant holding the count of operations (last operation + 1).
|
||||
type: string
|
||||
# End genetlink-c
|
||||
# Start genetlink-legacy
|
||||
kernel-policy:
|
||||
@ -53,6 +60,10 @@ properties:
|
||||
Defines if the input policy in the kernel is global, per-operation, or split per operation type.
|
||||
Default is split.
|
||||
enum: [ split, per-op, global ]
|
||||
version:
|
||||
description: Generic Netlink family version. Default is 1.
|
||||
type: integer
|
||||
minimum: 1
|
||||
# End genetlink-legacy
|
||||
|
||||
definitions:
|
||||
@ -180,14 +191,15 @@ properties:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name, type ]
|
||||
required: [ name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type: &attr-type
|
||||
description: The netlink attribute type
|
||||
enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
|
||||
enum: [ unused, pad, flag, binary, bitfield32,
|
||||
uint, sint, u8, u16, u32, u64, s32, s64,
|
||||
string, nest, array-nest, nest-type-value ]
|
||||
doc:
|
||||
description: Documentation of the attribute.
|
||||
@ -226,13 +238,19 @@ properties:
|
||||
type: string
|
||||
min:
|
||||
description: Min value for an integer attribute.
|
||||
type: integer
|
||||
$ref: '#/$defs/len-or-limit'
|
||||
max:
|
||||
description: Max value for an integer attribute.
|
||||
$ref: '#/$defs/len-or-limit'
|
||||
min-len:
|
||||
description: Min length for a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
max-len:
|
||||
description: Max length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
exact-len:
|
||||
description: Exact length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
sub-type: *attr-type
|
||||
display-hint: *display-hint
|
||||
# Start genetlink-c
|
||||
@ -254,6 +272,18 @@ properties:
|
||||
not:
|
||||
required: [ name-prefix ]
|
||||
|
||||
# type property is only required if not in subset definition
|
||||
if:
|
||||
properties:
|
||||
subset-of:
|
||||
not:
|
||||
type: string
|
||||
then:
|
||||
properties:
|
||||
attributes:
|
||||
items:
|
||||
required: [ type ]
|
||||
|
||||
operations:
|
||||
description: Operations supported by the protocol.
|
||||
type: object
|
||||
@ -316,12 +346,17 @@ properties:
|
||||
description: Command flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ admin-perm ]
|
||||
enum: [ admin-perm, uns-admin-perm ]
|
||||
dont-validate:
|
||||
description: Kernel attribute validation flags.
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump, dump-strict ]
|
||||
config-cond:
|
||||
description: |
|
||||
Name of the kernel config option gating the presence of
|
||||
the operation, without the 'CONFIG_' prefix.
|
||||
type: string
|
||||
# Start genetlink-legacy
|
||||
fixed-header: *fixed-header
|
||||
# End genetlink-legacy
|
||||
|
@ -13,6 +13,11 @@ $defs:
|
||||
type: [ string, integer ]
|
||||
pattern: ^[0-9A-Za-z_]+( - 1)?$
|
||||
minimum: 0
|
||||
len-or-limit:
|
||||
# literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc.
|
||||
type: [ string, integer ]
|
||||
pattern: ^[su](8|16|32|64)-(min|max)$
|
||||
minimum: 0
|
||||
|
||||
# Schema for specs
|
||||
title: Protocol
|
||||
@ -26,10 +31,6 @@ properties:
|
||||
type: string
|
||||
doc:
|
||||
type: string
|
||||
version:
|
||||
description: Generic Netlink family version. Default is 1.
|
||||
type: integer
|
||||
minimum: 1
|
||||
protocol:
|
||||
description: Schema compatibility level. Default is "genetlink".
|
||||
enum: [ genetlink ]
|
||||
@ -115,13 +116,14 @@ properties:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name, type ]
|
||||
required: [ name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type: &attr-type
|
||||
enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64,
|
||||
enum: [ unused, pad, flag, binary,
|
||||
uint, sint, u8, u16, u32, u64, s32, s64,
|
||||
string, nest, array-nest, nest-type-value ]
|
||||
doc:
|
||||
description: Documentation of the attribute.
|
||||
@ -160,13 +162,19 @@ properties:
|
||||
type: string
|
||||
min:
|
||||
description: Min value for an integer attribute.
|
||||
type: integer
|
||||
$ref: '#/$defs/len-or-limit'
|
||||
max:
|
||||
description: Max value for an integer attribute.
|
||||
$ref: '#/$defs/len-or-limit'
|
||||
min-len:
|
||||
description: Min length for a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
max-len:
|
||||
description: Max length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
exact-len:
|
||||
description: Exact length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
sub-type: *attr-type
|
||||
display-hint: &display-hint
|
||||
description: |
|
||||
@ -184,6 +192,18 @@ properties:
|
||||
not:
|
||||
required: [ name-prefix ]
|
||||
|
||||
# type property is only required if not in subset definition
|
||||
if:
|
||||
properties:
|
||||
subset-of:
|
||||
not:
|
||||
type: string
|
||||
then:
|
||||
properties:
|
||||
attributes:
|
||||
items:
|
||||
required: [ type ]
|
||||
|
||||
operations:
|
||||
description: Operations supported by the protocol.
|
||||
type: object
|
||||
@ -244,6 +264,11 @@ properties:
|
||||
type: array
|
||||
items:
|
||||
enum: [ strict, dump, dump-strict ]
|
||||
config-cond:
|
||||
description: |
|
||||
Name of the kernel config option gating the presence of
|
||||
the operation, without the 'CONFIG_' prefix.
|
||||
type: string
|
||||
do: &subop-type
|
||||
description: Main command handler.
|
||||
type: object
|
||||
|
@ -47,6 +47,12 @@ properties:
|
||||
max-by-define:
|
||||
description: Makes the number of attributes and commands be specified by a define, not an enum value.
|
||||
type: boolean
|
||||
cmd-max-name:
|
||||
description: Name of the define for the last operation in the list.
|
||||
type: string
|
||||
cmd-cnt-name:
|
||||
description: The explicit name for constant holding the count of operations (last operation + 1).
|
||||
type: string
|
||||
# End genetlink-c
|
||||
# Start genetlink-legacy
|
||||
kernel-policy:
|
||||
@ -187,7 +193,7 @@ properties:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [ name, type ]
|
||||
required: [ name ]
|
||||
additionalProperties: False
|
||||
properties:
|
||||
name:
|
||||
@ -240,6 +246,9 @@ properties:
|
||||
max-len:
|
||||
description: Max length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
exact-len:
|
||||
description: Exact length for a string or a binary attribute.
|
||||
$ref: '#/$defs/len-or-define'
|
||||
sub-type: *attr-type
|
||||
display-hint: *display-hint
|
||||
# Start genetlink-c
|
||||
@ -261,6 +270,18 @@ properties:
|
||||
not:
|
||||
required: [ name-prefix ]
|
||||
|
||||
# type property is only required if not in subset definition
|
||||
if:
|
||||
properties:
|
||||
subset-of:
|
||||
not:
|
||||
type: string
|
||||
then:
|
||||
properties:
|
||||
attributes:
|
||||
items:
|
||||
required: [ type ]
|
||||
|
||||
operations:
|
||||
description: Operations supported by the protocol.
|
||||
type: object
|
||||
|
File diff suppressed because it is too large
Load Diff
510
Documentation/netlink/specs/dpll.yaml
Normal file
510
Documentation/netlink/specs/dpll.yaml
Normal file
@ -0,0 +1,510 @@
|
||||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
|
||||
name: dpll
|
||||
|
||||
doc: DPLL subsystem.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: enum
|
||||
name: mode
|
||||
doc: |
|
||||
working modes a dpll can support, differentiates if and how dpll selects
|
||||
one of its inputs to syntonize with it, valid values for DPLL_A_MODE
|
||||
attribute
|
||||
entries:
|
||||
-
|
||||
name: manual
|
||||
doc: input can be only selected by sending a request to dpll
|
||||
value: 1
|
||||
-
|
||||
name: automatic
|
||||
doc: highest prio input pin auto selected by dpll
|
||||
render-max: true
|
||||
-
|
||||
type: enum
|
||||
name: lock-status
|
||||
doc: |
|
||||
provides information of dpll device lock status, valid values for
|
||||
DPLL_A_LOCK_STATUS attribute
|
||||
entries:
|
||||
-
|
||||
name: unlocked
|
||||
doc: |
|
||||
dpll was not yet locked to any valid input (or forced by setting
|
||||
DPLL_A_MODE to DPLL_MODE_DETACHED)
|
||||
value: 1
|
||||
-
|
||||
name: locked
|
||||
doc: |
|
||||
dpll is locked to a valid signal, but no holdover available
|
||||
-
|
||||
name: locked-ho-acq
|
||||
doc: |
|
||||
dpll is locked and holdover acquired
|
||||
-
|
||||
name: holdover
|
||||
doc: |
|
||||
dpll is in holdover state - lost a valid lock or was forced
|
||||
by disconnecting all the pins (latter possible only
|
||||
when dpll lock-state was already DPLL_LOCK_STATUS_LOCKED_HO_ACQ,
|
||||
if dpll lock-state was not DPLL_LOCK_STATUS_LOCKED_HO_ACQ, the
|
||||
dpll's lock-state shall remain DPLL_LOCK_STATUS_UNLOCKED)
|
||||
render-max: true
|
||||
-
|
||||
type: const
|
||||
name: temp-divider
|
||||
value: 1000
|
||||
doc: |
|
||||
temperature divider allowing userspace to calculate the
|
||||
temperature as float with three digit decimal precision.
|
||||
Value of (DPLL_A_TEMP / DPLL_TEMP_DIVIDER) is integer part of
|
||||
temperature value.
|
||||
Value of (DPLL_A_TEMP % DPLL_TEMP_DIVIDER) is fractional part of
|
||||
temperature value.
|
||||
-
|
||||
type: enum
|
||||
name: type
|
||||
doc: type of dpll, valid values for DPLL_A_TYPE attribute
|
||||
entries:
|
||||
-
|
||||
name: pps
|
||||
doc: dpll produces Pulse-Per-Second signal
|
||||
value: 1
|
||||
-
|
||||
name: eec
|
||||
doc: dpll drives the Ethernet Equipment Clock
|
||||
render-max: true
|
||||
-
|
||||
type: enum
|
||||
name: pin-type
|
||||
doc: |
|
||||
defines possible types of a pin, valid values for DPLL_A_PIN_TYPE
|
||||
attribute
|
||||
entries:
|
||||
-
|
||||
name: mux
|
||||
doc: aggregates another layer of selectable pins
|
||||
value: 1
|
||||
-
|
||||
name: ext
|
||||
doc: external input
|
||||
-
|
||||
name: synce-eth-port
|
||||
doc: ethernet port PHY's recovered clock
|
||||
-
|
||||
name: int-oscillator
|
||||
doc: device internal oscillator
|
||||
-
|
||||
name: gnss
|
||||
doc: GNSS recovered clock
|
||||
render-max: true
|
||||
-
|
||||
type: enum
|
||||
name: pin-direction
|
||||
doc: |
|
||||
defines possible direction of a pin, valid values for
|
||||
DPLL_A_PIN_DIRECTION attribute
|
||||
entries:
|
||||
-
|
||||
name: input
|
||||
doc: pin used as a input of a signal
|
||||
value: 1
|
||||
-
|
||||
name: output
|
||||
doc: pin used to output the signal
|
||||
render-max: true
|
||||
-
|
||||
type: const
|
||||
name: pin-frequency-1-hz
|
||||
value: 1
|
||||
-
|
||||
type: const
|
||||
name: pin-frequency-10-khz
|
||||
value: 10000
|
||||
-
|
||||
type: const
|
||||
name: pin-frequency-77_5-khz
|
||||
value: 77500
|
||||
-
|
||||
type: const
|
||||
name: pin-frequency-10-mhz
|
||||
value: 10000000
|
||||
-
|
||||
type: enum
|
||||
name: pin-state
|
||||
doc: |
|
||||
defines possible states of a pin, valid values for
|
||||
DPLL_A_PIN_STATE attribute
|
||||
entries:
|
||||
-
|
||||
name: connected
|
||||
doc: pin connected, active input of phase locked loop
|
||||
value: 1
|
||||
-
|
||||
name: disconnected
|
||||
doc: pin disconnected, not considered as a valid input
|
||||
-
|
||||
name: selectable
|
||||
doc: pin enabled for automatic input selection
|
||||
render-max: true
|
||||
-
|
||||
type: flags
|
||||
name: pin-capabilities
|
||||
doc: |
|
||||
defines possible capabilities of a pin, valid flags on
|
||||
DPLL_A_PIN_CAPABILITIES attribute
|
||||
entries:
|
||||
-
|
||||
name: direction-can-change
|
||||
doc: pin direction can be changed
|
||||
-
|
||||
name: priority-can-change
|
||||
doc: pin priority can be changed
|
||||
-
|
||||
name: state-can-change
|
||||
doc: pin state can be changed
|
||||
-
|
||||
type: const
|
||||
name: phase-offset-divider
|
||||
value: 1000
|
||||
doc: |
|
||||
phase offset divider allows userspace to calculate a value of
|
||||
measured signal phase difference between a pin and dpll device
|
||||
as a fractional value with three digit decimal precision.
|
||||
Value of (DPLL_A_PHASE_OFFSET / DPLL_PHASE_OFFSET_DIVIDER) is an
|
||||
integer part of a measured phase offset value.
|
||||
Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a
|
||||
fractional part of a measured phase offset value.
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: dpll
|
||||
enum-name: dpll_a
|
||||
attributes:
|
||||
-
|
||||
name: id
|
||||
type: u32
|
||||
-
|
||||
name: module-name
|
||||
type: string
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
-
|
||||
name: clock-id
|
||||
type: u64
|
||||
-
|
||||
name: mode
|
||||
type: u32
|
||||
enum: mode
|
||||
-
|
||||
name: mode-supported
|
||||
type: u32
|
||||
enum: mode
|
||||
multi-attr: true
|
||||
-
|
||||
name: lock-status
|
||||
type: u32
|
||||
enum: lock-status
|
||||
-
|
||||
name: temp
|
||||
type: s32
|
||||
-
|
||||
name: type
|
||||
type: u32
|
||||
enum: type
|
||||
-
|
||||
name: pin
|
||||
enum-name: dpll_a_pin
|
||||
attributes:
|
||||
-
|
||||
name: id
|
||||
type: u32
|
||||
-
|
||||
name: parent-id
|
||||
type: u32
|
||||
-
|
||||
name: module-name
|
||||
type: string
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
-
|
||||
name: clock-id
|
||||
type: u64
|
||||
-
|
||||
name: board-label
|
||||
type: string
|
||||
-
|
||||
name: panel-label
|
||||
type: string
|
||||
-
|
||||
name: package-label
|
||||
type: string
|
||||
-
|
||||
name: type
|
||||
type: u32
|
||||
enum: pin-type
|
||||
-
|
||||
name: direction
|
||||
type: u32
|
||||
enum: pin-direction
|
||||
-
|
||||
name: frequency
|
||||
type: u64
|
||||
-
|
||||
name: frequency-supported
|
||||
type: nest
|
||||
multi-attr: true
|
||||
nested-attributes: frequency-range
|
||||
-
|
||||
name: frequency-min
|
||||
type: u64
|
||||
-
|
||||
name: frequency-max
|
||||
type: u64
|
||||
-
|
||||
name: prio
|
||||
type: u32
|
||||
-
|
||||
name: state
|
||||
type: u32
|
||||
enum: pin-state
|
||||
-
|
||||
name: capabilities
|
||||
type: u32
|
||||
-
|
||||
name: parent-device
|
||||
type: nest
|
||||
multi-attr: true
|
||||
nested-attributes: pin-parent-device
|
||||
-
|
||||
name: parent-pin
|
||||
type: nest
|
||||
multi-attr: true
|
||||
nested-attributes: pin-parent-pin
|
||||
-
|
||||
name: phase-adjust-min
|
||||
type: s32
|
||||
-
|
||||
name: phase-adjust-max
|
||||
type: s32
|
||||
-
|
||||
name: phase-adjust
|
||||
type: s32
|
||||
-
|
||||
name: phase-offset
|
||||
type: s64
|
||||
-
|
||||
name: pin-parent-device
|
||||
subset-of: pin
|
||||
attributes:
|
||||
-
|
||||
name: parent-id
|
||||
-
|
||||
name: direction
|
||||
-
|
||||
name: prio
|
||||
-
|
||||
name: state
|
||||
-
|
||||
name: phase-offset
|
||||
-
|
||||
name: pin-parent-pin
|
||||
subset-of: pin
|
||||
attributes:
|
||||
-
|
||||
name: parent-id
|
||||
-
|
||||
name: state
|
||||
-
|
||||
name: frequency-range
|
||||
subset-of: pin
|
||||
attributes:
|
||||
-
|
||||
name: frequency-min
|
||||
-
|
||||
name: frequency-max
|
||||
|
||||
operations:
|
||||
enum-name: dpll_cmd
|
||||
list:
|
||||
-
|
||||
name: device-id-get
|
||||
doc: |
|
||||
Get id of dpll device that matches given attributes
|
||||
attribute-set: dpll
|
||||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
pre: dpll-lock-doit
|
||||
post: dpll-unlock-doit
|
||||
request:
|
||||
attributes:
|
||||
- module-name
|
||||
- clock-id
|
||||
- type
|
||||
reply:
|
||||
attributes:
|
||||
- id
|
||||
|
||||
-
|
||||
name: device-get
|
||||
doc: |
|
||||
Get list of DPLL devices (dump) or attributes of a single dpll device
|
||||
attribute-set: dpll
|
||||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
pre: dpll-pre-doit
|
||||
post: dpll-post-doit
|
||||
request:
|
||||
attributes:
|
||||
- id
|
||||
reply: &dev-attrs
|
||||
attributes:
|
||||
- id
|
||||
- module-name
|
||||
- mode
|
||||
- mode-supported
|
||||
- lock-status
|
||||
- temp
|
||||
- clock-id
|
||||
- type
|
||||
|
||||
dump:
|
||||
pre: dpll-lock-dumpit
|
||||
post: dpll-unlock-dumpit
|
||||
reply: *dev-attrs
|
||||
|
||||
-
|
||||
name: device-set
|
||||
doc: Set attributes for a DPLL device
|
||||
attribute-set: dpll
|
||||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
pre: dpll-pre-doit
|
||||
post: dpll-post-doit
|
||||
request:
|
||||
attributes:
|
||||
- id
|
||||
-
|
||||
name: device-create-ntf
|
||||
doc: Notification about device appearing
|
||||
notify: device-get
|
||||
mcgrp: monitor
|
||||
-
|
||||
name: device-delete-ntf
|
||||
doc: Notification about device disappearing
|
||||
notify: device-get
|
||||
mcgrp: monitor
|
||||
-
|
||||
name: device-change-ntf
|
||||
doc: Notification about device configuration being changed
|
||||
notify: device-get
|
||||
mcgrp: monitor
|
||||
-
|
||||
name: pin-id-get
|
||||
doc: |
|
||||
Get id of a pin that matches given attributes
|
||||
attribute-set: pin
|
||||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
pre: dpll-lock-doit
|
||||
post: dpll-unlock-doit
|
||||
request:
|
||||
attributes:
|
||||
- module-name
|
||||
- clock-id
|
||||
- board-label
|
||||
- panel-label
|
||||
- package-label
|
||||
- type
|
||||
reply:
|
||||
attributes:
|
||||
- id
|
||||
|
||||
-
|
||||
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
|
||||
a given dpll device
|
||||
- do request with target dpll and target pin - single pin attributes
|
||||
attribute-set: pin
|
||||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
pre: dpll-pin-pre-doit
|
||||
post: dpll-pin-post-doit
|
||||
request:
|
||||
attributes:
|
||||
- id
|
||||
reply: &pin-attrs
|
||||
attributes:
|
||||
- id
|
||||
- board-label
|
||||
- panel-label
|
||||
- package-label
|
||||
- type
|
||||
- frequency
|
||||
- frequency-supported
|
||||
- capabilities
|
||||
- parent-device
|
||||
- parent-pin
|
||||
- phase-adjust-min
|
||||
- phase-adjust-max
|
||||
- phase-adjust
|
||||
|
||||
dump:
|
||||
pre: dpll-lock-dumpit
|
||||
post: dpll-unlock-dumpit
|
||||
request:
|
||||
attributes:
|
||||
- id
|
||||
reply: *pin-attrs
|
||||
|
||||
-
|
||||
name: pin-set
|
||||
doc: Set attributes of a target pin
|
||||
attribute-set: pin
|
||||
flags: [ admin-perm ]
|
||||
|
||||
do:
|
||||
pre: dpll-pin-pre-doit
|
||||
post: dpll-pin-post-doit
|
||||
request:
|
||||
attributes:
|
||||
- id
|
||||
- frequency
|
||||
- direction
|
||||
- prio
|
||||
- state
|
||||
- parent-device
|
||||
- parent-pin
|
||||
- phase-adjust
|
||||
-
|
||||
name: pin-create-ntf
|
||||
doc: Notification about pin appearing
|
||||
notify: pin-get
|
||||
mcgrp: monitor
|
||||
-
|
||||
name: pin-delete-ntf
|
||||
doc: Notification about pin disappearing
|
||||
notify: pin-get
|
||||
mcgrp: monitor
|
||||
-
|
||||
name: pin-change-ntf
|
||||
doc: Notification about pin configuration being changed
|
||||
notify: pin-get
|
||||
mcgrp: monitor
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: monitor
|
@ -818,13 +818,10 @@ attribute-sets:
|
||||
attributes:
|
||||
-
|
||||
name: hist-bkt-low
|
||||
type: u32
|
||||
-
|
||||
name: hist-bkt-hi
|
||||
type: u32
|
||||
-
|
||||
name: hist-val
|
||||
type: u64
|
||||
-
|
||||
name: stats
|
||||
attributes:
|
||||
|
@ -34,16 +34,16 @@ attribute-sets:
|
||||
attributes:
|
||||
-
|
||||
name: cert
|
||||
type: u32
|
||||
type: s32
|
||||
-
|
||||
name: privkey
|
||||
type: u32
|
||||
type: s32
|
||||
-
|
||||
name: accept
|
||||
attributes:
|
||||
-
|
||||
name: sockfd
|
||||
type: u32
|
||||
type: s32
|
||||
-
|
||||
name: handler-class
|
||||
type: u32
|
||||
@ -79,7 +79,7 @@ attribute-sets:
|
||||
type: u32
|
||||
-
|
||||
name: sockfd
|
||||
type: u32
|
||||
type: s32
|
||||
-
|
||||
name: remote-auth
|
||||
type: u32
|
||||
|
393
Documentation/netlink/specs/mptcp.yaml
Normal file
393
Documentation/netlink/specs/mptcp.yaml
Normal file
@ -0,0 +1,393 @@
|
||||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
|
||||
name: mptcp_pm
|
||||
protocol: genetlink-legacy
|
||||
doc: Multipath TCP.
|
||||
|
||||
c-family-name: mptcp-pm-name
|
||||
c-version-name: mptcp-pm-ver
|
||||
max-by-define: true
|
||||
kernel-policy: per-op
|
||||
cmd-cnt-name: --mptcp-pm-cmd-after-last
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: enum
|
||||
name: event-type
|
||||
enum-name: mptcp-event-type
|
||||
name-prefix: mptcp-event-
|
||||
entries:
|
||||
-
|
||||
name: unspec
|
||||
doc: unused event
|
||||
-
|
||||
name: created
|
||||
doc:
|
||||
token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport
|
||||
A new MPTCP connection has been created. It is the good time to
|
||||
allocate memory and send ADD_ADDR if needed. Depending on the
|
||||
traffic-patterns it can take a long time until the
|
||||
MPTCP_EVENT_ESTABLISHED is sent.
|
||||
-
|
||||
name: established
|
||||
doc:
|
||||
token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport
|
||||
A MPTCP connection is established (can start new subflows).
|
||||
-
|
||||
name: closed
|
||||
doc:
|
||||
token
|
||||
A MPTCP connection has stopped.
|
||||
-
|
||||
name: announced
|
||||
value: 6
|
||||
doc:
|
||||
token, rem_id, family, daddr4 | daddr6 [, dport]
|
||||
A new address has been announced by the peer.
|
||||
-
|
||||
name: removed
|
||||
doc:
|
||||
token, rem_id
|
||||
An address has been lost by the peer.
|
||||
-
|
||||
name: sub-established
|
||||
value: 10
|
||||
doc:
|
||||
token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport,
|
||||
dport, backup, if_idx [, error]
|
||||
A new subflow has been established. 'error' should not be set.
|
||||
-
|
||||
name: sub-closed
|
||||
doc:
|
||||
token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport,
|
||||
dport, backup, if_idx [, error]
|
||||
A subflow has been closed. An error (copy of sk_err) could be set if an
|
||||
error has been detected for this subflow.
|
||||
-
|
||||
name: sub-priority
|
||||
value: 13
|
||||
doc:
|
||||
token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport,
|
||||
dport, backup, if_idx [, error]
|
||||
The priority of a subflow has changed. 'error' should not be set.
|
||||
-
|
||||
name: listener-created
|
||||
value: 15
|
||||
doc:
|
||||
family, sport, saddr4 | saddr6
|
||||
A new PM listener is created.
|
||||
-
|
||||
name: listener-closed
|
||||
doc:
|
||||
family, sport, saddr4 | saddr6
|
||||
A PM listener is closed.
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: address
|
||||
name-prefix: mptcp-pm-addr-attr-
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: family
|
||||
type: u16
|
||||
-
|
||||
name: id
|
||||
type: u8
|
||||
-
|
||||
name: addr4
|
||||
type: u32
|
||||
byte-order: big-endian
|
||||
-
|
||||
name: addr6
|
||||
type: binary
|
||||
checks:
|
||||
exact-len: 16
|
||||
-
|
||||
name: port
|
||||
type: u16
|
||||
byte-order: big-endian
|
||||
-
|
||||
name: flags
|
||||
type: u32
|
||||
-
|
||||
name: if-idx
|
||||
type: s32
|
||||
-
|
||||
name: subflow-attribute
|
||||
name-prefix: mptcp-subflow-attr-
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: token-rem
|
||||
type: u32
|
||||
-
|
||||
name: token-loc
|
||||
type: u32
|
||||
-
|
||||
name: relwrite-seq
|
||||
type: u32
|
||||
-
|
||||
name: map-seq
|
||||
type: u64
|
||||
-
|
||||
name: map-sfseq
|
||||
type: u32
|
||||
-
|
||||
name: ssn-offset
|
||||
type: u32
|
||||
-
|
||||
name: map-datalen
|
||||
type: u16
|
||||
-
|
||||
name: flags
|
||||
type: u32
|
||||
-
|
||||
name: id-rem
|
||||
type: u8
|
||||
-
|
||||
name: id-loc
|
||||
type: u8
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
-
|
||||
name: endpoint
|
||||
name-prefix: mptcp-pm-endpoint-
|
||||
attributes:
|
||||
-
|
||||
name: addr
|
||||
type: nest
|
||||
nested-attributes: address
|
||||
-
|
||||
name: attr
|
||||
name-prefix: mptcp-pm-attr-
|
||||
attr-cnt-name: --mptcp-attr-after-last
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: addr
|
||||
type: nest
|
||||
nested-attributes: address
|
||||
-
|
||||
name: rcv-add-addrs
|
||||
type: u32
|
||||
-
|
||||
name: subflows
|
||||
type: u32
|
||||
-
|
||||
name: token
|
||||
type: u32
|
||||
-
|
||||
name: loc-id
|
||||
type: u8
|
||||
-
|
||||
name: addr-remote
|
||||
type: nest
|
||||
nested-attributes: address
|
||||
-
|
||||
name: event-attr
|
||||
enum-name: mptcp-event-attr
|
||||
name-prefix: mptcp-attr-
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: token
|
||||
type: u32
|
||||
-
|
||||
name: family
|
||||
type: u16
|
||||
-
|
||||
name: loc-id
|
||||
type: u8
|
||||
-
|
||||
name: rem-id
|
||||
type: u8
|
||||
-
|
||||
name: saddr4
|
||||
type: u32
|
||||
byte-order: big-endian
|
||||
-
|
||||
name: saddr6
|
||||
type: binary
|
||||
checks:
|
||||
min-len: 16
|
||||
-
|
||||
name: daddr4
|
||||
type: u32
|
||||
byte-order: big-endian
|
||||
-
|
||||
name: daddr6
|
||||
type: binary
|
||||
checks:
|
||||
min-len: 16
|
||||
-
|
||||
name: sport
|
||||
type: u16
|
||||
byte-order: big-endian
|
||||
-
|
||||
name: dport
|
||||
type: u16
|
||||
byte-order: big-endian
|
||||
-
|
||||
name: backup
|
||||
type: u8
|
||||
-
|
||||
name: error
|
||||
type: u8
|
||||
-
|
||||
name: flags
|
||||
type: u16
|
||||
-
|
||||
name: timeout
|
||||
type: u32
|
||||
-
|
||||
name: if_idx
|
||||
type: u32
|
||||
-
|
||||
name: reset-reason
|
||||
type: u32
|
||||
-
|
||||
name: reset-flags
|
||||
type: u32
|
||||
-
|
||||
name: server-side
|
||||
type: u8
|
||||
|
||||
operations:
|
||||
list:
|
||||
-
|
||||
name: unspec
|
||||
doc: unused
|
||||
value: 0
|
||||
-
|
||||
name: add-addr
|
||||
doc: Add endpoint
|
||||
attribute-set: endpoint
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &add-addr-attrs
|
||||
request:
|
||||
attributes:
|
||||
- addr
|
||||
-
|
||||
name: del-addr
|
||||
doc: Delete endpoint
|
||||
attribute-set: endpoint
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: *add-addr-attrs
|
||||
-
|
||||
name: get-addr
|
||||
doc: Get endpoint information
|
||||
attribute-set: endpoint
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &get-addr-attrs
|
||||
request:
|
||||
attributes:
|
||||
- addr
|
||||
reply:
|
||||
attributes:
|
||||
- addr
|
||||
dump:
|
||||
reply:
|
||||
attributes:
|
||||
- addr
|
||||
-
|
||||
name: flush-addrs
|
||||
doc: flush addresses
|
||||
attribute-set: endpoint
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: *add-addr-attrs
|
||||
-
|
||||
name: set-limits
|
||||
doc: Set protocol limits
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &mptcp-limits
|
||||
request:
|
||||
attributes:
|
||||
- rcv-add-addrs
|
||||
- subflows
|
||||
-
|
||||
name: get-limits
|
||||
doc: Get protocol limits
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
do: &mptcp-get-limits
|
||||
request:
|
||||
attributes:
|
||||
- rcv-add-addrs
|
||||
- subflows
|
||||
reply:
|
||||
attributes:
|
||||
- rcv-add-addrs
|
||||
- subflows
|
||||
-
|
||||
name: set-flags
|
||||
doc: Change endpoint flags
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &mptcp-set-flags
|
||||
request:
|
||||
attributes:
|
||||
- addr
|
||||
- token
|
||||
- addr-remote
|
||||
-
|
||||
name: announce
|
||||
doc: announce new sf
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &announce-add
|
||||
request:
|
||||
attributes:
|
||||
- addr
|
||||
- token
|
||||
-
|
||||
name: remove
|
||||
doc: announce removal
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- token
|
||||
- loc-id
|
||||
-
|
||||
name: subflow-create
|
||||
doc: todo
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: &sf-create
|
||||
request:
|
||||
attributes:
|
||||
- addr
|
||||
- token
|
||||
- addr-remote
|
||||
-
|
||||
name: subflow-destroy
|
||||
doc: todo
|
||||
attribute-set: attr
|
||||
dont-validate: [ strict ]
|
||||
flags: [ uns-admin-perm ]
|
||||
do: *sf-create
|
@ -42,6 +42,19 @@ definitions:
|
||||
doc:
|
||||
This feature informs if netdev implements non-linear XDP buffer
|
||||
support in ndo_xdp_xmit callback.
|
||||
-
|
||||
type: flags
|
||||
name: xdp-rx-metadata
|
||||
render-max: true
|
||||
entries:
|
||||
-
|
||||
name: timestamp
|
||||
doc:
|
||||
Device is capable of exposing receive HW timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
-
|
||||
name: hash
|
||||
doc:
|
||||
Device is capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash().
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
@ -61,13 +74,18 @@ attribute-sets:
|
||||
doc: Bitmask of enabled xdp-features.
|
||||
type: u64
|
||||
enum: xdp-act
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: xdp-zc-max-segs
|
||||
doc: max fragment count supported by ZC driver
|
||||
type: u32
|
||||
checks:
|
||||
min: 1
|
||||
-
|
||||
name: xdp-rx-metadata-features
|
||||
doc: Bitmask of supported XDP receive metadata features.
|
||||
See Documentation/networking/xdp-rx-metadata.rst for more details.
|
||||
type: u64
|
||||
enum: xdp-rx-metadata
|
||||
|
||||
operations:
|
||||
list:
|
||||
@ -84,6 +102,7 @@ operations:
|
||||
- ifindex
|
||||
- xdp-features
|
||||
- xdp-zc-max-segs
|
||||
- xdp-rx-metadata-features
|
||||
dump:
|
||||
reply: *dev-all
|
||||
-
|
||||
|
@ -1,80 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
========================================
|
||||
The COPS LocalTalk Linux driver (cops.c)
|
||||
========================================
|
||||
|
||||
By Jay Schulist <jschlst@samba.org>
|
||||
|
||||
This driver has two modes and they are: Dayna mode and Tangent mode.
|
||||
Each mode corresponds with the type of card. It has been found
|
||||
that there are 2 main types of cards and all other cards are
|
||||
the same and just have different names or only have minor differences
|
||||
such as more IO ports. As this driver is tested it will
|
||||
become more clear exactly what cards are supported.
|
||||
|
||||
Right now these cards are known to work with the COPS driver. The
|
||||
LT-200 cards work in a somewhat more limited capacity than the
|
||||
DL200 cards, which work very well and are in use by many people.
|
||||
|
||||
TANGENT driver mode:
|
||||
- Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200
|
||||
|
||||
DAYNA driver mode:
|
||||
- Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95,
|
||||
- Farallon PhoneNET PC III, Farallon PhoneNET PC II
|
||||
|
||||
Other cards possibly supported mode unknown though:
|
||||
- Dayna DL2000 (Full length)
|
||||
|
||||
The COPS driver defaults to using Dayna mode. To change the driver's
|
||||
mode if you built a driver with dual support use board_type=1 or
|
||||
board_type=2 for Dayna or Tangent with insmod.
|
||||
|
||||
Operation/loading of the driver
|
||||
===============================
|
||||
|
||||
Use modprobe like this: /sbin/modprobe cops.o (IO #) (IRQ #)
|
||||
If you do not specify any options the driver will try and use the IO = 0x240,
|
||||
IRQ = 5. As of right now I would only use IRQ 5 for the card, if autoprobing.
|
||||
|
||||
To load multiple COPS driver Localtalk cards you can do one of the following::
|
||||
|
||||
insmod cops io=0x240 irq=5
|
||||
insmod -o cops2 cops io=0x260 irq=3
|
||||
|
||||
Or in lilo.conf put something like this::
|
||||
|
||||
append="ether=5,0x240,lt0 ether=3,0x260,lt1"
|
||||
|
||||
Then bring up the interface with ifconfig. It will look something like this::
|
||||
|
||||
lt0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-F7-00-00-00-00-00-00-00-00
|
||||
inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0
|
||||
UP BROADCAST RUNNING NOARP MULTICAST MTU:600 Metric:1
|
||||
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
|
||||
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 coll:0
|
||||
|
||||
Netatalk Configuration
|
||||
======================
|
||||
|
||||
You will need to configure atalkd with something like the following to make
|
||||
it work with the cops.c driver.
|
||||
|
||||
* For single LTalk card use::
|
||||
|
||||
dummy -seed -phase 2 -net 2000 -addr 2000.10 -zone "1033"
|
||||
lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033"
|
||||
|
||||
* For multiple cards, Ethernet and LocalTalk::
|
||||
|
||||
eth0 -seed -phase 2 -net 3000 -addr 3000.20 -zone "1033"
|
||||
lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033"
|
||||
|
||||
* For multiple LocalTalk cards, and an Ethernet card.
|
||||
|
||||
* Order seems to matter here, Ethernet last::
|
||||
|
||||
lt0 -seed -phase 1 -net 1000 -addr 1000.10 -zone "LocalTalk1"
|
||||
lt1 -seed -phase 1 -net 2000 -addr 2000.20 -zone "LocalTalk2"
|
||||
eth0 -seed -phase 2 -net 3000 -addr 3000.30 -zone "EtherTalk"
|
@ -1,18 +0,0 @@
|
||||
.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
|
||||
AppleTalk Device Drivers
|
||||
========================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
cops
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
@ -32,6 +32,7 @@ Contents:
|
||||
intel/e1000
|
||||
intel/e1000e
|
||||
intel/fm10k
|
||||
intel/idpf
|
||||
intel/igb
|
||||
intel/igbvf
|
||||
intel/ixgbe
|
||||
|
160
Documentation/networking/device_drivers/ethernet/intel/idpf.rst
Normal file
160
Documentation/networking/device_drivers/ethernet/intel/idpf.rst
Normal file
@ -0,0 +1,160 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
==========================================================================
|
||||
idpf Linux* Base Driver for the Intel(R) Infrastructure Data Path Function
|
||||
==========================================================================
|
||||
|
||||
Intel idpf Linux driver.
|
||||
Copyright(C) 2023 Intel Corporation.
|
||||
|
||||
.. contents::
|
||||
|
||||
The idpf driver serves as both the Physical Function (PF) and Virtual Function
|
||||
(VF) driver for the Intel(R) Infrastructure Data Path Function.
|
||||
|
||||
Driver information can be obtained using ethtool, lspci, and ip.
|
||||
|
||||
For questions related to hardware requirements, refer to the documentation
|
||||
supplied with your Intel adapter. All hardware requirements listed apply to use
|
||||
with Linux.
|
||||
|
||||
|
||||
Identifying Your Adapter
|
||||
========================
|
||||
For information on how to identify your adapter, and for the latest Intel
|
||||
network drivers, refer to the Intel Support website:
|
||||
http://www.intel.com/support
|
||||
|
||||
|
||||
Additional Features and Configurations
|
||||
======================================
|
||||
|
||||
ethtool
|
||||
-------
|
||||
The driver utilizes the ethtool interface for driver configuration and
|
||||
diagnostics, as well as displaying statistical information. The latest ethtool
|
||||
version is required for this functionality. If you don't have one yet, you can
|
||||
obtain it at:
|
||||
https://kernel.org/pub/software/network/ethtool/
|
||||
|
||||
|
||||
Viewing Link Messages
|
||||
---------------------
|
||||
Link messages will not be displayed to the console if the distribution is
|
||||
restricting system messages. In order to see network driver link messages on
|
||||
your console, set dmesg to eight by entering the following::
|
||||
|
||||
# dmesg -n 8
|
||||
|
||||
.. note::
|
||||
This setting is not saved across reboots.
|
||||
|
||||
|
||||
Jumbo Frames
|
||||
------------
|
||||
Jumbo Frames support is enabled by changing the Maximum Transmission Unit (MTU)
|
||||
to a value larger than the default value of 1500.
|
||||
|
||||
Use the ip command to increase the MTU size. For example, enter the following
|
||||
where <ethX> is the interface number::
|
||||
|
||||
# ip link set mtu 9000 dev <ethX>
|
||||
# ip link set up dev <ethX>
|
||||
|
||||
.. note::
|
||||
The maximum MTU setting for jumbo frames is 9706. This corresponds to the
|
||||
maximum jumbo frame size of 9728 bytes.
|
||||
|
||||
.. note::
|
||||
This driver will attempt to use multiple page sized buffers to receive
|
||||
each jumbo packet. This should help to avoid buffer starvation issues when
|
||||
allocating receive packets.
|
||||
|
||||
.. note::
|
||||
Packet loss may have a greater impact on throughput when you use jumbo
|
||||
frames. If you observe a drop in performance after enabling jumbo frames,
|
||||
enabling flow control may mitigate the issue.
|
||||
|
||||
|
||||
Performance Optimization
|
||||
========================
|
||||
Driver defaults are meant to fit a wide variety of workloads, but if further
|
||||
optimization is required, we recommend experimenting with the following
|
||||
settings.
|
||||
|
||||
|
||||
Interrupt Rate Limiting
|
||||
-----------------------
|
||||
This driver supports an adaptive interrupt throttle rate (ITR) mechanism that
|
||||
is tuned for general workloads. The user can customize the interrupt rate
|
||||
control for specific workloads, via ethtool, adjusting the number of
|
||||
microseconds between interrupts.
|
||||
|
||||
To set the interrupt rate manually, you must disable adaptive mode::
|
||||
|
||||
# ethtool -C <ethX> adaptive-rx off adaptive-tx off
|
||||
|
||||
For lower CPU utilization:
|
||||
- Disable adaptive ITR and lower Rx and Tx interrupts. The examples below
|
||||
affect every queue of the specified interface.
|
||||
|
||||
- Setting rx-usecs and tx-usecs to 80 will limit interrupts to about
|
||||
12,500 interrupts per second per queue::
|
||||
|
||||
# ethtool -C <ethX> adaptive-rx off adaptive-tx off rx-usecs 80
|
||||
tx-usecs 80
|
||||
|
||||
For reduced latency:
|
||||
- Disable adaptive ITR and ITR by setting rx-usecs and tx-usecs to 0
|
||||
using ethtool::
|
||||
|
||||
# ethtool -C <ethX> adaptive-rx off adaptive-tx off rx-usecs 0
|
||||
tx-usecs 0
|
||||
|
||||
Per-queue interrupt rate settings:
|
||||
- The following examples are for queues 1 and 3, but you can adjust other
|
||||
queues.
|
||||
|
||||
- To disable Rx adaptive ITR and set static Rx ITR to 10 microseconds or
|
||||
about 100,000 interrupts/second, for queues 1 and 3::
|
||||
|
||||
# ethtool --per-queue <ethX> queue_mask 0xa --coalesce adaptive-rx off
|
||||
rx-usecs 10
|
||||
|
||||
- To show the current coalesce settings for queues 1 and 3::
|
||||
|
||||
# ethtool --per-queue <ethX> queue_mask 0xa --show-coalesce
|
||||
|
||||
|
||||
|
||||
Virtualized Environments
|
||||
------------------------
|
||||
In addition to the other suggestions in this section, the following may be
|
||||
helpful to optimize performance in VMs.
|
||||
|
||||
- Using the appropriate mechanism (vcpupin) in the VM, pin the CPUs to
|
||||
individual LCPUs, making sure to use a set of CPUs included in the
|
||||
device's local_cpulist: /sys/class/net/<ethX>/device/local_cpulist.
|
||||
|
||||
- Configure as many Rx/Tx queues in the VM as available. (See the idpf driver
|
||||
documentation for the number of queues supported.) For example::
|
||||
|
||||
# ethtool -L <virt_interface> rx <max> tx <max>
|
||||
|
||||
|
||||
Support
|
||||
=======
|
||||
For general information, go to the Intel support website at:
|
||||
http://www.intel.com/support/
|
||||
|
||||
If an issue is identified with the released source code on a supported kernel
|
||||
with a supported adapter, email the specific information related to the issue
|
||||
to intel-wired-lan@lists.osuosl.org.
|
||||
|
||||
|
||||
Trademarks
|
||||
==========
|
||||
Intel is a trademark or registered trademark of Intel Corporation or its
|
||||
subsidiaries in the United States and/or other countries.
|
||||
|
||||
* Other names and brands may be claimed as the property of others.
|
@ -67,7 +67,7 @@ Enabling the driver and kconfig options
|
||||
| Enables :ref:`IPSec XFRM cryptography-offload acceleration <xfrm_device>`.
|
||||
|
||||
|
||||
**CONFIG_MLX5_EN_MACSEC=(y/n)**
|
||||
**CONFIG_MLX5_MACSEC=(y/n)**
|
||||
|
||||
| Build support for MACsec cryptography-offload acceleration in the NIC.
|
||||
|
||||
|
@ -8,7 +8,6 @@ Contents:
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
appletalk/index
|
||||
atm/index
|
||||
cable/index
|
||||
can/index
|
||||
|
59
Documentation/networking/devlink/i40e.rst
Normal file
59
Documentation/networking/devlink/i40e.rst
Normal file
@ -0,0 +1,59 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
====================
|
||||
i40e devlink support
|
||||
====================
|
||||
|
||||
This document describes the devlink features implemented by the ``i40e``
|
||||
device driver.
|
||||
|
||||
Info versions
|
||||
=============
|
||||
|
||||
The ``i40e`` driver reports the following versions
|
||||
|
||||
.. list-table:: devlink info versions implemented
|
||||
:widths: 5 5 5 90
|
||||
|
||||
* - Name
|
||||
- Type
|
||||
- Example
|
||||
- Description
|
||||
* - ``board.id``
|
||||
- fixed
|
||||
- K15190-000
|
||||
- The Product Board Assembly (PBA) identifier of the board.
|
||||
* - ``fw.mgmt``
|
||||
- running
|
||||
- 9.130
|
||||
- 2-digit version number of the management firmware that controls the
|
||||
PHY, link, etc.
|
||||
* - ``fw.mgmt.api``
|
||||
- running
|
||||
- 1.15
|
||||
- 2-digit version number of the API exported over the AdminQ by the
|
||||
management firmware. Used by the driver to identify what commands
|
||||
are supported.
|
||||
* - ``fw.mgmt.build``
|
||||
- running
|
||||
- 73618
|
||||
- Build number of the source for the management firmware.
|
||||
* - ``fw.undi``
|
||||
- running
|
||||
- 1.3429.0
|
||||
- Version of the Option ROM containing the UEFI driver. The version is
|
||||
reported in ``major.minor.patch`` format. The major version is
|
||||
incremented whenever a major breaking change occurs, or when the
|
||||
minor version would overflow. The minor version is incremented for
|
||||
non-breaking changes and reset to 1 when the major version is
|
||||
incremented. The patch version is normally 0 but is incremented when
|
||||
a fix is delivered as a patch against an older base Option ROM.
|
||||
* - ``fw.psid.api``
|
||||
- running
|
||||
- 9.30
|
||||
- Version defining the format of the flash contents.
|
||||
* - ``fw.bundle_id``
|
||||
- running
|
||||
- 0x8000e5f3
|
||||
- Unique identifier of the firmware image file that was loaded onto
|
||||
the device. Also referred to as the EETRACK identifier of the NVM.
|
@ -18,6 +18,34 @@ netlink commands.
|
||||
|
||||
Drivers are encouraged to use the devlink instance lock for their own needs.
|
||||
|
||||
Drivers need to be cautious when taking devlink instance lock and
|
||||
taking RTNL lock at the same time. Devlink instance lock needs to be taken
|
||||
first, only after that RTNL lock could be taken.
|
||||
|
||||
Nested instances
|
||||
----------------
|
||||
|
||||
Some objects, like linecards or port functions, could have another
|
||||
devlink instances created underneath. In that case, drivers should make
|
||||
sure to respect following rules:
|
||||
|
||||
- Lock ordering should be maintained. If driver needs to take instance
|
||||
lock of both nested and parent instances at the same time, devlink
|
||||
instance lock of the parent instance should be taken first, only then
|
||||
instance lock of the nested instance could be taken.
|
||||
- Driver should use object-specific helpers to setup the
|
||||
nested relationship:
|
||||
|
||||
- ``devl_nested_devlink_set()`` - called to setup devlink -> nested
|
||||
devlink relationship (could be user for multiple nested instances.
|
||||
- ``devl_port_fn_devlink_set()`` - called to setup port function ->
|
||||
nested devlink relationship.
|
||||
- ``devlink_linecard_nested_dl_set()`` - called to setup linecard ->
|
||||
nested devlink relationship.
|
||||
|
||||
The nested devlink info is exposed to the userspace over object-specific
|
||||
attributes of devlink netlink.
|
||||
|
||||
Interface documentation
|
||||
-----------------------
|
||||
|
||||
@ -52,6 +80,7 @@ parameters, info versions, and other features it supports.
|
||||
bnxt
|
||||
etas_es58x
|
||||
hns3
|
||||
i40e
|
||||
ionic
|
||||
ice
|
||||
mlx4
|
||||
|
@ -52,7 +52,7 @@ VLAN programming would basically change the CPU port's default PVID and make
|
||||
it untagged, undesirable.
|
||||
|
||||
In difference to the configuration described in :ref:`dsa-vlan-configuration`
|
||||
the default VLAN 1 has to be removed from the slave interface configuration in
|
||||
the default VLAN 1 has to be removed from the user interface configuration in
|
||||
single port and gateway configuration, while there is no need to add an extra
|
||||
VLAN configuration in the bridge showcase.
|
||||
|
||||
@ -68,13 +68,13 @@ By default packages are tagged with vid 1:
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
ip link add link eth0 name eth0.3 type vlan id 3
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
# The conduit interface needs to be brought up before the user ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
ip link set eth0.3 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
@ -113,11 +113,11 @@ bridge
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
# The conduit interface needs to be brought up before the user ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
@ -149,12 +149,12 @@ gateway
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
|
||||
# The master interface needs to be brought up before the slave ports.
|
||||
# The conduit interface needs to be brought up before the user ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
|
@ -67,7 +67,7 @@ MDIO indirect accesses
|
||||
----------------------
|
||||
|
||||
Due to a limitation in how Broadcom switches have been designed, external
|
||||
Broadcom switches connected to a SF2 require the use of the DSA slave MDIO bus
|
||||
Broadcom switches connected to a SF2 require the use of the DSA user MDIO bus
|
||||
in order to properly configure them. By default, the SF2 pseudo-PHY address, and
|
||||
an external switch pseudo-PHY address will both be snooping for incoming MDIO
|
||||
transactions, since they are at the same address (30), resulting in some kind of
|
||||
|
@ -31,38 +31,38 @@ at https://www.kernel.org/pub/linux/utils/net/iproute2/
|
||||
|
||||
Through DSA every port of a switch is handled like a normal linux Ethernet
|
||||
interface. The CPU port is the switch port connected to an Ethernet MAC chip.
|
||||
The corresponding linux Ethernet interface is called the master interface.
|
||||
All other corresponding linux interfaces are called slave interfaces.
|
||||
The corresponding linux Ethernet interface is called the conduit interface.
|
||||
All other corresponding linux interfaces are called user interfaces.
|
||||
|
||||
The slave interfaces depend on the master interface being up in order for them
|
||||
to send or receive traffic. Prior to kernel v5.12, the state of the master
|
||||
The user interfaces depend on the conduit interface being up in order for them
|
||||
to send or receive traffic. Prior to kernel v5.12, the state of the conduit
|
||||
interface had to be managed explicitly by the user. Starting with kernel v5.12,
|
||||
the behavior is as follows:
|
||||
|
||||
- when a DSA slave interface is brought up, the master interface is
|
||||
- when a DSA user interface is brought up, the conduit interface is
|
||||
automatically brought up.
|
||||
- when the master interface is brought down, all DSA slave interfaces are
|
||||
- when the conduit interface is brought down, all DSA user interfaces are
|
||||
automatically brought down.
|
||||
|
||||
In this documentation the following Ethernet interfaces are used:
|
||||
|
||||
*eth0*
|
||||
the master interface
|
||||
the conduit interface
|
||||
|
||||
*eth1*
|
||||
another master interface
|
||||
another conduit interface
|
||||
|
||||
*lan1*
|
||||
a slave interface
|
||||
a user interface
|
||||
|
||||
*lan2*
|
||||
another slave interface
|
||||
another user interface
|
||||
|
||||
*lan3*
|
||||
a third slave interface
|
||||
a third user interface
|
||||
|
||||
*wan*
|
||||
A slave interface dedicated for upstream traffic
|
||||
A user interface dedicated for upstream traffic
|
||||
|
||||
Further Ethernet interfaces can be configured similar.
|
||||
The configured IPs and networks are:
|
||||
@ -96,11 +96,11 @@ without using a VLAN based configuration.
|
||||
ip addr add 192.0.2.5/30 dev lan2
|
||||
ip addr add 192.0.2.9/30 dev lan3
|
||||
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
# For kernels earlier than v5.12, the conduit interface needs to be
|
||||
# brought up manually before the user ports.
|
||||
ip link set eth0 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
@ -108,11 +108,11 @@ without using a VLAN based configuration.
|
||||
*bridge*
|
||||
.. code-block:: sh
|
||||
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
# For kernels earlier than v5.12, the conduit interface needs to be
|
||||
# brought up manually before the user ports.
|
||||
ip link set eth0 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
@ -134,11 +134,11 @@ without using a VLAN based configuration.
|
||||
*gateway*
|
||||
.. code-block:: sh
|
||||
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
# For kernels earlier than v5.12, the conduit interface needs to be
|
||||
# brought up manually before the user ports.
|
||||
ip link set eth0 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
@ -178,14 +178,14 @@ configuration.
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
ip link add link eth0 name eth0.3 type vlan id 3
|
||||
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
# For kernels earlier than v5.12, the conduit interface needs to be
|
||||
# brought up manually before the user ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
ip link set eth0.3 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
@ -221,12 +221,12 @@ configuration.
|
||||
# tag traffic on CPU port
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
# For kernels earlier than v5.12, the conduit interface needs to be
|
||||
# brought up manually before the user ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
ip link set lan3 up
|
||||
@ -261,13 +261,13 @@ configuration.
|
||||
ip link add link eth0 name eth0.1 type vlan id 1
|
||||
ip link add link eth0 name eth0.2 type vlan id 2
|
||||
|
||||
# For kernels earlier than v5.12, the master interface needs to be
|
||||
# brought up manually before the slave ports.
|
||||
# For kernels earlier than v5.12, the conduit interface needs to be
|
||||
# brought up manually before the user ports.
|
||||
ip link set eth0 up
|
||||
ip link set eth0.1 up
|
||||
ip link set eth0.2 up
|
||||
|
||||
# bring up the slave interfaces
|
||||
# bring up the user interfaces
|
||||
ip link set wan up
|
||||
ip link set lan1 up
|
||||
ip link set lan2 up
|
||||
@ -380,22 +380,22 @@ affinities according to the available CPU ports.
|
||||
|
||||
Secondly, it is possible to perform load balancing between CPU ports on a per
|
||||
packet basis, rather than statically assigning user ports to CPU ports.
|
||||
This can be achieved by placing the DSA masters under a LAG interface (bonding
|
||||
This can be achieved by placing the DSA conduits under a LAG interface (bonding
|
||||
or team). DSA monitors this operation and creates a mirror of this software LAG
|
||||
on the CPU ports facing the physical DSA masters that constitute the LAG slave
|
||||
on the CPU ports facing the physical DSA conduits that constitute the LAG slave
|
||||
devices.
|
||||
|
||||
To make use of multiple CPU ports, the firmware (device tree) description of
|
||||
the switch must mark all the links between CPU ports and their DSA masters
|
||||
the switch must mark all the links between CPU ports and their DSA conduits
|
||||
using the ``ethernet`` reference/phandle. At startup, only a single CPU port
|
||||
and DSA master will be used - the numerically first port from the firmware
|
||||
and DSA conduit will be used - the numerically first port from the firmware
|
||||
description which has an ``ethernet`` property. It is up to the user to
|
||||
configure the system for the switch to use other masters.
|
||||
configure the system for the switch to use other conduits.
|
||||
|
||||
DSA uses the ``rtnl_link_ops`` mechanism (with a "dsa" ``kind``) to allow
|
||||
changing the DSA master of a user port. The ``IFLA_DSA_MASTER`` u32 netlink
|
||||
attribute contains the ifindex of the master device that handles each slave
|
||||
device. The DSA master must be a valid candidate based on firmware node
|
||||
changing the DSA conduit of a user port. The ``IFLA_DSA_CONDUIT`` u32 netlink
|
||||
attribute contains the ifindex of the conduit device that handles each user
|
||||
device. The DSA conduit must be a valid candidate based on firmware node
|
||||
information, or a LAG interface which contains only slaves which are valid
|
||||
candidates.
|
||||
|
||||
@ -403,7 +403,7 @@ Using iproute2, the following manipulations are possible:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# See the DSA master in current use
|
||||
# See the DSA conduit in current use
|
||||
ip -d link show dev swp0
|
||||
(...)
|
||||
dsa master eth0
|
||||
@ -414,7 +414,7 @@ Using iproute2, the following manipulations are possible:
|
||||
ip link set swp2 type dsa master eth1
|
||||
ip link set swp3 type dsa master eth0
|
||||
|
||||
# CPU ports in LAG, using explicit assignment of the DSA master
|
||||
# CPU ports in LAG, using explicit assignment of the DSA conduit
|
||||
ip link add bond0 type bond mode balance-xor && ip link set bond0 up
|
||||
ip link set eth1 down && ip link set eth1 master bond0
|
||||
ip link set swp0 type dsa master bond0
|
||||
@ -426,7 +426,7 @@ Using iproute2, the following manipulations are possible:
|
||||
(...)
|
||||
dsa master bond0
|
||||
|
||||
# CPU ports in LAG, relying on implicit migration of the DSA master
|
||||
# CPU ports in LAG, relying on implicit migration of the DSA conduit
|
||||
ip link add bond0 type bond mode balance-xor && ip link set bond0 up
|
||||
ip link set eth0 down && ip link set eth0 master bond0
|
||||
ip link set eth1 down && ip link set eth1 master bond0
|
||||
@ -435,24 +435,24 @@ Using iproute2, the following manipulations are possible:
|
||||
dsa master bond0
|
||||
|
||||
Notice that in the case of CPU ports under a LAG, the use of the
|
||||
``IFLA_DSA_MASTER`` netlink attribute is not strictly needed, but rather, DSA
|
||||
reacts to the ``IFLA_MASTER`` attribute change of its present master (``eth0``)
|
||||
``IFLA_DSA_CONDUIT`` netlink attribute is not strictly needed, but rather, DSA
|
||||
reacts to the ``IFLA_MASTER`` attribute change of its present conduit (``eth0``)
|
||||
and migrates all user ports to the new upper of ``eth0``, ``bond0``. Similarly,
|
||||
when ``bond0`` is destroyed using ``RTM_DELLINK``, DSA migrates the user ports
|
||||
that were assigned to this interface to the first physical DSA master which is
|
||||
that were assigned to this interface to the first physical DSA conduit which is
|
||||
eligible, based on the firmware description (it effectively reverts to the
|
||||
startup configuration).
|
||||
|
||||
In a setup with more than 2 physical CPU ports, it is therefore possible to mix
|
||||
static user to CPU port assignment with LAG between DSA masters. It is not
|
||||
possible to statically assign a user port towards a DSA master that has any
|
||||
upper interfaces (this includes LAG devices - the master must always be the LAG
|
||||
static user to CPU port assignment with LAG between DSA conduits. It is not
|
||||
possible to statically assign a user port towards a DSA conduit that has any
|
||||
upper interfaces (this includes LAG devices - the conduit must always be the LAG
|
||||
in this case).
|
||||
|
||||
Live changing of the DSA master (and thus CPU port) affinity of a user port is
|
||||
Live changing of the DSA conduit (and thus CPU port) affinity of a user port is
|
||||
permitted, in order to allow dynamic redistribution in response to traffic.
|
||||
|
||||
Physical DSA masters are allowed to join and leave at any time a LAG interface
|
||||
used as a DSA master; however, DSA will reject a LAG interface as a valid
|
||||
candidate for being a DSA master unless it has at least one physical DSA master
|
||||
Physical DSA conduits are allowed to join and leave at any time a LAG interface
|
||||
used as a DSA conduit; however, DSA will reject a LAG interface as a valid
|
||||
candidate for being a DSA conduit unless it has at least one physical DSA conduit
|
||||
as a slave device.
|
||||
|
@ -25,7 +25,7 @@ presence of a management port connected to an Ethernet controller capable of
|
||||
receiving Ethernet frames from the switch. This is a very common setup for all
|
||||
kinds of Ethernet switches found in Small Home and Office products: routers,
|
||||
gateways, or even top-of-rack switches. This host Ethernet controller will
|
||||
be later referred to as "master" and "cpu" in DSA terminology and code.
|
||||
be later referred to as "conduit" and "cpu" in DSA terminology and code.
|
||||
|
||||
The D in DSA stands for Distributed, because the subsystem has been designed
|
||||
with the ability to configure and manage cascaded switches on top of each other
|
||||
@ -35,7 +35,7 @@ of multiple switches connected to each other is called a "switch tree".
|
||||
|
||||
For each front-panel port, DSA creates specialized network devices which are
|
||||
used as controlling and data-flowing endpoints for use by the Linux networking
|
||||
stack. These specialized network interfaces are referred to as "slave" network
|
||||
stack. These specialized network interfaces are referred to as "user" network
|
||||
interfaces in DSA terminology and code.
|
||||
|
||||
The ideal case for using DSA is when an Ethernet switch supports a "switch tag"
|
||||
@ -56,12 +56,16 @@ Note that DSA does not currently create network interfaces for the "cpu" and
|
||||
|
||||
- the "cpu" port is the Ethernet switch facing side of the management
|
||||
controller, and as such, would create a duplication of feature, since you
|
||||
would get two interfaces for the same conduit: master netdev, and "cpu" netdev
|
||||
would get two interfaces for the same conduit: conduit netdev, and "cpu" netdev
|
||||
|
||||
- the "dsa" port(s) are just conduits between two or more switches, and as such
|
||||
cannot really be used as proper network interfaces either, only the
|
||||
downstream, or the top-most upstream interface makes sense with that model
|
||||
|
||||
NB: for the past 15 years, the DSA subsystem had been making use of the terms
|
||||
"master" (rather than "conduit") and "slave" (rather than "user"). These terms
|
||||
have been removed from the DSA codebase and phased out of the uAPI.
|
||||
|
||||
Switch tagging protocols
|
||||
------------------------
|
||||
|
||||
@ -80,14 +84,14 @@ methods of the ``struct dsa_device_ops`` structure, which are detailed below.
|
||||
Tagging protocols generally fall in one of three categories:
|
||||
|
||||
1. The switch-specific frame header is located before the Ethernet header,
|
||||
shifting to the right (from the perspective of the DSA master's frame
|
||||
shifting to the right (from the perspective of the DSA conduit's frame
|
||||
parser) the MAC DA, MAC SA, EtherType and the entire L2 payload.
|
||||
2. The switch-specific frame header is located before the EtherType, keeping
|
||||
the MAC DA and MAC SA in place from the DSA master's perspective, but
|
||||
the MAC DA and MAC SA in place from the DSA conduit's perspective, but
|
||||
shifting the 'real' EtherType and L2 payload to the right.
|
||||
3. The switch-specific frame header is located at the tail of the packet,
|
||||
keeping all frame headers in place and not altering the view of the packet
|
||||
that the DSA master's frame parser has.
|
||||
that the DSA conduit's frame parser has.
|
||||
|
||||
A tagging protocol may tag all packets with switch tags of the same length, or
|
||||
the tag length might vary (for example packets with PTP timestamps might
|
||||
@ -95,7 +99,7 @@ require an extended switch tag, or there might be one tag length on TX and a
|
||||
different one on RX). Either way, the tagging protocol driver must populate the
|
||||
``struct dsa_device_ops::needed_headroom`` and/or ``struct dsa_device_ops::needed_tailroom``
|
||||
with the length in octets of the longest switch frame header/trailer. The DSA
|
||||
framework will automatically adjust the MTU of the master interface to
|
||||
framework will automatically adjust the MTU of the conduit interface to
|
||||
accommodate for this extra size in order for DSA user ports to support the
|
||||
standard MTU (L2 payload length) of 1500 octets. The ``needed_headroom`` and
|
||||
``needed_tailroom`` properties are also used to request from the network stack,
|
||||
@ -140,18 +144,18 @@ adding or removing the ``ETH_P_EDSA`` EtherType and some padding octets).
|
||||
It is possible to construct cascaded setups of DSA switches even if their
|
||||
tagging protocols are not compatible with one another. In this case, there are
|
||||
no DSA links in this fabric, and each switch constitutes a disjoint DSA switch
|
||||
tree. The DSA links are viewed as simply a pair of a DSA master (the out-facing
|
||||
tree. The DSA links are viewed as simply a pair of a DSA conduit (the out-facing
|
||||
port of the upstream DSA switch) and a CPU port (the in-facing port of the
|
||||
downstream DSA switch).
|
||||
|
||||
The tagging protocol of the attached DSA switch tree can be viewed through the
|
||||
``dsa/tagging`` sysfs attribute of the DSA master::
|
||||
``dsa/tagging`` sysfs attribute of the DSA conduit::
|
||||
|
||||
cat /sys/class/net/eth0/dsa/tagging
|
||||
|
||||
If the hardware and driver are capable, the tagging protocol of the DSA switch
|
||||
tree can be changed at runtime. This is done by writing the new tagging
|
||||
protocol name to the same sysfs device attribute as above (the DSA master and
|
||||
protocol name to the same sysfs device attribute as above (the DSA conduit and
|
||||
all attached switch ports must be down while doing this).
|
||||
|
||||
It is desirable that all tagging protocols are testable with the ``dsa_loop``
|
||||
@ -159,7 +163,7 @@ mockup driver, which can be attached to any network interface. The goal is that
|
||||
any network interface should be capable of transmitting the same packet in the
|
||||
same way, and the tagger should decode the same received packet in the same way
|
||||
regardless of the driver used for the switch control path, and the driver used
|
||||
for the DSA master.
|
||||
for the DSA conduit.
|
||||
|
||||
The transmission of a packet goes through the tagger's ``xmit`` function.
|
||||
The passed ``struct sk_buff *skb`` has ``skb->data`` pointing at
|
||||
@ -183,44 +187,44 @@ virtual DSA user network interface corresponding to the physical front-facing
|
||||
switch port that the packet was received on.
|
||||
|
||||
Since tagging protocols in category 1 and 2 break software (and most often also
|
||||
hardware) packet dissection on the DSA master, features such as RPS (Receive
|
||||
Packet Steering) on the DSA master would be broken. The DSA framework deals
|
||||
hardware) packet dissection on the DSA conduit, features such as RPS (Receive
|
||||
Packet Steering) on the DSA conduit would be broken. The DSA framework deals
|
||||
with this by hooking into the flow dissector and shifting the offset at which
|
||||
the IP header is to be found in the tagged frame as seen by the DSA master.
|
||||
the IP header is to be found in the tagged frame as seen by the DSA conduit.
|
||||
This behavior is automatic based on the ``overhead`` value of the tagging
|
||||
protocol. If not all packets are of equal size, the tagger can implement the
|
||||
``flow_dissect`` method of the ``struct dsa_device_ops`` and override this
|
||||
default behavior by specifying the correct offset incurred by each individual
|
||||
RX packet. Tail taggers do not cause issues to the flow dissector.
|
||||
|
||||
Checksum offload should work with category 1 and 2 taggers when the DSA master
|
||||
Checksum offload should work with category 1 and 2 taggers when the DSA conduit
|
||||
driver declares NETIF_F_HW_CSUM in vlan_features and looks at csum_start and
|
||||
csum_offset. For those cases, DSA will shift the checksum start and offset by
|
||||
the tag size. If the DSA master driver still uses the legacy NETIF_F_IP_CSUM
|
||||
the tag size. If the DSA conduit driver still uses the legacy NETIF_F_IP_CSUM
|
||||
or NETIF_F_IPV6_CSUM in vlan_features, the offload might only work if the
|
||||
offload hardware already expects that specific tag (perhaps due to matching
|
||||
vendors). DSA slaves inherit those flags from the master port, and it is up to
|
||||
vendors). DSA user ports inherit those flags from the conduit, and it is up to
|
||||
the driver to correctly fall back to software checksum when the IP header is not
|
||||
where the hardware expects. If that check is ineffective, the packets might go
|
||||
to the network without a proper checksum (the checksum field will have the
|
||||
pseudo IP header sum). For category 3, when the offload hardware does not
|
||||
already expect the switch tag in use, the checksum must be calculated before any
|
||||
tag is inserted (i.e. inside the tagger). Otherwise, the DSA master would
|
||||
tag is inserted (i.e. inside the tagger). Otherwise, the DSA conduit would
|
||||
include the tail tag in the (software or hardware) checksum calculation. Then,
|
||||
when the tag gets stripped by the switch during transmission, it will leave an
|
||||
incorrect IP checksum in place.
|
||||
|
||||
Due to various reasons (most common being category 1 taggers being associated
|
||||
with DSA-unaware masters, mangling what the master perceives as MAC DA), the
|
||||
tagging protocol may require the DSA master to operate in promiscuous mode, to
|
||||
with DSA-unaware conduits, mangling what the conduit perceives as MAC DA), the
|
||||
tagging protocol may require the DSA conduit to operate in promiscuous mode, to
|
||||
receive all frames regardless of the value of the MAC DA. This can be done by
|
||||
setting the ``promisc_on_master`` property of the ``struct dsa_device_ops``.
|
||||
Note that this assumes a DSA-unaware master driver, which is the norm.
|
||||
setting the ``promisc_on_conduit`` property of the ``struct dsa_device_ops``.
|
||||
Note that this assumes a DSA-unaware conduit driver, which is the norm.
|
||||
|
||||
Master network devices
|
||||
----------------------
|
||||
Conduit network devices
|
||||
-----------------------
|
||||
|
||||
Master network devices are regular, unmodified Linux network device drivers for
|
||||
Conduit network devices are regular, unmodified Linux network device drivers for
|
||||
the CPU/management Ethernet interface. Such a driver might occasionally need to
|
||||
know whether DSA is enabled (e.g.: to enable/disable specific offload features),
|
||||
but the DSA subsystem has been proven to work with industry standard drivers:
|
||||
@ -232,14 +236,14 @@ Ethernet switch.
|
||||
Networking stack hooks
|
||||
----------------------
|
||||
|
||||
When a master netdev is used with DSA, a small hook is placed in the
|
||||
When a conduit netdev is used with DSA, a small hook is placed in the
|
||||
networking stack is in order to have the DSA subsystem process the Ethernet
|
||||
switch specific tagging protocol. DSA accomplishes this by registering a
|
||||
specific (and fake) Ethernet type (later becoming ``skb->protocol``) with the
|
||||
networking stack, this is also known as a ``ptype`` or ``packet_type``. A typical
|
||||
Ethernet Frame receive sequence looks like this:
|
||||
|
||||
Master network device (e.g.: e1000e):
|
||||
Conduit network device (e.g.: e1000e):
|
||||
|
||||
1. Receive interrupt fires:
|
||||
|
||||
@ -269,16 +273,16 @@ Master network device (e.g.: e1000e):
|
||||
|
||||
- inspect and strip switch tag protocol to determine originating port
|
||||
- locate per-port network device
|
||||
- invoke ``eth_type_trans()`` with the DSA slave network device
|
||||
- invoke ``eth_type_trans()`` with the DSA user network device
|
||||
- invoked ``netif_receive_skb()``
|
||||
|
||||
Past this point, the DSA slave network devices get delivered regular Ethernet
|
||||
Past this point, the DSA user network devices get delivered regular Ethernet
|
||||
frames that can be processed by the networking stack.
|
||||
|
||||
Slave network devices
|
||||
---------------------
|
||||
User network devices
|
||||
--------------------
|
||||
|
||||
Slave network devices created by DSA are stacked on top of their master network
|
||||
User network devices created by DSA are stacked on top of their conduit network
|
||||
device, each of these network interfaces will be responsible for being a
|
||||
controlling and data-flowing end-point for each front-panel port of the switch.
|
||||
These interfaces are specialized in order to:
|
||||
@ -289,31 +293,31 @@ These interfaces are specialized in order to:
|
||||
Wake-on-LAN, register dumps...
|
||||
- manage external/internal PHY: link, auto-negotiation, etc.
|
||||
|
||||
These slave network devices have custom net_device_ops and ethtool_ops function
|
||||
These user network devices have custom net_device_ops and ethtool_ops function
|
||||
pointers which allow DSA to introduce a level of layering between the networking
|
||||
stack/ethtool and the switch driver implementation.
|
||||
|
||||
Upon frame transmission from these slave network devices, DSA will look up which
|
||||
Upon frame transmission from these user network devices, DSA will look up which
|
||||
switch tagging protocol is currently registered with these network devices and
|
||||
invoke a specific transmit routine which takes care of adding the relevant
|
||||
switch tag in the Ethernet frames.
|
||||
|
||||
These frames are then queued for transmission using the master network device
|
||||
These frames are then queued for transmission using the conduit network device
|
||||
``ndo_start_xmit()`` function. Since they contain the appropriate switch tag, the
|
||||
Ethernet switch will be able to process these incoming frames from the
|
||||
management interface and deliver them to the physical switch port.
|
||||
|
||||
When using multiple CPU ports, it is possible to stack a LAG (bonding/team)
|
||||
device between the DSA slave devices and the physical DSA masters. The LAG
|
||||
device is thus also a DSA master, but the LAG slave devices continue to be DSA
|
||||
masters as well (just with no user port assigned to them; this is needed for
|
||||
recovery in case the LAG DSA master disappears). Thus, the data path of the LAG
|
||||
DSA master is used asymmetrically. On RX, the ``ETH_P_XDSA`` handler, which
|
||||
calls ``dsa_switch_rcv()``, is invoked early (on the physical DSA master;
|
||||
LAG slave). Therefore, the RX data path of the LAG DSA master is not used.
|
||||
On the other hand, TX takes place linearly: ``dsa_slave_xmit`` calls
|
||||
``dsa_enqueue_skb``, which calls ``dev_queue_xmit`` towards the LAG DSA master.
|
||||
The latter calls ``dev_queue_xmit`` towards one physical DSA master or the
|
||||
device between the DSA user devices and the physical DSA conduits. The LAG
|
||||
device is thus also a DSA conduit, but the LAG slave devices continue to be DSA
|
||||
conduits as well (just with no user port assigned to them; this is needed for
|
||||
recovery in case the LAG DSA conduit disappears). Thus, the data path of the LAG
|
||||
DSA conduit is used asymmetrically. On RX, the ``ETH_P_XDSA`` handler, which
|
||||
calls ``dsa_switch_rcv()``, is invoked early (on the physical DSA conduit;
|
||||
LAG slave). Therefore, the RX data path of the LAG DSA conduit is not used.
|
||||
On the other hand, TX takes place linearly: ``dsa_user_xmit`` calls
|
||||
``dsa_enqueue_skb``, which calls ``dev_queue_xmit`` towards the LAG DSA conduit.
|
||||
The latter calls ``dev_queue_xmit`` towards one physical DSA conduit or the
|
||||
other, and in both cases, the packet exits the system through a hardware path
|
||||
towards the switch.
|
||||
|
||||
@ -352,11 +356,11 @@ perspective::
|
||||
|| swp0 | | swp1 | | swp2 | | swp3 ||
|
||||
++------+-+------+-+------+-+------++
|
||||
|
||||
Slave MDIO bus
|
||||
--------------
|
||||
User MDIO bus
|
||||
-------------
|
||||
|
||||
In order to be able to read to/from a switch PHY built into it, DSA creates a
|
||||
slave MDIO bus which allows a specific switch driver to divert and intercept
|
||||
In order to be able to read to/from a switch PHY built into it, DSA creates an
|
||||
user MDIO bus which allows a specific switch driver to divert and intercept
|
||||
MDIO reads/writes towards specific PHY addresses. In most MDIO-connected
|
||||
switches, these functions would utilize direct or indirect PHY addressing mode
|
||||
to return standard MII registers from the switch builtin PHYs, allowing the PHY
|
||||
@ -364,7 +368,7 @@ library and/or to return link status, link partner pages, auto-negotiation
|
||||
results, etc.
|
||||
|
||||
For Ethernet switches which have both external and internal MDIO buses, the
|
||||
slave MII bus can be utilized to mux/demux MDIO reads and writes towards either
|
||||
user MII bus can be utilized to mux/demux MDIO reads and writes towards either
|
||||
internal or external MDIO devices this switch might be connected to: internal
|
||||
PHYs, external PHYs, or even external switches.
|
||||
|
||||
@ -381,10 +385,10 @@ DSA data structures are defined in ``include/net/dsa.h`` as well as
|
||||
|
||||
- ``dsa_platform_data``: platform device configuration data which can reference
|
||||
a collection of dsa_chip_data structures if multiple switches are cascaded,
|
||||
the master network device this switch tree is attached to needs to be
|
||||
the conduit network device this switch tree is attached to needs to be
|
||||
referenced
|
||||
|
||||
- ``dsa_switch_tree``: structure assigned to the master network device under
|
||||
- ``dsa_switch_tree``: structure assigned to the conduit network device under
|
||||
``dsa_ptr``, this structure references a dsa_platform_data structure as well as
|
||||
the tagging protocol supported by the switch tree, and which receive/transmit
|
||||
function hooks should be invoked, information about the directly attached
|
||||
@ -392,7 +396,7 @@ DSA data structures are defined in ``include/net/dsa.h`` as well as
|
||||
referenced to address individual switches in the tree.
|
||||
|
||||
- ``dsa_switch``: structure describing a switch device in the tree, referencing
|
||||
a ``dsa_switch_tree`` as a backpointer, slave network devices, master network
|
||||
a ``dsa_switch_tree`` as a backpointer, user network devices, conduit network
|
||||
device, and a reference to the backing``dsa_switch_ops``
|
||||
|
||||
- ``dsa_switch_ops``: structure referencing function pointers, see below for a
|
||||
@ -404,7 +408,7 @@ Design limitations
|
||||
Lack of CPU/DSA network devices
|
||||
-------------------------------
|
||||
|
||||
DSA does not currently create slave network devices for the CPU or DSA ports, as
|
||||
DSA does not currently create user network devices for the CPU or DSA ports, as
|
||||
described before. This might be an issue in the following cases:
|
||||
|
||||
- inability to fetch switch CPU port statistics counters using ethtool, which
|
||||
@ -419,7 +423,7 @@ described before. This might be an issue in the following cases:
|
||||
Common pitfalls using DSA setups
|
||||
--------------------------------
|
||||
|
||||
Once a master network device is configured to use DSA (dev->dsa_ptr becomes
|
||||
Once a conduit network device is configured to use DSA (dev->dsa_ptr becomes
|
||||
non-NULL), and the switch behind it expects a tagging protocol, this network
|
||||
interface can only exclusively be used as a conduit interface. Sending packets
|
||||
directly through this interface (e.g.: opening a socket using this interface)
|
||||
@ -440,7 +444,7 @@ DSA currently leverages the following subsystems:
|
||||
MDIO/PHY library
|
||||
----------------
|
||||
|
||||
Slave network devices exposed by DSA may or may not be interfacing with PHY
|
||||
User network devices exposed by DSA may or may not be interfacing with PHY
|
||||
devices (``struct phy_device`` as defined in ``include/linux/phy.h)``, but the DSA
|
||||
subsystem deals with all possible combinations:
|
||||
|
||||
@ -450,7 +454,7 @@ subsystem deals with all possible combinations:
|
||||
- special, non-autonegotiated or non MDIO-managed PHY devices: SFPs, MoCA; a.k.a
|
||||
fixed PHYs
|
||||
|
||||
The PHY configuration is done by the ``dsa_slave_phy_setup()`` function and the
|
||||
The PHY configuration is done by the ``dsa_user_phy_setup()`` function and the
|
||||
logic basically looks like this:
|
||||
|
||||
- if Device Tree is used, the PHY device is looked up using the standard
|
||||
@ -463,7 +467,7 @@ logic basically looks like this:
|
||||
and connected transparently using the special fixed MDIO bus driver
|
||||
|
||||
- finally, if the PHY is built into the switch, as is very common with
|
||||
standalone switch packages, the PHY is probed using the slave MII bus created
|
||||
standalone switch packages, the PHY is probed using the user MII bus created
|
||||
by DSA
|
||||
|
||||
|
||||
@ -472,7 +476,7 @@ SWITCHDEV
|
||||
|
||||
DSA directly utilizes SWITCHDEV when interfacing with the bridge layer, and
|
||||
more specifically with its VLAN filtering portion when configuring VLANs on top
|
||||
of per-port slave network devices. As of today, the only SWITCHDEV objects
|
||||
of per-port user network devices. As of today, the only SWITCHDEV objects
|
||||
supported by DSA are the FDB and VLAN objects.
|
||||
|
||||
Devlink
|
||||
@ -589,8 +593,8 @@ is torn down when the first switch unregisters.
|
||||
It is mandatory for DSA switch drivers to implement the ``shutdown()`` callback
|
||||
of their respective bus, and call ``dsa_switch_shutdown()`` from it (a minimal
|
||||
version of the full teardown performed by ``dsa_unregister_switch()``).
|
||||
The reason is that DSA keeps a reference on the master net device, and if the
|
||||
driver for the master device decides to unbind on shutdown, DSA's reference
|
||||
The reason is that DSA keeps a reference on the conduit net device, and if the
|
||||
driver for the conduit device decides to unbind on shutdown, DSA's reference
|
||||
will block that operation from finalizing.
|
||||
|
||||
Either ``dsa_switch_shutdown()`` or ``dsa_unregister_switch()`` must be called,
|
||||
@ -615,7 +619,7 @@ Switch configuration
|
||||
tag formats.
|
||||
|
||||
- ``change_tag_protocol``: when the default tagging protocol has compatibility
|
||||
problems with the master or other issues, the driver may support changing it
|
||||
problems with the conduit or other issues, the driver may support changing it
|
||||
at runtime, either through a device tree property or through sysfs. In that
|
||||
case, further calls to ``get_tag_protocol`` should report the protocol in
|
||||
current use.
|
||||
@ -643,22 +647,22 @@ Switch configuration
|
||||
PHY cannot be found. In this case, probing of the DSA switch continues
|
||||
without that particular port.
|
||||
|
||||
- ``port_change_master``: method through which the affinity (association used
|
||||
- ``port_change_conduit``: method through which the affinity (association used
|
||||
for traffic termination purposes) between a user port and a CPU port can be
|
||||
changed. By default all user ports from a tree are assigned to the first
|
||||
available CPU port that makes sense for them (most of the times this means
|
||||
the user ports of a tree are all assigned to the same CPU port, except for H
|
||||
topologies as described in commit 2c0b03258b8b). The ``port`` argument
|
||||
represents the index of the user port, and the ``master`` argument represents
|
||||
the new DSA master ``net_device``. The CPU port associated with the new
|
||||
master can be retrieved by looking at ``struct dsa_port *cpu_dp =
|
||||
master->dsa_ptr``. Additionally, the master can also be a LAG device where
|
||||
all the slave devices are physical DSA masters. LAG DSA masters also have a
|
||||
valid ``master->dsa_ptr`` pointer, however this is not unique, but rather a
|
||||
duplicate of the first physical DSA master's (LAG slave) ``dsa_ptr``. In case
|
||||
of a LAG DSA master, a further call to ``port_lag_join`` will be emitted
|
||||
represents the index of the user port, and the ``conduit`` argument represents
|
||||
the new DSA conduit ``net_device``. The CPU port associated with the new
|
||||
conduit can be retrieved by looking at ``struct dsa_port *cpu_dp =
|
||||
conduit->dsa_ptr``. Additionally, the conduit can also be a LAG device where
|
||||
all the slave devices are physical DSA conduits. LAG DSA also have a
|
||||
valid ``conduit->dsa_ptr`` pointer, however this is not unique, but rather a
|
||||
duplicate of the first physical DSA conduit's (LAG slave) ``dsa_ptr``. In case
|
||||
of a LAG DSA conduit, a further call to ``port_lag_join`` will be emitted
|
||||
separately for the physical CPU ports associated with the physical DSA
|
||||
masters, requesting them to create a hardware LAG associated with the LAG
|
||||
conduits, requesting them to create a hardware LAG associated with the LAG
|
||||
interface.
|
||||
|
||||
PHY devices and link management
|
||||
@ -670,16 +674,16 @@ PHY devices and link management
|
||||
should return a 32-bit bitmask of "flags" that is private between the switch
|
||||
driver and the Ethernet PHY driver in ``drivers/net/phy/\*``.
|
||||
|
||||
- ``phy_read``: Function invoked by the DSA slave MDIO bus when attempting to read
|
||||
- ``phy_read``: Function invoked by the DSA user MDIO bus when attempting to read
|
||||
the switch port MDIO registers. If unavailable, return 0xffff for each read.
|
||||
For builtin switch Ethernet PHYs, this function should allow reading the link
|
||||
status, auto-negotiation results, link partner pages, etc.
|
||||
|
||||
- ``phy_write``: Function invoked by the DSA slave MDIO bus when attempting to write
|
||||
- ``phy_write``: Function invoked by the DSA user MDIO bus when attempting to write
|
||||
to the switch port MDIO registers. If unavailable return a negative error
|
||||
code.
|
||||
|
||||
- ``adjust_link``: Function invoked by the PHY library when a slave network device
|
||||
- ``adjust_link``: Function invoked by the PHY library when a user network device
|
||||
is attached to a PHY device. This function is responsible for appropriately
|
||||
configuring the switch port link parameters: speed, duplex, pause based on
|
||||
what the ``phy_device`` is providing.
|
||||
@ -698,14 +702,14 @@ Ethtool operations
|
||||
typically return statistics strings, private flags strings, etc.
|
||||
|
||||
- ``get_ethtool_stats``: ethtool function used to query per-port statistics and
|
||||
return their values. DSA overlays slave network devices general statistics:
|
||||
return their values. DSA overlays user network devices general statistics:
|
||||
RX/TX counters from the network device, with switch driver specific statistics
|
||||
per port
|
||||
|
||||
- ``get_sset_count``: ethtool function used to query the number of statistics items
|
||||
|
||||
- ``get_wol``: ethtool function used to obtain Wake-on-LAN settings per-port, this
|
||||
function may for certain implementations also query the master network device
|
||||
function may for certain implementations also query the conduit network device
|
||||
Wake-on-LAN settings if this interface needs to participate in Wake-on-LAN
|
||||
|
||||
- ``set_wol``: ethtool function used to configure Wake-on-LAN settings per-port,
|
||||
@ -747,13 +751,13 @@ Power management
|
||||
should resume all Ethernet switch activities and re-configure the switch to be
|
||||
in a fully active state
|
||||
|
||||
- ``port_enable``: function invoked by the DSA slave network device ndo_open
|
||||
- ``port_enable``: function invoked by the DSA user network device ndo_open
|
||||
function when a port is administratively brought up, this function should
|
||||
fully enable a given switch port. DSA takes care of marking the port with
|
||||
``BR_STATE_BLOCKING`` if the port is a bridge member, or ``BR_STATE_FORWARDING`` if it
|
||||
was not, and propagating these changes down to the hardware
|
||||
|
||||
- ``port_disable``: function invoked by the DSA slave network device ndo_close
|
||||
- ``port_disable``: function invoked by the DSA user network device ndo_close
|
||||
function when a port is administratively brought down, this function should
|
||||
fully disable a given switch port. DSA takes care of marking the port with
|
||||
``BR_STATE_DISABLED`` and propagating changes to the hardware if this port is
|
||||
|
@ -4,7 +4,7 @@ LAN9303 Ethernet switch driver
|
||||
|
||||
The LAN9303 is a three port 10/100 Mbps ethernet switch with integrated phys for
|
||||
the two external ethernet ports. The third port is an RMII/MII interface to a
|
||||
host master network interface (e.g. fixed link).
|
||||
host conduit network interface (e.g. fixed link).
|
||||
|
||||
|
||||
Driver details
|
||||
|
@ -79,7 +79,7 @@ The hardware tags all traffic internally with a port-based VLAN (pvid), or it
|
||||
decodes the VLAN information from the 802.1Q tag. Advanced VLAN classification
|
||||
is not possible. Once attributed a VLAN tag, frames are checked against the
|
||||
port's membership rules and dropped at ingress if they don't match any VLAN.
|
||||
This behavior is available when switch ports are enslaved to a bridge with
|
||||
This behavior is available when switch ports join a bridge with
|
||||
``vlan_filtering 1``.
|
||||
|
||||
Normally the hardware is not configurable with respect to VLAN awareness, but
|
||||
@ -122,7 +122,7 @@ on egress. Using ``vlan_filtering=1``, the behavior is the other way around:
|
||||
offloaded flows can be steered to TX queues based on the VLAN PCP, but the DSA
|
||||
net devices are no longer able to do that. To inject frames into a hardware TX
|
||||
queue with VLAN awareness active, it is necessary to create a VLAN
|
||||
sub-interface on the DSA master port, and send normal (0x8100) VLAN-tagged
|
||||
sub-interface on the DSA conduit port, and send normal (0x8100) VLAN-tagged
|
||||
towards the switch, with the VLAN PCP bits set appropriately.
|
||||
|
||||
Management traffic (having DMAC 01-80-C2-xx-xx-xx or 01-19-1B-xx-xx-xx) is the
|
||||
@ -389,7 +389,7 @@ MDIO bus and PHY management
|
||||
The SJA1105 does not have an MDIO bus and does not perform in-band AN either.
|
||||
Therefore there is no link state notification coming from the switch device.
|
||||
A board would need to hook up the PHYs connected to the switch to any other
|
||||
MDIO bus available to Linux within the system (e.g. to the DSA master's MDIO
|
||||
MDIO bus available to Linux within the system (e.g. to the DSA conduit's MDIO
|
||||
bus). Link state management then works by the driver manually keeping in sync
|
||||
(over SPI commands) the MAC link speed with the settings negotiated by the PHY.
|
||||
|
||||
|
@ -650,8 +650,8 @@ before a conversion to the new layout is being done behind the scenes!
|
||||
|
||||
Currently, the classic BPF format is being used for JITing on most
|
||||
32-bit architectures, whereas x86-64, aarch64, s390x, powerpc64,
|
||||
sparc64, arm32, riscv64, riscv32 perform JIT compilation from eBPF
|
||||
instruction set.
|
||||
sparc64, arm32, riscv64, riscv32, loongarch64 perform JIT compilation
|
||||
from eBPF instruction set.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
@ -59,7 +59,6 @@ Contents:
|
||||
gtp
|
||||
ila
|
||||
ioam6-sysctl
|
||||
ipddp
|
||||
ip_dynaddr
|
||||
ipsec
|
||||
ip-sysctl
|
||||
@ -107,6 +106,7 @@ Contents:
|
||||
sysfs-tagging
|
||||
tc-actions-env-rules
|
||||
tc-queue-filters
|
||||
tcp_ao
|
||||
tcp-thin
|
||||
team
|
||||
timestamping
|
||||
|
@ -745,6 +745,13 @@ tcp_comp_sack_nr - INTEGER
|
||||
|
||||
Default : 44
|
||||
|
||||
tcp_backlog_ack_defer - BOOLEAN
|
||||
If set, user thread processing socket backlog tries sending
|
||||
one ACK for the whole queue. This helps to avoid potential
|
||||
long latencies at end of a TCP socket syscall.
|
||||
|
||||
Default : true
|
||||
|
||||
tcp_slow_start_after_idle - BOOLEAN
|
||||
If set, provide RFC2861 behavior and time out the congestion
|
||||
window after an idle period. An idle period is defined at
|
||||
@ -1176,6 +1183,19 @@ tcp_plb_cong_thresh - INTEGER
|
||||
|
||||
Default: 128
|
||||
|
||||
tcp_pingpong_thresh - INTEGER
|
||||
The number of estimated data replies sent for estimated incoming data
|
||||
requests that must happen before TCP considers that a connection is a
|
||||
"ping-pong" (request-response) connection for which delayed
|
||||
acknowledgments can provide benefits.
|
||||
|
||||
This threshold is 1 by default, but some applications may need a higher
|
||||
threshold for optimal performance.
|
||||
|
||||
Possible Values: 1 - 255
|
||||
|
||||
Default: 1
|
||||
|
||||
UDP variables
|
||||
=============
|
||||
|
||||
@ -2304,6 +2324,17 @@ accept_ra_pinfo - BOOLEAN
|
||||
- enabled if accept_ra is enabled.
|
||||
- disabled if accept_ra is disabled.
|
||||
|
||||
ra_honor_pio_life - BOOLEAN
|
||||
Whether to use RFC4862 Section 5.5.3e to determine the valid
|
||||
lifetime of an address matching a prefix sent in a Router
|
||||
Advertisement Prefix Information Option.
|
||||
|
||||
- If enabled, the PIO valid lifetime will always be honored.
|
||||
- If disabled, RFC4862 section 5.5.3e is used to determine
|
||||
the valid lifetime of the address.
|
||||
|
||||
Default: 0 (disabled)
|
||||
|
||||
accept_ra_rt_info_min_plen - INTEGER
|
||||
Minimum prefix length of Route Information in RA.
|
||||
|
||||
@ -2471,12 +2502,18 @@ use_tempaddr - INTEGER
|
||||
* -1 (for point-to-point devices and loopback devices)
|
||||
|
||||
temp_valid_lft - INTEGER
|
||||
valid lifetime (in seconds) for temporary addresses.
|
||||
valid lifetime (in seconds) for temporary addresses. If less than the
|
||||
minimum required lifetime (typically 5 seconds), temporary addresses
|
||||
will not be created.
|
||||
|
||||
Default: 172800 (2 days)
|
||||
|
||||
temp_prefered_lft - INTEGER
|
||||
Preferred lifetime (in seconds) for temporary addresses.
|
||||
Preferred lifetime (in seconds) for temporary addresses. If
|
||||
temp_prefered_lft is less than the minimum required lifetime (typically
|
||||
5 seconds), the preferred lifetime is the minimum required. If
|
||||
temp_prefered_lft is greater than temp_valid_lft, the preferred lifetime
|
||||
is temp_valid_lft.
|
||||
|
||||
Default: 86400 (1 day)
|
||||
|
||||
|
@ -1,78 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================================================
|
||||
AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
|
||||
=========================================================
|
||||
|
||||
Documentation ipddp.c
|
||||
|
||||
This file is written by Jay Schulist <jschlst@samba.org>
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
AppleTalk-IP (IPDDP) is the method computers connected to AppleTalk
|
||||
networks can use to communicate via IP. AppleTalk-IP is simply IP datagrams
|
||||
inside AppleTalk packets.
|
||||
|
||||
Through this driver you can either allow your Linux box to communicate
|
||||
IP over an AppleTalk network or you can provide IP gatewaying functions
|
||||
for your AppleTalk users.
|
||||
|
||||
You can currently encapsulate or decapsulate AppleTalk-IP on LocalTalk,
|
||||
EtherTalk and PPPTalk. The only limit on the protocol is that of what
|
||||
kernel AppleTalk layer and drivers are available.
|
||||
|
||||
Each mode requires its own user space software.
|
||||
|
||||
Compiling AppleTalk-IP Decapsulation/Encapsulation
|
||||
==================================================
|
||||
|
||||
AppleTalk-IP decapsulation needs to be compiled into your kernel. You
|
||||
will need to turn on AppleTalk-IP driver support. Then you will need to
|
||||
select ONE of the two options; IP to AppleTalk-IP encapsulation support or
|
||||
AppleTalk-IP to IP decapsulation support. If you compile the driver
|
||||
statically you will only be able to use the driver for the function you have
|
||||
enabled in the kernel. If you compile the driver as a module you can
|
||||
select what mode you want it to run in via a module loading param.
|
||||
ipddp_mode=1 for AppleTalk-IP encapsulation and ipddp_mode=2 for
|
||||
AppleTalk-IP to IP decapsulation.
|
||||
|
||||
Basic instructions for user space tools
|
||||
=======================================
|
||||
|
||||
I will briefly describe the operation of the tools, but you will
|
||||
need to consult the supporting documentation for each set of tools.
|
||||
|
||||
Decapsulation - You will need to download a software package called
|
||||
MacGate. In this distribution there will be a tool called MacRoute
|
||||
which enables you to add routes to the kernel for your Macs by hand.
|
||||
Also the tool MacRegGateWay is included to register the
|
||||
proper IP Gateway and IP addresses for your machine. Included in this
|
||||
distribution is a patch to netatalk-1.4b2+asun2.0a17.2 (available from
|
||||
ftp.u.washington.edu/pub/user-supported/asun/) this patch is optional
|
||||
but it allows automatic adding and deleting of routes for Macs. (Handy
|
||||
for locations with large Mac installations)
|
||||
|
||||
Encapsulation - You will need to download a software daemon called ipddpd.
|
||||
This software expects there to be an AppleTalk-IP gateway on the network.
|
||||
You will also need to add the proper routes to route your Linux box's IP
|
||||
traffic out the ipddp interface.
|
||||
|
||||
Common Uses of ipddp.c
|
||||
----------------------
|
||||
Of course AppleTalk-IP decapsulation and encapsulation, but specifically
|
||||
decapsulation is being used most for connecting LocalTalk networks to
|
||||
IP networks. Although it has been used on EtherTalk networks to allow
|
||||
Macs that are only able to tunnel IP over EtherTalk.
|
||||
|
||||
Encapsulation has been used to allow a Linux box stuck on a LocalTalk
|
||||
network to use IP. It should work equally well if you are stuck on an
|
||||
EtherTalk only network.
|
||||
|
||||
Further Assistance
|
||||
-------------------
|
||||
You can contact me (Jay Schulist <jschlst@samba.org>) with any
|
||||
questions regarding decapsulation or encapsulation. Bradford W. Johnson
|
||||
<johns393@maroon.tc.umn.edu> originally wrote the ipddp.c driver for IP
|
||||
encapsulation in AppleTalk.
|
@ -25,6 +25,17 @@ 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.
|
||||
|
||||
|
@ -7,7 +7,8 @@ Intro
|
||||
=====
|
||||
|
||||
The MSG_ZEROCOPY flag enables copy avoidance for socket send calls.
|
||||
The feature is currently implemented for TCP and UDP sockets.
|
||||
The feature is currently implemented for TCP, UDP and VSOCK (with
|
||||
virtio transport) sockets.
|
||||
|
||||
|
||||
Opportunity and Caveats
|
||||
@ -174,7 +175,9 @@ read_notification() call in the previous snippet. A notification
|
||||
is encoded in the standard error format, sock_extended_err.
|
||||
|
||||
The level and type fields in the control data are protocol family
|
||||
specific, IP_RECVERR or IPV6_RECVERR.
|
||||
specific, IP_RECVERR or IPV6_RECVERR (for TCP or UDP socket).
|
||||
For VSOCK socket, cmsg_level will be SOL_VSOCK and cmsg_type will be
|
||||
VSOCK_RECVERR.
|
||||
|
||||
Error origin is the new type SO_EE_ORIGIN_ZEROCOPY. ee_errno is zero,
|
||||
as explained before, to avoid blocking read and write system calls on
|
||||
@ -235,12 +238,15 @@ Implementation
|
||||
Loopback
|
||||
--------
|
||||
|
||||
For TCP and UDP:
|
||||
Data sent to local sockets can be queued indefinitely if the receive
|
||||
process does not read its socket. Unbound notification latency is not
|
||||
acceptable. For this reason all packets generated with MSG_ZEROCOPY
|
||||
that are looped to a local socket will incur a deferred copy. This
|
||||
includes looping onto packet sockets (e.g., tcpdump) and tun devices.
|
||||
|
||||
For VSOCK:
|
||||
Data path sent to local sockets is the same as for non-local sockets.
|
||||
|
||||
Testing
|
||||
=======
|
||||
@ -254,3 +260,6 @@ instance when run with msg_zerocopy.sh between a veth pair across
|
||||
namespaces, the test will not show any improvement. For testing, the
|
||||
loopback restriction can be temporarily relaxed by making
|
||||
skb_orphan_frags_rx identical to skb_orphan_frags.
|
||||
|
||||
For VSOCK type of socket example can be found in
|
||||
tools/testing/vsock/vsock_test_zerocopy.c.
|
||||
|
@ -99,9 +99,6 @@ Dynamic reconfiguration:
|
||||
Dynamic reconfigurability is a useful addition to netconsole that enables
|
||||
remote logging targets to be dynamically added, removed, or have their
|
||||
parameters reconfigured at runtime from a configfs-based userspace interface.
|
||||
[ Note that the parameters of netconsole targets that were specified/created
|
||||
from the boot/module option are not exposed via this interface, and hence
|
||||
cannot be modified dynamically. ]
|
||||
|
||||
To include this feature, select CONFIG_NETCONSOLE_DYNAMIC when building the
|
||||
netconsole module (or kernel, if netconsole is built-in).
|
||||
@ -155,6 +152,25 @@ You can also update the local interface dynamically. This is especially
|
||||
useful if you want to use interfaces that have newly come up (and may not
|
||||
have existed when netconsole was loaded / initialized).
|
||||
|
||||
Netconsole targets defined at boot time (or module load time) with the
|
||||
`netconsole=` param are assigned the name `cmdline<index>`. For example, the
|
||||
first target in the parameter is named `cmdline0`. You can control and modify
|
||||
these targets by creating configfs directories with the matching name.
|
||||
|
||||
Let's suppose you have two netconsole targets defined at boot time::
|
||||
|
||||
netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc;4444@10.0.0.1/eth1,9353@10.0.0.3/12:34:56:78:9a:bc
|
||||
|
||||
You can modify these targets in runtime by creating the following targets::
|
||||
|
||||
mkdir cmdline0
|
||||
cat cmdline0/remote_ip
|
||||
10.0.0.2
|
||||
|
||||
mkdir cmdline1
|
||||
cat cmdline1/remote_ip
|
||||
10.0.0.3
|
||||
|
||||
Extended console:
|
||||
=================
|
||||
|
||||
|
@ -58,7 +58,9 @@ a page will cause no race conditions is enough.
|
||||
|
||||
.. kernel-doc:: include/net/page_pool/helpers.h
|
||||
:identifiers: page_pool_put_page page_pool_put_full_page
|
||||
page_pool_recycle_direct page_pool_dev_alloc_pages
|
||||
page_pool_recycle_direct page_pool_free_va
|
||||
page_pool_dev_alloc_pages page_pool_dev_alloc_frag
|
||||
page_pool_dev_alloc page_pool_dev_alloc_va
|
||||
page_pool_get_dma_addr page_pool_get_dma_dir
|
||||
|
||||
.. kernel-doc:: net/core/page_pool.c
|
||||
|
@ -178,6 +178,7 @@ Examples::
|
||||
IPSEC # IPsec encapsulation (needs CONFIG_XFRM)
|
||||
NODE_ALLOC # node specific memory allocation
|
||||
NO_TIMESTAMP # disable timestamping
|
||||
SHARED # enable shared SKB
|
||||
pgset 'flag ![name]' Clear a flag to determine behaviour.
|
||||
Note that you might need to use single quote in
|
||||
interactive mode, so that your shell wouldn't expand
|
||||
@ -288,6 +289,16 @@ To avoid breaking existing testbed scripts for using AH type and tunnel mode,
|
||||
you can use "pgset spi SPI_VALUE" to specify which transformation mode
|
||||
to employ.
|
||||
|
||||
Disable shared SKB
|
||||
==================
|
||||
By default, SKBs sent by pktgen are shared (user count > 1).
|
||||
To test with non-shared SKBs, remove the "SHARED" flag by simply setting::
|
||||
|
||||
pg_set "flag !SHARED"
|
||||
|
||||
However, if the "clone_skb" or "burst" parameters are configured, the skb
|
||||
still needs to be held by pktgen for further access. Hence the skb must be
|
||||
shared.
|
||||
|
||||
Current commands and configuration options
|
||||
==========================================
|
||||
@ -357,6 +368,7 @@ Current commands and configuration options
|
||||
IPSEC
|
||||
NODE_ALLOC
|
||||
NO_TIMESTAMP
|
||||
SHARED
|
||||
|
||||
spi (ipsec)
|
||||
|
||||
|
@ -105,6 +105,48 @@ a separate CPU. For interrupt handling, HT has shown no benefit in
|
||||
initial tests, so limit the number of queues to the number of CPU cores
|
||||
in the system.
|
||||
|
||||
Dedicated RSS contexts
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Modern NICs support creating multiple co-existing RSS configurations
|
||||
which are selected based on explicit matching rules. This can be very
|
||||
useful when application wants to constrain the set of queues receiving
|
||||
traffic for e.g. a particular destination port or IP address.
|
||||
The example below shows how to direct all traffic to TCP port 22
|
||||
to queues 0 and 1.
|
||||
|
||||
To create an additional RSS context use::
|
||||
|
||||
# ethtool -X eth0 hfunc toeplitz context new
|
||||
New RSS context is 1
|
||||
|
||||
Kernel reports back the ID of the allocated context (the default, always
|
||||
present RSS context has ID of 0). The new context can be queried and
|
||||
modified using the same APIs as the default context::
|
||||
|
||||
# ethtool -x eth0 context 1
|
||||
RX flow hash indirection table for eth0 with 13 RX ring(s):
|
||||
0: 0 1 2 3 4 5 6 7
|
||||
8: 8 9 10 11 12 0 1 2
|
||||
[...]
|
||||
# ethtool -X eth0 equal 2 context 1
|
||||
# ethtool -x eth0 context 1
|
||||
RX flow hash indirection table for eth0 with 13 RX ring(s):
|
||||
0: 0 1 0 1 0 1 0 1
|
||||
8: 0 1 0 1 0 1 0 1
|
||||
[...]
|
||||
|
||||
To make use of the new context direct traffic to it using an n-tuple
|
||||
filter::
|
||||
|
||||
# ethtool -N eth0 flow-type tcp6 dst-port 22 context 1
|
||||
Added rule with ID 1023
|
||||
|
||||
When done, remove the context and the rule::
|
||||
|
||||
# ethtool -N eth0 delete 1023
|
||||
# ethtool -X eth0 context 1 delete
|
||||
|
||||
|
||||
RPS: Receive Packet Steering
|
||||
============================
|
||||
|
@ -200,10 +200,12 @@ this documentation.
|
||||
when the in-band link state changes - otherwise the link will never
|
||||
come up.
|
||||
|
||||
The :c:func:`validate` method should mask the supplied supported mask,
|
||||
and ``state->advertising`` with the supported ethtool link modes.
|
||||
These are the new ethtool link modes, so bitmask operations must be
|
||||
used. For an example, see ``drivers/net/ethernet/marvell/mvneta.c``.
|
||||
The :c:func:`mac_get_caps` method is optional, and if provided should
|
||||
return the phylink MAC capabilities that are supported for the passed
|
||||
``interface`` mode. In general, there is no need to implement this method.
|
||||
Phylink will use these capabilities in combination with permissible
|
||||
capabilities for ``interface`` to determine the allowable ethtool link
|
||||
modes.
|
||||
|
||||
The :c:func:`mac_link_state` method is used to read the link state
|
||||
from the MAC, and report back the settings that the MAC is currently
|
||||
|
444
Documentation/networking/tcp_ao.rst
Normal file
444
Documentation/networking/tcp_ao.rst
Normal file
@ -0,0 +1,444 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
========================================================
|
||||
TCP Authentication Option Linux implementation (RFC5925)
|
||||
========================================================
|
||||
|
||||
TCP Authentication Option (TCP-AO) provides a TCP extension aimed at verifying
|
||||
segments between trusted peers. It adds a new TCP header option with
|
||||
a Message Authentication Code (MAC). MACs are produced from the content
|
||||
of a TCP segment using a hashing function with a password known to both peers.
|
||||
The intent of TCP-AO is to deprecate TCP-MD5 providing better security,
|
||||
key rotation and support for variety of hashing algorithms.
|
||||
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
.. table:: Short and Limited Comparison of TCP-AO and TCP-MD5
|
||||
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| | TCP-MD5 | TCP-AO |
|
||||
+======================+========================+=======================+
|
||||
|Supported hashing |MD5 |Must support HMAC-SHA1 |
|
||||
|algorithms |(cryptographically weak)|(chosen-prefix attacks)|
|
||||
| | |and CMAC-AES-128 (only |
|
||||
| | |side-channel attacks). |
|
||||
| | |May support any hashing|
|
||||
| | |algorithm. |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Length of MACs (bytes)|16 |Typically 12-16. |
|
||||
| | |Other variants that fit|
|
||||
| | |TCP header permitted. |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Number of keys per |1 |Many |
|
||||
|TCP connection | | |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Possibility to change |Non-practical (both |Supported by protocol |
|
||||
|an active key |peers have to change | |
|
||||
| |them during MSL) | |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Protection against |No |Yes: ignoring them |
|
||||
|ICMP 'hard errors' | |by default on |
|
||||
| | |established connections|
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Protection against |No |Yes: pseudo-header |
|
||||
|traffic-crossing | |includes TCP ports. |
|
||||
|attack | | |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Protection against |No |Sequence Number |
|
||||
|replayed TCP segments | |Extension (SNE) and |
|
||||
| | |Initial Sequence |
|
||||
| | |Numbers (ISNs) |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Supports |Yes |No. ISNs+SNE are needed|
|
||||
|Connectionless Resets | |to correctly sign RST. |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|Standards |RFC 2385 |RFC 5925, RFC 5926 |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|
||||
|
||||
1.1 Frequently Asked Questions (FAQ) with references to RFC 5925
|
||||
----------------------------------------------------------------
|
||||
|
||||
Q: Can either SendID or RecvID be non-unique for the same 4-tuple
|
||||
(srcaddr, srcport, dstaddr, dstport)?
|
||||
|
||||
A: No [3.1]::
|
||||
|
||||
>> The IDs of MKTs MUST NOT overlap where their TCP connection
|
||||
identifiers overlap.
|
||||
|
||||
Q: Can Master Key Tuple (MKT) for an active connection be removed?
|
||||
|
||||
A: No, unless it's copied to Transport Control Block (TCB) [3.1]::
|
||||
|
||||
It is presumed that an MKT affecting a particular connection cannot
|
||||
be destroyed during an active connection -- or, equivalently, that
|
||||
its parameters are copied to an area local to the connection (i.e.,
|
||||
instantiated) and so changes would affect only new connections.
|
||||
|
||||
Q: If an old MKT needs to be deleted, how should it be done in order
|
||||
to not remove it for an active connection? (As it can be still in use
|
||||
at any moment later)
|
||||
|
||||
A: Not specified by RFC 5925, seems to be a problem for key management
|
||||
to ensure that no one uses such MKT before trying to remove it.
|
||||
|
||||
Q: Can an old MKT exist forever and be used by another peer?
|
||||
|
||||
A: It can, it's a key management task to decide when to remove an old key [6.1]::
|
||||
|
||||
Deciding when to start using a key is a performance issue. Deciding
|
||||
when to remove an MKT is a security issue. Invalid MKTs are expected
|
||||
to be removed. TCP-AO provides no mechanism to coordinate their removal,
|
||||
as we consider this a key management operation.
|
||||
|
||||
also [6.1]::
|
||||
|
||||
The only way to avoid reuse of previously used MKTs is to remove the MKT
|
||||
when it is no longer considered permitted.
|
||||
|
||||
Linux TCP-AO will try its best to prevent you from removing a key that's
|
||||
being used, considering it a key management failure. But sine keeping
|
||||
an outdated key may become a security issue and as a peer may
|
||||
unintentionally prevent the removal of an old key by always setting
|
||||
it as RNextKeyID - a forced key removal mechanism is provided, where
|
||||
userspace has to supply KeyID to use instead of the one that's being removed
|
||||
and the kernel will atomically delete the old key, even if the peer is
|
||||
still requesting it. There are no guarantees for force-delete as the peer
|
||||
may yet not have the new key - the TCP connection may just break.
|
||||
Alternatively, one may choose to shut down the socket.
|
||||
|
||||
Q: What happens when a packet is received on a new connection with no known
|
||||
MKT's RecvID?
|
||||
|
||||
A: RFC 5925 specifies that by default it is accepted with a warning logged, but
|
||||
the behaviour can be configured by the user [7.5.1.a]::
|
||||
|
||||
If the segment is a SYN, then this is the first segment of a new
|
||||
connection. Find the matching MKT for this segment, using the segment's
|
||||
socket pair and its TCP-AO KeyID, matched against the MKT's TCP connection
|
||||
identifier and the MKT's RecvID.
|
||||
|
||||
i. If there is no matching MKT, remove TCP-AO from the segment.
|
||||
Proceed with further TCP handling of the segment.
|
||||
NOTE: this presumes that connections that do not match any MKT
|
||||
should be silently accepted, as noted in Section 7.3.
|
||||
|
||||
[7.3]::
|
||||
|
||||
>> A TCP-AO implementation MUST allow for configuration of the behavior
|
||||
of segments with TCP-AO but that do not match an MKT. The initial default
|
||||
of this configuration SHOULD be to silently accept such connections.
|
||||
If this is not the desired case, an MKT can be included to match such
|
||||
connections, or the connection can indicate that TCP-AO is required.
|
||||
Alternately, the configuration can be changed to discard segments with
|
||||
the AO option not matching an MKT.
|
||||
|
||||
[10.2.b]::
|
||||
|
||||
Connections not matching any MKT do not require TCP-AO. Further, incoming
|
||||
segments with TCP-AO are not discarded solely because they include
|
||||
the option, provided they do not match any MKT.
|
||||
|
||||
Note that Linux TCP-AO implementation differs in this aspect. Currently, TCP-AO
|
||||
segments with unknown key signatures are discarded with warnings logged.
|
||||
|
||||
Q: Does the RFC imply centralized kernel key management in any way?
|
||||
(i.e. that a key on all connections MUST be rotated at the same time?)
|
||||
|
||||
A: Not specified. MKTs can be managed in userspace, the only relevant part to
|
||||
key changes is [7.3]::
|
||||
|
||||
>> All TCP segments MUST be checked against the set of MKTs for matching
|
||||
TCP connection identifiers.
|
||||
|
||||
Q: What happens when RNextKeyID requested by a peer is unknown? Should
|
||||
the connection be reset?
|
||||
|
||||
A: It should not, no action needs to be performed [7.5.2.e]::
|
||||
|
||||
ii. If they differ, determine whether the RNextKeyID MKT is ready.
|
||||
|
||||
1. If the MKT corresponding to the segment’s socket pair and RNextKeyID
|
||||
is not available, no action is required (RNextKeyID of a received
|
||||
segment needs to match the MKT’s SendID).
|
||||
|
||||
Q: How current_key is set and when does it change? It is a user-triggered
|
||||
change, or is it by a request from the remote peer? Is it set by the user
|
||||
explicitly, or by a matching rule?
|
||||
|
||||
A: current_key is set by RNextKeyID [6.1]::
|
||||
|
||||
Rnext_key is changed only by manual user intervention or MKT management
|
||||
protocol operation. It is not manipulated by TCP-AO. Current_key is updated
|
||||
by TCP-AO when processing received TCP segments as discussed in the segment
|
||||
processing description in Section 7.5. Note that the algorithm allows
|
||||
the current_key to change to a new MKT, then change back to a previously
|
||||
used MKT (known as "backing up"). This can occur during an MKT change when
|
||||
segments are received out of order, and is considered a feature of TCP-AO,
|
||||
because reordering does not result in drops.
|
||||
|
||||
[7.5.2.e.ii]::
|
||||
|
||||
2. If the matching MKT corresponding to the segment’s socket pair and
|
||||
RNextKeyID is available:
|
||||
|
||||
a. Set current_key to the RNextKeyID MKT.
|
||||
|
||||
Q: If both peers have multiple MKTs matching the connection's socket pair
|
||||
(with different KeyIDs), how should the sender/receiver pick KeyID to use?
|
||||
|
||||
A: Some mechanism should pick the "desired" MKT [3.3]::
|
||||
|
||||
Multiple MKTs may match a single outgoing segment, e.g., when MKTs
|
||||
are being changed. Those MKTs cannot have conflicting IDs (as noted
|
||||
elsewhere), and some mechanism must determine which MKT to use for each
|
||||
given outgoing segment.
|
||||
|
||||
>> An outgoing TCP segment MUST match at most one desired MKT, indicated
|
||||
by the segment’s socket pair. The segment MAY match multiple MKTs, provided
|
||||
that exactly one MKT is indicated as desired. Other information in
|
||||
the segment MAY be used to determine the desired MKT when multiple MKTs
|
||||
match; such information MUST NOT include values in any TCP option fields.
|
||||
|
||||
Q: Can TCP-MD5 connection migrate to TCP-AO (and vice-versa):
|
||||
|
||||
A: No [1]::
|
||||
|
||||
TCP MD5-protected connections cannot be migrated to TCP-AO because TCP MD5
|
||||
does not support any changes to a connection’s security algorithm
|
||||
once established.
|
||||
|
||||
Q: If all MKTs are removed on a connection, can it become a non-TCP-AO signed
|
||||
connection?
|
||||
|
||||
A: [7.5.2] doesn't have the same choice as SYN packet handling in [7.5.1.i]
|
||||
that would allow accepting segments without a sign (which would be insecure).
|
||||
While switching to non-TCP-AO connection is not prohibited directly, it seems
|
||||
what the RFC means. Also, there's a requirement for TCP-AO connections to
|
||||
always have one current_key [3.3]::
|
||||
|
||||
TCP-AO requires that every protected TCP segment match exactly one MKT.
|
||||
|
||||
[3.3]::
|
||||
|
||||
>> An incoming TCP segment including TCP-AO MUST match exactly one MKT,
|
||||
indicated solely by the segment’s socket pair and its TCP-AO KeyID.
|
||||
|
||||
[4.4]::
|
||||
|
||||
One or more MKTs. These are the MKTs that match this connection’s
|
||||
socket pair.
|
||||
|
||||
Q: Can a non-TCP-AO connection become a TCP-AO-enabled one?
|
||||
|
||||
A: No: for already established non-TCP-AO connection it would be impossible
|
||||
to switch using TCP-AO as the traffic key generation requires the initial
|
||||
sequence numbers. Paraphrasing, starting using TCP-AO would require
|
||||
re-establishing the TCP connection.
|
||||
|
||||
2. In-kernel MKTs database vs database in userspace
|
||||
===================================================
|
||||
|
||||
Linux TCP-AO support is implemented using ``setsockopt()s``, in a similar way
|
||||
to TCP-MD5. It means that a userspace application that wants to use TCP-AO
|
||||
should perform ``setsockopt()`` on a TCP socket when it wants to add,
|
||||
remove or rotate MKTs. This approach moves the key management responsibility
|
||||
to userspace as well as decisions on corner cases, i.e. what to do if
|
||||
the peer doesn't respect RNextKeyID; moving more code to userspace, especially
|
||||
responsible for the policy decisions. Besides, it's flexible and scales well
|
||||
(with less locking needed than in the case of an in-kernel database). One also
|
||||
should keep in mind that mainly intended users are BGP processes, not any
|
||||
random applications, which means that compared to IPsec tunnels,
|
||||
no transparency is really needed and modern BGP daemons already have
|
||||
``setsockopt()s`` for TCP-MD5 support.
|
||||
|
||||
.. table:: Considered pros and cons of the approaches
|
||||
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| | ``setsockopt()`` | in-kernel DB |
|
||||
+======================+========================+=======================+
|
||||
| Extendability | ``setsockopt()`` | Netlink messages are |
|
||||
| | commands should be | simple and extendable |
|
||||
| | extendable syscalls | |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| Required userspace | BGP or any application | could be transparent |
|
||||
| changes | that wants TCP-AO needs| as tunnels, providing |
|
||||
| | to perform | something like |
|
||||
| | ``setsockopt()s`` | ``ip tcpao add key`` |
|
||||
| | and do key management | (delete/show/rotate) |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|MKTs removal or adding| harder for userspace | harder for kernel |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| Dump-ability | ``getsockopt()`` | Netlink .dump() |
|
||||
| | | callback |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| Limits on kernel | equal |
|
||||
| resources/memory | |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| Scalability | contention on | contention on |
|
||||
| | ``TCP_LISTEN`` sockets | the whole database |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| Monitoring & warnings| ``TCP_DIAG`` | same Netlink socket |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
| Matching of MKTs | half-problem: only | hard |
|
||||
| | listen sockets | |
|
||||
+----------------------+------------------------+-----------------------+
|
||||
|
||||
|
||||
3. uAPI
|
||||
=======
|
||||
|
||||
Linux provides a set of ``setsockopt()s`` and ``getsockopt()s`` that let
|
||||
userspace manage TCP-AO on a per-socket basis. In order to add/delete MKTs
|
||||
``TCP_AO_ADD_KEY`` and ``TCP_AO_DEL_KEY`` TCP socket options must be used
|
||||
It is not allowed to add a key on an established non-TCP-AO connection
|
||||
as well as to remove the last key from TCP-AO connection.
|
||||
|
||||
``setsockopt(TCP_AO_DEL_KEY)`` command may specify ``tcp_ao_del::current_key``
|
||||
+ ``tcp_ao_del::set_current`` and/or ``tcp_ao_del::rnext``
|
||||
+ ``tcp_ao_del::set_rnext`` which makes such delete "forced": it
|
||||
provides userspace a way to delete a key that's being used and atomically set
|
||||
another one instead. This is not intended for normal use and should be used
|
||||
only when the peer ignores RNextKeyID and keeps requesting/using an old key.
|
||||
It provides a way to force-delete a key that's not trusted but may break
|
||||
the TCP-AO connection.
|
||||
|
||||
The usual/normal key-rotation can be performed with ``setsockopt(TCP_AO_INFO)``.
|
||||
It also provides a uAPI to change per-socket TCP-AO settings, such as
|
||||
ignoring ICMPs, as well as clear per-socket TCP-AO packet counters.
|
||||
The corresponding ``getsockopt(TCP_AO_INFO)`` can be used to get those
|
||||
per-socket TCP-AO settings.
|
||||
|
||||
Another useful command is ``getsockopt(TCP_AO_GET_KEYS)``. One can use it
|
||||
to list all MKTs on a TCP socket or use a filter to get keys for a specific
|
||||
peer and/or sndid/rcvid, VRF L3 interface or get current_key/rnext_key.
|
||||
|
||||
To repair TCP-AO connections ``setsockopt(TCP_AO_REPAIR)`` is available,
|
||||
provided that the user previously has checkpointed/dumped the socket with
|
||||
``getsockopt(TCP_AO_REPAIR)``.
|
||||
|
||||
A tip here for scaled TCP_LISTEN sockets, that may have some thousands TCP-AO
|
||||
keys, is: use filters in ``getsockopt(TCP_AO_GET_KEYS)`` and asynchronous
|
||||
delete with ``setsockopt(TCP_AO_DEL_KEY)``.
|
||||
|
||||
Linux TCP-AO also provides a bunch of segment counters that can be helpful
|
||||
with troubleshooting/debugging issues. Every MKT has good/bad counters
|
||||
that reflect how many packets passed/failed verification.
|
||||
Each TCP-AO socket has the following counters:
|
||||
- for good segments (properly signed)
|
||||
- for bad segments (failed TCP-AO verification)
|
||||
- for segments with unknown keys
|
||||
- for segments where an AO signature was expected, but wasn't found
|
||||
- for the number of ignored ICMPs
|
||||
|
||||
TCP-AO per-socket counters are also duplicated with per-netns counters,
|
||||
exposed with SNMP. Those are ``TCPAOGood``, ``TCPAOBad``, ``TCPAOKeyNotFound``,
|
||||
``TCPAORequired`` and ``TCPAODroppedIcmps``.
|
||||
|
||||
RFC 5925 very permissively specifies how TCP port matching can be done for
|
||||
MKTs::
|
||||
|
||||
TCP connection identifier. A TCP socket pair, i.e., a local IP
|
||||
address, a remote IP address, a TCP local port, and a TCP remote port.
|
||||
Values can be partially specified using ranges (e.g., 2-30), masks
|
||||
(e.g., 0xF0), wildcards (e.g., "*"), or any other suitable indication.
|
||||
|
||||
Currently Linux TCP-AO implementation doesn't provide any TCP port matching.
|
||||
Probably, port ranges are the most flexible for uAPI, but so far
|
||||
not implemented.
|
||||
|
||||
4. ``setsockopt()`` vs ``accept()`` race
|
||||
========================================
|
||||
|
||||
In contrast with TCP-MD5 established connection which has just one key,
|
||||
TCP-AO connections may have many keys, which means that accepted connections
|
||||
on a listen socket may have any amount of keys as well. As copying all those
|
||||
keys on a first properly signed SYN would make the request socket bigger, that
|
||||
would be undesirable. Currently, the implementation doesn't copy keys
|
||||
to request sockets, but rather look them up on the "parent" listener socket.
|
||||
|
||||
The result is that when userspace removes TCP-AO keys, that may break
|
||||
not-yet-established connections on request sockets as well as not removing
|
||||
keys from sockets that were already established, but not yet ``accept()``'ed,
|
||||
hanging in the accept queue.
|
||||
|
||||
The reverse is valid as well: if userspace adds a new key for a peer on
|
||||
a listener socket, the established sockets in accept queue won't
|
||||
have the new keys.
|
||||
|
||||
At this moment, the resolution for the two races:
|
||||
``setsockopt(TCP_AO_ADD_KEY)`` vs ``accept()``
|
||||
and ``setsockopt(TCP_AO_DEL_KEY)`` vs ``accept()`` is delegated to userspace.
|
||||
This means that it's expected that userspace would check the MKTs on the socket
|
||||
that was returned by ``accept()`` to verify that any key rotation that
|
||||
happened on listen socket is reflected on the newly established connection.
|
||||
|
||||
This is a similar "do-nothing" approach to TCP-MD5 from the kernel side and
|
||||
may be changed later by introducing new flags to ``tcp_ao_add``
|
||||
and ``tcp_ao_del``.
|
||||
|
||||
Note that this race is rare for it needs TCP-AO key rotation to happen
|
||||
during the 3-way handshake for the new TCP connection.
|
||||
|
||||
5. Interaction with TCP-MD5
|
||||
===========================
|
||||
|
||||
A TCP connection can not migrate between TCP-AO and TCP-MD5 options. The
|
||||
established sockets that have either AO or MD5 keys are restricted for
|
||||
adding keys of the other option.
|
||||
|
||||
For listening sockets the picture is different: BGP server may want to receive
|
||||
both TCP-AO and (deprecated) TCP-MD5 clients. As a result, both types of keys
|
||||
may be added to TCP_CLOSED or TCP_LISTEN sockets. It's not allowed to add
|
||||
different types of keys for the same peer.
|
||||
|
||||
6. SNE Linux implementation
|
||||
===========================
|
||||
|
||||
RFC 5925 [6.2] describes the algorithm of how to extend TCP sequence numbers
|
||||
with SNE. In short: TCP has to track the previous sequence numbers and set
|
||||
sne_flag when the current SEQ number rolls over. The flag is cleared when
|
||||
both current and previous SEQ numbers cross 0x7fff, which is 32Kb.
|
||||
|
||||
In times when sne_flag is set, the algorithm compares SEQ for each packet with
|
||||
0x7fff and if it's higher than 32Kb, it assumes that the packet should be
|
||||
verified with SNE before the increment. As a result, there's
|
||||
this [0; 32Kb] window, when packets with (SNE - 1) can be accepted.
|
||||
|
||||
Linux implementation simplifies this a bit: as the network stack already tracks
|
||||
the first SEQ byte that ACK is wanted for (snd_una) and the next SEQ byte that
|
||||
is wanted (rcv_nxt) - that's enough information for a rough estimation
|
||||
on where in the 4GB SEQ number space both sender and receiver are.
|
||||
When they roll over to zero, the corresponding SNE gets incremented.
|
||||
|
||||
tcp_ao_compute_sne() is called for each TCP-AO segment. It compares SEQ numbers
|
||||
from the segment with snd_una or rcv_nxt and fits the result into a 2GB window around them,
|
||||
detecting SEQ numbers rolling over. That simplifies the code a lot and only
|
||||
requires SNE numbers to be stored on every TCP-AO socket.
|
||||
|
||||
The 2GB window at first glance seems much more permissive compared to
|
||||
RFC 5926. But that is only used to pick the correct SNE before/after
|
||||
a rollover. It allows more TCP segment replays, but yet all regular
|
||||
TCP checks in tcp_sequence() are applied on the verified segment.
|
||||
So, it trades a bit more permissive acceptance of replayed/retransmitted
|
||||
segments for the simplicity of the algorithm and what seems better behaviour
|
||||
for large TCP windows.
|
||||
|
||||
7. Links
|
||||
========
|
||||
|
||||
RFC 5925 The TCP Authentication Option
|
||||
https://www.rfc-editor.org/rfc/pdfrfc/rfc5925.txt.pdf
|
||||
|
||||
RFC 5926 Cryptographic Algorithms for the TCP Authentication Option (TCP-AO)
|
||||
https://www.rfc-editor.org/rfc/pdfrfc/rfc5926.txt.pdf
|
||||
|
||||
Draft "SHA-2 Algorithm for the TCP Authentication Option (TCP-AO)"
|
||||
https://datatracker.ietf.org/doc/html/draft-nayak-tcp-sha2-03
|
||||
|
||||
RFC 2385 Protection of BGP Sessions via the TCP MD5 Signature Option
|
||||
https://www.rfc-editor.org/rfc/pdfrfc/rfc2385.txt.pdf
|
||||
|
||||
:Author: Dmitry Safonov <dima@arista.com>
|
@ -105,6 +105,13 @@ bpf_tail_call
|
||||
Adding programs that access metadata kfuncs to the ``BPF_MAP_TYPE_PROG_ARRAY``
|
||||
is currently not supported.
|
||||
|
||||
Supported Devices
|
||||
=================
|
||||
|
||||
It is possible to query which kfunc the particular netdev implements via
|
||||
netlink. See ``xdp-rx-metadata-features`` attribute set in
|
||||
``Documentation/netlink/specs/netdev.yaml``.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
|
@ -146,6 +146,7 @@ pull. The git request-pull command can be helpful in this regard; it will
|
||||
format the request as other developers expect, and will also check to be
|
||||
sure that you have remembered to push those changes to the public server.
|
||||
|
||||
.. _development_advancedtopics_reviews:
|
||||
|
||||
Reviewing patches
|
||||
-----------------
|
||||
@ -167,6 +168,12 @@ comments as questions rather than criticisms. Asking "how does the lock
|
||||
get released in this path?" will always work better than stating "the
|
||||
locking here is wrong."
|
||||
|
||||
Another technique that is useful in case of a disagreement is to ask for others
|
||||
to chime in. If a discussion reaches a stalemate after a few exchanges,
|
||||
then call for opinions of other reviewers or maintainers. Often those in
|
||||
agreement with a reviewer remain silent unless called upon.
|
||||
The opinion of multiple people carries exponentially more weight.
|
||||
|
||||
Different developers will review code from different points of view. Some
|
||||
are mostly concerned with coding style and whether code lines have trailing
|
||||
white space. Others will focus primarily on whether the change implemented
|
||||
@ -176,3 +183,14 @@ security issues, duplication of code found elsewhere, adequate
|
||||
documentation, adverse effects on performance, user-space ABI changes, etc.
|
||||
All types of review, if they lead to better code going into the kernel, are
|
||||
welcome and worthwhile.
|
||||
|
||||
There is no strict requirement to use specific tags like ``Reviewed-by``.
|
||||
In fact reviews in plain English are more informative and encouraged
|
||||
even when a tag is provided, e.g. "I looked at aspects A, B and C of this
|
||||
submission and it looks good to me."
|
||||
Some form of a review message or reply is obviously necessary otherwise
|
||||
maintainers will not know that the reviewer has looked at the patch at all!
|
||||
|
||||
Last but not least patch review may become a negative process, focused
|
||||
on pointing out problems. Please throw in a compliment once in a while,
|
||||
particularly for newbies!
|
||||
|
@ -441,6 +441,21 @@ in a way which would break what would normally be considered uAPI.
|
||||
new ``netdevsim`` features must be accompanied by selftests under
|
||||
``tools/testing/selftests/``.
|
||||
|
||||
Reviewer guidance
|
||||
-----------------
|
||||
|
||||
Reviewing other people's patches on the list is highly encouraged,
|
||||
regardless of the level of expertise. For general guidance and
|
||||
helpful tips please see :ref:`development_advancedtopics_reviews`.
|
||||
|
||||
It's safe to assume that netdev maintainers know the community and the level
|
||||
of expertise of the reviewers. The reviewers should not be concerned about
|
||||
their comments impeding or derailing the patch flow.
|
||||
|
||||
Less experienced reviewers are highly encouraged to do more in-depth
|
||||
review of submissions and not focus exclusively on trivial or subjective
|
||||
matters like code formatting, tags etc.
|
||||
|
||||
Testimonials / feedback
|
||||
-----------------------
|
||||
|
||||
|
@ -11,6 +11,20 @@ the ``genetlink-legacy`` protocol level.
|
||||
Specification
|
||||
=============
|
||||
|
||||
Globals
|
||||
-------
|
||||
|
||||
Attributes listed directly at the root level of the spec file.
|
||||
|
||||
version
|
||||
~~~~~~~
|
||||
|
||||
Generic Netlink family version, default is 1.
|
||||
|
||||
``version`` has historically been used to introduce family changes
|
||||
which may break backwards compatibility. Since compatibility breaking changes
|
||||
are generally not allowed ``version`` is very rarely used.
|
||||
|
||||
Attribute type nests
|
||||
--------------------
|
||||
|
||||
@ -168,7 +182,7 @@ members
|
||||
|
||||
- ``name`` - The attribute name of the struct member
|
||||
- ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``,
|
||||
``s16``, ``s32``, ``s64``, ``string`` or ``binary``.
|
||||
``s16``, ``s32``, ``s64``, ``string``, ``binary`` or ``bitfield32``.
|
||||
- ``byte-order`` - ``big-endian`` or ``little-endian``
|
||||
- ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for
|
||||
:ref:`attribute definitions <attribute_properties>`
|
||||
|
@ -86,11 +86,6 @@ name
|
||||
Name of the family. Name identifies the family in a unique way, since
|
||||
the Family IDs are allocated dynamically.
|
||||
|
||||
version
|
||||
~~~~~~~
|
||||
|
||||
Generic Netlink family version, default is 1.
|
||||
|
||||
protocol
|
||||
~~~~~~~~
|
||||
|
||||
@ -408,10 +403,21 @@ This section describes the attribute types supported by the ``genetlink``
|
||||
compatibility level. Refer to documentation of different levels for additional
|
||||
attribute types.
|
||||
|
||||
Scalar integer types
|
||||
Common integer types
|
||||
--------------------
|
||||
|
||||
Fixed-width integer types:
|
||||
``sint`` and ``uint`` represent signed and unsigned 64 bit integers.
|
||||
If the value can fit on 32 bits only 32 bits are carried in netlink
|
||||
messages, otherwise full 64 bits are carried. Note that the payload
|
||||
is only aligned to 4B, so the full 64 bit value may be unaligned!
|
||||
|
||||
Common integer types should be preferred over fix-width types in majority
|
||||
of cases.
|
||||
|
||||
Fix-width integer types
|
||||
-----------------------
|
||||
|
||||
Fixed-width integer types include:
|
||||
``u8``, ``u16``, ``u32``, ``u64``, ``s8``, ``s16``, ``s32``, ``s64``.
|
||||
|
||||
Note that types smaller than 32 bit should be avoided as using them
|
||||
@ -421,6 +427,9 @@ See :ref:`pad_type` for padding of 64 bit attributes.
|
||||
The payload of the attribute is the integer in host order unless ``byte-order``
|
||||
specifies otherwise.
|
||||
|
||||
64 bit values are usually aligned by the kernel but it is recommended
|
||||
that the user space is able to deal with unaligned values.
|
||||
|
||||
.. _pad_type:
|
||||
|
||||
pad
|
||||
|
51
MAINTAINERS
51
MAINTAINERS
@ -1460,7 +1460,6 @@ F: drivers/hwmon/applesmc.c
|
||||
APPLETALK NETWORK LAYER
|
||||
L: netdev@vger.kernel.org
|
||||
S: Odd fixes
|
||||
F: drivers/net/appletalk/
|
||||
F: include/linux/atalk.h
|
||||
F: include/uapi/linux/atalk.h
|
||||
F: net/appletalk/
|
||||
@ -3622,9 +3621,10 @@ F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
|
||||
F: drivers/iio/accel/bma400*
|
||||
|
||||
BPF JIT for ARM
|
||||
M: Shubham Bansal <illusionist.neo@gmail.com>
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
M: Puranjay Mohan <puranjay12@gmail.com>
|
||||
L: bpf@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
S: Maintained
|
||||
F: arch/arm/net/
|
||||
|
||||
BPF JIT for ARM64
|
||||
@ -3804,6 +3804,15 @@ L: bpf@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
K: (?:\b|_)bpf(?:\b|_)
|
||||
|
||||
BPF [NETKIT] (BPF-programmable network device)
|
||||
M: Daniel Borkmann <daniel@iogearbox.net>
|
||||
M: Nikolay Aleksandrov <razor@blackwall.org>
|
||||
L: bpf@vger.kernel.org
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/netkit.c
|
||||
F: include/net/netkit.h
|
||||
|
||||
BPF [NETWORKING] (struct_ops, reuseport)
|
||||
M: Martin KaFai Lau <martin.lau@linux.dev>
|
||||
L: bpf@vger.kernel.org
|
||||
@ -4346,8 +4355,7 @@ F: drivers/net/ethernet/broadcom/bcmsysport.*
|
||||
F: drivers/net/ethernet/broadcom/unimac.h
|
||||
|
||||
BROADCOM TG3 GIGABIT ETHERNET DRIVER
|
||||
M: Siva Reddy Kallam <siva.kallam@broadcom.com>
|
||||
M: Prashant Sreedharan <prashant@broadcom.com>
|
||||
M: Pavan Chebbi <pavan.chebbi@broadcom.com>
|
||||
M: Michael Chan <mchan@broadcom.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
@ -5343,12 +5351,6 @@ M: Bence Csókás <bence98@sch.bme.hu>
|
||||
S: Maintained
|
||||
F: drivers/i2c/busses/i2c-cp2615.c
|
||||
|
||||
CPMAC ETHERNET DRIVER
|
||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/ti/cpmac.c
|
||||
|
||||
CPU FREQUENCY DRIVERS - VEXPRESS SPC ARM BIG LITTLE
|
||||
M: Viresh Kumar <viresh.kumar@linaro.org>
|
||||
M: Sudeep Holla <sudeep.holla@arm.com>
|
||||
@ -6368,6 +6370,17 @@ F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/switch-drive
|
||||
F: drivers/net/ethernet/freescale/dpaa2/dpaa2-switch*
|
||||
F: drivers/net/ethernet/freescale/dpaa2/dpsw*
|
||||
|
||||
DPLL SUBSYSTEM
|
||||
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
|
||||
M: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/driver-api/dpll.rst
|
||||
F: drivers/dpll/*
|
||||
F: include/linux/dpll.h
|
||||
F: include/uapi/linux/dpll.h
|
||||
|
||||
DRBD DRIVER
|
||||
M: Philipp Reisner <philipp.reisner@linbit.com>
|
||||
M: Lars Ellenberg <lars.ellenberg@linbit.com>
|
||||
@ -10476,7 +10489,6 @@ F: drivers/platform/x86/intel/atomisp2/led.c
|
||||
|
||||
INTEL BIOS SAR INT1092 DRIVER
|
||||
M: Shravan Sudhakar <s.shravan@intel.com>
|
||||
M: Intel Corporation <linuxwwan@intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/intel/int1092/
|
||||
@ -10906,7 +10918,6 @@ F: drivers/platform/x86/intel/wmi/thunderbolt.c
|
||||
|
||||
INTEL WWAN IOSM DRIVER
|
||||
M: M Chetan Kumar <m.chetan.kumar@intel.com>
|
||||
M: Intel Corporation <linuxwwan@intel.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/wwan/iosm/
|
||||
@ -13531,7 +13542,6 @@ F: net/dsa/tag_mtk.c
|
||||
|
||||
MEDIATEK T7XX 5G WWAN MODEM DRIVER
|
||||
M: Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
|
||||
M: Intel Corporation <linuxwwan@intel.com>
|
||||
R: Chiranjeevi Rapolu <chiranjeevi.rapolu@linux.intel.com>
|
||||
R: Liu Haijun <haijun.liu@mediatek.com>
|
||||
R: M Chetan Kumar <m.chetan.kumar@linux.intel.com>
|
||||
@ -14376,9 +14386,11 @@ MIPS/LOONGSON1 ARCHITECTURE
|
||||
M: Keguang Zhang <keguang.zhang@gmail.com>
|
||||
L: linux-mips@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml
|
||||
F: arch/mips/include/asm/mach-loongson32/
|
||||
F: arch/mips/loongson32/
|
||||
F: drivers/*/*loongson1*
|
||||
F: drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c
|
||||
|
||||
MIPS/LOONGSON2EF ARCHITECTURE
|
||||
M: Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
@ -14985,10 +14997,11 @@ W: https://github.com/multipath-tcp/mptcp_net-next/wiki
|
||||
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.yaml
|
||||
F: Documentation/networking/mptcp-sysctl.rst
|
||||
F: include/net/mptcp.h
|
||||
F: include/trace/events/mptcp.h
|
||||
F: include/uapi/linux/mptcp.h
|
||||
F: include/uapi/linux/mptcp*.h
|
||||
F: net/mptcp/
|
||||
F: tools/testing/selftests/bpf/*/*mptcp*.c
|
||||
F: tools/testing/selftests/net/mptcp/
|
||||
@ -17957,7 +17970,6 @@ F: arch/mips/boot/dts/ralink/mt7621*
|
||||
|
||||
RALINK RT2X00 WIRELESS LAN DRIVER
|
||||
M: Stanislaw Gruszka <stf_xl@wp.pl>
|
||||
M: Helmut Schaa <helmut.schaa@googlemail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/ralink/rt2x00/
|
||||
@ -23066,7 +23078,7 @@ F: drivers/scsi/vmw_pvscsi.c
|
||||
F: drivers/scsi/vmw_pvscsi.h
|
||||
|
||||
VMWARE VIRTUAL PTP CLOCK DRIVER
|
||||
M: Deep Shah <sdeep@vmware.com>
|
||||
M: Jeff Sipek <jsipek@vmware.com>
|
||||
R: Ajay Kaher <akaher@vmware.com>
|
||||
R: Alexey Makhalov <amakhalov@vmware.com>
|
||||
R: VMware PV-Drivers Reviewers <pv-drivers@vmware.com>
|
||||
@ -23713,6 +23725,11 @@ F: Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml
|
||||
F: drivers/gpio/gpio-xilinx.c
|
||||
F: drivers/gpio/gpio-zynq.c
|
||||
|
||||
XILINX LL TEMAC ETHERNET DRIVER
|
||||
L: netdev@vger.kernel.org
|
||||
S: Orphan
|
||||
F: drivers/net/ethernet/xilinx/ll_temac*
|
||||
|
||||
XILINX PWM DRIVER
|
||||
M: Sean Anderson <sean.anderson@seco.com>
|
||||
S: Maintained
|
||||
|
@ -2,6 +2,7 @@
|
||||
/*
|
||||
* Just-In-Time compiler for eBPF filters on 32bit ARM
|
||||
*
|
||||
* Copyright (c) 2023 Puranjay Mohan <puranjay12@gmail.com>
|
||||
* Copyright (c) 2017 Shubham Bansal <illusionist.neo@gmail.com>
|
||||
* Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
|
||||
*/
|
||||
@ -15,6 +16,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/hwcap.h>
|
||||
@ -228,6 +230,44 @@ static u32 jit_mod32(u32 dividend, u32 divisor)
|
||||
return dividend % divisor;
|
||||
}
|
||||
|
||||
static s32 jit_sdiv32(s32 dividend, s32 divisor)
|
||||
{
|
||||
return dividend / divisor;
|
||||
}
|
||||
|
||||
static s32 jit_smod32(s32 dividend, s32 divisor)
|
||||
{
|
||||
return dividend % divisor;
|
||||
}
|
||||
|
||||
/* Wrappers for 64-bit div/mod */
|
||||
static u64 jit_udiv64(u64 dividend, u64 divisor)
|
||||
{
|
||||
return div64_u64(dividend, divisor);
|
||||
}
|
||||
|
||||
static u64 jit_mod64(u64 dividend, u64 divisor)
|
||||
{
|
||||
u64 rem;
|
||||
|
||||
div64_u64_rem(dividend, divisor, &rem);
|
||||
return rem;
|
||||
}
|
||||
|
||||
static s64 jit_sdiv64(s64 dividend, s64 divisor)
|
||||
{
|
||||
return div64_s64(dividend, divisor);
|
||||
}
|
||||
|
||||
static s64 jit_smod64(s64 dividend, s64 divisor)
|
||||
{
|
||||
u64 q;
|
||||
|
||||
q = div64_s64(dividend, divisor);
|
||||
|
||||
return dividend - q * divisor;
|
||||
}
|
||||
|
||||
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
|
||||
{
|
||||
inst |= (cond << 28);
|
||||
@ -333,6 +373,9 @@ static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8)
|
||||
#define ARM_LDRD_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRD_I, rt, rn, off)
|
||||
#define ARM_LDRH_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, rn, off)
|
||||
|
||||
#define ARM_LDRSH_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRSH_I, rt, rn, off)
|
||||
#define ARM_LDRSB_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRSB_I, rt, rn, off)
|
||||
|
||||
#define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off)
|
||||
#define ARM_STRB_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, rn, off)
|
||||
#define ARM_STRD_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_STRD_I, rt, rn, off)
|
||||
@ -474,17 +517,18 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
|
||||
return to - from - 2;
|
||||
}
|
||||
|
||||
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
||||
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op, u8 sign)
|
||||
{
|
||||
const int exclude_mask = BIT(ARM_R0) | BIT(ARM_R1);
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
u32 dst;
|
||||
|
||||
#if __LINUX_ARM_ARCH__ == 7
|
||||
if (elf_hwcap & HWCAP_IDIVA) {
|
||||
if (op == BPF_DIV)
|
||||
emit(ARM_UDIV(rd, rm, rn), ctx);
|
||||
else {
|
||||
emit(ARM_UDIV(ARM_IP, rm, rn), ctx);
|
||||
if (op == BPF_DIV) {
|
||||
emit(sign ? ARM_SDIV(rd, rm, rn) : ARM_UDIV(rd, rm, rn), ctx);
|
||||
} else {
|
||||
emit(sign ? ARM_SDIV(ARM_IP, rm, rn) : ARM_UDIV(ARM_IP, rm, rn), ctx);
|
||||
emit(ARM_MLS(rd, rn, ARM_IP, rm), ctx);
|
||||
}
|
||||
return;
|
||||
@ -512,8 +556,19 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
||||
emit(ARM_PUSH(CALLER_MASK & ~exclude_mask), ctx);
|
||||
|
||||
/* Call appropriate function */
|
||||
emit_mov_i(ARM_IP, op == BPF_DIV ?
|
||||
(u32)jit_udiv32 : (u32)jit_mod32, ctx);
|
||||
if (sign) {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_sdiv32;
|
||||
else
|
||||
dst = (u32)jit_smod32;
|
||||
} else {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_udiv32;
|
||||
else
|
||||
dst = (u32)jit_mod32;
|
||||
}
|
||||
|
||||
emit_mov_i(ARM_IP, dst, ctx);
|
||||
emit_blx_r(ARM_IP, ctx);
|
||||
|
||||
/* Restore caller-saved registers from stack */
|
||||
@ -530,6 +585,78 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
||||
emit(ARM_MOV_R(ARM_R0, tmp[1]), ctx);
|
||||
}
|
||||
|
||||
static inline void emit_udivmod64(const s8 *rd, const s8 *rm, const s8 *rn, struct jit_ctx *ctx,
|
||||
u8 op, u8 sign)
|
||||
{
|
||||
u32 dst;
|
||||
|
||||
/* Push caller-saved registers on stack */
|
||||
emit(ARM_PUSH(CALLER_MASK), ctx);
|
||||
|
||||
/*
|
||||
* As we are implementing 64-bit div/mod as function calls, We need to put the dividend in
|
||||
* R0-R1 and the divisor in R2-R3. As we have already pushed these registers on the stack,
|
||||
* we can recover them later after returning from the function call.
|
||||
*/
|
||||
if (rm[1] != ARM_R0 || rn[1] != ARM_R2) {
|
||||
/*
|
||||
* Move Rm to {R1, R0} if it is not already there.
|
||||
*/
|
||||
if (rm[1] != ARM_R0) {
|
||||
if (rn[1] == ARM_R0)
|
||||
emit(ARM_PUSH(BIT(ARM_R0) | BIT(ARM_R1)), ctx);
|
||||
emit(ARM_MOV_R(ARM_R1, rm[0]), ctx);
|
||||
emit(ARM_MOV_R(ARM_R0, rm[1]), ctx);
|
||||
if (rn[1] == ARM_R0) {
|
||||
emit(ARM_POP(BIT(ARM_R2) | BIT(ARM_R3)), ctx);
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Move Rn to {R3, R2} if it is not already there.
|
||||
*/
|
||||
if (rn[1] != ARM_R2) {
|
||||
emit(ARM_MOV_R(ARM_R3, rn[0]), ctx);
|
||||
emit(ARM_MOV_R(ARM_R2, rn[1]), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
cont:
|
||||
|
||||
/* Call appropriate function */
|
||||
if (sign) {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_sdiv64;
|
||||
else
|
||||
dst = (u32)jit_smod64;
|
||||
} else {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_udiv64;
|
||||
else
|
||||
dst = (u32)jit_mod64;
|
||||
}
|
||||
|
||||
emit_mov_i(ARM_IP, dst, ctx);
|
||||
emit_blx_r(ARM_IP, ctx);
|
||||
|
||||
/* Save return value */
|
||||
if (rd[1] != ARM_R0) {
|
||||
emit(ARM_MOV_R(rd[0], ARM_R1), ctx);
|
||||
emit(ARM_MOV_R(rd[1], ARM_R0), ctx);
|
||||
}
|
||||
|
||||
/* Recover {R3, R2} and {R1, R0} from stack if they are not Rd */
|
||||
if (rd[1] != ARM_R0 && rd[1] != ARM_R2) {
|
||||
emit(ARM_POP(CALLER_MASK), ctx);
|
||||
} else if (rd[1] != ARM_R0) {
|
||||
emit(ARM_POP(BIT(ARM_R0) | BIT(ARM_R1)), ctx);
|
||||
emit(ARM_ADD_I(ARM_SP, ARM_SP, 8), ctx);
|
||||
} else {
|
||||
emit(ARM_ADD_I(ARM_SP, ARM_SP, 8), ctx);
|
||||
emit(ARM_POP(BIT(ARM_R2) | BIT(ARM_R3)), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is the translated BPF register on stack? */
|
||||
static bool is_stacked(s8 reg)
|
||||
{
|
||||
@ -744,12 +871,16 @@ static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
|
||||
}
|
||||
|
||||
/* dst = src (4 bytes)*/
|
||||
static inline void emit_a32_mov_r(const s8 dst, const s8 src,
|
||||
static inline void emit_a32_mov_r(const s8 dst, const s8 src, const u8 off,
|
||||
struct jit_ctx *ctx) {
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
s8 rt;
|
||||
|
||||
rt = arm_bpf_get_reg32(src, tmp[0], ctx);
|
||||
if (off && off != 32) {
|
||||
emit(ARM_LSL_I(rt, rt, 32 - off), ctx);
|
||||
emit(ARM_ASR_I(rt, rt, 32 - off), ctx);
|
||||
}
|
||||
arm_bpf_put_reg32(dst, rt, ctx);
|
||||
}
|
||||
|
||||
@ -758,15 +889,15 @@ static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
|
||||
const s8 src[],
|
||||
struct jit_ctx *ctx) {
|
||||
if (!is64) {
|
||||
emit_a32_mov_r(dst_lo, src_lo, ctx);
|
||||
emit_a32_mov_r(dst_lo, src_lo, 0, ctx);
|
||||
if (!ctx->prog->aux->verifier_zext)
|
||||
/* Zero out high 4 bytes */
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
} else if (__LINUX_ARM_ARCH__ < 6 &&
|
||||
ctx->cpu_architecture < CPU_ARCH_ARMv5TE) {
|
||||
/* complete 8 byte move */
|
||||
emit_a32_mov_r(dst_lo, src_lo, ctx);
|
||||
emit_a32_mov_r(dst_hi, src_hi, ctx);
|
||||
emit_a32_mov_r(dst_lo, src_lo, 0, ctx);
|
||||
emit_a32_mov_r(dst_hi, src_hi, 0, ctx);
|
||||
} else if (is_stacked(src_lo) && is_stacked(dst_lo)) {
|
||||
const u8 *tmp = bpf2a32[TMP_REG_1];
|
||||
|
||||
@ -782,6 +913,24 @@ static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
|
||||
}
|
||||
}
|
||||
|
||||
/* dst = (signed)src */
|
||||
static inline void emit_a32_movsx_r64(const bool is64, const u8 off, const s8 dst[], const s8 src[],
|
||||
struct jit_ctx *ctx) {
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
const s8 *rt;
|
||||
|
||||
rt = arm_bpf_get_reg64(dst, tmp, ctx);
|
||||
|
||||
emit_a32_mov_r(dst_lo, src_lo, off, ctx);
|
||||
if (!is64) {
|
||||
if (!ctx->prog->aux->verifier_zext)
|
||||
/* Zero out high 4 bytes */
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
} else {
|
||||
emit(ARM_ASR_I(rt[0], rt[1], 31), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shift operations */
|
||||
static inline void emit_a32_alu_i(const s8 dst, const u32 val,
|
||||
struct jit_ctx *ctx, const u8 op) {
|
||||
@ -1026,6 +1175,24 @@ static bool is_ldst_imm(s16 off, const u8 size)
|
||||
return -off_max <= off && off <= off_max;
|
||||
}
|
||||
|
||||
static bool is_ldst_imm8(s16 off, const u8 size)
|
||||
{
|
||||
s16 off_max = 0;
|
||||
|
||||
switch (size) {
|
||||
case BPF_B:
|
||||
off_max = 0xff;
|
||||
break;
|
||||
case BPF_W:
|
||||
off_max = 0xfff;
|
||||
break;
|
||||
case BPF_H:
|
||||
off_max = 0xff;
|
||||
break;
|
||||
}
|
||||
return -off_max <= off && off <= off_max;
|
||||
}
|
||||
|
||||
/* *(size *)(dst + off) = src */
|
||||
static inline void emit_str_r(const s8 dst, const s8 src[],
|
||||
s16 off, struct jit_ctx *ctx, const u8 sz){
|
||||
@ -1105,6 +1272,50 @@ static inline void emit_ldx_r(const s8 dst[], const s8 src,
|
||||
arm_bpf_put_reg64(dst, rd, ctx);
|
||||
}
|
||||
|
||||
/* dst = *(signed size*)(src + off) */
|
||||
static inline void emit_ldsx_r(const s8 dst[], const s8 src,
|
||||
s16 off, struct jit_ctx *ctx, const u8 sz){
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
const s8 *rd = is_stacked(dst_lo) ? tmp : dst;
|
||||
s8 rm = src;
|
||||
int add_off;
|
||||
|
||||
if (!is_ldst_imm8(off, sz)) {
|
||||
/*
|
||||
* offset does not fit in the load/store immediate,
|
||||
* construct an ADD instruction to apply the offset.
|
||||
*/
|
||||
add_off = imm8m(off);
|
||||
if (add_off > 0) {
|
||||
emit(ARM_ADD_I(tmp[0], src, add_off), ctx);
|
||||
rm = tmp[0];
|
||||
} else {
|
||||
emit_a32_mov_i(tmp[0], off, ctx);
|
||||
emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx);
|
||||
rm = tmp[0];
|
||||
}
|
||||
off = 0;
|
||||
}
|
||||
|
||||
switch (sz) {
|
||||
case BPF_B:
|
||||
/* Load a Byte with sign extension*/
|
||||
emit(ARM_LDRSB_I(rd[1], rm, off), ctx);
|
||||
break;
|
||||
case BPF_H:
|
||||
/* Load a HalfWord with sign extension*/
|
||||
emit(ARM_LDRSH_I(rd[1], rm, off), ctx);
|
||||
break;
|
||||
case BPF_W:
|
||||
/* Load a Word*/
|
||||
emit(ARM_LDR_I(rd[1], rm, off), ctx);
|
||||
break;
|
||||
}
|
||||
/* Carry the sign extension to upper 32 bits */
|
||||
emit(ARM_ASR_I(rd[0], rd[1], 31), ctx);
|
||||
arm_bpf_put_reg64(dst, rd, ctx);
|
||||
}
|
||||
|
||||
/* Arithmatic Operation */
|
||||
static inline void emit_ar_r(const u8 rd, const u8 rt, const u8 rm,
|
||||
const u8 rn, struct jit_ctx *ctx, u8 op,
|
||||
@ -1385,7 +1596,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
break;
|
||||
}
|
||||
emit_a32_mov_r64(is64, dst, src, ctx);
|
||||
if (insn->off)
|
||||
emit_a32_movsx_r64(is64, insn->off, dst, src, ctx);
|
||||
else
|
||||
emit_a32_mov_r64(is64, dst, src, ctx);
|
||||
break;
|
||||
case BPF_K:
|
||||
/* Sign-extend immediate value to destination reg */
|
||||
@ -1461,7 +1675,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
rt = src_lo;
|
||||
break;
|
||||
}
|
||||
emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code));
|
||||
emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code), off);
|
||||
arm_bpf_put_reg32(dst_lo, rd_lo, ctx);
|
||||
if (!ctx->prog->aux->verifier_zext)
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
@ -1470,7 +1684,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
goto notyet;
|
||||
rd = arm_bpf_get_reg64(dst, tmp2, ctx);
|
||||
switch (BPF_SRC(code)) {
|
||||
case BPF_X:
|
||||
rs = arm_bpf_get_reg64(src, tmp, ctx);
|
||||
break;
|
||||
case BPF_K:
|
||||
rs = tmp;
|
||||
emit_a32_mov_se_i64(is64, rs, imm, ctx);
|
||||
break;
|
||||
}
|
||||
emit_udivmod64(rd, rd, rs, ctx, BPF_OP(code), off);
|
||||
arm_bpf_put_reg64(dst, rd, ctx);
|
||||
break;
|
||||
/* dst = dst << imm */
|
||||
/* dst = dst >> imm */
|
||||
/* dst = dst >> imm (signed) */
|
||||
@ -1545,10 +1771,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
break;
|
||||
/* dst = htole(dst) */
|
||||
/* dst = htobe(dst) */
|
||||
case BPF_ALU | BPF_END | BPF_FROM_LE:
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
||||
case BPF_ALU | BPF_END | BPF_FROM_LE: /* also BPF_TO_LE */
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE: /* also BPF_TO_BE */
|
||||
/* dst = bswap(dst) */
|
||||
case BPF_ALU64 | BPF_END | BPF_FROM_LE: /* also BPF_TO_LE */
|
||||
rd = arm_bpf_get_reg64(dst, tmp, ctx);
|
||||
if (BPF_SRC(code) == BPF_FROM_LE)
|
||||
if (BPF_SRC(code) == BPF_FROM_LE && BPF_CLASS(code) != BPF_ALU64)
|
||||
goto emit_bswap_uxt;
|
||||
switch (imm) {
|
||||
case 16:
|
||||
@ -1603,8 +1831,15 @@ exit:
|
||||
case BPF_LDX | BPF_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_MEM | BPF_B:
|
||||
case BPF_LDX | BPF_MEM | BPF_DW:
|
||||
/* LDSX: dst = *(signed size *)(src + off) */
|
||||
case BPF_LDX | BPF_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_W:
|
||||
rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
|
||||
emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
|
||||
if (BPF_MODE(insn->code) == BPF_MEMSX)
|
||||
emit_ldsx_r(dst, rn, off, ctx, BPF_SIZE(code));
|
||||
else
|
||||
emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
|
||||
break;
|
||||
/* speculation barrier */
|
||||
case BPF_ST | BPF_NOSPEC:
|
||||
@ -1761,10 +1996,15 @@ go_jmp:
|
||||
break;
|
||||
/* JMP OFF */
|
||||
case BPF_JMP | BPF_JA:
|
||||
case BPF_JMP32 | BPF_JA:
|
||||
{
|
||||
if (off == 0)
|
||||
if (BPF_CLASS(code) == BPF_JMP32 && imm != 0)
|
||||
jmp_offset = bpf2a32_offset(i + imm, i, ctx);
|
||||
else if (BPF_CLASS(code) == BPF_JMP && off != 0)
|
||||
jmp_offset = bpf2a32_offset(i + off, i, ctx);
|
||||
else
|
||||
break;
|
||||
jmp_offset = bpf2a32_offset(i+off, i, ctx);
|
||||
|
||||
check_imm24(jmp_offset);
|
||||
emit(ARM_B(jmp_offset), ctx);
|
||||
break;
|
||||
|
@ -79,9 +79,11 @@
|
||||
#define ARM_INST_LDST__IMM12 0x00000fff
|
||||
#define ARM_INST_LDRB_I 0x05500000
|
||||
#define ARM_INST_LDRB_R 0x07d00000
|
||||
#define ARM_INST_LDRSB_I 0x015000d0
|
||||
#define ARM_INST_LDRD_I 0x014000d0
|
||||
#define ARM_INST_LDRH_I 0x015000b0
|
||||
#define ARM_INST_LDRH_R 0x019000b0
|
||||
#define ARM_INST_LDRSH_I 0x015000f0
|
||||
#define ARM_INST_LDR_I 0x05100000
|
||||
#define ARM_INST_LDR_R 0x07900000
|
||||
|
||||
@ -137,6 +139,7 @@
|
||||
#define ARM_INST_TST_I 0x03100000
|
||||
|
||||
#define ARM_INST_UDIV 0x0730f010
|
||||
#define ARM_INST_SDIV 0x0710f010
|
||||
|
||||
#define ARM_INST_UMULL 0x00800090
|
||||
|
||||
@ -265,6 +268,7 @@
|
||||
#define ARM_TST_I(rn, imm) _AL3_I(ARM_INST_TST, 0, rn, imm)
|
||||
|
||||
#define ARM_UDIV(rd, rn, rm) (ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
|
||||
#define ARM_SDIV(rd, rn, rm) (ARM_INST_SDIV | (rd) << 16 | (rn) | (rm) << 8)
|
||||
|
||||
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
|
||||
| (rd_lo) << 12 | (rm) << 8 | rn)
|
||||
|
@ -13,7 +13,7 @@
|
||||
/ {
|
||||
aliases {
|
||||
ethernet0 = ð0;
|
||||
/* for dsa slave device */
|
||||
/* for DSA user port device */
|
||||
ethernet1 = &switch0port1;
|
||||
ethernet2 = &switch0port2;
|
||||
ethernet3 = &switch0port3;
|
||||
|
@ -288,7 +288,7 @@ static bool is_lsi_offset(int offset, int scale)
|
||||
static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
|
||||
{
|
||||
const struct bpf_prog *prog = ctx->prog;
|
||||
const bool is_main_prog = prog->aux->func_idx == 0;
|
||||
const bool is_main_prog = !bpf_is_subprog(prog);
|
||||
const u8 r6 = bpf2a64[BPF_REG_6];
|
||||
const u8 r7 = bpf2a64[BPF_REG_7];
|
||||
const u8 r8 = bpf2a64[BPF_REG_8];
|
||||
|
@ -556,7 +556,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
EMIT6_PCREL_RILC(0xc0040000, 0, jit->prologue_plt);
|
||||
jit->prologue_plt_ret = jit->prg;
|
||||
|
||||
if (fp->aux->func_idx == 0) {
|
||||
if (!bpf_is_subprog(fp)) {
|
||||
/* Initialize the tail call counter in the main program. */
|
||||
/* xc STK_OFF_TCCNT(4,%r15),STK_OFF_TCCNT(%r15) */
|
||||
_EMIT6(0xd703f000 | STK_OFF_TCCNT, 0xf000 | STK_OFF_TCCNT);
|
||||
@ -670,15 +670,18 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)
|
||||
static int get_probe_mem_regno(const u8 *insn)
|
||||
{
|
||||
/*
|
||||
* insn must point to llgc, llgh, llgf or lg, which have destination
|
||||
* register at the same position.
|
||||
* 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 llgc, llgh, llgf and lg prefix */
|
||||
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] != 0x04 && /* lg */
|
||||
insn[5] != 0x77 && /* lgb */
|
||||
insn[5] != 0x15 && /* lgh */
|
||||
insn[5] != 0x14) /* lgf */
|
||||
return -1;
|
||||
return insn[1] >> 4;
|
||||
}
|
||||
@ -776,6 +779,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
int i, bool extra_pass, u32 stack_depth)
|
||||
{
|
||||
struct bpf_insn *insn = &fp->insnsi[i];
|
||||
s16 branch_oc_off = insn->off;
|
||||
u32 dst_reg = insn->dst_reg;
|
||||
u32 src_reg = insn->src_reg;
|
||||
int last, insn_count = 1;
|
||||
@ -788,22 +792,55 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
int err;
|
||||
|
||||
if (BPF_CLASS(insn->code) == BPF_LDX &&
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEM)
|
||||
(BPF_MODE(insn->code) == BPF_PROBE_MEM ||
|
||||
BPF_MODE(insn->code) == BPF_PROBE_MEMSX))
|
||||
probe_prg = jit->prg;
|
||||
|
||||
switch (insn->code) {
|
||||
/*
|
||||
* BPF_MOV
|
||||
*/
|
||||
case BPF_ALU | BPF_MOV | BPF_X: /* dst = (u32) src */
|
||||
/* llgfr %dst,%src */
|
||||
EMIT4(0xb9160000, dst_reg, src_reg);
|
||||
if (insn_is_zext(&insn[1]))
|
||||
insn_count = 2;
|
||||
case BPF_ALU | BPF_MOV | BPF_X:
|
||||
switch (insn->off) {
|
||||
case 0: /* DST = (u32) SRC */
|
||||
/* llgfr %dst,%src */
|
||||
EMIT4(0xb9160000, dst_reg, src_reg);
|
||||
if (insn_is_zext(&insn[1]))
|
||||
insn_count = 2;
|
||||
break;
|
||||
case 8: /* DST = (u32)(s8) SRC */
|
||||
/* lbr %dst,%src */
|
||||
EMIT4(0xb9260000, dst_reg, src_reg);
|
||||
/* llgfr %dst,%dst */
|
||||
EMIT4(0xb9160000, dst_reg, dst_reg);
|
||||
break;
|
||||
case 16: /* DST = (u32)(s16) SRC */
|
||||
/* lhr %dst,%src */
|
||||
EMIT4(0xb9270000, dst_reg, src_reg);
|
||||
/* llgfr %dst,%dst */
|
||||
EMIT4(0xb9160000, dst_reg, dst_reg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */
|
||||
/* lgr %dst,%src */
|
||||
EMIT4(0xb9040000, dst_reg, src_reg);
|
||||
case BPF_ALU64 | BPF_MOV | BPF_X:
|
||||
switch (insn->off) {
|
||||
case 0: /* DST = SRC */
|
||||
/* lgr %dst,%src */
|
||||
EMIT4(0xb9040000, dst_reg, src_reg);
|
||||
break;
|
||||
case 8: /* DST = (s8) SRC */
|
||||
/* lgbr %dst,%src */
|
||||
EMIT4(0xb9060000, dst_reg, src_reg);
|
||||
break;
|
||||
case 16: /* DST = (s16) SRC */
|
||||
/* lghr %dst,%src */
|
||||
EMIT4(0xb9070000, dst_reg, src_reg);
|
||||
break;
|
||||
case 32: /* DST = (s32) SRC */
|
||||
/* lgfr %dst,%src */
|
||||
EMIT4(0xb9140000, dst_reg, src_reg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BPF_ALU | BPF_MOV | BPF_K: /* dst = (u32) imm */
|
||||
/* llilf %dst,imm */
|
||||
@ -912,66 +949,115 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
/*
|
||||
* BPF_DIV / BPF_MOD
|
||||
*/
|
||||
case BPF_ALU | BPF_DIV | BPF_X: /* dst = (u32) dst / (u32) src */
|
||||
case BPF_ALU | BPF_MOD | BPF_X: /* dst = (u32) dst % (u32) src */
|
||||
case BPF_ALU | BPF_DIV | BPF_X:
|
||||
case BPF_ALU | BPF_MOD | BPF_X:
|
||||
{
|
||||
int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
|
||||
|
||||
/* lhi %w0,0 */
|
||||
EMIT4_IMM(0xa7080000, REG_W0, 0);
|
||||
/* lr %w1,%dst */
|
||||
EMIT2(0x1800, REG_W1, dst_reg);
|
||||
/* dlr %w0,%src */
|
||||
EMIT4(0xb9970000, REG_W0, src_reg);
|
||||
switch (off) {
|
||||
case 0: /* dst = (u32) dst {/,%} (u32) src */
|
||||
/* xr %w0,%w0 */
|
||||
EMIT2(0x1700, REG_W0, REG_W0);
|
||||
/* lr %w1,%dst */
|
||||
EMIT2(0x1800, REG_W1, dst_reg);
|
||||
/* dlr %w0,%src */
|
||||
EMIT4(0xb9970000, REG_W0, src_reg);
|
||||
break;
|
||||
case 1: /* dst = (u32) ((s32) dst {/,%} (s32) src) */
|
||||
/* lgfr %r1,%dst */
|
||||
EMIT4(0xb9140000, REG_W1, dst_reg);
|
||||
/* dsgfr %r0,%src */
|
||||
EMIT4(0xb91d0000, REG_W0, src_reg);
|
||||
break;
|
||||
}
|
||||
/* llgfr %dst,%rc */
|
||||
EMIT4(0xb9160000, dst_reg, rc_reg);
|
||||
if (insn_is_zext(&insn[1]))
|
||||
insn_count = 2;
|
||||
break;
|
||||
}
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X: /* dst = dst / src */
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X: /* dst = dst % src */
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
{
|
||||
int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
|
||||
|
||||
/* lghi %w0,0 */
|
||||
EMIT4_IMM(0xa7090000, REG_W0, 0);
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* dlgr %w0,%dst */
|
||||
EMIT4(0xb9870000, REG_W0, src_reg);
|
||||
switch (off) {
|
||||
case 0: /* dst = dst {/,%} src */
|
||||
/* lghi %w0,0 */
|
||||
EMIT4_IMM(0xa7090000, REG_W0, 0);
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* dlgr %w0,%src */
|
||||
EMIT4(0xb9870000, REG_W0, src_reg);
|
||||
break;
|
||||
case 1: /* dst = (s64) dst {/,%} (s64) src */
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* dsgr %w0,%src */
|
||||
EMIT4(0xb90d0000, REG_W0, src_reg);
|
||||
break;
|
||||
}
|
||||
/* lgr %dst,%rc */
|
||||
EMIT4(0xb9040000, dst_reg, rc_reg);
|
||||
break;
|
||||
}
|
||||
case BPF_ALU | BPF_DIV | BPF_K: /* dst = (u32) dst / (u32) imm */
|
||||
case BPF_ALU | BPF_MOD | BPF_K: /* dst = (u32) dst % (u32) imm */
|
||||
case BPF_ALU | BPF_DIV | BPF_K:
|
||||
case BPF_ALU | BPF_MOD | BPF_K:
|
||||
{
|
||||
int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
|
||||
|
||||
if (imm == 1) {
|
||||
if (BPF_OP(insn->code) == BPF_MOD)
|
||||
/* lhgi %dst,0 */
|
||||
/* lghi %dst,0 */
|
||||
EMIT4_IMM(0xa7090000, dst_reg, 0);
|
||||
else
|
||||
EMIT_ZERO(dst_reg);
|
||||
break;
|
||||
}
|
||||
/* lhi %w0,0 */
|
||||
EMIT4_IMM(0xa7080000, REG_W0, 0);
|
||||
/* lr %w1,%dst */
|
||||
EMIT2(0x1800, REG_W1, dst_reg);
|
||||
if (!is_first_pass(jit) && can_use_ldisp_for_lit32(jit)) {
|
||||
/* dl %w0,<d(imm)>(%l) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0097, REG_W0, REG_0, REG_L,
|
||||
EMIT_CONST_U32(imm));
|
||||
switch (off) {
|
||||
case 0: /* dst = (u32) dst {/,%} (u32) imm */
|
||||
/* xr %w0,%w0 */
|
||||
EMIT2(0x1700, REG_W0, REG_W0);
|
||||
/* lr %w1,%dst */
|
||||
EMIT2(0x1800, REG_W1, dst_reg);
|
||||
/* dl %w0,<d(imm)>(%l) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0097, REG_W0, REG_0,
|
||||
REG_L, EMIT_CONST_U32(imm));
|
||||
break;
|
||||
case 1: /* dst = (s32) dst {/,%} (s32) imm */
|
||||
/* lgfr %r1,%dst */
|
||||
EMIT4(0xb9140000, REG_W1, dst_reg);
|
||||
/* dsgf %r0,<d(imm)>(%l) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x001d, REG_W0, REG_0,
|
||||
REG_L, EMIT_CONST_U32(imm));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* lgfrl %dst,imm */
|
||||
EMIT6_PCREL_RILB(0xc40c0000, dst_reg,
|
||||
_EMIT_CONST_U32(imm));
|
||||
jit->seen |= SEEN_LITERAL;
|
||||
/* dlr %w0,%dst */
|
||||
EMIT4(0xb9970000, REG_W0, dst_reg);
|
||||
switch (off) {
|
||||
case 0: /* dst = (u32) dst {/,%} (u32) imm */
|
||||
/* xr %w0,%w0 */
|
||||
EMIT2(0x1700, REG_W0, REG_W0);
|
||||
/* lr %w1,%dst */
|
||||
EMIT2(0x1800, REG_W1, dst_reg);
|
||||
/* lrl %dst,imm */
|
||||
EMIT6_PCREL_RILB(0xc40d0000, dst_reg,
|
||||
_EMIT_CONST_U32(imm));
|
||||
jit->seen |= SEEN_LITERAL;
|
||||
/* dlr %w0,%dst */
|
||||
EMIT4(0xb9970000, REG_W0, dst_reg);
|
||||
break;
|
||||
case 1: /* dst = (s32) dst {/,%} (s32) imm */
|
||||
/* lgfr %w1,%dst */
|
||||
EMIT4(0xb9140000, REG_W1, dst_reg);
|
||||
/* lgfrl %dst,imm */
|
||||
EMIT6_PCREL_RILB(0xc40c0000, dst_reg,
|
||||
_EMIT_CONST_U32(imm));
|
||||
jit->seen |= SEEN_LITERAL;
|
||||
/* dsgr %w0,%dst */
|
||||
EMIT4(0xb90d0000, REG_W0, dst_reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* llgfr %dst,%rc */
|
||||
EMIT4(0xb9160000, dst_reg, rc_reg);
|
||||
@ -979,8 +1065,8 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
insn_count = 2;
|
||||
break;
|
||||
}
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K: /* dst = dst / imm */
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K: /* dst = dst % imm */
|
||||
case BPF_ALU64 | BPF_DIV | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
{
|
||||
int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;
|
||||
|
||||
@ -990,21 +1076,50 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
EMIT4_IMM(0xa7090000, dst_reg, 0);
|
||||
break;
|
||||
}
|
||||
/* lghi %w0,0 */
|
||||
EMIT4_IMM(0xa7090000, REG_W0, 0);
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
|
||||
/* dlg %w0,<d(imm)>(%l) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0087, REG_W0, REG_0, REG_L,
|
||||
EMIT_CONST_U64(imm));
|
||||
switch (off) {
|
||||
case 0: /* dst = dst {/,%} imm */
|
||||
/* lghi %w0,0 */
|
||||
EMIT4_IMM(0xa7090000, REG_W0, 0);
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* dlg %w0,<d(imm)>(%l) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0087, REG_W0, REG_0,
|
||||
REG_L, EMIT_CONST_U64(imm));
|
||||
break;
|
||||
case 1: /* dst = (s64) dst {/,%} (s64) imm */
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* dsg %w0,<d(imm)>(%l) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x000d, REG_W0, REG_0,
|
||||
REG_L, EMIT_CONST_U64(imm));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* lgrl %dst,imm */
|
||||
EMIT6_PCREL_RILB(0xc4080000, dst_reg,
|
||||
_EMIT_CONST_U64(imm));
|
||||
jit->seen |= SEEN_LITERAL;
|
||||
/* dlgr %w0,%dst */
|
||||
EMIT4(0xb9870000, REG_W0, dst_reg);
|
||||
switch (off) {
|
||||
case 0: /* dst = dst {/,%} imm */
|
||||
/* lghi %w0,0 */
|
||||
EMIT4_IMM(0xa7090000, REG_W0, 0);
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* lgrl %dst,imm */
|
||||
EMIT6_PCREL_RILB(0xc4080000, dst_reg,
|
||||
_EMIT_CONST_U64(imm));
|
||||
jit->seen |= SEEN_LITERAL;
|
||||
/* dlgr %w0,%dst */
|
||||
EMIT4(0xb9870000, REG_W0, dst_reg);
|
||||
break;
|
||||
case 1: /* dst = (s64) dst {/,%} (s64) imm */
|
||||
/* lgr %w1,%dst */
|
||||
EMIT4(0xb9040000, REG_W1, dst_reg);
|
||||
/* lgrl %dst,imm */
|
||||
EMIT6_PCREL_RILB(0xc4080000, dst_reg,
|
||||
_EMIT_CONST_U64(imm));
|
||||
jit->seen |= SEEN_LITERAL;
|
||||
/* dsgr %w0,%dst */
|
||||
EMIT4(0xb90d0000, REG_W0, dst_reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* lgr %dst,%rc */
|
||||
EMIT4(0xb9040000, dst_reg, rc_reg);
|
||||
@ -1217,6 +1332,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
}
|
||||
break;
|
||||
case BPF_ALU | BPF_END | BPF_FROM_LE:
|
||||
case BPF_ALU64 | BPF_END | BPF_FROM_LE:
|
||||
switch (imm) {
|
||||
case 16: /* dst = (u16) cpu_to_le16(dst) */
|
||||
/* lrvr %dst,%dst */
|
||||
@ -1374,6 +1490,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
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) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0077, dst_reg, src_reg, REG_0, off);
|
||||
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) */
|
||||
@ -1382,6 +1504,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
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) */
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0015, dst_reg, src_reg, REG_0, off);
|
||||
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:
|
||||
/* llgf %dst,off(%src) */
|
||||
@ -1390,6 +1518,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
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:
|
||||
/* lgf %dst,off(%src) */
|
||||
jit->seen |= SEEN_MEM;
|
||||
EMIT6_DISP_LH(0xe3000000, 0x0014, dst_reg, src_reg, REG_0, off);
|
||||
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) */
|
||||
@ -1570,6 +1704,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
* instruction itself (loop) and for BPF with offset 0 we
|
||||
* branch to the instruction behind the branch.
|
||||
*/
|
||||
case BPF_JMP32 | BPF_JA: /* if (true) */
|
||||
branch_oc_off = imm;
|
||||
fallthrough;
|
||||
case BPF_JMP | BPF_JA: /* if (true) */
|
||||
mask = 0xf000; /* j */
|
||||
goto branch_oc;
|
||||
@ -1738,14 +1875,16 @@ branch_xu:
|
||||
break;
|
||||
branch_oc:
|
||||
if (!is_first_pass(jit) &&
|
||||
can_use_rel(jit, addrs[i + off + 1])) {
|
||||
can_use_rel(jit, addrs[i + branch_oc_off + 1])) {
|
||||
/* brc mask,off */
|
||||
EMIT4_PCREL_RIC(0xa7040000,
|
||||
mask >> 12, addrs[i + off + 1]);
|
||||
mask >> 12,
|
||||
addrs[i + branch_oc_off + 1]);
|
||||
} else {
|
||||
/* brcl mask,off */
|
||||
EMIT6_PCREL_RILC(0xc0040000,
|
||||
mask >> 12, addrs[i + off + 1]);
|
||||
mask >> 12,
|
||||
addrs[i + branch_oc_off + 1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/unwind.h>
|
||||
|
||||
static bool all_callee_regs_used[4] = {true, true, true, true};
|
||||
|
||||
static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
|
||||
{
|
||||
@ -255,6 +258,14 @@ struct jit_context {
|
||||
/* Number of bytes that will be skipped on tailcall */
|
||||
#define X86_TAIL_CALL_OFFSET (11 + ENDBR_INSN_SIZE)
|
||||
|
||||
static void push_r12(u8 **pprog)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
EMIT2(0x41, 0x54); /* push r12 */
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void push_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
@ -270,6 +281,14 @@ static void push_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void pop_r12(u8 **pprog)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
EMIT2(0x41, 0x5C); /* pop r12 */
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void pop_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
@ -291,7 +310,8 @@ static void pop_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
* while jumping to another program
|
||||
*/
|
||||
static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
|
||||
bool tail_call_reachable, bool is_subprog)
|
||||
bool tail_call_reachable, bool is_subprog,
|
||||
bool is_exception_cb)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
@ -303,12 +323,30 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
|
||||
prog += X86_PATCH_SIZE;
|
||||
if (!ebpf_from_cbpf) {
|
||||
if (tail_call_reachable && !is_subprog)
|
||||
/* When it's the entry of the whole tailcall context,
|
||||
* zeroing rax means initialising tail_call_cnt.
|
||||
*/
|
||||
EMIT2(0x31, 0xC0); /* xor eax, eax */
|
||||
else
|
||||
/* Keep the same instruction layout. */
|
||||
EMIT2(0x66, 0x90); /* nop2 */
|
||||
}
|
||||
EMIT1(0x55); /* push rbp */
|
||||
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
||||
/* Exception callback receives FP as third parameter */
|
||||
if (is_exception_cb) {
|
||||
EMIT3(0x48, 0x89, 0xF4); /* mov rsp, rsi */
|
||||
EMIT3(0x48, 0x89, 0xD5); /* mov rbp, rdx */
|
||||
/* The main frame must have exception_boundary as true, so we
|
||||
* first restore those callee-saved regs from stack, before
|
||||
* reusing the stack frame.
|
||||
*/
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
/* Reset the stack frame. */
|
||||
EMIT3(0x48, 0x89, 0xEC); /* mov rsp, rbp */
|
||||
} else {
|
||||
EMIT1(0x55); /* push rbp */
|
||||
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
||||
}
|
||||
|
||||
/* X86_TAIL_CALL_OFFSET is here */
|
||||
EMIT_ENDBR();
|
||||
@ -467,7 +505,8 @@ static void emit_return(u8 **pprog, u8 *ip)
|
||||
* goto *(prog->bpf_func + prologue_size);
|
||||
* out:
|
||||
*/
|
||||
static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||
static void emit_bpf_tail_call_indirect(struct bpf_prog *bpf_prog,
|
||||
u8 **pprog, bool *callee_regs_used,
|
||||
u32 stack_depth, u8 *ip,
|
||||
struct jit_context *ctx)
|
||||
{
|
||||
@ -517,7 +556,12 @@ static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||
offset = ctx->tail_call_indirect_label - (prog + 2 - start);
|
||||
EMIT2(X86_JE, offset); /* je out */
|
||||
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
} else {
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
|
||||
EMIT1(0x58); /* pop rax */
|
||||
if (stack_depth)
|
||||
@ -541,7 +585,8 @@ static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke,
|
||||
static void emit_bpf_tail_call_direct(struct bpf_prog *bpf_prog,
|
||||
struct bpf_jit_poke_descriptor *poke,
|
||||
u8 **pprog, u8 *ip,
|
||||
bool *callee_regs_used, u32 stack_depth,
|
||||
struct jit_context *ctx)
|
||||
@ -570,7 +615,13 @@ static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke,
|
||||
emit_jump(&prog, (u8 *)poke->tailcall_target + X86_PATCH_SIZE,
|
||||
poke->tailcall_bypass);
|
||||
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
} else {
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
|
||||
EMIT1(0x58); /* pop rax */
|
||||
if (stack_depth)
|
||||
EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8));
|
||||
@ -1018,6 +1069,10 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op)
|
||||
|
||||
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
|
||||
|
||||
/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
|
||||
#define RESTORE_TAIL_CALL_CNT(stack) \
|
||||
EMIT3_off32(0x48, 0x8B, 0x85, -round_up(stack, 8) - 8)
|
||||
|
||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
|
||||
int oldproglen, struct jit_context *ctx, bool jmp_padding)
|
||||
{
|
||||
@ -1041,8 +1096,20 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
||||
|
||||
emit_prologue(&prog, bpf_prog->aux->stack_depth,
|
||||
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
|
||||
bpf_prog->aux->func_idx != 0);
|
||||
push_callee_regs(&prog, callee_regs_used);
|
||||
bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
|
||||
/* Exception callback will clobber callee regs for its own use, and
|
||||
* restore the original callee regs from main prog's stack frame.
|
||||
*/
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
/* We also need to save r12, which is not mapped to any BPF
|
||||
* register, as we throw after entry into the kernel, which may
|
||||
* overwrite r12.
|
||||
*/
|
||||
push_r12(&prog);
|
||||
push_callee_regs(&prog, all_callee_regs_used);
|
||||
} else {
|
||||
push_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
|
||||
ilen = prog - temp;
|
||||
if (rw_image)
|
||||
@ -1623,9 +1690,7 @@ st: if (is_imm8(insn->off))
|
||||
|
||||
func = (u8 *) __bpf_call_base + imm32;
|
||||
if (tail_call_reachable) {
|
||||
/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
|
||||
EMIT3_off32(0x48, 0x8B, 0x85,
|
||||
-round_up(bpf_prog->aux->stack_depth, 8) - 8);
|
||||
RESTORE_TAIL_CALL_CNT(bpf_prog->aux->stack_depth);
|
||||
if (!imm32)
|
||||
return -EINVAL;
|
||||
offs = 7 + x86_call_depth_emit_accounting(&prog, func);
|
||||
@ -1641,13 +1706,15 @@ st: if (is_imm8(insn->off))
|
||||
|
||||
case BPF_JMP | BPF_TAIL_CALL:
|
||||
if (imm32)
|
||||
emit_bpf_tail_call_direct(&bpf_prog->aux->poke_tab[imm32 - 1],
|
||||
emit_bpf_tail_call_direct(bpf_prog,
|
||||
&bpf_prog->aux->poke_tab[imm32 - 1],
|
||||
&prog, image + addrs[i - 1],
|
||||
callee_regs_used,
|
||||
bpf_prog->aux->stack_depth,
|
||||
ctx);
|
||||
else
|
||||
emit_bpf_tail_call_indirect(&prog,
|
||||
emit_bpf_tail_call_indirect(bpf_prog,
|
||||
&prog,
|
||||
callee_regs_used,
|
||||
bpf_prog->aux->stack_depth,
|
||||
image + addrs[i - 1],
|
||||
@ -1900,7 +1967,12 @@ emit_jmp:
|
||||
seen_exit = true;
|
||||
/* Update cleanup_addr */
|
||||
ctx->cleanup_addr = proglen;
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
} else {
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
EMIT1(0xC9); /* leave */
|
||||
emit_return(&prog, image + addrs[i - 1] + (prog - temp));
|
||||
break;
|
||||
@ -2400,6 +2472,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
* [ ... ]
|
||||
* [ stack_arg2 ]
|
||||
* RBP - arg_stack_off [ stack_arg1 ]
|
||||
* RSP [ tail_call_cnt ] BPF_TRAMP_F_TAIL_CALL_CTX
|
||||
*/
|
||||
|
||||
/* room for return value of orig_call or fentry prog */
|
||||
@ -2464,6 +2537,8 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
else
|
||||
/* sub rsp, stack_size */
|
||||
EMIT4(0x48, 0x83, 0xEC, stack_size);
|
||||
if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
EMIT1(0x50); /* push rax */
|
||||
/* mov QWORD PTR [rbp - rbx_off], rbx */
|
||||
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_6, -rbx_off);
|
||||
|
||||
@ -2516,9 +2591,15 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
restore_regs(m, &prog, regs_off);
|
||||
save_args(m, &prog, arg_stack_off, true);
|
||||
|
||||
if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
/* Before calling the original function, restore the
|
||||
* tail_call_cnt from stack to rax.
|
||||
*/
|
||||
RESTORE_TAIL_CALL_CNT(stack_size);
|
||||
|
||||
if (flags & BPF_TRAMP_F_ORIG_STACK) {
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, 8);
|
||||
EMIT2(0xff, 0xd0); /* call *rax */
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, 8);
|
||||
EMIT2(0xff, 0xd3); /* call *rbx */
|
||||
} else {
|
||||
/* call original function */
|
||||
if (emit_rsb_call(&prog, orig_call, prog)) {
|
||||
@ -2569,7 +2650,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
} else if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
/* Before running the original function, restore the
|
||||
* tail_call_cnt from stack to rax.
|
||||
*/
|
||||
RESTORE_TAIL_CALL_CNT(stack_size);
|
||||
|
||||
/* restore return value of orig_call or fentry prog back into RAX */
|
||||
if (save_ret)
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8);
|
||||
@ -2913,3 +2999,29 @@ void bpf_jit_free(struct bpf_prog *prog)
|
||||
|
||||
bpf_prog_unlock_free(prog);
|
||||
}
|
||||
|
||||
bool bpf_jit_supports_exceptions(void)
|
||||
{
|
||||
/* We unwind through both kernel frames (starting from within bpf_throw
|
||||
* call) and BPF frames. Therefore we require ORC unwinder to be enabled
|
||||
* to walk kernel frames and reach BPF frames in the stack trace.
|
||||
*/
|
||||
return IS_ENABLED(CONFIG_UNWINDER_ORC);
|
||||
}
|
||||
|
||||
void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
|
||||
{
|
||||
#if defined(CONFIG_UNWINDER_ORC)
|
||||
struct unwind_state state;
|
||||
unsigned long addr;
|
||||
|
||||
for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
|
||||
unwind_next_frame(&state)) {
|
||||
addr = unwind_get_return_address(&state);
|
||||
if (!addr || !consume_fn(cookie, (u64)addr, (u64)state.sp, (u64)state.bp))
|
||||
break;
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
WARN(1, "verification of programs using bpf_throw should have failed\n");
|
||||
}
|
||||
|
@ -243,4 +243,6 @@ source "drivers/hte/Kconfig"
|
||||
|
||||
source "drivers/cdx/Kconfig"
|
||||
|
||||
source "drivers/dpll/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -197,5 +197,6 @@ obj-$(CONFIG_PECI) += peci/
|
||||
obj-$(CONFIG_HTE) += hte/
|
||||
obj-$(CONFIG_DRM_ACCEL) += accel/
|
||||
obj-$(CONFIG_CDX_BUS) += cdx/
|
||||
obj-$(CONFIG_DPLL) += dpll/
|
||||
|
||||
obj-$(CONFIG_S390) += s390/
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/openprom.h>
|
||||
#include <asm/oplib.h>
|
||||
@ -2520,18 +2520,12 @@ static int fore200e_init(struct fore200e *fore200e, struct device *parent)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SBUS
|
||||
static const struct of_device_id fore200e_sba_match[];
|
||||
static int fore200e_sba_probe(struct platform_device *op)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct fore200e *fore200e;
|
||||
static int index = 0;
|
||||
int err;
|
||||
|
||||
match = of_match_device(fore200e_sba_match, &op->dev);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
|
||||
if (!fore200e)
|
||||
return -ENOMEM;
|
||||
|
@ -118,6 +118,7 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
#define BTMTKSDIO_FUNC_ENABLED 3
|
||||
#define BTMTKSDIO_PATCH_ENABLED 4
|
||||
#define BTMTKSDIO_HW_RESET_ACTIVE 5
|
||||
#define BTMTKSDIO_BT_WAKE_ENABLED 6
|
||||
|
||||
struct mtkbtsdio_hdr {
|
||||
__le16 len;
|
||||
@ -554,7 +555,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
/* Disable interrupt */
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
txrx_timeout = jiffies + 5 * HZ;
|
||||
|
||||
@ -576,7 +577,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
if ((int_status & FW_MAILBOX_INT) &&
|
||||
bdev->data->chipid == 0x7921) {
|
||||
sdio_writel(bdev->func, PH2DSM0R_DRIVER_OWN,
|
||||
MTK_REG_PH2DSM0R, 0);
|
||||
MTK_REG_PH2DSM0R, NULL);
|
||||
}
|
||||
|
||||
if (int_status & FW_OWN_BACK_INT)
|
||||
@ -608,7 +609,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
} while (int_status || time_is_before_jiffies(txrx_timeout));
|
||||
|
||||
/* Enable interrupt */
|
||||
sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, 0);
|
||||
sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
@ -620,8 +621,14 @@ static void btmtksdio_interrupt(struct sdio_func *func)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = sdio_get_drvdata(func);
|
||||
|
||||
if (test_bit(BTMTKSDIO_BT_WAKE_ENABLED, &bdev->tx_state)) {
|
||||
if (bdev->hdev->suspended)
|
||||
pm_wakeup_event(bdev->dev, 0);
|
||||
clear_bit(BTMTKSDIO_BT_WAKE_ENABLED, &bdev->tx_state);
|
||||
}
|
||||
|
||||
/* Disable interrupt */
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
schedule_work(&bdev->txrx_work);
|
||||
}
|
||||
@ -1454,6 +1461,23 @@ static int btmtksdio_runtime_suspend(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_system_suspend(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct btmtksdio_dev *bdev;
|
||||
|
||||
bdev = sdio_get_drvdata(func);
|
||||
if (!bdev)
|
||||
return 0;
|
||||
|
||||
if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
|
||||
return 0;
|
||||
|
||||
set_bit(BTMTKSDIO_BT_WAKE_ENABLED, &bdev->tx_state);
|
||||
|
||||
return btmtksdio_runtime_suspend(dev);
|
||||
}
|
||||
|
||||
static int btmtksdio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
@ -1474,8 +1498,16 @@ static int btmtksdio_runtime_resume(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(btmtksdio_pm_ops, btmtksdio_runtime_suspend,
|
||||
btmtksdio_runtime_resume, NULL);
|
||||
static int btmtksdio_system_resume(struct device *dev)
|
||||
{
|
||||
return btmtksdio_runtime_resume(dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops btmtksdio_pm_ops = {
|
||||
SYSTEM_SLEEP_PM_OPS(btmtksdio_system_suspend, btmtksdio_system_resume)
|
||||
RUNTIME_PM_OPS(btmtksdio_runtime_suspend, btmtksdio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
#define BTMTKSDIO_PM_OPS (&btmtksdio_pm_ops)
|
||||
#else /* CONFIG_PM */
|
||||
#define BTMTKSDIO_PM_OPS NULL
|
||||
|
@ -205,6 +205,44 @@ static int qca_send_reset(struct hci_dev *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
|
||||
{
|
||||
u8 cmd;
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
int err = 0;
|
||||
|
||||
cmd = EDL_GET_BID_REQ_CMD;
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
|
||||
&cmd, 0, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "Reading QCA board ID failed (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
edl = skb_pull_data(skb, sizeof(*edl));
|
||||
if (!edl) {
|
||||
bt_dev_err(hdev, "QCA read board ID with no header");
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
|
||||
edl->rtype != EDL_GET_BID_REQ_CMD) {
|
||||
bt_dev_err(hdev, "QCA Wrong packet: %d %d", edl->cresp, edl->rtype);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*bid = (edl->data[1] << 8) + edl->data[2];
|
||||
bt_dev_dbg(hdev, "%s: bid = %x", __func__, *bid);
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -574,6 +612,23 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
|
||||
|
||||
static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size,
|
||||
struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
|
||||
{
|
||||
const char *variant;
|
||||
|
||||
/* hsp gf chip */
|
||||
if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
|
||||
variant = "g";
|
||||
else
|
||||
variant = "";
|
||||
|
||||
if (bid == 0x0)
|
||||
snprintf(fwname, max_size, "qca/hpnv%02x%s.bin", rom_ver, variant);
|
||||
else
|
||||
snprintf(fwname, max_size, "qca/hpnv%02x%s.%x", rom_ver, variant, bid);
|
||||
}
|
||||
|
||||
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
|
||||
const char *firmware_name)
|
||||
@ -582,6 +637,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
int err;
|
||||
u8 rom_ver = 0;
|
||||
u32 soc_ver;
|
||||
u16 boardid = 0;
|
||||
|
||||
bt_dev_dbg(hdev, "QCA setup on UART");
|
||||
|
||||
@ -615,6 +671,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
case QCA_QCA2066:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htbtfw%02x.tlv", rom_ver);
|
||||
@ -649,6 +709,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
/* Give the controller some time to get ready to receive the NVM */
|
||||
msleep(10);
|
||||
|
||||
if (soc_type == QCA_QCA2066)
|
||||
qca_read_fw_board_id(hdev, &boardid);
|
||||
|
||||
/* Download NVM configuration */
|
||||
config.type = TLV_TYPE_NVM;
|
||||
if (firmware_name) {
|
||||
@ -671,6 +734,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_QCA2066:
|
||||
qca_generate_hsp_nvm_name(config.fwname,
|
||||
sizeof(config.fwname), ver, rom_ver, boardid);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
@ -702,6 +769,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3991:
|
||||
case QCA_QCA2066:
|
||||
case QCA_QCA6390:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define EDL_PATCH_VER_REQ_CMD (0x19)
|
||||
#define EDL_PATCH_TLV_REQ_CMD (0x1E)
|
||||
#define EDL_GET_BUILD_INFO_CMD (0x20)
|
||||
#define EDL_GET_BID_REQ_CMD (0x23)
|
||||
#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01)
|
||||
#define EDL_PATCH_CONFIG_CMD (0x28)
|
||||
#define MAX_SIZE_PER_TLV_SEGMENT (243)
|
||||
@ -47,7 +48,8 @@
|
||||
((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver)))
|
||||
|
||||
#define QCA_FW_BUILD_VER_LEN 255
|
||||
|
||||
#define QCA_HSP_GF_SOC_ID 0x1200
|
||||
#define QCA_HSP_GF_SOC_MASK 0x0000ff00
|
||||
|
||||
enum qca_baudrate {
|
||||
QCA_BAUDRATE_115200 = 0,
|
||||
@ -146,6 +148,7 @@ enum qca_btsoc_type {
|
||||
QCA_WCN3990,
|
||||
QCA_WCN3998,
|
||||
QCA_WCN3991,
|
||||
QCA_QCA2066,
|
||||
QCA_QCA6390,
|
||||
QCA_WCN6750,
|
||||
QCA_WCN6855,
|
||||
|
@ -477,6 +477,7 @@ static const struct usb_device_id quirks_table[] = {
|
||||
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0038), .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 |
|
||||
@ -543,6 +544,10 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xb85b), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
@ -644,6 +649,9 @@ static const struct usb_device_id quirks_table[] = {
|
||||
{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional Realtek 8723AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
|
||||
@ -2818,6 +2826,9 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
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) {
|
||||
|
@ -512,6 +512,7 @@ struct bcm4377_hw {
|
||||
unsigned long disable_aspm : 1;
|
||||
unsigned long broken_ext_scan : 1;
|
||||
unsigned long broken_mws_transport_config : 1;
|
||||
unsigned long broken_le_coded : 1;
|
||||
|
||||
int (*send_calibration)(struct bcm4377_data *bcm4377);
|
||||
int (*send_ptb)(struct bcm4377_data *bcm4377,
|
||||
@ -2372,6 +2373,8 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
set_bit(HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG, &hdev->quirks);
|
||||
if (bcm4377->hw->broken_ext_scan)
|
||||
set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks);
|
||||
if (bcm4377->hw->broken_le_coded)
|
||||
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
|
||||
|
||||
pci_set_drvdata(pdev, bcm4377);
|
||||
hci_set_drvdata(hdev, bcm4377);
|
||||
@ -2461,6 +2464,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
|
||||
.bar0_core2_window2 = 0x18107000,
|
||||
.has_bar0_core2_window2 = true,
|
||||
.broken_mws_transport_config = true,
|
||||
.broken_le_coded = true,
|
||||
.send_calibration = bcm4378_send_calibration,
|
||||
.send_ptb = bcm4378_send_ptb,
|
||||
},
|
||||
@ -2474,6 +2478,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
|
||||
.has_bar0_core2_window2 = true,
|
||||
.clear_pciecfg_subsystem_ctrl_bit19 = true,
|
||||
.broken_mws_transport_config = true,
|
||||
.broken_le_coded = true,
|
||||
.send_calibration = bcm4387_send_calibration,
|
||||
.send_ptb = bcm4378_send_ptb,
|
||||
},
|
||||
|
@ -1841,6 +1841,10 @@ static int qca_setup(struct hci_uart *hu)
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_QCA2066:
|
||||
soc_name = "qca2066";
|
||||
break;
|
||||
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
@ -2032,6 +2036,11 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = {
|
||||
.soc_type = QCA_QCA2066,
|
||||
.num_vregs = 0,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
|
||||
.soc_type = QCA_QCA6390,
|
||||
.num_vregs = 0,
|
||||
@ -2559,6 +2568,7 @@ static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id qca_bluetooth_of_match[] = {
|
||||
{ .compatible = "qcom,qca2066-bt", .data = &qca_soc_data_qca2066},
|
||||
{ .compatible = "qcom,qca6174-bt" },
|
||||
{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
|
||||
{ .compatible = "qcom,qca9377-bt" },
|
||||
@ -2576,6 +2586,7 @@ MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
|
||||
{ "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 },
|
||||
{ "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
|
7
drivers/dpll/Kconfig
Normal file
7
drivers/dpll/Kconfig
Normal file
@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Generic DPLL drivers configuration
|
||||
#
|
||||
|
||||
config DPLL
|
||||
bool
|
9
drivers/dpll/Makefile
Normal file
9
drivers/dpll/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for DPLL drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DPLL) += dpll.o
|
||||
dpll-y += dpll_core.o
|
||||
dpll-y += dpll_netlink.o
|
||||
dpll-y += dpll_nl.o
|
798
drivers/dpll/dpll_core.c
Normal file
798
drivers/dpll/dpll_core.c
Normal file
@ -0,0 +1,798 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* dpll_core.c - DPLL subsystem kernel-space interface implementation.
|
||||
*
|
||||
* Copyright (c) 2023 Meta Platforms, Inc. and affiliates
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "dpll_core.h"
|
||||
#include "dpll_netlink.h"
|
||||
|
||||
/* Mutex lock to protect DPLL subsystem devices and pins */
|
||||
DEFINE_MUTEX(dpll_lock);
|
||||
|
||||
DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
|
||||
DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC);
|
||||
|
||||
static u32 dpll_xa_id;
|
||||
|
||||
#define ASSERT_DPLL_REGISTERED(d) \
|
||||
WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
|
||||
#define ASSERT_DPLL_NOT_REGISTERED(d) \
|
||||
WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))
|
||||
#define ASSERT_PIN_REGISTERED(p) \
|
||||
WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED))
|
||||
|
||||
struct dpll_device_registration {
|
||||
struct list_head list;
|
||||
const struct dpll_device_ops *ops;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct dpll_pin_registration {
|
||||
struct list_head list;
|
||||
const struct dpll_pin_ops *ops;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct dpll_device *dpll_device_get_by_id(int id)
|
||||
{
|
||||
if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED))
|
||||
return xa_load(&dpll_device_xa, id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dpll_pin_registration *
|
||||
dpll_pin_registration_find(struct dpll_pin_ref *ref,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
|
||||
list_for_each_entry(reg, &ref->registration_list, list) {
|
||||
if (reg->ops == ops && reg->priv == priv)
|
||||
return reg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
struct dpll_pin_ref *ref;
|
||||
bool ref_exists = false;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
xa_for_each(xa_pins, i, ref) {
|
||||
if (ref->pin != pin)
|
||||
continue;
|
||||
reg = dpll_pin_registration_find(ref, ops, priv);
|
||||
if (reg) {
|
||||
refcount_inc(&ref->refcount);
|
||||
return 0;
|
||||
}
|
||||
ref_exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ref_exists) {
|
||||
ref = kzalloc(sizeof(*ref), GFP_KERNEL);
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
ref->pin = pin;
|
||||
INIT_LIST_HEAD(&ref->registration_list);
|
||||
ret = xa_insert(xa_pins, pin->pin_idx, ref, GFP_KERNEL);
|
||||
if (ret) {
|
||||
kfree(ref);
|
||||
return ret;
|
||||
}
|
||||
refcount_set(&ref->refcount, 1);
|
||||
}
|
||||
|
||||
reg = kzalloc(sizeof(*reg), GFP_KERNEL);
|
||||
if (!reg) {
|
||||
if (!ref_exists) {
|
||||
xa_erase(xa_pins, pin->pin_idx);
|
||||
kfree(ref);
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
reg->ops = ops;
|
||||
reg->priv = priv;
|
||||
if (ref_exists)
|
||||
refcount_inc(&ref->refcount);
|
||||
list_add_tail(®->list, &ref->registration_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i;
|
||||
|
||||
xa_for_each(xa_pins, i, ref) {
|
||||
if (ref->pin != pin)
|
||||
continue;
|
||||
reg = dpll_pin_registration_find(ref, ops, priv);
|
||||
if (WARN_ON(!reg))
|
||||
return -EINVAL;
|
||||
if (refcount_dec_and_test(&ref->refcount)) {
|
||||
list_del(®->list);
|
||||
kfree(reg);
|
||||
xa_erase(xa_pins, i);
|
||||
WARN_ON(!list_empty(&ref->registration_list));
|
||||
kfree(ref);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
struct dpll_pin_ref *ref;
|
||||
bool ref_exists = false;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
xa_for_each(xa_dplls, i, ref) {
|
||||
if (ref->dpll != dpll)
|
||||
continue;
|
||||
reg = dpll_pin_registration_find(ref, ops, priv);
|
||||
if (reg) {
|
||||
refcount_inc(&ref->refcount);
|
||||
return 0;
|
||||
}
|
||||
ref_exists = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ref_exists) {
|
||||
ref = kzalloc(sizeof(*ref), GFP_KERNEL);
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
ref->dpll = dpll;
|
||||
INIT_LIST_HEAD(&ref->registration_list);
|
||||
ret = xa_insert(xa_dplls, dpll->id, ref, GFP_KERNEL);
|
||||
if (ret) {
|
||||
kfree(ref);
|
||||
return ret;
|
||||
}
|
||||
refcount_set(&ref->refcount, 1);
|
||||
}
|
||||
|
||||
reg = kzalloc(sizeof(*reg), GFP_KERNEL);
|
||||
if (!reg) {
|
||||
if (!ref_exists) {
|
||||
xa_erase(xa_dplls, dpll->id);
|
||||
kfree(ref);
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
reg->ops = ops;
|
||||
reg->priv = priv;
|
||||
if (ref_exists)
|
||||
refcount_inc(&ref->refcount);
|
||||
list_add_tail(®->list, &ref->registration_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i;
|
||||
|
||||
xa_for_each(xa_dplls, i, ref) {
|
||||
if (ref->dpll != dpll)
|
||||
continue;
|
||||
reg = dpll_pin_registration_find(ref, ops, priv);
|
||||
if (WARN_ON(!reg))
|
||||
return;
|
||||
if (refcount_dec_and_test(&ref->refcount)) {
|
||||
list_del(®->list);
|
||||
kfree(reg);
|
||||
xa_erase(xa_dplls, i);
|
||||
WARN_ON(!list_empty(&ref->registration_list));
|
||||
kfree(ref);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs)
|
||||
{
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i = 0;
|
||||
|
||||
ref = xa_find(xa_refs, &i, ULONG_MAX, XA_PRESENT);
|
||||
WARN_ON(!ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
static struct dpll_device *
|
||||
dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module)
|
||||
{
|
||||
struct dpll_device *dpll;
|
||||
int ret;
|
||||
|
||||
dpll = kzalloc(sizeof(*dpll), GFP_KERNEL);
|
||||
if (!dpll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
refcount_set(&dpll->refcount, 1);
|
||||
INIT_LIST_HEAD(&dpll->registration_list);
|
||||
dpll->device_idx = device_idx;
|
||||
dpll->clock_id = clock_id;
|
||||
dpll->module = module;
|
||||
ret = xa_alloc_cyclic(&dpll_device_xa, &dpll->id, dpll, xa_limit_32b,
|
||||
&dpll_xa_id, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
kfree(dpll);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
xa_init_flags(&dpll->pin_refs, XA_FLAGS_ALLOC);
|
||||
|
||||
return dpll;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_device_get - find existing or create new dpll device
|
||||
* @clock_id: clock_id of creator
|
||||
* @device_idx: idx given by device driver
|
||||
* @module: reference to registering module
|
||||
*
|
||||
* Get existing object of a dpll device, unique for given arguments.
|
||||
* Create new if doesn't exist yet.
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Return:
|
||||
* * valid dpll_device struct pointer if succeeded
|
||||
* * ERR_PTR(X) - error
|
||||
*/
|
||||
struct dpll_device *
|
||||
dpll_device_get(u64 clock_id, u32 device_idx, struct module *module)
|
||||
{
|
||||
struct dpll_device *dpll, *ret = NULL;
|
||||
unsigned long index;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
xa_for_each(&dpll_device_xa, index, dpll) {
|
||||
if (dpll->clock_id == clock_id &&
|
||||
dpll->device_idx == device_idx &&
|
||||
dpll->module == module) {
|
||||
ret = dpll;
|
||||
refcount_inc(&ret->refcount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
ret = dpll_device_alloc(clock_id, device_idx, module);
|
||||
mutex_unlock(&dpll_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_device_get);
|
||||
|
||||
/**
|
||||
* dpll_device_put - decrease the refcount and free memory if possible
|
||||
* @dpll: dpll_device struct pointer
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Drop reference for a dpll device, if all references are gone, delete
|
||||
* dpll device object.
|
||||
*/
|
||||
void dpll_device_put(struct dpll_device *dpll)
|
||||
{
|
||||
mutex_lock(&dpll_lock);
|
||||
if (refcount_dec_and_test(&dpll->refcount)) {
|
||||
ASSERT_DPLL_NOT_REGISTERED(dpll);
|
||||
WARN_ON_ONCE(!xa_empty(&dpll->pin_refs));
|
||||
xa_destroy(&dpll->pin_refs);
|
||||
xa_erase(&dpll_device_xa, dpll->id);
|
||||
WARN_ON(!list_empty(&dpll->registration_list));
|
||||
kfree(dpll);
|
||||
}
|
||||
mutex_unlock(&dpll_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_device_put);
|
||||
|
||||
static struct dpll_device_registration *
|
||||
dpll_device_registration_find(struct dpll_device *dpll,
|
||||
const struct dpll_device_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
list_for_each_entry(reg, &dpll->registration_list, list) {
|
||||
if (reg->ops == ops && reg->priv == priv)
|
||||
return reg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_device_register - register the dpll device in the subsystem
|
||||
* @dpll: pointer to a dpll
|
||||
* @type: type of a dpll
|
||||
* @ops: ops for a dpll device
|
||||
* @priv: pointer to private information of owner
|
||||
*
|
||||
* Make dpll device available for user space.
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * negative - error value
|
||||
*/
|
||||
int dpll_device_register(struct dpll_device *dpll, enum dpll_type type,
|
||||
const struct dpll_device_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
bool first_registration = false;
|
||||
|
||||
if (WARN_ON(!ops))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(!ops->mode_get))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(!ops->lock_status_get))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(type < DPLL_TYPE_PPS || type > DPLL_TYPE_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
reg = dpll_device_registration_find(dpll, ops, priv);
|
||||
if (reg) {
|
||||
mutex_unlock(&dpll_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
reg = kzalloc(sizeof(*reg), GFP_KERNEL);
|
||||
if (!reg) {
|
||||
mutex_unlock(&dpll_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
reg->ops = ops;
|
||||
reg->priv = priv;
|
||||
dpll->type = type;
|
||||
first_registration = list_empty(&dpll->registration_list);
|
||||
list_add_tail(®->list, &dpll->registration_list);
|
||||
if (!first_registration) {
|
||||
mutex_unlock(&dpll_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
|
||||
dpll_device_create_ntf(dpll);
|
||||
mutex_unlock(&dpll_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_device_register);
|
||||
|
||||
/**
|
||||
* dpll_device_unregister - unregister dpll device
|
||||
* @dpll: registered dpll pointer
|
||||
* @ops: ops for a dpll device
|
||||
* @priv: pointer to private information of owner
|
||||
*
|
||||
* Unregister device, make it unavailable for userspace.
|
||||
* Note: It does not free the memory
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
*/
|
||||
void dpll_device_unregister(struct dpll_device *dpll,
|
||||
const struct dpll_device_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
ASSERT_DPLL_REGISTERED(dpll);
|
||||
dpll_device_delete_ntf(dpll);
|
||||
reg = dpll_device_registration_find(dpll, ops, priv);
|
||||
if (WARN_ON(!reg)) {
|
||||
mutex_unlock(&dpll_lock);
|
||||
return;
|
||||
}
|
||||
list_del(®->list);
|
||||
kfree(reg);
|
||||
|
||||
if (!list_empty(&dpll->registration_list)) {
|
||||
mutex_unlock(&dpll_lock);
|
||||
return;
|
||||
}
|
||||
xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
|
||||
mutex_unlock(&dpll_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_device_unregister);
|
||||
|
||||
static struct dpll_pin *
|
||||
dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
|
||||
const struct dpll_pin_properties *prop)
|
||||
{
|
||||
struct dpll_pin *pin;
|
||||
int ret;
|
||||
|
||||
pin = kzalloc(sizeof(*pin), GFP_KERNEL);
|
||||
if (!pin)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
pin->pin_idx = pin_idx;
|
||||
pin->clock_id = clock_id;
|
||||
pin->module = module;
|
||||
if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX ||
|
||||
prop->type > DPLL_PIN_TYPE_MAX)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
pin->prop = prop;
|
||||
refcount_set(&pin->refcount, 1);
|
||||
xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC);
|
||||
xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC);
|
||||
ret = xa_alloc(&dpll_pin_xa, &pin->id, pin, xa_limit_16b, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto err;
|
||||
return pin;
|
||||
err:
|
||||
xa_destroy(&pin->dpll_refs);
|
||||
xa_destroy(&pin->parent_refs);
|
||||
kfree(pin);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_pin_get - find existing or create new dpll pin
|
||||
* @clock_id: clock_id of creator
|
||||
* @pin_idx: idx given by dev driver
|
||||
* @module: reference to registering module
|
||||
* @prop: dpll pin properties
|
||||
*
|
||||
* Get existing object of a pin (unique for given arguments) or create new
|
||||
* if doesn't exist yet.
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Return:
|
||||
* * valid allocated dpll_pin struct pointer if succeeded
|
||||
* * ERR_PTR(X) - error
|
||||
*/
|
||||
struct dpll_pin *
|
||||
dpll_pin_get(u64 clock_id, u32 pin_idx, struct module *module,
|
||||
const struct dpll_pin_properties *prop)
|
||||
{
|
||||
struct dpll_pin *pos, *ret = NULL;
|
||||
unsigned long i;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
xa_for_each(&dpll_pin_xa, i, pos) {
|
||||
if (pos->clock_id == clock_id &&
|
||||
pos->pin_idx == pin_idx &&
|
||||
pos->module == module) {
|
||||
ret = pos;
|
||||
refcount_inc(&ret->refcount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
ret = dpll_pin_alloc(clock_id, pin_idx, module, prop);
|
||||
mutex_unlock(&dpll_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_get);
|
||||
|
||||
/**
|
||||
* dpll_pin_put - decrease the refcount and free memory if possible
|
||||
* @pin: pointer to a pin to be put
|
||||
*
|
||||
* Drop reference for a pin, if all references are gone, delete pin object.
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
*/
|
||||
void dpll_pin_put(struct dpll_pin *pin)
|
||||
{
|
||||
mutex_lock(&dpll_lock);
|
||||
if (refcount_dec_and_test(&pin->refcount)) {
|
||||
xa_destroy(&pin->dpll_refs);
|
||||
xa_destroy(&pin->parent_refs);
|
||||
xa_erase(&dpll_pin_xa, pin->id);
|
||||
kfree(pin);
|
||||
}
|
||||
mutex_unlock(&dpll_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_put);
|
||||
|
||||
static int
|
||||
__dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dpll_xa_ref_pin_add(&dpll->pin_refs, pin, ops, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = dpll_xa_ref_dpll_add(&pin->dpll_refs, dpll, ops, priv);
|
||||
if (ret)
|
||||
goto ref_pin_del;
|
||||
xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
|
||||
dpll_pin_create_ntf(pin);
|
||||
|
||||
return ret;
|
||||
|
||||
ref_pin_del:
|
||||
dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_pin_register - register the dpll pin in the subsystem
|
||||
* @dpll: pointer to a dpll
|
||||
* @pin: pointer to a dpll pin
|
||||
* @ops: ops for a dpll pin ops
|
||||
* @priv: pointer to private information of owner
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * negative - error value
|
||||
*/
|
||||
int
|
||||
dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!ops) ||
|
||||
WARN_ON(!ops->state_on_dpll_get) ||
|
||||
WARN_ON(!ops->direction_get))
|
||||
return -EINVAL;
|
||||
if (ASSERT_DPLL_REGISTERED(dpll))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
if (WARN_ON(!(dpll->module == pin->module &&
|
||||
dpll->clock_id == pin->clock_id)))
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = __dpll_pin_register(dpll, pin, ops, priv);
|
||||
mutex_unlock(&dpll_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_register);
|
||||
|
||||
static void
|
||||
__dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv);
|
||||
dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv);
|
||||
if (xa_empty(&pin->dpll_refs))
|
||||
xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_pin_unregister - unregister dpll pin from dpll device
|
||||
* @dpll: registered dpll pointer
|
||||
* @pin: pointer to a pin
|
||||
* @ops: ops for a dpll pin
|
||||
* @priv: pointer to private information of owner
|
||||
*
|
||||
* Note: It does not free the memory
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
*/
|
||||
void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
if (WARN_ON(xa_empty(&dpll->pin_refs)))
|
||||
return;
|
||||
if (WARN_ON(!xa_empty(&pin->parent_refs)))
|
||||
return;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
dpll_pin_delete_ntf(pin);
|
||||
__dpll_pin_unregister(dpll, pin, ops, priv);
|
||||
mutex_unlock(&dpll_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_unregister);
|
||||
|
||||
/**
|
||||
* dpll_pin_on_pin_register - register a pin with a parent pin
|
||||
* @parent: pointer to a parent pin
|
||||
* @pin: pointer to a pin
|
||||
* @ops: ops for a dpll pin
|
||||
* @priv: pointer to private information of owner
|
||||
*
|
||||
* Register a pin with a parent pin, create references between them and
|
||||
* between newly registered pin and dplls connected with a parent pin.
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Return:
|
||||
* * 0 on success
|
||||
* * negative - error value
|
||||
*/
|
||||
int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i, stop;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(parent->prop->type != DPLL_PIN_TYPE_MUX))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!ops) ||
|
||||
WARN_ON(!ops->state_on_pin_get) ||
|
||||
WARN_ON(!ops->direction_get))
|
||||
return -EINVAL;
|
||||
if (ASSERT_PIN_REGISTERED(parent))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
refcount_inc(&pin->refcount);
|
||||
xa_for_each(&parent->dpll_refs, i, ref) {
|
||||
ret = __dpll_pin_register(ref->dpll, pin, ops, priv);
|
||||
if (ret) {
|
||||
stop = i;
|
||||
goto dpll_unregister;
|
||||
}
|
||||
dpll_pin_create_ntf(pin);
|
||||
}
|
||||
mutex_unlock(&dpll_lock);
|
||||
|
||||
return ret;
|
||||
|
||||
dpll_unregister:
|
||||
xa_for_each(&parent->dpll_refs, i, ref)
|
||||
if (i < stop) {
|
||||
__dpll_pin_unregister(ref->dpll, pin, ops, priv);
|
||||
dpll_pin_delete_ntf(pin);
|
||||
}
|
||||
refcount_dec(&pin->refcount);
|
||||
dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv);
|
||||
unlock:
|
||||
mutex_unlock(&dpll_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_on_pin_register);
|
||||
|
||||
/**
|
||||
* dpll_pin_on_pin_unregister - unregister dpll pin from a parent pin
|
||||
* @parent: pointer to a parent pin
|
||||
* @pin: pointer to a pin
|
||||
* @ops: ops for a dpll pin
|
||||
* @priv: pointer to private information of owner
|
||||
*
|
||||
* Context: Acquires a lock (dpll_lock)
|
||||
* Note: It does not free the memory
|
||||
*/
|
||||
void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
dpll_pin_delete_ntf(pin);
|
||||
dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv);
|
||||
refcount_dec(&pin->refcount);
|
||||
xa_for_each(&pin->dpll_refs, i, ref)
|
||||
__dpll_pin_unregister(ref->dpll, pin, ops, priv);
|
||||
mutex_unlock(&dpll_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
|
||||
|
||||
static struct dpll_device_registration *
|
||||
dpll_device_registration_first(struct dpll_device *dpll)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
|
||||
struct dpll_device_registration, list);
|
||||
WARN_ON(!reg);
|
||||
return reg;
|
||||
}
|
||||
|
||||
void *dpll_priv(struct dpll_device *dpll)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = dpll_device_registration_first(dpll);
|
||||
return reg->priv;
|
||||
}
|
||||
|
||||
const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = dpll_device_registration_first(dpll);
|
||||
return reg->ops;
|
||||
}
|
||||
|
||||
static struct dpll_pin_registration *
|
||||
dpll_pin_registration_first(struct dpll_pin_ref *ref)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
|
||||
reg = list_first_entry_or_null(&ref->registration_list,
|
||||
struct dpll_pin_registration, list);
|
||||
WARN_ON(!reg);
|
||||
return reg;
|
||||
}
|
||||
|
||||
void *dpll_pin_on_dpll_priv(struct dpll_device *dpll,
|
||||
struct dpll_pin *pin)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
struct dpll_pin_ref *ref;
|
||||
|
||||
ref = xa_load(&dpll->pin_refs, pin->pin_idx);
|
||||
if (!ref)
|
||||
return NULL;
|
||||
reg = dpll_pin_registration_first(ref);
|
||||
return reg->priv;
|
||||
}
|
||||
|
||||
void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
|
||||
struct dpll_pin *pin)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
struct dpll_pin_ref *ref;
|
||||
|
||||
ref = xa_load(&pin->parent_refs, parent->pin_idx);
|
||||
if (!ref)
|
||||
return NULL;
|
||||
reg = dpll_pin_registration_first(ref);
|
||||
return reg->priv;
|
||||
}
|
||||
|
||||
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
|
||||
{
|
||||
struct dpll_pin_registration *reg;
|
||||
|
||||
reg = dpll_pin_registration_first(ref);
|
||||
return reg->ops;
|
||||
}
|
||||
|
||||
static int __init dpll_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genl_register_family(&dpll_nl_family);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
mutex_destroy(&dpll_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit dpll_exit(void)
|
||||
{
|
||||
genl_unregister_family(&dpll_nl_family);
|
||||
mutex_destroy(&dpll_lock);
|
||||
}
|
||||
|
||||
subsys_initcall(dpll_init);
|
||||
module_exit(dpll_exit);
|
89
drivers/dpll/dpll_core.h
Normal file
89
drivers/dpll/dpll_core.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2023 Meta Platforms, Inc. and affiliates
|
||||
* Copyright (c) 2023 Intel and affiliates
|
||||
*/
|
||||
|
||||
#ifndef __DPLL_CORE_H__
|
||||
#define __DPLL_CORE_H__
|
||||
|
||||
#include <linux/dpll.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/refcount.h>
|
||||
#include "dpll_nl.h"
|
||||
|
||||
#define DPLL_REGISTERED XA_MARK_1
|
||||
|
||||
/**
|
||||
* struct dpll_device - stores DPLL device internal data
|
||||
* @id: unique id number for device given by dpll subsystem
|
||||
* @device_idx: id given by dev driver
|
||||
* @clock_id: unique identifier (clock_id) of a dpll
|
||||
* @module: module of creator
|
||||
* @type: type of a dpll
|
||||
* @pin_refs: stores pins registered within a dpll
|
||||
* @refcount: refcount
|
||||
* @registration_list: list of registered ops and priv data of dpll owners
|
||||
**/
|
||||
struct dpll_device {
|
||||
u32 id;
|
||||
u32 device_idx;
|
||||
u64 clock_id;
|
||||
struct module *module;
|
||||
enum dpll_type type;
|
||||
struct xarray pin_refs;
|
||||
refcount_t refcount;
|
||||
struct list_head registration_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpll_pin - structure for a dpll pin
|
||||
* @id: unique id number for pin given by dpll subsystem
|
||||
* @pin_idx: index of a pin given by dev driver
|
||||
* @clock_id: clock_id of creator
|
||||
* @module: module of creator
|
||||
* @dpll_refs: hold referencees to dplls pin was registered with
|
||||
* @parent_refs: hold references to parent pins pin was registered with
|
||||
* @prop: pointer to pin properties given by registerer
|
||||
* @rclk_dev_name: holds name of device when pin can recover clock from it
|
||||
* @refcount: refcount
|
||||
**/
|
||||
struct dpll_pin {
|
||||
u32 id;
|
||||
u32 pin_idx;
|
||||
u64 clock_id;
|
||||
struct module *module;
|
||||
struct xarray dpll_refs;
|
||||
struct xarray parent_refs;
|
||||
const struct dpll_pin_properties *prop;
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpll_pin_ref - structure for referencing either dpll or pins
|
||||
* @dpll: pointer to a dpll
|
||||
* @pin: pointer to a pin
|
||||
* @registration_list: list of ops and priv data registered with the ref
|
||||
* @refcount: refcount
|
||||
**/
|
||||
struct dpll_pin_ref {
|
||||
union {
|
||||
struct dpll_device *dpll;
|
||||
struct dpll_pin *pin;
|
||||
};
|
||||
struct list_head registration_list;
|
||||
refcount_t refcount;
|
||||
};
|
||||
|
||||
void *dpll_priv(struct dpll_device *dpll);
|
||||
void *dpll_pin_on_dpll_priv(struct dpll_device *dpll, struct dpll_pin *pin);
|
||||
void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin);
|
||||
|
||||
const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll);
|
||||
struct dpll_device *dpll_device_get_by_id(int id);
|
||||
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref);
|
||||
struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);
|
||||
extern struct xarray dpll_device_xa;
|
||||
extern struct xarray dpll_pin_xa;
|
||||
extern struct mutex dpll_lock;
|
||||
#endif
|
1423
drivers/dpll/dpll_netlink.c
Normal file
1423
drivers/dpll/dpll_netlink.c
Normal file
File diff suppressed because it is too large
Load Diff
13
drivers/dpll/dpll_netlink.h
Normal file
13
drivers/dpll/dpll_netlink.h
Normal file
@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2023 Meta Platforms, Inc. and affiliates
|
||||
* Copyright (c) 2023 Intel and affiliates
|
||||
*/
|
||||
|
||||
int dpll_device_create_ntf(struct dpll_device *dpll);
|
||||
|
||||
int dpll_device_delete_ntf(struct dpll_device *dpll);
|
||||
|
||||
int dpll_pin_create_ntf(struct dpll_pin *pin);
|
||||
|
||||
int dpll_pin_delete_ntf(struct dpll_pin *pin);
|
164
drivers/dpll/dpll_nl.c
Normal file
164
drivers/dpll/dpll_nl.c
Normal file
@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/dpll.yaml */
|
||||
/* YNL-GEN kernel source */
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "dpll_nl.h"
|
||||
|
||||
#include <uapi/linux/dpll.h>
|
||||
|
||||
/* Common nested types */
|
||||
const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1] = {
|
||||
[DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, },
|
||||
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
|
||||
[DPLL_A_PIN_PRIO] = { .type = NLA_U32, },
|
||||
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
|
||||
[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
|
||||
};
|
||||
|
||||
const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = {
|
||||
[DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, },
|
||||
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
|
||||
};
|
||||
|
||||
/* DPLL_CMD_DEVICE_ID_GET - do */
|
||||
static const struct nla_policy dpll_device_id_get_nl_policy[DPLL_A_TYPE + 1] = {
|
||||
[DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_CLOCK_ID] = { .type = NLA_U64, },
|
||||
[DPLL_A_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
|
||||
};
|
||||
|
||||
/* DPLL_CMD_DEVICE_GET - do */
|
||||
static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = {
|
||||
[DPLL_A_ID] = { .type = NLA_U32, },
|
||||
};
|
||||
|
||||
/* DPLL_CMD_DEVICE_SET - do */
|
||||
static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_ID + 1] = {
|
||||
[DPLL_A_ID] = { .type = NLA_U32, },
|
||||
};
|
||||
|
||||
/* DPLL_CMD_PIN_ID_GET - do */
|
||||
static const struct nla_policy dpll_pin_id_get_nl_policy[DPLL_A_PIN_TYPE + 1] = {
|
||||
[DPLL_A_PIN_MODULE_NAME] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_CLOCK_ID] = { .type = NLA_U64, },
|
||||
[DPLL_A_PIN_BOARD_LABEL] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_PANEL_LABEL] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_PACKAGE_LABEL] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 5),
|
||||
};
|
||||
|
||||
/* DPLL_CMD_PIN_GET - do */
|
||||
static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_ID + 1] = {
|
||||
[DPLL_A_PIN_ID] = { .type = NLA_U32, },
|
||||
};
|
||||
|
||||
/* DPLL_CMD_PIN_GET - dump */
|
||||
static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] = {
|
||||
[DPLL_A_PIN_ID] = { .type = NLA_U32, },
|
||||
};
|
||||
|
||||
/* DPLL_CMD_PIN_SET - do */
|
||||
static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1] = {
|
||||
[DPLL_A_PIN_ID] = { .type = NLA_U32, },
|
||||
[DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, },
|
||||
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
|
||||
[DPLL_A_PIN_PRIO] = { .type = NLA_U32, },
|
||||
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
|
||||
[DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy),
|
||||
[DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy),
|
||||
[DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, },
|
||||
};
|
||||
|
||||
/* Ops table for dpll */
|
||||
static const struct genl_split_ops dpll_nl_ops[] = {
|
||||
{
|
||||
.cmd = DPLL_CMD_DEVICE_ID_GET,
|
||||
.pre_doit = dpll_lock_doit,
|
||||
.doit = dpll_nl_device_id_get_doit,
|
||||
.post_doit = dpll_unlock_doit,
|
||||
.policy = dpll_device_id_get_nl_policy,
|
||||
.maxattr = DPLL_A_TYPE,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_DEVICE_GET,
|
||||
.pre_doit = dpll_pre_doit,
|
||||
.doit = dpll_nl_device_get_doit,
|
||||
.post_doit = dpll_post_doit,
|
||||
.policy = dpll_device_get_nl_policy,
|
||||
.maxattr = DPLL_A_ID,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_DEVICE_GET,
|
||||
.start = dpll_lock_dumpit,
|
||||
.dumpit = dpll_nl_device_get_dumpit,
|
||||
.done = dpll_unlock_dumpit,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_DEVICE_SET,
|
||||
.pre_doit = dpll_pre_doit,
|
||||
.doit = dpll_nl_device_set_doit,
|
||||
.post_doit = dpll_post_doit,
|
||||
.policy = dpll_device_set_nl_policy,
|
||||
.maxattr = DPLL_A_ID,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_PIN_ID_GET,
|
||||
.pre_doit = dpll_lock_doit,
|
||||
.doit = dpll_nl_pin_id_get_doit,
|
||||
.post_doit = dpll_unlock_doit,
|
||||
.policy = dpll_pin_id_get_nl_policy,
|
||||
.maxattr = DPLL_A_PIN_TYPE,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_PIN_GET,
|
||||
.pre_doit = dpll_pin_pre_doit,
|
||||
.doit = dpll_nl_pin_get_doit,
|
||||
.post_doit = dpll_pin_post_doit,
|
||||
.policy = dpll_pin_get_do_nl_policy,
|
||||
.maxattr = DPLL_A_PIN_ID,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_PIN_GET,
|
||||
.start = dpll_lock_dumpit,
|
||||
.dumpit = dpll_nl_pin_get_dumpit,
|
||||
.done = dpll_unlock_dumpit,
|
||||
.policy = dpll_pin_get_dump_nl_policy,
|
||||
.maxattr = DPLL_A_PIN_ID,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
|
||||
},
|
||||
{
|
||||
.cmd = DPLL_CMD_PIN_SET,
|
||||
.pre_doit = dpll_pin_pre_doit,
|
||||
.doit = dpll_nl_pin_set_doit,
|
||||
.post_doit = dpll_pin_post_doit,
|
||||
.policy = dpll_pin_set_nl_policy,
|
||||
.maxattr = DPLL_A_PIN_PHASE_ADJUST,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group dpll_nl_mcgrps[] = {
|
||||
[DPLL_NLGRP_MONITOR] = { "monitor", },
|
||||
};
|
||||
|
||||
struct genl_family dpll_nl_family __ro_after_init = {
|
||||
.name = DPLL_FAMILY_NAME,
|
||||
.version = DPLL_FAMILY_VERSION,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.module = THIS_MODULE,
|
||||
.split_ops = dpll_nl_ops,
|
||||
.n_split_ops = ARRAY_SIZE(dpll_nl_ops),
|
||||
.mcgrps = dpll_nl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(dpll_nl_mcgrps),
|
||||
};
|
51
drivers/dpll/dpll_nl.h
Normal file
51
drivers/dpll/dpll_nl.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/dpll.yaml */
|
||||
/* YNL-GEN kernel header */
|
||||
|
||||
#ifndef _LINUX_DPLL_GEN_H
|
||||
#define _LINUX_DPLL_GEN_H
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include <uapi/linux/dpll.h>
|
||||
|
||||
/* Common nested types */
|
||||
extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1];
|
||||
extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1];
|
||||
|
||||
int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
void
|
||||
dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
void
|
||||
dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
void
|
||||
dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
int dpll_lock_dumpit(struct netlink_callback *cb);
|
||||
int dpll_unlock_dumpit(struct netlink_callback *cb);
|
||||
|
||||
int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
enum {
|
||||
DPLL_NLGRP_MONITOR,
|
||||
};
|
||||
|
||||
extern struct genl_family dpll_nl_family;
|
||||
|
||||
#endif /* _LINUX_DPLL_GEN_H */
|
@ -22,6 +22,7 @@
|
||||
static DEFINE_IDR(i3c_bus_idr);
|
||||
static DEFINE_MUTEX(i3c_core_lock);
|
||||
static int __i3c_first_dynamic_bus_num;
|
||||
static BLOCKING_NOTIFIER_HEAD(i3c_bus_notifier);
|
||||
|
||||
/**
|
||||
* i3c_bus_maintenance_lock - Lock the bus for a maintenance operation
|
||||
@ -453,6 +454,36 @@ static int i3c_bus_init(struct i3c_bus *i3cbus, struct device_node *np)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i3c_for_each_bus_locked(int (*fn)(struct i3c_bus *bus, void *data),
|
||||
void *data)
|
||||
{
|
||||
struct i3c_bus *bus;
|
||||
int id;
|
||||
|
||||
mutex_lock(&i3c_core_lock);
|
||||
idr_for_each_entry(&i3c_bus_idr, bus, id)
|
||||
fn(bus, data);
|
||||
mutex_unlock(&i3c_core_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_for_each_bus_locked);
|
||||
|
||||
int i3c_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&i3c_bus_notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_register_notifier);
|
||||
|
||||
int i3c_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&i3c_bus_notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_unregister_notifier);
|
||||
|
||||
static void i3c_bus_notify(struct i3c_bus *bus, unsigned int action)
|
||||
{
|
||||
blocking_notifier_call_chain(&i3c_bus_notifier, action, bus);
|
||||
}
|
||||
|
||||
static const char * const i3c_bus_mode_strings[] = {
|
||||
[I3C_BUS_MODE_PURE] = "pure",
|
||||
[I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
|
||||
@ -2682,6 +2713,8 @@ int i3c_master_register(struct i3c_master_controller *master,
|
||||
if (ret)
|
||||
goto err_del_dev;
|
||||
|
||||
i3c_bus_notify(i3cbus, I3C_NOTIFY_BUS_ADD);
|
||||
|
||||
/*
|
||||
* We're done initializing the bus and the controller, we can now
|
||||
* register I3C devices discovered during the initial DAA.
|
||||
@ -2714,6 +2747,8 @@ EXPORT_SYMBOL_GPL(i3c_master_register);
|
||||
*/
|
||||
void i3c_master_unregister(struct i3c_master_controller *master)
|
||||
{
|
||||
i3c_bus_notify(&master->bus, I3C_NOTIFY_BUS_REMOVE);
|
||||
|
||||
i3c_master_i2c_adapter_cleanup(master);
|
||||
i3c_master_unregister_i3c_devs(master);
|
||||
i3c_master_bus_cleanup(master);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user