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:
Linus Torvalds 2023-10-31 05:10:11 -10:00
commit 89ed67ef12
1865 changed files with 121439 additions and 33186 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ properties:
- mediatek,mt7622-wed
- mediatek,mt7981-wed
- mediatek,mt7986-wed
- mediatek,mt7988-wed
- const: syscon
reg:

View File

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

View File

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

View File

@ -158,6 +158,8 @@ allOf:
patternProperties:
"^ethernet-phy@[0-9a-f]$":
type: object
$ref: ethernet-phy.yaml#
unevaluatedProperties: false
description:
Integrated PHY node

View File

@ -53,7 +53,7 @@ properties:
const: 0
patternProperties:
"^port@[0-9]+$":
"^port@[0-9a-f]+$":
type: object
$ref: ethernet-controller.yaml#

View File

@ -78,6 +78,7 @@ properties:
ports:
type: object
additionalProperties: true
patternProperties:
'^port@[0-9a-f]$':

View File

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

View File

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

View File

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

View File

@ -37,8 +37,9 @@ properties:
patternProperties:
"^(ethernet-)?ports$":
additionalProperties: true
patternProperties:
"^(ethernet-)?port@[0-9]+$":
"^(ethernet-)?port@[0-7]$":
allOf:
- if:
properties:

View File

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

View File

@ -73,6 +73,7 @@ $ref: dsa.yaml#
patternProperties:
"^(ethernet-)?ports$":
type: object
additionalProperties: true
patternProperties:
"^(ethernet-)?port@[0-6]$":
type: object

View File

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

View File

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

View File

@ -63,6 +63,7 @@ properties:
mdio:
type: object
$ref: mdio.yaml#
unevaluatedProperties: false
description: optional node for embedded MDIO controller
required:

View File

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

View File

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

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

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

View File

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

View File

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

View File

@ -81,9 +81,8 @@ properties:
active-high
patternProperties:
"^ethernet-phy@[0-9a-f]$":
"@[0-9a-f]$":
type: object
$ref: ethernet-phy.yaml#
required:
- compatible

View File

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

View File

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

View File

@ -86,7 +86,7 @@ properties:
const: 0
patternProperties:
"^port@[0-9]+$":
"^port@[12]$":
type: object
description: CPSW external ports

View File

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

View File

@ -20,6 +20,7 @@ properties:
items:
- enum:
- mediatek,mt7986-wo-ccif
- mediatek,mt7988-wo-ccif
- const: syscon
reg:

View File

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

View 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``.

View File

@ -114,6 +114,7 @@ available subsections can be seen below.
zorro
hte/index
wmi
dpll
.. only:: subproject and html

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

@ -32,6 +32,7 @@ Contents:
intel/e1000
intel/e1000e
intel/fm10k
intel/idpf
intel/igb
intel/igbvf
intel/ixgbe

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

View File

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

View File

@ -8,7 +8,6 @@ Contents:
.. toctree::
:maxdepth: 2
appletalk/index
atm/index
cable/index
can/index

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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 segments socket pair and RNextKeyID
is not available, no action is required (RNextKeyID of a received
segment needs to match the MKTs 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 segments 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 segments 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 connections 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 segments socket pair and its TCP-AO KeyID.
[4.4]::
One or more MKTs. These are the MKTs that match this connections
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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@
/ {
aliases {
ethernet0 = &eth0;
/* for dsa slave device */
/* for DSA user port device */
ethernet1 = &switch0port1;
ethernet2 = &switch0port2;
ethernet3 = &switch0port3;

View File

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

View File

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

View File

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

View File

@ -243,4 +243,6 @@ source "drivers/hte/Kconfig"
source "drivers/cdx/Kconfig"
source "drivers/dpll/Kconfig"
endmenu

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
View 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
View 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
View 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(&reg->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(&reg->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(&reg->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(&reg->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(&reg->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(&reg->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
View 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

File diff suppressed because it is too large Load Diff

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

View File

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