Merge: CNB97: ethtool: update ethtool core to upstream v6.15.
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6775 JIRA: https://issues.redhat.com/browse/RHEL-89014 Update ethtool upto kernel v6.15. Brew: [https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=67396250](https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=67705537) Depends: !6842 Signed-off-by: Mohammad Heib <mheib@redhat.com> New features: - Include a new readable timestamping string, **'option-rx-filter'**, which will appear when using the -T option. - add support for writing firmware blocks using EPL (Extended Payload). - Make timestamping hardware PTP provider selectable. - add support for configuring hds-thresh - Add support for 200Gbps per lane link modes. Omitted-fix: 6db9d3a536cd netdevsim: don't assume core pre-populates HDS params on GET * The targeted code was dropped during the update, so this fix is irrelevant. Omitted-fix: 19f72d95ae31 Docs/zh_CN: Translate index.rst to Simplified Chinese * Changes are not relevant for networking. Omitted-fix: 869413825088 selftests: drv-net: wait for iperf client to stop sending * [mschmidt] This is just for selftests. It appeared too late. We can't afford to block this MR any further. Approved-by: Antoine Tenart <atenart@redhat.com> Approved-by: Michal Schmidt <mschmidt@redhat.com> Approved-by: Corinna Vinschen <vinschen@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
This commit is contained in:
commit
c18e5c4e54
|
@ -106,6 +106,9 @@ properties:
|
|||
name-prefix:
|
||||
description: For enum the prefix of the values, optional.
|
||||
type: string
|
||||
enum-cnt-name:
|
||||
description: Name of the render-max counter enum entry.
|
||||
type: string
|
||||
# End genetlink-c
|
||||
|
||||
attribute-sets:
|
||||
|
|
|
@ -117,6 +117,9 @@ properties:
|
|||
name-prefix:
|
||||
description: For enum the prefix of the values, optional.
|
||||
type: string
|
||||
enum-cnt-name:
|
||||
description: Name of the render-max counter enum entry.
|
||||
type: string
|
||||
# End genetlink-c
|
||||
# Start genetlink-legacy
|
||||
members:
|
||||
|
|
|
@ -5,6 +5,10 @@ name: ethtool
|
|||
protocol: genetlink-legacy
|
||||
|
||||
doc: Partial family for Ethtool Netlink.
|
||||
uapi-header: linux/ethtool_netlink_generated.h
|
||||
|
||||
c-family-name: ethtool-genl-name
|
||||
c-version-name: ethtool-genl-version
|
||||
|
||||
definitions:
|
||||
-
|
||||
|
@ -12,43 +16,101 @@ definitions:
|
|||
enum-name:
|
||||
type: enum
|
||||
entries: [ vxlan, geneve, vxlan-gpe ]
|
||||
enum-cnt-name: __ethtool-udp-tunnel-type-cnt
|
||||
render-max: true
|
||||
-
|
||||
name: stringset
|
||||
type: enum
|
||||
entries: []
|
||||
header: linux/ethtool.h # skip rendering, no actual definition
|
||||
-
|
||||
name: header-flags
|
||||
type: flags
|
||||
entries: [ compact-bitsets, omit-reply, stats ]
|
||||
name-prefix: ethtool-flag-
|
||||
doc: common ethtool header flags
|
||||
entries:
|
||||
-
|
||||
name: compact-bitsets
|
||||
doc: use compact bitsets in reply
|
||||
-
|
||||
name: omit-reply
|
||||
doc: provide optional reply for SET or ACT requests
|
||||
-
|
||||
name: stats
|
||||
doc: request statistics, if supported by the driver
|
||||
-
|
||||
name: module-fw-flash-status
|
||||
type: enum
|
||||
entries: [ started, in_progress, completed, error ]
|
||||
doc: plug-in module firmware flashing status
|
||||
header: linux/ethtool.h
|
||||
entries:
|
||||
-
|
||||
name: started
|
||||
doc: The firmware flashing process has started.
|
||||
-
|
||||
name: in_progress
|
||||
doc: The firmware flashing process is in progress.
|
||||
-
|
||||
name: completed
|
||||
doc: The firmware flashing process was completed successfully.
|
||||
-
|
||||
name: error
|
||||
doc: The firmware flashing process was stopped due to an error.
|
||||
-
|
||||
name: c33-pse-ext-state
|
||||
enum-name:
|
||||
doc: "groups of PSE extended states functions. IEEE 802.3-2022 33.2.4.4 Variables"
|
||||
type: enum
|
||||
name-prefix: ethtool-c33-pse-ext-state-
|
||||
header: linux/ethtool.h
|
||||
entries:
|
||||
- none
|
||||
- error-condition
|
||||
- mr-mps-valid
|
||||
- mr-pse-enable
|
||||
- option-detect-ted
|
||||
- option-vport-lim
|
||||
- ovld-detected
|
||||
- power-not-available
|
||||
- short-detected
|
||||
-
|
||||
name: none
|
||||
doc: none
|
||||
-
|
||||
name: error-condition
|
||||
doc: Group of error_condition states
|
||||
-
|
||||
name: mr-mps-valid
|
||||
doc: Group of mr_mps_valid states
|
||||
-
|
||||
name: mr-pse-enable
|
||||
doc: Group of mr_pse_enable states
|
||||
-
|
||||
name: option-detect-ted
|
||||
doc: Group of option_detect_ted states
|
||||
-
|
||||
name: option-vport-lim
|
||||
doc: Group of option_vport_lim states
|
||||
-
|
||||
name: ovld-detected
|
||||
doc: Group of ovld_detected states
|
||||
-
|
||||
name: power-not-available
|
||||
doc: Group of power_not_available states
|
||||
-
|
||||
name: short-detected
|
||||
doc: Group of short_detected states
|
||||
-
|
||||
name: phy-upstream-type
|
||||
enum-name:
|
||||
enum-name: phy-upstream
|
||||
header: linux/ethtool.h
|
||||
type: enum
|
||||
name-prefix: phy-upstream
|
||||
entries: [ mac, phy ]
|
||||
-
|
||||
name: tcp-data-split
|
||||
type: enum
|
||||
entries: [ unknown, disabled, enabled ]
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: header
|
||||
attr-cnt-name: __ethtool-a-header-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: dev-index
|
||||
type: u32
|
||||
|
@ -65,7 +127,12 @@ attribute-sets:
|
|||
|
||||
-
|
||||
name: bitset-bit
|
||||
attr-cnt-name: __ethtool-a-bitset-bit-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: index
|
||||
type: u32
|
||||
|
@ -77,7 +144,12 @@ attribute-sets:
|
|||
type: flag
|
||||
-
|
||||
name: bitset-bits
|
||||
attr-cnt-name: __ethtool-a-bitset-bits-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: bit
|
||||
type: nest
|
||||
|
@ -85,7 +157,12 @@ attribute-sets:
|
|||
nested-attributes: bitset-bit
|
||||
-
|
||||
name: bitset
|
||||
attr-cnt-name: __ethtool-a-bitset-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: nomask
|
||||
type: flag
|
||||
|
@ -96,10 +173,20 @@ attribute-sets:
|
|||
name: bits
|
||||
type: nest
|
||||
nested-attributes: bitset-bits
|
||||
|
||||
-
|
||||
name: value
|
||||
type: binary
|
||||
-
|
||||
name: mask
|
||||
type: binary
|
||||
-
|
||||
name: string
|
||||
attr-cnt-name: __ethtool-a-string-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: index
|
||||
type: u32
|
||||
|
@ -108,7 +195,16 @@ attribute-sets:
|
|||
type: string
|
||||
-
|
||||
name: strings
|
||||
attr-cnt-name: __ethtool-a-strings-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: string
|
||||
type: nest
|
||||
|
@ -116,7 +212,12 @@ attribute-sets:
|
|||
nested-attributes: string
|
||||
-
|
||||
name: stringset
|
||||
attr-cnt-name: __ethtool-a-stringset-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: id
|
||||
type: u32
|
||||
|
@ -130,7 +231,12 @@ attribute-sets:
|
|||
nested-attributes: strings
|
||||
-
|
||||
name: stringsets
|
||||
attr-cnt-name: __ethtool-a-stringsets-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: stringset
|
||||
type: nest
|
||||
|
@ -138,7 +244,12 @@ attribute-sets:
|
|||
nested-attributes: stringset
|
||||
-
|
||||
name: strset
|
||||
attr-cnt-name: __ethtool-a-strset-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -153,7 +264,12 @@ attribute-sets:
|
|||
|
||||
-
|
||||
name: privflags
|
||||
attr-cnt-name: __ethtool-a-privflags-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -165,7 +281,12 @@ attribute-sets:
|
|||
|
||||
-
|
||||
name: rings
|
||||
attr-cnt-name: __ethtool-a-rings-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -200,6 +321,7 @@ attribute-sets:
|
|||
-
|
||||
name: tcp-data-split
|
||||
type: u8
|
||||
enum: tcp-data-split
|
||||
-
|
||||
name: cqe-size
|
||||
type: u32
|
||||
|
@ -215,34 +337,57 @@ attribute-sets:
|
|||
-
|
||||
name: tx-push-buf-len-max
|
||||
type: u32
|
||||
-
|
||||
name: hds-thresh
|
||||
type: u32
|
||||
-
|
||||
name: hds-thresh-max
|
||||
type: u32
|
||||
|
||||
-
|
||||
name: mm-stat
|
||||
attr-cnt-name: __ethtool-a-mm-stat-cnt
|
||||
doc: MAC Merge (802.3)
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
-
|
||||
name: reassembly-errors
|
||||
doc: aMACMergeFrameAssErrorCount
|
||||
type: u64
|
||||
-
|
||||
name: smd-errors
|
||||
doc: aMACMergeFrameSmdErrorCount
|
||||
type: u64
|
||||
-
|
||||
name: reassembly-ok
|
||||
doc: aMACMergeFrameAssOkCount
|
||||
type: u64
|
||||
-
|
||||
name: rx-frag-count
|
||||
doc: aMACMergeFragCountRx
|
||||
type: u64
|
||||
-
|
||||
name: tx-frag-count
|
||||
doc: aMACMergeFragCountTx
|
||||
type: u64
|
||||
-
|
||||
name: hold-count
|
||||
doc: aMACMergeHoldCount
|
||||
type: u64
|
||||
-
|
||||
name: mm
|
||||
attr-cnt-name: __ethtool-a-mm-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -280,7 +425,12 @@ attribute-sets:
|
|||
nested-attributes: mm-stat
|
||||
-
|
||||
name: linkinfo
|
||||
attr-cnt-name: __ethtool-a-linkinfo-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -302,7 +452,12 @@ attribute-sets:
|
|||
type: u8
|
||||
-
|
||||
name: linkmodes
|
||||
attr-cnt-name: __ethtool-a-linkmodes-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -338,7 +493,12 @@ attribute-sets:
|
|||
type: u8
|
||||
-
|
||||
name: linkstate
|
||||
attr-cnt-name: __ethtool-a-linkstate-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -363,7 +523,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: debug
|
||||
attr-cnt-name: __ethtool-a-debug-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -374,7 +539,12 @@ attribute-sets:
|
|||
nested-attributes: bitset
|
||||
-
|
||||
name: wol
|
||||
attr-cnt-name: __ethtool-a-wol-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -388,7 +558,12 @@ attribute-sets:
|
|||
type: binary
|
||||
-
|
||||
name: features
|
||||
attr-cnt-name: __ethtool-a-features-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -411,7 +586,12 @@ attribute-sets:
|
|||
nested-attributes: bitset
|
||||
-
|
||||
name: channels
|
||||
attr-cnt-name: __ethtool-a-channels-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -443,7 +623,12 @@ attribute-sets:
|
|||
|
||||
-
|
||||
name: irq-moderation
|
||||
attr-cnt-name: __ethtool-a-irq-moderation-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: usec
|
||||
type: u32
|
||||
|
@ -455,7 +640,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: profile
|
||||
attr-cnt-name: __ethtool-a-profile-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: irq-moderation
|
||||
type: nest
|
||||
|
@ -463,7 +653,12 @@ attribute-sets:
|
|||
nested-attributes: irq-moderation
|
||||
-
|
||||
name: coalesce
|
||||
attr-cnt-name: __ethtool-a-coalesce-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -560,7 +755,12 @@ attribute-sets:
|
|||
|
||||
-
|
||||
name: pause-stat
|
||||
attr-cnt-name: __ethtool-a-pause-stat-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
|
@ -572,7 +772,12 @@ attribute-sets:
|
|||
type: u64
|
||||
-
|
||||
name: pause
|
||||
attr-cnt-name: __ethtool-a-pause-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -595,7 +800,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: eee
|
||||
attr-cnt-name: __ethtool-a-eee-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -622,7 +832,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: ts-stat
|
||||
attr-cnt-name: __ethtool-a-ts-stat-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: tx-pkts
|
||||
type: uint
|
||||
|
@ -632,9 +847,31 @@ attribute-sets:
|
|||
-
|
||||
name: tx-err
|
||||
type: uint
|
||||
-
|
||||
name: tx-onestep-pkts-unconfirmed
|
||||
type: uint
|
||||
-
|
||||
name: ts-hwtstamp-provider
|
||||
attr-cnt-name: __ethtool-a-ts-hwtstamp-provider-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: index
|
||||
type: u32
|
||||
-
|
||||
name: qualifier
|
||||
type: u32
|
||||
-
|
||||
name: tsinfo
|
||||
attr-cnt-name: __ethtool-a-tsinfo-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -658,21 +895,38 @@ attribute-sets:
|
|||
name: stats
|
||||
type: nest
|
||||
nested-attributes: ts-stat
|
||||
-
|
||||
name: hwtstamp-provider
|
||||
type: nest
|
||||
nested-attributes: ts-hwtstamp-provider
|
||||
-
|
||||
name: cable-result
|
||||
attr-cnt-name: __ethtool-a-cable-result-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pair
|
||||
doc: ETHTOOL_A_CABLE_PAIR
|
||||
type: u8
|
||||
-
|
||||
name: code
|
||||
doc: ETHTOOL_A_CABLE_RESULT_CODE
|
||||
type: u8
|
||||
-
|
||||
name: src
|
||||
doc: ETHTOOL_A_CABLE_INF_SRC
|
||||
type: u32
|
||||
-
|
||||
name: cable-fault-length
|
||||
attr-cnt-name: __ethtool-a-cable-fault-length-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pair
|
||||
type: u8
|
||||
|
@ -684,7 +938,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: cable-nest
|
||||
attr-cnt-name: __ethtool-a-cable-nest-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: result
|
||||
type: nest
|
||||
|
@ -695,20 +954,31 @@ attribute-sets:
|
|||
nested-attributes: cable-fault-length
|
||||
-
|
||||
name: cable-test
|
||||
attr-cnt-name: __ethtool-a-cable-test-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
name: cable-test-ntf
|
||||
attr-cnt-name: __ethtool-a-cable-test-ntf-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
name: status
|
||||
doc: _STARTED/_COMPLETE
|
||||
type: u8
|
||||
-
|
||||
name: nest
|
||||
|
@ -716,7 +986,12 @@ attribute-sets:
|
|||
nested-attributes: cable-nest
|
||||
-
|
||||
name: cable-test-tdr-cfg
|
||||
attr-cnt-name: __ethtool-a-cable-test-tdr-cfg-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: first
|
||||
type: u32
|
||||
|
@ -731,7 +1006,12 @@ attribute-sets:
|
|||
type: u8
|
||||
-
|
||||
name: cable-test-tdr-ntf
|
||||
attr-cnt-name: __ethtool-a-cable-test-tdr-ntf-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -745,7 +1025,12 @@ attribute-sets:
|
|||
nested-attributes: cable-nest
|
||||
-
|
||||
name: cable-test-tdr
|
||||
attr-cnt-name: __ethtool-a-cable-test-tdr-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -756,7 +1041,12 @@ attribute-sets:
|
|||
nested-attributes: cable-test-tdr-cfg
|
||||
-
|
||||
name: tunnel-udp-entry
|
||||
attr-cnt-name: __ethtool-a-tunnel-udp-entry-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: port
|
||||
type: u16
|
||||
|
@ -767,7 +1057,12 @@ attribute-sets:
|
|||
enum: udp-tunnel-type
|
||||
-
|
||||
name: tunnel-udp-table
|
||||
attr-cnt-name: __ethtool-a-tunnel-udp-table-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: size
|
||||
type: u32
|
||||
|
@ -782,14 +1077,24 @@ attribute-sets:
|
|||
nested-attributes: tunnel-udp-entry
|
||||
-
|
||||
name: tunnel-udp
|
||||
attr-cnt-name: __ethtool-a-tunnel-udp-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: table
|
||||
type: nest
|
||||
nested-attributes: tunnel-udp-table
|
||||
-
|
||||
name: tunnel-info
|
||||
attr-cnt-name: __ethtool-a-tunnel-info-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -800,7 +1105,12 @@ attribute-sets:
|
|||
nested-attributes: tunnel-udp
|
||||
-
|
||||
name: fec-stat
|
||||
attr-cnt-name: __ethtool-a-fec-stat-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
|
@ -818,7 +1128,12 @@ attribute-sets:
|
|||
sub-type: u64
|
||||
-
|
||||
name: fec
|
||||
attr-cnt-name: __ethtool-a-fec-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -839,7 +1154,12 @@ attribute-sets:
|
|||
nested-attributes: fec-stat
|
||||
-
|
||||
name: module-eeprom
|
||||
attr-cnt-name: __ethtool-a-module-eeprom-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -864,7 +1184,12 @@ attribute-sets:
|
|||
type: binary
|
||||
-
|
||||
name: stats-grp
|
||||
attr-cnt-name: __ethtool-a-stats-grp-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
|
@ -907,7 +1232,12 @@ attribute-sets:
|
|||
name: hist-val
|
||||
-
|
||||
name: stats
|
||||
attr-cnt-name: __ethtool-a-stats-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: pad
|
||||
type: pad
|
||||
|
@ -928,7 +1258,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: phc-vclocks
|
||||
attr-cnt-name: __ethtool-a-phc-vclocks-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -942,7 +1277,12 @@ attribute-sets:
|
|||
sub-type: s32
|
||||
-
|
||||
name: module
|
||||
attr-cnt-name: __ethtool-a-module-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -955,7 +1295,13 @@ attribute-sets:
|
|||
type: u8
|
||||
-
|
||||
name: c33-pse-pw-limit
|
||||
attr-cnt-name: __ethtool-a-c33-pse-pw-limit-cnt
|
||||
attr-max-name: __ethtool-a-c33-pse-pw-limit-max
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: min
|
||||
type: u32
|
||||
|
@ -964,7 +1310,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: pse
|
||||
attr-cnt-name: __ethtool-a-pse-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -1022,7 +1373,12 @@ attribute-sets:
|
|||
nested-attributes: c33-pse-pw-limit
|
||||
-
|
||||
name: rss
|
||||
attr-cnt-name: __ethtool-a-rss-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -1048,7 +1404,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: plca
|
||||
attr-cnt-name: __ethtool-a-plca-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -1079,7 +1440,12 @@ attribute-sets:
|
|||
type: u32
|
||||
-
|
||||
name: module-fw-flash
|
||||
attr-cnt-name: __ethtool-a-module-fw-flash-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -1105,7 +1471,12 @@ attribute-sets:
|
|||
type: uint
|
||||
-
|
||||
name: phy
|
||||
attr-cnt-name: __ethtool-a-phy-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
|
@ -1132,6 +1503,34 @@ attribute-sets:
|
|||
-
|
||||
name: downstream-sfp-name
|
||||
type: string
|
||||
-
|
||||
name: tsconfig
|
||||
attr-cnt-name: __ethtool-a-tsconfig-cnt
|
||||
attributes:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: header
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
name: hwtstamp-provider
|
||||
type: nest
|
||||
nested-attributes: ts-hwtstamp-provider
|
||||
-
|
||||
name: tx-types
|
||||
type: nest
|
||||
nested-attributes: bitset
|
||||
-
|
||||
name: rx-filters
|
||||
type: nest
|
||||
nested-attributes: bitset
|
||||
-
|
||||
name: hwtstamp-flags
|
||||
type: nest
|
||||
nested-attributes: bitset
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
|
@ -1393,6 +1792,8 @@ operations:
|
|||
- rx-push
|
||||
- tx-push-buf-len
|
||||
- tx-push-buf-len-max
|
||||
- hds-thresh
|
||||
- hds-thresh-max
|
||||
dump: *ring-get-op
|
||||
-
|
||||
name: rings-set
|
||||
|
@ -1573,6 +1974,7 @@ operations:
|
|||
request:
|
||||
attributes:
|
||||
- header
|
||||
- hwtstamp-provider
|
||||
reply:
|
||||
attributes:
|
||||
- header
|
||||
|
@ -1581,6 +1983,7 @@ operations:
|
|||
- rx-filters
|
||||
- phc-index
|
||||
- stats
|
||||
- hwtstamp-provider
|
||||
dump: *tsinfo-get-op
|
||||
-
|
||||
name: cable-test-act
|
||||
|
@ -1951,3 +2354,36 @@ operations:
|
|||
- upstream-sfp-name
|
||||
- downstream-sfp-name
|
||||
dump: *phy-get-op
|
||||
-
|
||||
name: phy-ntf
|
||||
doc: Notification for change in PHY devices.
|
||||
notify: phy-get
|
||||
-
|
||||
name: tsconfig-get
|
||||
doc: Get hwtstamp config.
|
||||
|
||||
attribute-set: tsconfig
|
||||
|
||||
do: &tsconfig-get-op
|
||||
request:
|
||||
attributes:
|
||||
- header
|
||||
reply:
|
||||
attributes: &tsconfig
|
||||
- header
|
||||
- hwtstamp-provider
|
||||
- tx-types
|
||||
- rx-filters
|
||||
- hwtstamp-flags
|
||||
dump: *tsconfig-get-op
|
||||
-
|
||||
name: tsconfig-set
|
||||
doc: Set hwtstamp config.
|
||||
|
||||
attribute-set: tsconfig
|
||||
|
||||
do:
|
||||
request:
|
||||
attributes: *tsconfig
|
||||
reply:
|
||||
attributes: *tsconfig
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
======================
|
||||
Networking Diagnostics
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
twisted_pair_layer1_diagnostics.rst
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
|
@ -0,0 +1,784 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Diagnostic Concept for Investigating Twisted Pair Ethernet Variants at OSI Layer 1
|
||||
==================================================================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This documentation is designed for two primary audiences:
|
||||
|
||||
1. **Users and System Administrators**: For those dealing with real-world
|
||||
Ethernet issues, this guide provides a practical, step-by-step
|
||||
troubleshooting flow to help identify and resolve common problems in Twisted
|
||||
Pair Ethernet at OSI Layer 1. If you're facing unstable links, speed drops,
|
||||
or mysterious network issues, jump right into the step-by-step guide and
|
||||
follow it through to find your solution.
|
||||
|
||||
2. **Kernel Developers**: For developers working with network drivers and PHY
|
||||
support, this documentation outlines the diagnostic process and highlights
|
||||
areas where the Linux kernel’s diagnostic interfaces could be extended or
|
||||
improved. By understanding the diagnostic flow, developers can better
|
||||
prioritize future enhancements.
|
||||
|
||||
Step-by-Step Diagnostic Guide from Linux (General Ethernet)
|
||||
-----------------------------------------------------------
|
||||
|
||||
This diagnostic guide covers common Ethernet troubleshooting scenarios,
|
||||
focusing on **link stability and detection** across different Ethernet
|
||||
environments, including **Single-Pair Ethernet (SPE)** and **Multi-Pair
|
||||
Ethernet (MPE)**, as well as power delivery technologies like **PoDL** (Power
|
||||
over Data Line) and **PoE** (Clause 33 PSE).
|
||||
|
||||
The guide is designed to help users diagnose physical layer (Layer 1) issues on
|
||||
systems running **Linux kernel version 6.11 or newer**, utilizing **ethtool
|
||||
version 6.10 or later** and **iproute2 version 6.4.0 or later**.
|
||||
|
||||
In this guide, we assume that users may have **limited or no access to the link
|
||||
partner** and will focus on diagnosing issues locally.
|
||||
|
||||
Diagnostic Scenarios
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **Link is up and stable, but no data transfer**: If the link is stable but
|
||||
there are issues with data transmission, refer to the **OSI Layer 2
|
||||
Troubleshooting Guide**.
|
||||
|
||||
- **Link is unstable**: Link resets, speed drops, or other fluctuations
|
||||
indicate potential issues at the hardware or physical layer.
|
||||
|
||||
- **No link detected**: The interface is up, but no link is established.
|
||||
|
||||
Verify Interface Status
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Begin by verifying the status of the Ethernet interface to check if it is
|
||||
administratively up. Unlike `ethtool`, which provides information on the link
|
||||
and PHY status, it does not show the **administrative state** of the interface.
|
||||
To check this, you should use the `ip` command, which describes the interface
|
||||
state within the angle brackets `"<>"` in its output.
|
||||
|
||||
For example, in the output `<NO-CARRIER,BROADCAST,MULTICAST,UP>`, the important
|
||||
keywords are:
|
||||
|
||||
- **UP**: The interface is in the administrative "UP" state.
|
||||
- **NO-CARRIER**: The interface is administratively up, but no physical link is
|
||||
detected.
|
||||
|
||||
If the output shows `<BROADCAST,MULTICAST>`, this indicates the interface is in
|
||||
the administrative "DOWN" state.
|
||||
|
||||
- **Command:** `ip link show dev <interface>`
|
||||
|
||||
- **Expected Output:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
4: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 ...
|
||||
link/ether 88:14:2b:00:96:f2 brd ff:ff:ff:ff:ff:ff
|
||||
|
||||
- **Interpreting the Output:**
|
||||
|
||||
- **Administrative UP State**:
|
||||
|
||||
- If the output contains **"UP"**, the interface is administratively up,
|
||||
and the system is trying to establish a physical link.
|
||||
|
||||
- If you also see **"NO-CARRIER"**, it means the physical link has not been
|
||||
detected, indicating potential Layer 1 issues like a cable fault,
|
||||
misconfiguration, or no connection at the link partner. In this case,
|
||||
proceed to the **Inspect Link Status and PHY Configuration** section.
|
||||
|
||||
- **Administrative DOWN State**:
|
||||
|
||||
- If the output lacks **"UP"** and shows only states like
|
||||
**"<BROADCAST,MULTICAST>"**, it means the interface is administratively
|
||||
down. In this case, bring the interface up using the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ip link set dev <interface> up
|
||||
|
||||
- **Next Steps**:
|
||||
|
||||
- If the interface is **administratively up** but shows **NO-CARRIER**,
|
||||
proceed to the **Inspect Link Status and PHY Configuration** section to
|
||||
troubleshoot potential physical layer issues.
|
||||
|
||||
- If the interface was **administratively down** and you have brought it up,
|
||||
ensure to **repeat this verification step** to confirm the new state of the
|
||||
interface before proceeding
|
||||
|
||||
- **If the interface is up and the link is detected**:
|
||||
|
||||
- If the output shows **"UP"** and there is **no `NO-CARRIER`**, the
|
||||
interface is administratively up, and the physical link has been
|
||||
successfully established. If everything is working as expected, the Layer
|
||||
1 diagnostics are complete, and no further action is needed.
|
||||
|
||||
- If the interface is up and the link is detected but **no data is being
|
||||
transferred**, the issue is likely beyond Layer 1, and you should proceed
|
||||
with diagnosing the higher layers of the OSI model. This may involve
|
||||
checking Layer 2 configurations (such as VLANs or MAC address issues),
|
||||
Layer 3 settings (like IP addresses, routing, or ARP), or Layer 4 and
|
||||
above (firewalls, services, etc.).
|
||||
|
||||
- If the **link is unstable** or **frequently resetting or dropping**, this
|
||||
may indicate a physical layer issue such as a faulty cable, interference,
|
||||
or power delivery problems. In this case, proceed with the next step in
|
||||
this guide.
|
||||
|
||||
Inspect Link Status and PHY Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use `ethtool -I` to check the link status, PHY configuration, supported link
|
||||
modes, and additional statistics such as the **Link Down Events** counter. This
|
||||
step is essential for diagnosing Layer 1 problems such as speed mismatches,
|
||||
duplex issues, and link instability.
|
||||
|
||||
For both **Single-Pair Ethernet (SPE)** and **Multi-Pair Ethernet (MPE)**
|
||||
devices, you will use this step to gather key details about the link. **SPE**
|
||||
links generally support a single speed and mode without autonegotiation (with
|
||||
the exception of **10BaseT1L**), while **MPE** devices typically support
|
||||
multiple link modes and autonegotiation.
|
||||
|
||||
- **Command:** `ethtool -I <interface>`
|
||||
|
||||
- **Example Output for SPE Interface (Non-autonegotiation)**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Settings for spe4:
|
||||
Supported ports: [ TP ]
|
||||
Supported link modes: 100baseT1/Full
|
||||
Supported pause frame use: No
|
||||
Supports auto-negotiation: No
|
||||
Supported FEC modes: Not reported
|
||||
Advertised link modes: Not applicable
|
||||
Advertised pause frame use: No
|
||||
Advertised auto-negotiation: No
|
||||
Advertised FEC modes: Not reported
|
||||
Speed: 100Mb/s
|
||||
Duplex: Full
|
||||
Auto-negotiation: off
|
||||
master-slave cfg: forced slave
|
||||
master-slave status: slave
|
||||
Port: Twisted Pair
|
||||
PHYAD: 6
|
||||
Transceiver: external
|
||||
MDI-X: Unknown
|
||||
Supports Wake-on: d
|
||||
Wake-on: d
|
||||
Link detected: yes
|
||||
SQI: 7/7
|
||||
Link Down Events: 2
|
||||
|
||||
- **Example Output for MPE Interface (Autonegotiation)**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Settings for eth1:
|
||||
Supported ports: [ TP MII ]
|
||||
Supported link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
Supported pause frame use: Symmetric Receive-only
|
||||
Supports auto-negotiation: Yes
|
||||
Supported FEC modes: Not reported
|
||||
Advertised link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
Advertised pause frame use: Symmetric Receive-only
|
||||
Advertised auto-negotiation: Yes
|
||||
Advertised FEC modes: Not reported
|
||||
Link partner advertised link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
Link partner advertised pause frame use: Symmetric Receive-only
|
||||
Link partner advertised auto-negotiation: Yes
|
||||
Link partner advertised FEC modes: Not reported
|
||||
Speed: 100Mb/s
|
||||
Duplex: Full
|
||||
Auto-negotiation: on
|
||||
Port: Twisted Pair
|
||||
PHYAD: 10
|
||||
Transceiver: internal
|
||||
MDI-X: Unknown
|
||||
Supports Wake-on: pg
|
||||
Wake-on: p
|
||||
Link detected: yes
|
||||
Link Down Events: 1
|
||||
|
||||
- **Next Steps**:
|
||||
|
||||
- Record the output provided by `ethtool`, particularly noting the
|
||||
**master-slave status**, **speed**, **duplex**, and other relevant fields.
|
||||
This information will be useful for further analysis or troubleshooting.
|
||||
Once the **ethtool** output has been collected and stored, move on to the
|
||||
next diagnostic step.
|
||||
|
||||
Check Power Delivery (PoDL or PoE)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If it is known that **PoDL** or **PoE** is **not implemented** on the system,
|
||||
or the **PSE** (Power Sourcing Equipment) is managed by proprietary user-space
|
||||
software or external tools, you can skip this step. In such cases, verify power
|
||||
delivery through alternative methods, such as checking hardware indicators
|
||||
(LEDs), using multimeters, or consulting vendor-specific software for
|
||||
monitoring power status.
|
||||
|
||||
If **PoDL** or **PoE** is implemented and managed directly by Linux, follow
|
||||
these steps to ensure power is being delivered correctly:
|
||||
|
||||
- **Command:** `ethtool --show-pse <interface>`
|
||||
|
||||
- **Expected Output Examples**:
|
||||
|
||||
1. **PSE Not Supported**:
|
||||
|
||||
If no PSE is attached or the interface does not support PSE, the following
|
||||
output is expected:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
netlink error: No PSE is attached
|
||||
netlink error: Operation not supported
|
||||
|
||||
2. **PoDL (Single-Pair Ethernet)**:
|
||||
|
||||
When PoDL is implemented, you might see the following attributes:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
PSE attributes for eth1:
|
||||
PoDL PSE Admin State: enabled
|
||||
PoDL PSE Power Detection Status: delivering power
|
||||
|
||||
3. **PoE (Clause 33 PSE)**:
|
||||
|
||||
For standard PoE, the output may look like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
PSE attributes for eth1:
|
||||
Clause 33 PSE Admin State: enabled
|
||||
Clause 33 PSE Power Detection Status: delivering power
|
||||
Clause 33 PSE Available Power Limit: 18000
|
||||
|
||||
- **Adjust Power Limit (if needed)**:
|
||||
|
||||
- Sometimes, the available power limit may not be sufficient for the link
|
||||
partner. You can increase the power limit as needed.
|
||||
|
||||
- **Command:** `ethtool --set-pse <interface> c33-pse-avail-pw-limit <limit>`
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool --set-pse eth1 c33-pse-avail-pw-limit 18000
|
||||
ethtool --show-pse eth1
|
||||
|
||||
**Expected Output** after adjusting the power limit:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Clause 33 PSE Available Power Limit: 18000
|
||||
|
||||
|
||||
- **Next Steps**:
|
||||
|
||||
- **PoE or PoDL Not Used**: If **PoE** or **PoDL** is not implemented or used
|
||||
on the system, proceed to the next diagnostic step, as power delivery is
|
||||
not relevant for this setup.
|
||||
|
||||
- **PoE or PoDL Controlled Externally**: If **PoE** or **PoDL** is used but
|
||||
is not managed by the Linux kernel's **PSE-PD** framework (i.e., it is
|
||||
controlled by proprietary user-space software or external tools), this part
|
||||
is out of scope for this documentation. Please consult vendor-specific
|
||||
documentation or external tools for monitoring and managing power delivery.
|
||||
|
||||
- **PSE Admin State Disabled**:
|
||||
|
||||
- If the `PSE Admin State:` is **disabled**, enable it by running one of
|
||||
the following commands:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool --set-pse <devname> podl-pse-admin-control enable
|
||||
|
||||
or, for Clause 33 PSE (PoE):
|
||||
|
||||
ethtool --set-pse <devname> c33-pse-admin-control enable
|
||||
|
||||
- After enabling the PSE Admin State, return to the start of the **Check
|
||||
Power Delivery (PoDL or PoE)** step to recheck the power delivery status.
|
||||
|
||||
- **Power Not Delivered**: If the `Power Detection Status` shows something
|
||||
other than "delivering power" (e.g., `over current`), troubleshoot the
|
||||
**PSE**. Check for potential issues such as a short circuit in the cable,
|
||||
insufficient power delivery, or a fault in the PSE itself.
|
||||
|
||||
- **Power Delivered but No Link**: If power is being delivered but no link is
|
||||
established, proceed with further diagnostics by performing **Cable
|
||||
Diagnostics** or reviewing the **Inspect Link Status and PHY
|
||||
Configuration** steps to identify any underlying issues with the physical
|
||||
link or settings.
|
||||
|
||||
Cable Diagnostics
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use `ethtool` to test for physical layer issues such as cable faults. The test
|
||||
results can vary depending on the cable's condition, the technology in use, and
|
||||
the state of the link partner. The results from the cable test will help in
|
||||
diagnosing issues like open circuits, shorts, impedance mismatches, and
|
||||
noise-related problems.
|
||||
|
||||
- **Command:** `ethtool --cable-test <interface>`
|
||||
|
||||
The following are the typical outputs for **Single-Pair Ethernet (SPE)** and
|
||||
**Multi-Pair Ethernet (MPE)**:
|
||||
|
||||
- **For Single-Pair Ethernet (SPE)**:
|
||||
- **Expected Output (SPE)**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Cable test completed for device eth1.
|
||||
Pair A, fault length: 25.00m
|
||||
Pair A code Open Circuit
|
||||
|
||||
This indicates an open circuit or cable fault at the reported distance, but
|
||||
results can be influenced by the link partner's state. Refer to the
|
||||
**"Troubleshooting Based on Cable Test Results"** section for further
|
||||
interpretation of these results.
|
||||
|
||||
- **For Multi-Pair Ethernet (MPE)**:
|
||||
- **Expected Output (MPE)**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Cable test completed for device eth0.
|
||||
Pair A code OK
|
||||
Pair B code OK
|
||||
Pair C code Open Circuit
|
||||
|
||||
Here, Pair C is reported as having an open circuit, while Pairs A and B are
|
||||
functioning correctly. However, if autonegotiation is in use on Pairs A and
|
||||
B, the cable test may be disrupted. Refer to the **"Troubleshooting Based on
|
||||
Cable Test Results"** section for a detailed explanation of these issues and
|
||||
how to resolve them.
|
||||
|
||||
For detailed descriptions of the different possible cable test results, please
|
||||
refer to the **"Troubleshooting Based on Cable Test Results"** section.
|
||||
|
||||
Troubleshooting Based on Cable Test Results
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After running the cable test, the results can help identify specific issues in
|
||||
the physical connection. However, it is important to note that **cable testing
|
||||
results heavily depend on the capabilities and characteristics of both the
|
||||
local hardware and the link partner**. The accuracy and reliability of the
|
||||
results can vary significantly between different hardware implementations.
|
||||
|
||||
In some cases, this can introduce **blind spots** in the current cable testing
|
||||
implementation, where certain results may not accurately reflect the actual
|
||||
physical state of the cable. For example:
|
||||
|
||||
- An **Open Circuit** result might not only indicate a damaged or disconnected
|
||||
cable but also occur if the cable is properly attached to a powered-down link
|
||||
partner.
|
||||
|
||||
- Some PHYs may report a **Short within Pair** if the link partner is in
|
||||
**forced slave mode**, even though there is no actual short in the cable.
|
||||
|
||||
To help users interpret the results more effectively, it could be beneficial to
|
||||
extend the **kernel UAPI** (User API) to provide additional context or
|
||||
**possible variants** of issues based on the hardware’s characteristics. Since
|
||||
these quirks are often hardware-specific, the **kernel driver** would be an
|
||||
ideal source of such information. By providing flags or hints related to
|
||||
potential false positives for each test result, users would have a better
|
||||
understanding of what to verify and where to investigate further.
|
||||
|
||||
Until such improvements are made, users should be aware of these limitations
|
||||
and manually verify cable issues as needed. Physical inspections may help
|
||||
resolve uncertainties related to false positive results.
|
||||
|
||||
The results can be one of the following:
|
||||
|
||||
- **OK**:
|
||||
|
||||
- The cable is functioning correctly, and no issues were detected.
|
||||
|
||||
- **Next Steps**: If you are still experiencing issues, it might be related
|
||||
to higher-layer problems, such as duplex mismatches or speed negotiation,
|
||||
which are not physical-layer issues.
|
||||
|
||||
- **Special Case for `BaseT1` (1000/100/10BaseT1)**: In `BaseT1` systems, an
|
||||
"OK" result typically also means that the link is up and likely in **slave
|
||||
mode**, since cable tests usually only pass in this mode. For some
|
||||
**10BaseT1L** PHYs, an "OK" result may occur even if the cable is too long
|
||||
for the PHY's configured range (for example, when the range is configured
|
||||
for short-distance mode).
|
||||
|
||||
- **Open Circuit**:
|
||||
|
||||
- An **Open Circuit** result typically indicates that the cable is damaged or
|
||||
disconnected at the reported fault length. Consider these possibilities:
|
||||
|
||||
- If the link partner is in **admin down** state or powered off, you might
|
||||
still get an "Open Circuit" result even if the cable is functional.
|
||||
|
||||
- **Next Steps**: Inspect the cable at the fault length for visible damage
|
||||
or loose connections. Verify the link partner is powered on and in the
|
||||
correct mode.
|
||||
|
||||
- **Short within Pair**:
|
||||
|
||||
- A **Short within Pair** indicates an unintended connection within the same
|
||||
pair of wires, typically caused by physical damage to the cable.
|
||||
|
||||
- **Next Steps**: Replace or repair the cable and check for any physical
|
||||
damage or improperly crimped connectors.
|
||||
|
||||
- **Short to Another Pair**:
|
||||
|
||||
- A **Short to Another Pair** means the wires from different pairs are
|
||||
shorted, which could occur due to physical damage or incorrect wiring.
|
||||
|
||||
- **Next Steps**: Replace or repair the damaged cable. Inspect the cable for
|
||||
incorrect terminations or pinched wiring.
|
||||
|
||||
- **Impedance Mismatch**:
|
||||
|
||||
- **Impedance Mismatch** indicates a reflection caused by an impedance
|
||||
discontinuity in the cable. This can happen when a part of the cable has
|
||||
abnormal impedance (e.g., when different cable types are spliced together
|
||||
or when there is a defect in the cable).
|
||||
|
||||
- **Next Steps**: Check the cable quality and ensure consistent impedance
|
||||
throughout its length. Replace any sections of the cable that do not meet
|
||||
specifications.
|
||||
|
||||
- **Noise**:
|
||||
|
||||
- **Noise** means that the Time Domain Reflectometry (TDR) test could not
|
||||
complete due to excessive noise on the cable, which can be caused by
|
||||
interference from electromagnetic sources.
|
||||
|
||||
- **Next Steps**: Identify and eliminate sources of electromagnetic
|
||||
interference (EMI) near the cable. Consider using shielded cables or
|
||||
rerouting the cable away from noise sources.
|
||||
|
||||
- **Resolution Not Possible**:
|
||||
|
||||
- **Resolution Not Possible** means that the TDR test could not detect the
|
||||
issue due to the resolution limitations of the test or because the fault is
|
||||
beyond the distance that the test can measure.
|
||||
|
||||
- **Next Steps**: Inspect the cable manually if possible, or use alternative
|
||||
diagnostic tools that can handle greater distances or higher resolution.
|
||||
|
||||
- **Unknown**:
|
||||
|
||||
- An **Unknown** result may occur when the test cannot classify the fault or
|
||||
when a specific issue is outside the scope of the tool's detection
|
||||
capabilities.
|
||||
|
||||
- **Next Steps**: Re-run the test, verify the link partner's state, and inspect
|
||||
the cable manually if necessary.
|
||||
|
||||
Verify Link Partner PHY Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the cable test passes but the link is still not functioning correctly, it’s
|
||||
essential to verify the configuration of the link partner’s PHY. Mismatches in
|
||||
speed, duplex settings, or master-slave roles can cause connection issues.
|
||||
|
||||
Autonegotiation Mismatch
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- If both link partners support autonegotiation, ensure that autonegotiation is
|
||||
enabled on both sides and that all supported link modes are advertised. A
|
||||
mismatch can lead to connectivity problems or sub optimal performance.
|
||||
|
||||
- **Quick Fix:** Reset autonegotiation to the default settings, which will
|
||||
advertise all default link modes:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool -s <interface> autoneg on
|
||||
|
||||
- **Command to check configuration:** `ethtool <interface>`
|
||||
|
||||
- **Expected Output:** Ensure that both sides advertise compatible link modes.
|
||||
If autonegotiation is off, verify that both link partners are configured for
|
||||
the same speed and duplex.
|
||||
|
||||
The following example shows a case where the local PHY advertises fewer link
|
||||
modes than it supports. This will reduce the number of overlapping link modes
|
||||
with the link partner. In the worst case, there will be no common link modes,
|
||||
and the link will not be created:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Settings for eth0:
|
||||
Supported link modes: 1000baseT/Full, 100baseT/Full
|
||||
Advertised link modes: 1000baseT/Full
|
||||
Speed: 1000Mb/s
|
||||
Duplex: Full
|
||||
Auto-negotiation: on
|
||||
|
||||
Combined Mode Mismatch (Autonegotiation on One Side, Forced on the Other)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- One possible issue occurs when one side is using **autonegotiation** (as in
|
||||
most modern systems), and the other side is set to a **forced link mode**
|
||||
(e.g., older hardware with single-speed hubs). In such cases, modern PHYs
|
||||
will attempt to detect the forced mode on the other side. If the link is
|
||||
established, you may notice:
|
||||
|
||||
- **No or empty "Link partner advertised link modes"**.
|
||||
|
||||
- **"Link partner advertised auto-negotiation:"** will be **"no"** or not
|
||||
present.
|
||||
|
||||
- This type of detection does not always work reliably:
|
||||
|
||||
- Typically, the modern PHY will default to **Half Duplex**, even if the link
|
||||
partner is actually configured for **Full Duplex**.
|
||||
|
||||
- Some PHYs may not work reliably if the link partner switches from one
|
||||
forced mode to another. In this case, only a down/up cycle may help.
|
||||
|
||||
- **Next Steps**: Set both sides to the same fixed speed and duplex mode to
|
||||
avoid potential detection issues.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool -s <interface> speed 1000 duplex full autoneg off
|
||||
|
||||
Master/Slave Role Mismatch (BaseT1 and 1000BaseT PHYs)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- In **BaseT1** systems (e.g., 1000BaseT1, 100BaseT1), link establishment
|
||||
requires that one device is configured as **master** and the other as
|
||||
**slave**. A mismatch in this master-slave configuration can prevent the link
|
||||
from being established. However, **1000BaseT** also supports configurable
|
||||
master/slave roles and can face similar issues.
|
||||
|
||||
- **Role Preference in 1000BaseT**: The **1000BaseT** specification allows link
|
||||
partners to negotiate master-slave roles or role preferences during
|
||||
autonegotiation. Some PHYs have hardware limitations or bugs that prevent
|
||||
them from functioning properly in certain roles. In such cases, drivers may
|
||||
force these PHYs into a specific role (e.g., **forced master** or **forced
|
||||
slave**) or try a weaker option by setting preferences. If both link partners
|
||||
have the same issue and are forced into the same mode (e.g., both forced into
|
||||
master mode), they will not be able to establish a link.
|
||||
|
||||
- **Next Steps**: Ensure that one side is configured as **master** and the
|
||||
other as **slave** to avoid this issue, particularly when hardware
|
||||
limitations are involved, or try the weaker **preferred** option instead of
|
||||
**forced**. Check for any driver-related restrictions or forced modes.
|
||||
|
||||
- **Command to force master/slave mode**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool -s <interface> master-slave forced-master
|
||||
|
||||
or:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool -s <interface> master-slave forced-master speed 1000 duplex full autoneg off
|
||||
|
||||
|
||||
- **Check the current master/slave status**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool <interface>
|
||||
|
||||
Example Output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
master-slave cfg: forced-master
|
||||
master-slave status: master
|
||||
|
||||
- **Hardware Bugs and Driver Forcing**: If a known hardware issue forces the
|
||||
PHY into a specific mode, it’s essential to check the driver source code or
|
||||
hardware documentation for details. Ensure that the roles are compatible
|
||||
across both link partners, and if both PHYs are forced into the same mode,
|
||||
adjust one side accordingly to resolve the mismatch.
|
||||
|
||||
Monitor Link Resets and Speed Drops
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the link is unstable, showing frequent resets or speed drops, this may
|
||||
indicate issues with the cable, PHY configuration, or environmental factors.
|
||||
While there is still no completely unified way in Linux to directly monitor
|
||||
downshift events or link speed changes via user space tools, both the Linux
|
||||
kernel logs and `ethtool` can provide valuable insights, especially if the
|
||||
driver supports reporting such events.
|
||||
|
||||
- **Monitor Kernel Logs for Link Resets and Speed Drops**:
|
||||
|
||||
- The Linux kernel will print link status changes, including downshift
|
||||
events, in the system logs. These messages typically include speed changes,
|
||||
duplex mode, and downshifted link speed (if the driver supports it).
|
||||
|
||||
- **Command to monitor kernel logs in real-time:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
dmesg -w | grep "Link is Up\|Link is Down"
|
||||
|
||||
- Example Output (if a downshift occurs):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
eth0: Link is Up - 100Mbps/Full (downshifted) - flow control rx/tx
|
||||
eth0: Link is Down
|
||||
|
||||
This indicates that the link has been established but has downshifted from
|
||||
a higher speed.
|
||||
|
||||
- **Note**: Not all drivers or PHYs support downshift reporting, so you may
|
||||
not see this information for all devices.
|
||||
|
||||
- **Monitor Link Down Events Using `ethtool`**:
|
||||
|
||||
- Starting with the latest kernel and `ethtool` versions, you can track
|
||||
**Link Down Events** using the `ethtool -I` command. This will provide
|
||||
counters for link drops, helping to diagnose link instability issues if
|
||||
supported by the driver.
|
||||
|
||||
- **Command to monitor link down events:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool -I <interface>
|
||||
|
||||
- Example Output (if supported):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
PSE attributes for eth1:
|
||||
Link Down Events: 5
|
||||
|
||||
This indicates that the link has dropped 5 times. Frequent link down events
|
||||
may indicate cable or environmental issues that require further
|
||||
investigation.
|
||||
|
||||
- **Check Link Status and Speed**:
|
||||
|
||||
- Even though downshift counts or events are not easily tracked, you can
|
||||
still use `ethtool` to manually check the current link speed and status.
|
||||
|
||||
- **Command:** `ethtool <interface>`
|
||||
|
||||
- **Expected Output:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Speed: 1000Mb/s
|
||||
Duplex: Full
|
||||
Auto-negotiation: on
|
||||
Link detected: yes
|
||||
|
||||
Any inconsistencies in the expected speed or duplex setting could indicate
|
||||
an issue.
|
||||
|
||||
- **Disable Energy-Efficient Ethernet (EEE) for Diagnostics**:
|
||||
|
||||
- **EEE** (Energy-Efficient Ethernet) can be a source of link instability due
|
||||
to transitions in and out of low-power states. For diagnostic purposes, it
|
||||
may be useful to **temporarily** disable EEE to determine if it is
|
||||
contributing to link instability. This is **not a generic recommendation**
|
||||
for disabling power management.
|
||||
|
||||
- **Next Steps**: Disable EEE and monitor if the link becomes stable. If
|
||||
disabling EEE resolves the issue, report the bug so that the driver can be
|
||||
fixed.
|
||||
|
||||
- **Command:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ethtool --set-eee <interface> eee off
|
||||
|
||||
- **Important**: If disabling EEE resolves the instability, the issue should
|
||||
be reported to the maintainers as a bug, and the driver should be corrected
|
||||
to handle EEE properly without causing instability. Disabling EEE
|
||||
permanently should not be seen as a solution.
|
||||
|
||||
- **Monitor Error Counters**:
|
||||
|
||||
- Use `ethtool -S <interface> --all-groups` to retrieve standardized interface
|
||||
statistics if the driver supports the unified interface:
|
||||
|
||||
- **Command:** `ethtool -S <interface> --all-groups`
|
||||
|
||||
- **Example Output (if supported)**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
phydev-RxFrames: 100391
|
||||
phydev-RxErrors: 0
|
||||
phydev-TxFrames: 9
|
||||
phydev-TxErrors: 0
|
||||
|
||||
- If the unified interface is not supported, use `ethtool -S <interface>` to
|
||||
retrieve MAC and PHY counters. Note that non-standardized PHY counter names
|
||||
vary by driver and must be interpreted accordingly:
|
||||
|
||||
- **Command:** `ethtool -S <interface>`
|
||||
|
||||
- **Example Output (if supported)**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
rx_crc_errors: 123
|
||||
tx_errors: 45
|
||||
rx_frame_errors: 78
|
||||
|
||||
- **Note**: If no meaningful error counters are available or if counters are
|
||||
not supported, you may need to rely on physical inspections (e.g., cable
|
||||
condition) or kernel log messages (e.g., link up/down events) to further
|
||||
diagnose the issue.
|
||||
|
||||
- **Compare Counters**:
|
||||
|
||||
- Compare the egress and ingress frame counts reported by the PHY and MAC.
|
||||
|
||||
- A small difference may occur due to sampling rate differences between the
|
||||
MAC and PHY drivers, or if the PHY and MAC are not always fully
|
||||
synchronized in their UP or DOWN states.
|
||||
|
||||
- Significant discrepancies indicate potential issues in the data path
|
||||
between the MAC and PHY.
|
||||
|
||||
When All Else Fails...
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
So you've checked the cables, monitored the logs, disabled EEE, and still...
|
||||
nothing? Don’t worry, you’re not alone. Sometimes, Ethernet gremlins just don’t
|
||||
want to cooperate.
|
||||
|
||||
But before you throw in the towel (or the Ethernet cable), take a deep breath.
|
||||
It’s always possible that:
|
||||
|
||||
1. Your PHY has a unique, undocumented personality.
|
||||
|
||||
2. The problem is lying dormant, waiting for just the right moment to magically
|
||||
resolve itself (hey, it happens!).
|
||||
|
||||
3. Or, it could be that the ultimate solution simply hasn’t been invented yet.
|
||||
|
||||
If none of the above bring you comfort, there’s one final step: contribute! If
|
||||
you've uncovered new or unusual issues, or have creative diagnostic methods,
|
||||
feel free to share your findings and extend this documentation. Together, we
|
||||
can hunt down every elusive network issue - one twisted pair at a time.
|
||||
|
||||
Remember: sometimes the solution is just a reboot away, but if not, it’s time to
|
||||
dig deeper - or report that bug!
|
||||
|
|
@ -236,6 +236,9 @@ Userspace to kernel:
|
|||
``ETHTOOL_MSG_MM_GET`` get MAC merge layer state
|
||||
``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
|
||||
``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware
|
||||
``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information
|
||||
``ETHTOOL_MSG_TSCONFIG_GET`` get hw timestamping configuration
|
||||
``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration
|
||||
===================================== =================================
|
||||
|
||||
Kernel to userspace:
|
||||
|
@ -283,6 +286,10 @@ Kernel to userspace:
|
|||
``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters
|
||||
``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status
|
||||
``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates
|
||||
``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information
|
||||
``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change
|
||||
``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration
|
||||
``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configuration
|
||||
======================================== =================================
|
||||
|
||||
``GET`` requests are sent by userspace applications to retrieve device
|
||||
|
@ -892,6 +899,10 @@ Kernel response contents:
|
|||
``ETHTOOL_A_RINGS_RX_PUSH`` u8 flag of RX Push mode
|
||||
``ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN`` u32 size of TX push buffer
|
||||
``ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX`` u32 max size of TX push buffer
|
||||
``ETHTOOL_A_RINGS_HDS_THRESH`` u32 threshold of
|
||||
header / data split
|
||||
``ETHTOOL_A_RINGS_HDS_THRESH_MAX`` u32 max threshold of
|
||||
header / data split
|
||||
======================================= ====== ===========================
|
||||
|
||||
``ETHTOOL_A_RINGS_TCP_DATA_SPLIT`` indicates whether the device is usable with
|
||||
|
@ -934,10 +945,12 @@ Request contents:
|
|||
``ETHTOOL_A_RINGS_RX_JUMBO`` u32 size of RX jumbo ring
|
||||
``ETHTOOL_A_RINGS_TX`` u32 size of TX ring
|
||||
``ETHTOOL_A_RINGS_RX_BUF_LEN`` u32 size of buffers on the ring
|
||||
``ETHTOOL_A_RINGS_TCP_DATA_SPLIT`` u8 TCP header / data split
|
||||
``ETHTOOL_A_RINGS_CQE_SIZE`` u32 Size of TX/RX CQE
|
||||
``ETHTOOL_A_RINGS_TX_PUSH`` u8 flag of TX Push mode
|
||||
``ETHTOOL_A_RINGS_RX_PUSH`` u8 flag of RX Push mode
|
||||
``ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN`` u32 size of TX push buffer
|
||||
``ETHTOOL_A_RINGS_HDS_THRESH`` u32 threshold of header / data split
|
||||
==================================== ====== ===========================
|
||||
|
||||
Kernel checks that requested ring sizes do not exceed limits reported by
|
||||
|
@ -954,6 +967,10 @@ A bigger CQE can have more receive buffer pointers, and in turn the NIC can
|
|||
transfer a bigger frame from wire. Based on the NIC hardware, the overall
|
||||
completion queue size can be adjusted in the driver if CQE size is modified.
|
||||
|
||||
``ETHTOOL_A_RINGS_HDS_THRESH`` specifies the threshold value of
|
||||
header / data split feature. If a received packet size is larger than this
|
||||
threshold value, header and data will be split.
|
||||
|
||||
CHANNELS_GET
|
||||
============
|
||||
|
||||
|
@ -1242,9 +1259,10 @@ Gets timestamping information like ``ETHTOOL_GET_TS_INFO`` ioctl request.
|
|||
|
||||
Request contents:
|
||||
|
||||
===================================== ====== ==========================
|
||||
``ETHTOOL_A_TSINFO_HEADER`` nested request header
|
||||
===================================== ====== ==========================
|
||||
======================================== ====== ============================
|
||||
``ETHTOOL_A_TSINFO_HEADER`` nested request header
|
||||
``ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
|
||||
======================================== ====== ============================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
|
@ -1263,11 +1281,17 @@ would be empty (no bit set).
|
|||
|
||||
Additional hardware timestamping statistics response contents:
|
||||
|
||||
===================================== ====== ===================================
|
||||
``ETHTOOL_A_TS_STAT_TX_PKTS`` uint Packets with Tx HW timestamps
|
||||
``ETHTOOL_A_TS_STAT_TX_LOST`` uint Tx HW timestamp not arrived count
|
||||
``ETHTOOL_A_TS_STAT_TX_ERR`` uint HW error request Tx timestamp count
|
||||
===================================== ====== ===================================
|
||||
================================================== ====== =====================
|
||||
``ETHTOOL_A_TS_STAT_TX_PKTS`` uint Packets with Tx
|
||||
HW timestamps
|
||||
``ETHTOOL_A_TS_STAT_TX_LOST`` uint Tx HW timestamp
|
||||
not arrived count
|
||||
``ETHTOOL_A_TS_STAT_TX_ERR`` uint HW error request
|
||||
Tx timestamp count
|
||||
``ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED`` uint Packets with one-step
|
||||
HW TX timestamps with
|
||||
unconfirmed delivery
|
||||
================================================== ====== =====================
|
||||
|
||||
CABLE_TEST
|
||||
==========
|
||||
|
@ -1608,6 +1632,7 @@ the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:
|
|||
ETHTOOL_STATS_ETH_PHY eth-phy Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
|
||||
ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
|
||||
ETHTOOL_STATS_RMON rmon RMON (RFC 2819) statistics
|
||||
ETHTOOL_STATS_PHY phy Additional PHY statistics, not defined by IEEE
|
||||
====================== ======== ===============================================
|
||||
|
||||
Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
|
||||
|
@ -1909,7 +1934,7 @@ ETHTOOL_A_RSS_INDIR attribute returns RSS indirection table where each byte
|
|||
indicates queue number.
|
||||
ETHTOOL_A_RSS_INPUT_XFRM attribute is a bitmap indicating the type of
|
||||
transformation applied to the input protocol fields before given to the RSS
|
||||
hfunc. Current supported option is symmetric-xor.
|
||||
hfunc. Current supported options are symmetric-xor and symmetric-or-xor.
|
||||
|
||||
PLCA_GET_CFG
|
||||
============
|
||||
|
@ -2240,6 +2265,75 @@ Kernel response contents:
|
|||
When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is
|
||||
another PHY.
|
||||
|
||||
TSCONFIG_GET
|
||||
============
|
||||
|
||||
Retrieves the information about the current hardware timestamping source and
|
||||
configuration.
|
||||
|
||||
It is similar to the deprecated ``SIOCGHWTSTAMP`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
==================================== ====== ==========================
|
||||
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
|
||||
==================================== ====== ==========================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
======================================== ====== ============================
|
||||
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
|
||||
``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
|
||||
``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
|
||||
======================================== ====== ============================
|
||||
|
||||
When set the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` attribute identifies the
|
||||
source of the hw timestamping provider. It is composed by
|
||||
``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX`` attribute which describe the index of
|
||||
the PTP device and ``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER`` which describe
|
||||
the qualifier of the timestamp.
|
||||
|
||||
When set the ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS``
|
||||
and the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` attributes identify the Tx
|
||||
type, the Rx filter and the flags configured for the current hw timestamping
|
||||
provider. The attributes are propagated to the driver through the following
|
||||
structure:
|
||||
|
||||
.. kernel-doc:: include/linux/net_tstamp.h
|
||||
:identifiers: kernel_hwtstamp_config
|
||||
|
||||
TSCONFIG_SET
|
||||
============
|
||||
|
||||
Set the information about the current hardware timestamping source and
|
||||
configuration.
|
||||
|
||||
It is similar to the deprecated ``SIOCSHWTSTAMP`` ioctl request.
|
||||
|
||||
Request contents:
|
||||
|
||||
======================================== ====== ============================
|
||||
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
|
||||
``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
|
||||
``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
|
||||
======================================== ====== ============================
|
||||
|
||||
Kernel response contents:
|
||||
|
||||
======================================== ====== ============================
|
||||
``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
|
||||
``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
|
||||
``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
|
||||
======================================== ====== ============================
|
||||
|
||||
For a description of each attribute, see ``TSCONFIG_GET``.
|
||||
|
||||
Request translation
|
||||
===================
|
||||
|
||||
|
@ -2348,4 +2442,6 @@ are netlink only.
|
|||
n/a ``ETHTOOL_MSG_MM_SET``
|
||||
n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT``
|
||||
n/a ``ETHTOOL_MSG_PHY_GET``
|
||||
``SIOCGHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_GET``
|
||||
``SIOCSHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_SET``
|
||||
=================================== =====================================
|
||||
|
|
|
@ -13,6 +13,7 @@ Contents:
|
|||
can
|
||||
can_ucan_protocol
|
||||
device_drivers/index
|
||||
diagnostic/index
|
||||
dsa/index
|
||||
devlink/index
|
||||
caif/index
|
||||
|
|
|
@ -49,14 +49,21 @@ destination address) and TCP/UDP (source port, destination port) tuples
|
|||
are swapped, the computed hash is the same. This is beneficial in some
|
||||
applications that monitor TCP/IP flows (IDS, firewalls, ...etc) and need
|
||||
both directions of the flow to land on the same Rx queue (and CPU). The
|
||||
"Symmetric-XOR" is a type of RSS algorithms that achieves this hash
|
||||
symmetry by XORing the input source and destination fields of the IP
|
||||
and/or L4 protocols. This, however, results in reduced input entropy and
|
||||
could potentially be exploited. Specifically, the algorithm XORs the input
|
||||
"Symmetric-XOR" and "Symmetric-OR-XOR" are types of RSS algorithms that
|
||||
achieve this hash symmetry by XOR/ORing the input source and destination
|
||||
fields of the IP and/or L4 protocols. This, however, results in reduced
|
||||
input entropy and could potentially be exploited.
|
||||
|
||||
Specifically, the "Symmetric-XOR" algorithm XORs the input
|
||||
as follows::
|
||||
|
||||
# (SRC_IP ^ DST_IP, SRC_IP ^ DST_IP, SRC_PORT ^ DST_PORT, SRC_PORT ^ DST_PORT)
|
||||
|
||||
The "Symmetric-OR-XOR" algorithm, on the other hand, transforms the input as
|
||||
follows::
|
||||
|
||||
# (SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT)
|
||||
|
||||
The result is then fed to the underlying RSS algorithm.
|
||||
|
||||
Some advanced NICs allow steering packets to queues based on
|
||||
|
|
|
@ -266,6 +266,23 @@ SOF_TIMESTAMPING_OPT_TX_SWHW:
|
|||
two separate messages will be looped to the socket's error queue,
|
||||
each containing just one timestamp.
|
||||
|
||||
SOF_TIMESTAMPING_OPT_RX_FILTER:
|
||||
Filter out spurious receive timestamps: report a receive timestamp
|
||||
only if the matching timestamp generation flag is enabled.
|
||||
|
||||
Receive timestamps are generated early in the ingress path, before a
|
||||
packet's destination socket is known. If any socket enables receive
|
||||
timestamps, packets for all socket will receive timestamped packets.
|
||||
Including those that request timestamp reporting with
|
||||
SOF_TIMESTAMPING_SOFTWARE and/or SOF_TIMESTAMPING_RAW_HARDWARE, but
|
||||
do not request receive timestamp generation. This can happen when
|
||||
requesting transmit timestamps only.
|
||||
|
||||
Receiving spurious timestamps is generally benign. A process can
|
||||
ignore the unexpected non-zero value. But it makes behavior subtly
|
||||
dependent on other sockets. This flag isolates the socket for more
|
||||
deterministic behavior.
|
||||
|
||||
New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to
|
||||
disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate
|
||||
regardless of the setting of sysctl net.core.tstamp_allow_data.
|
||||
|
@ -492,8 +509,8 @@ implicitly defined. ts[0] holds a software timestamp if set, ts[1]
|
|||
is again deprecated and ts[2] holds a hardware timestamp if set.
|
||||
|
||||
|
||||
3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP
|
||||
=======================================================================
|
||||
3. Hardware Timestamping configuration: ETHTOOL_MSG_TSCONFIG_SET/GET
|
||||
====================================================================
|
||||
|
||||
Hardware time stamping must also be initialized for each device driver
|
||||
that is expected to do hardware time stamping. The parameter is defined in
|
||||
|
@ -506,12 +523,14 @@ include/uapi/linux/net_tstamp.h as::
|
|||
};
|
||||
|
||||
Desired behavior is passed into the kernel and to a specific device by
|
||||
calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose
|
||||
ifr_data points to a struct hwtstamp_config. The tx_type and
|
||||
rx_filter are hints to the driver what it is expected to do. If
|
||||
the requested fine-grained filtering for incoming packets is not
|
||||
supported, the driver may time stamp more than just the requested types
|
||||
of packets.
|
||||
calling the tsconfig netlink socket ``ETHTOOL_MSG_TSCONFIG_SET``.
|
||||
The ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` and
|
||||
``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` netlink attributes are then used to set
|
||||
the struct hwtstamp_config accordingly.
|
||||
|
||||
The ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` netlink nested attribute is used
|
||||
to select the source of the hardware time stamping. It is composed of an index
|
||||
for the device source and a qualifier for the type of time stamping.
|
||||
|
||||
Drivers are free to use a more permissive configuration than the requested
|
||||
configuration. It is expected that drivers should only implement directly the
|
||||
|
@ -530,9 +549,16 @@ Only a processes with admin rights may change the configuration. User
|
|||
space is responsible to ensure that multiple processes don't interfere
|
||||
with each other and that the settings are reset.
|
||||
|
||||
Any process can read the actual configuration by passing this
|
||||
structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has
|
||||
not been implemented in all drivers.
|
||||
Any process can read the actual configuration by requesting tsconfig netlink
|
||||
socket ``ETHTOOL_MSG_TSCONFIG_GET``.
|
||||
|
||||
The legacy configuration is the use of the ioctl(SIOCSHWTSTAMP) with a pointer
|
||||
to a struct ifreq whose ifr_data points to a struct hwtstamp_config.
|
||||
The tx_type and rx_filter are hints to the driver what it is expected to do.
|
||||
If the requested fine-grained filtering for incoming packets is not
|
||||
supported, the driver may time stamp more than just the requested types
|
||||
of packets. ioctl(SIOCGHWTSTAMP) is used in the same way as the
|
||||
ioctl(SIOCSHWTSTAMP). However, this has not been implemented in all drivers.
|
||||
|
||||
::
|
||||
|
||||
|
@ -577,9 +603,10 @@ not been implemented in all drivers.
|
|||
--------------------------------------------------------
|
||||
|
||||
A driver which supports hardware time stamping must support the
|
||||
SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
|
||||
the actual values as described in the section on SIOCSHWTSTAMP. It
|
||||
should also support SIOCGHWTSTAMP.
|
||||
ndo_hwtstamp_set NDO or the legacy SIOCSHWTSTAMP ioctl and update the
|
||||
supplied struct hwtstamp_config with the actual values as described in
|
||||
the section on SIOCSHWTSTAMP. It should also support ndo_hwtstamp_get or
|
||||
the legacy SIOCGHWTSTAMP.
|
||||
|
||||
Time stamps for received packets must be stored in the skb. To get a pointer
|
||||
to the shared time stamp structure of the skb call skb_hwtstamps(). Then
|
||||
|
|
|
@ -56,7 +56,9 @@ If ``name-prefix`` is specified it replaces the ``$family-$enum``
|
|||
portion of the entry name.
|
||||
|
||||
Boolean ``render-max`` controls creation of the max values
|
||||
(which are enabled by default for attribute enums).
|
||||
(which are enabled by default for attribute enums). These max
|
||||
values are named ``__$pfx-MAX`` and ``$pfx-MAX``. The name
|
||||
of the first value can be overridden via ``enum-cnt-name`` property.
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
|
|
@ -1852,7 +1852,7 @@ static int iavf_set_rxfh(struct net_device *netdev,
|
|||
static const struct ethtool_ops iavf_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_USE_ADAPTIVE,
|
||||
.cap_rss_sym_xor_supported = true,
|
||||
.supported_input_xfrm = RXH_XFRM_SYM_XOR,
|
||||
.get_drvinfo = iavf_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_ringparam = iavf_get_ringparam,
|
||||
|
|
|
@ -4770,7 +4770,7 @@ static const struct ethtool_ops ice_ethtool_ops = {
|
|||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_USE_ADAPTIVE |
|
||||
ETHTOOL_COALESCE_RX_USECS_HIGH,
|
||||
.cap_rss_sym_xor_supported = true,
|
||||
.supported_input_xfrm = RXH_XFRM_SYM_XOR,
|
||||
.rxfh_per_ctx_key = true,
|
||||
.get_link_ksettings = ice_get_link_ksettings,
|
||||
.set_link_ksettings = ice_set_link_ksettings,
|
||||
|
|
|
@ -59,6 +59,7 @@ const struct ethtool_ops ef100_ethtool_ops = {
|
|||
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
|
||||
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
|
||||
.rxfh_per_ctx_key = true,
|
||||
.cap_rss_rxnfc_adds = true,
|
||||
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
|
||||
.get_rxfh = efx_ethtool_get_rxfh,
|
||||
.set_rxfh = efx_ethtool_set_rxfh,
|
||||
|
|
|
@ -263,6 +263,7 @@ const struct ethtool_ops efx_ethtool_ops = {
|
|||
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
|
||||
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
|
||||
.rxfh_per_ctx_key = true,
|
||||
.cap_rss_rxnfc_adds = true,
|
||||
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
|
||||
.get_rxfh = efx_ethtool_get_rxfh,
|
||||
.set_rxfh = efx_ethtool_set_rxfh,
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// Copyright (c) 2020 Facebook
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
#include "netdevsim.h"
|
||||
|
||||
|
@ -72,6 +72,10 @@ static void nsim_get_ringparam(struct net_device *dev,
|
|||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
memcpy(ring, &ns->ethtool.ring, sizeof(ns->ethtool.ring));
|
||||
kernel_ring->hds_thresh_max = NSIM_HDS_THRESHOLD_MAX;
|
||||
|
||||
if (kernel_ring->tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN)
|
||||
kernel_ring->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
|
||||
}
|
||||
|
||||
static int nsim_set_ringparam(struct net_device *dev,
|
||||
|
@ -161,6 +165,8 @@ static int nsim_get_ts_info(struct net_device *dev,
|
|||
|
||||
static const struct ethtool_ops nsim_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_ALL_PARAMS,
|
||||
.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT |
|
||||
ETHTOOL_RING_USE_HDS_THRS,
|
||||
.get_pause_stats = nsim_get_pause_stats,
|
||||
.get_pauseparam = nsim_get_pauseparam,
|
||||
.set_pauseparam = nsim_set_pauseparam,
|
||||
|
@ -182,6 +188,7 @@ static void nsim_ethtool_ring_init(struct netdevsim *ns)
|
|||
ns->ethtool.ring.rx_jumbo_max_pending = 4096;
|
||||
ns->ethtool.ring.rx_mini_max_pending = 4096;
|
||||
ns->ethtool.ring.tx_max_pending = 4096;
|
||||
|
||||
}
|
||||
|
||||
void nsim_ethtool_init(struct netdevsim *ns)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
@ -54,6 +55,7 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
struct net_device *peer_dev;
|
||||
unsigned int len = skb->len;
|
||||
struct netdevsim *peer_ns;
|
||||
struct netdev_config *cfg;
|
||||
struct nsim_rq *rq;
|
||||
int rxq;
|
||||
|
||||
|
@ -71,6 +73,13 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
rxq = rxq % peer_dev->num_rx_queues;
|
||||
rq = &peer_ns->rq[rxq];
|
||||
|
||||
cfg = peer_dev->cfg;
|
||||
if (skb_is_nonlinear(skb) &&
|
||||
(cfg->hds_config != ETHTOOL_TCP_DATA_SPLIT_ENABLED ||
|
||||
(cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
|
||||
cfg->hds_thresh > len)))
|
||||
skb_linearize(skb);
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
if (unlikely(nsim_forward_skb(peer_dev, skb, rq) == NET_RX_DROP))
|
||||
goto out_drop_cnt;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
@ -36,6 +37,8 @@
|
|||
#define NSIM_IPSEC_VALID BIT(31)
|
||||
#define NSIM_UDP_TUNNEL_N_PORTS 4
|
||||
|
||||
#define NSIM_HDS_THRESHOLD_MAX 1024
|
||||
|
||||
struct nsim_sa {
|
||||
struct xfrm_state *xs;
|
||||
__be32 ipaddr[4];
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
const char *phy_speed_to_str(int speed)
|
||||
{
|
||||
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 103,
|
||||
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 121,
|
||||
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
|
||||
"If a speed or mode has been added please update phy_speed_to_str "
|
||||
"and the PHY settings array.\n");
|
||||
|
@ -169,6 +169,12 @@ static const struct phy_setting settings[] = {
|
|||
PHY_SETTING( 800000, FULL, 800000baseDR8_2_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseSR8_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseVR8_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseCR4_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseKR4_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseDR4_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseDR4_2_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseSR4_Full ),
|
||||
PHY_SETTING( 800000, FULL, 800000baseVR4_Full ),
|
||||
/* 400G */
|
||||
PHY_SETTING( 400000, FULL, 400000baseCR8_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseKR8_Full ),
|
||||
|
@ -180,6 +186,12 @@ static const struct phy_setting settings[] = {
|
|||
PHY_SETTING( 400000, FULL, 400000baseLR4_ER4_FR4_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseDR4_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseSR4_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseCR2_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseKR2_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseDR2_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseDR2_2_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseSR2_Full ),
|
||||
PHY_SETTING( 400000, FULL, 400000baseVR2_Full ),
|
||||
/* 200G */
|
||||
PHY_SETTING( 200000, FULL, 200000baseCR4_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseKR4_Full ),
|
||||
|
@ -191,6 +203,12 @@ static const struct phy_setting settings[] = {
|
|||
PHY_SETTING( 200000, FULL, 200000baseLR2_ER2_FR2_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseDR2_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseSR2_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseCR_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseKR_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseDR_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseDR_2_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseSR_Full ),
|
||||
PHY_SETTING( 200000, FULL, 200000baseVR_Full ),
|
||||
/* 100G */
|
||||
PHY_SETTING( 100000, FULL, 100000baseCR4_Full ),
|
||||
PHY_SETTING( 100000, FULL, 100000baseKR4_Full ),
|
||||
|
|
|
@ -615,6 +615,49 @@ int phy_ethtool_get_stats(struct phy_device *phydev,
|
|||
}
|
||||
EXPORT_SYMBOL(phy_ethtool_get_stats);
|
||||
|
||||
/**
|
||||
* __phy_ethtool_get_phy_stats - Retrieve standardized PHY statistics
|
||||
* @phydev: Pointer to the PHY device
|
||||
* @phy_stats: Pointer to ethtool_eth_phy_stats structure
|
||||
* @phydev_stats: Pointer to ethtool_phy_stats structure
|
||||
*
|
||||
* Fetches PHY statistics using a kernel-defined interface for consistent
|
||||
* diagnostics. Unlike phy_ethtool_get_stats(), which allows custom stats,
|
||||
* this function enforces a standardized format for better interoperability.
|
||||
*/
|
||||
void __phy_ethtool_get_phy_stats(struct phy_device *phydev,
|
||||
struct ethtool_eth_phy_stats *phy_stats,
|
||||
struct ethtool_phy_stats *phydev_stats)
|
||||
{
|
||||
if (!phydev->drv || !phydev->drv->get_phy_stats)
|
||||
return;
|
||||
|
||||
mutex_lock(&phydev->lock);
|
||||
phydev->drv->get_phy_stats(phydev, phy_stats, phydev_stats);
|
||||
mutex_unlock(&phydev->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* __phy_ethtool_get_link_ext_stats - Retrieve extended link statistics for a PHY
|
||||
* @phydev: Pointer to the PHY device
|
||||
* @link_stats: Pointer to the structure to store extended link statistics
|
||||
*
|
||||
* Populates the ethtool_link_ext_stats structure with link down event counts
|
||||
* and additional driver-specific link statistics, if available.
|
||||
*/
|
||||
void __phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
|
||||
struct ethtool_link_ext_stats *link_stats)
|
||||
{
|
||||
link_stats->link_down_events = READ_ONCE(phydev->link_down_events);
|
||||
|
||||
if (!phydev->drv || !phydev->drv->get_link_stats)
|
||||
return;
|
||||
|
||||
mutex_lock(&phydev->lock);
|
||||
phydev->drv->get_link_stats(phydev, link_stats);
|
||||
mutex_unlock(&phydev->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* phy_ethtool_get_plca_cfg - Get PLCA RS configuration
|
||||
* @phydev: the phy_device struct
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/phy_link_topology.h>
|
||||
#include <linux/pse-pd/pse.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/sfp.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
@ -1998,6 +1999,15 @@ void phy_detach(struct phy_device *phydev)
|
|||
|
||||
phy_suspend(phydev);
|
||||
if (dev) {
|
||||
struct hwtstamp_provider *hwprov;
|
||||
|
||||
hwprov = rtnl_dereference(dev->hwprov);
|
||||
/* Disable timestamp if it is the one selected */
|
||||
if (hwprov && hwprov->phydev == phydev) {
|
||||
rcu_assign_pointer(dev->hwprov, NULL);
|
||||
kfree_rcu(hwprov, rcu_head);
|
||||
}
|
||||
|
||||
phydev->attached_dev->phydev = NULL;
|
||||
phydev->attached_dev = NULL;
|
||||
phy_link_topo_del_phy(dev, phydev);
|
||||
|
@ -3748,6 +3758,8 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = {
|
|||
static const struct phylib_stubs __phylib_stubs = {
|
||||
.hwtstamp_get = __phy_hwtstamp_get,
|
||||
.hwtstamp_set = __phy_hwtstamp_set,
|
||||
.get_phy_stats = __phy_ethtool_get_phy_stats,
|
||||
.get_link_ext_stats = __phy_ethtool_get_link_ext_stats,
|
||||
};
|
||||
|
||||
static void phylib_register_stubs(void)
|
||||
|
|
|
@ -80,6 +80,9 @@ enum {
|
|||
* @cqe_size: Size of TX/RX completion queue event
|
||||
* @tx_push_buf_len: Size of TX push buffer
|
||||
* @tx_push_buf_max_len: Maximum allowed size of TX push buffer
|
||||
* @hds_thresh: Packet size threshold for header data split (HDS)
|
||||
* @hds_thresh_max: Maximum supported setting for @hds_threshold
|
||||
*
|
||||
*/
|
||||
struct kernel_ethtool_ringparam {
|
||||
u32 rx_buf_len;
|
||||
|
@ -89,6 +92,8 @@ struct kernel_ethtool_ringparam {
|
|||
u32 cqe_size;
|
||||
u32 tx_push_buf_len;
|
||||
u32 tx_push_buf_max_len;
|
||||
u32 hds_thresh;
|
||||
u32 hds_thresh_max;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -99,6 +104,7 @@ struct kernel_ethtool_ringparam {
|
|||
* @ETHTOOL_RING_USE_RX_PUSH: capture for setting rx_push
|
||||
* @ETHTOOL_RING_USE_TX_PUSH_BUF_LEN: capture for setting tx_push_buf_len
|
||||
* @ETHTOOL_RING_USE_TCP_DATA_SPLIT: capture for setting tcp_data_split
|
||||
* @ETHTOOL_RING_USE_HDS_THRS: capture for setting header-data-split-thresh
|
||||
*/
|
||||
enum ethtool_supported_ring_param {
|
||||
ETHTOOL_RING_USE_RX_BUF_LEN = BIT(0),
|
||||
|
@ -107,6 +113,7 @@ enum ethtool_supported_ring_param {
|
|||
ETHTOOL_RING_USE_RX_PUSH = BIT(3),
|
||||
ETHTOOL_RING_USE_TX_PUSH_BUF_LEN = BIT(4),
|
||||
ETHTOOL_RING_USE_TCP_DATA_SPLIT = BIT(5),
|
||||
ETHTOOL_RING_USE_HDS_THRS = BIT(6),
|
||||
};
|
||||
|
||||
#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit))
|
||||
|
@ -205,6 +212,14 @@ static inline u8 *ethtool_rxfh_context_key(struct ethtool_rxfh_context *ctx)
|
|||
|
||||
void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id);
|
||||
|
||||
struct link_mode_info {
|
||||
int speed;
|
||||
u8 lanes;
|
||||
u8 duplex;
|
||||
};
|
||||
|
||||
extern const struct link_mode_info link_mode_params[];
|
||||
|
||||
/* declare a link mode bitmap */
|
||||
#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \
|
||||
DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
|
||||
|
@ -417,6 +432,29 @@ struct ethtool_eth_phy_stats {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ethtool_phy_stats - PHY-level statistics counters
|
||||
* @rx_packets: Total successfully received frames
|
||||
* @rx_bytes: Total successfully received bytes
|
||||
* @rx_errors: Total received frames with errors (e.g., CRC errors)
|
||||
* @tx_packets: Total successfully transmitted frames
|
||||
* @tx_bytes: Total successfully transmitted bytes
|
||||
* @tx_errors: Total transmitted frames with errors
|
||||
*
|
||||
* This structure provides a standardized interface for reporting
|
||||
* PHY-level statistics counters. It is designed to expose statistics
|
||||
* commonly provided by PHYs but not explicitly defined in the IEEE
|
||||
* 802.3 standard.
|
||||
*/
|
||||
struct ethtool_phy_stats {
|
||||
u64 rx_packets;
|
||||
u64 rx_bytes;
|
||||
u64 rx_errors;
|
||||
u64 tx_packets;
|
||||
u64 tx_bytes;
|
||||
u64 tx_errors;
|
||||
};
|
||||
|
||||
/* Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*), not otherwise exposed
|
||||
* via a more targeted API.
|
||||
*/
|
||||
|
@ -534,6 +572,12 @@ struct ethtool_rmon_stats {
|
|||
/**
|
||||
* struct ethtool_ts_stats - HW timestamping statistics
|
||||
* @pkts: Number of packets successfully timestamped by the hardware.
|
||||
* @onestep_pkts_unconfirmed: Number of PTP packets with one-step TX
|
||||
* timestamping that were sent, but for which the
|
||||
* device offers no confirmation whether they made
|
||||
* it onto the wire and the timestamp was inserted
|
||||
* in the originTimestamp or correctionField, or
|
||||
* not.
|
||||
* @lost: Number of hardware timestamping requests where the timestamping
|
||||
* information from the hardware never arrived for submission with
|
||||
* the skb.
|
||||
|
@ -546,6 +590,7 @@ struct ethtool_rmon_stats {
|
|||
struct ethtool_ts_stats {
|
||||
struct_group(tx_stats,
|
||||
u64 pkts;
|
||||
u64 onestep_pkts_unconfirmed;
|
||||
u64 lost;
|
||||
u64 err;
|
||||
);
|
||||
|
@ -716,6 +761,7 @@ struct ethtool_rxfh_param {
|
|||
* @cmd: command number = %ETHTOOL_GET_TS_INFO
|
||||
* @so_timestamping: bit mask of the sum of the supported SO_TIMESTAMPING flags
|
||||
* @phc_index: device index of the associated PHC, or -1 if there is none
|
||||
* @phc_qualifier: qualifier of the associated PHC
|
||||
* @tx_types: bit mask of the supported hwtstamp_tx_types enumeration values
|
||||
* @rx_filters: bit mask of the supported hwtstamp_rx_filters enumeration values
|
||||
*/
|
||||
|
@ -723,22 +769,25 @@ struct kernel_ethtool_ts_info {
|
|||
u32 cmd;
|
||||
u32 so_timestamping;
|
||||
int phc_index;
|
||||
enum hwtstamp_provider_qualifier phc_qualifier;
|
||||
enum hwtstamp_tx_types tx_types;
|
||||
enum hwtstamp_rx_filters rx_filters;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ethtool_ops - optional netdev operations
|
||||
* @supported_input_xfrm: supported types of input xfrm from %RXH_XFRM_*.
|
||||
* @cap_link_lanes_supported: indicates if the driver supports lanes
|
||||
* parameter.
|
||||
* @cap_rss_ctx_supported: indicates if the driver supports RSS
|
||||
* contexts via legacy API, drivers implementing @create_rxfh_context
|
||||
* do not have to set this bit.
|
||||
* @cap_rss_sym_xor_supported: indicates if the driver supports symmetric-xor
|
||||
* RSS.
|
||||
* @rxfh_per_ctx_key: device supports setting different RSS key for each
|
||||
* additional context. Netlink API should report hfunc, key, and input_xfrm
|
||||
* for every context, not just context 0.
|
||||
* @cap_rss_rxnfc_adds: device supports nonzero ring_cookie in filters with
|
||||
* %FLOW_RSS flag; the queue ID from the filter is added to the value from
|
||||
* the indirection table to determine the delivery queue.
|
||||
* @rxfh_indir_space: max size of RSS indirection tables, if indirection table
|
||||
* size as returned by @get_rxfh_indir_size may change during lifetime
|
||||
* of the device. Leave as 0 if the table size is constant.
|
||||
|
@ -751,6 +800,7 @@ struct kernel_ethtool_ts_info {
|
|||
* @rss_context argument to @create_rxfh_context and friends.
|
||||
* @supported_coalesce_params: supported types of interrupt coalescing.
|
||||
* @supported_ring_params: supported ring params.
|
||||
* @supported_hwtstamp_qualifiers: bitfield of supported hwtstamp qualifier.
|
||||
* @get_drvinfo: Report driver/device information. Modern drivers no
|
||||
* longer have to implement this callback. Most fields are
|
||||
* correctly filled in by the core using system information, or
|
||||
|
@ -957,16 +1007,18 @@ struct kernel_ethtool_ts_info {
|
|||
* of the generic netdev features interface.
|
||||
*/
|
||||
struct ethtool_ops {
|
||||
u32 supported_input_xfrm:8;
|
||||
u32 cap_link_lanes_supported:1;
|
||||
u32 cap_rss_ctx_supported:1;
|
||||
u32 cap_rss_sym_xor_supported:1;
|
||||
u32 rxfh_per_ctx_key:1;
|
||||
u32 cap_rss_rxnfc_adds:1;
|
||||
u32 rxfh_indir_space;
|
||||
u16 rxfh_key_space;
|
||||
u16 rxfh_priv_size;
|
||||
u32 rxfh_max_num_contexts;
|
||||
u32 supported_coalesce_params;
|
||||
u32 supported_ring_params;
|
||||
u32 supported_hwtstamp_qualifiers;
|
||||
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
|
||||
int (*get_regs_len)(struct net_device *);
|
||||
void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
|
||||
|
|
|
@ -12,6 +12,33 @@ enum hwtstamp_source {
|
|||
HWTSTAMP_SOURCE_PHYLIB,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hwtstamp_provider_desc - hwtstamp provider description
|
||||
*
|
||||
* @index: index of the hwtstamp provider.
|
||||
* @qualifier: hwtstamp provider qualifier.
|
||||
*/
|
||||
struct hwtstamp_provider_desc {
|
||||
int index;
|
||||
enum hwtstamp_provider_qualifier qualifier;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hwtstamp_provider - hwtstamp provider object
|
||||
*
|
||||
* @rcu_head: RCU callback used to free the struct.
|
||||
* @source: source of the hwtstamp provider.
|
||||
* @phydev: pointer of the phydev source in case a PTP coming from phylib
|
||||
* @desc: hwtstamp provider description.
|
||||
*/
|
||||
|
||||
struct hwtstamp_provider {
|
||||
struct rcu_head rcu_head;
|
||||
enum hwtstamp_source source;
|
||||
struct phy_device *phydev;
|
||||
struct hwtstamp_provider_desc desc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
|
||||
*
|
||||
|
@ -24,6 +51,7 @@ enum hwtstamp_source {
|
|||
* copied the ioctl request back to user space
|
||||
* @source: indication whether timestamps should come from the netdev or from
|
||||
* an attached phylib PHY
|
||||
* @qualifier: qualifier of the hwtstamp provider
|
||||
*
|
||||
* Prefer using this structure for in-kernel processing of hardware
|
||||
* timestamping configuration, over the inextensible struct hwtstamp_config
|
||||
|
@ -36,6 +64,7 @@ struct kernel_hwtstamp_config {
|
|||
struct ifreq *ifr;
|
||||
bool copied_to_user;
|
||||
enum hwtstamp_source source;
|
||||
enum hwtstamp_provider_qualifier qualifier;
|
||||
|
||||
RH_KABI_RESERVE(1)
|
||||
RH_KABI_RESERVE(2)
|
||||
|
|
|
@ -64,6 +64,7 @@ struct dsa_port;
|
|||
struct ip_tunnel_parm_kern;
|
||||
struct macsec_context;
|
||||
struct macsec_ops;
|
||||
struct netdev_config;
|
||||
struct netdev_name_node;
|
||||
struct sd_flow_limit;
|
||||
struct sfp_bus;
|
||||
|
@ -81,6 +82,7 @@ struct xdp_buff;
|
|||
struct xdp_md;
|
||||
struct ethtool_netdev_state;
|
||||
struct phy_link_topology;
|
||||
struct hwtstamp_provider;
|
||||
|
||||
void synchronize_net(void);
|
||||
void netdev_set_default_ethtool_ops(struct net_device *dev,
|
||||
|
@ -2116,6 +2118,7 @@ enum netdev_reg_state {
|
|||
* @gro_flush_timeout: timeout for GRO layer in NAPI
|
||||
* @napi_defer_hard_irqs: If not zero, provides a counter that would
|
||||
* allow to avoid NIC hard IRQ, on busy queues.
|
||||
* @hwprov: Tracks which PTP performs hardware packet time stamping.
|
||||
*
|
||||
* FIXME: cleanup struct net_device such that network protocol info
|
||||
* moves out.
|
||||
|
@ -2487,6 +2490,14 @@ struct net_device {
|
|||
const struct udp_tunnel_nic_info *udp_tunnel_nic_info;
|
||||
struct udp_tunnel_nic *udp_tunnel_nic;
|
||||
|
||||
/** @cfg: net_device queue-related configuration */
|
||||
struct netdev_config *cfg;
|
||||
/**
|
||||
* @cfg_pending: same as @cfg but when device is being actively
|
||||
* reconfigured includes any changes to the configuration
|
||||
* requested by the user, but which may or may not be rejected.
|
||||
*/
|
||||
struct netdev_config *cfg_pending;
|
||||
struct ethtool_netdev_state *ethtool;
|
||||
|
||||
/* protected by rtnl_lock */
|
||||
|
@ -2528,6 +2539,8 @@ struct net_device {
|
|||
struct net_shaper_hierarchy *net_shaper_hierarchy;
|
||||
#endif
|
||||
|
||||
struct hwtstamp_provider __rcu *hwprov;
|
||||
|
||||
RH_KABI_RESERVE(1)
|
||||
RH_KABI_RESERVE(2)
|
||||
RH_KABI_RESERVE(3)
|
||||
|
@ -4127,9 +4140,6 @@ int generic_hwtstamp_get_lower(struct net_device *dev,
|
|||
int generic_hwtstamp_set_lower(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *kernel_cfg,
|
||||
struct netlink_ext_ack *extack);
|
||||
int dev_set_hwtstamp_phylib(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *cfg,
|
||||
struct netlink_ext_ack *extack);
|
||||
int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata);
|
||||
unsigned int dev_get_flags(const struct net_device *);
|
||||
int __dev_change_flags(struct net_device *dev, unsigned int flags,
|
||||
|
@ -4165,6 +4175,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
|||
|
||||
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
|
||||
u8 dev_xdp_prog_count(struct net_device *dev);
|
||||
u8 dev_xdp_sb_prog_count(struct net_device *dev);
|
||||
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
|
||||
|
||||
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
|
||||
|
|
|
@ -1093,6 +1093,35 @@ struct phy_driver {
|
|||
int (*cable_test_get_status)(struct phy_device *dev, bool *finished);
|
||||
|
||||
/* Get statistics from the PHY using ethtool */
|
||||
/**
|
||||
* @get_phy_stats: Retrieve PHY statistics.
|
||||
* @dev: The PHY device for which the statistics are retrieved.
|
||||
* @eth_stats: structure where Ethernet PHY stats will be stored.
|
||||
* @stats: structure where additional PHY-specific stats will be stored.
|
||||
*
|
||||
* Retrieves the supported PHY statistics and populates the provided
|
||||
* structures. The input structures are pre-initialized with
|
||||
* `ETHTOOL_STAT_NOT_SET`, and the driver must only modify members
|
||||
* corresponding to supported statistics. Unmodified members will remain
|
||||
* set to `ETHTOOL_STAT_NOT_SET` and will not be returned to userspace.
|
||||
*/
|
||||
void (*get_phy_stats)(struct phy_device *dev,
|
||||
struct ethtool_eth_phy_stats *eth_stats,
|
||||
struct ethtool_phy_stats *stats);
|
||||
|
||||
/**
|
||||
* @get_link_stats: Retrieve link statistics.
|
||||
* @dev: The PHY device for which the statistics are retrieved.
|
||||
* @link_stats: structure where link-specific stats will be stored.
|
||||
*
|
||||
* Retrieves link-related statistics for the given PHY device. The input
|
||||
* structure is pre-initialized with `ETHTOOL_STAT_NOT_SET`, and the
|
||||
* driver must only modify members corresponding to supported
|
||||
* statistics. Unmodified members will remain set to
|
||||
* `ETHTOOL_STAT_NOT_SET` and will not be returned to userspace.
|
||||
*/
|
||||
void (*get_link_stats)(struct phy_device *dev,
|
||||
struct ethtool_link_ext_stats *link_stats);
|
||||
/** @get_sset_count: Number of statistic counters */
|
||||
int (*get_sset_count)(struct phy_device *dev);
|
||||
/** @get_strings: Names of the statistic counters */
|
||||
|
@ -2057,6 +2086,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data);
|
|||
int phy_ethtool_get_sset_count(struct phy_device *phydev);
|
||||
int phy_ethtool_get_stats(struct phy_device *phydev,
|
||||
struct ethtool_stats *stats, u64 *data);
|
||||
|
||||
void __phy_ethtool_get_phy_stats(struct phy_device *phydev,
|
||||
struct ethtool_eth_phy_stats *phy_stats,
|
||||
struct ethtool_phy_stats *phydev_stats);
|
||||
void __phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
|
||||
struct ethtool_link_ext_stats *link_stats);
|
||||
|
||||
int phy_ethtool_get_plca_cfg(struct phy_device *phydev,
|
||||
struct phy_plca_cfg *plca_cfg);
|
||||
int phy_ethtool_set_plca_cfg(struct phy_device *phydev,
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
struct ethtool_eth_phy_stats;
|
||||
struct ethtool_link_ext_stats;
|
||||
struct ethtool_phy_stats;
|
||||
struct kernel_hwtstamp_config;
|
||||
struct netlink_ext_ack;
|
||||
struct phy_device;
|
||||
|
@ -19,6 +22,11 @@ struct phylib_stubs {
|
|||
int (*hwtstamp_set)(struct phy_device *phydev,
|
||||
struct kernel_hwtstamp_config *config,
|
||||
struct netlink_ext_ack *extack);
|
||||
void (*get_phy_stats)(struct phy_device *phydev,
|
||||
struct ethtool_eth_phy_stats *phy_stats,
|
||||
struct ethtool_phy_stats *phydev_stats);
|
||||
void (*get_link_ext_stats)(struct phy_device *phydev,
|
||||
struct ethtool_link_ext_stats *link_stats);
|
||||
};
|
||||
|
||||
static inline int phy_hwtstamp_get(struct phy_device *phydev,
|
||||
|
@ -50,6 +58,29 @@ static inline int phy_hwtstamp_set(struct phy_device *phydev,
|
|||
return phylib_stubs->hwtstamp_set(phydev, config, extack);
|
||||
}
|
||||
|
||||
static inline void phy_ethtool_get_phy_stats(struct phy_device *phydev,
|
||||
struct ethtool_eth_phy_stats *phy_stats,
|
||||
struct ethtool_phy_stats *phydev_stats)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!phylib_stubs)
|
||||
return;
|
||||
|
||||
phylib_stubs->get_phy_stats(phydev, phy_stats, phydev_stats);
|
||||
}
|
||||
|
||||
static inline void phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
|
||||
struct ethtool_link_ext_stats *link_stats)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!phylib_stubs)
|
||||
return;
|
||||
|
||||
phylib_stubs->get_link_ext_stats(phydev, link_stats);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int phy_hwtstamp_get(struct phy_device *phydev,
|
||||
|
@ -65,4 +96,15 @@ static inline int phy_hwtstamp_set(struct phy_device *phydev,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void phy_ethtool_get_phy_stats(struct phy_device *phydev,
|
||||
struct ethtool_eth_phy_stats *phy_stats,
|
||||
struct ethtool_phy_stats *phydev_stats)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void phy_ethtool_get_link_ext_stats(struct phy_device *phydev,
|
||||
struct ethtool_link_ext_stats *link_stats)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,16 @@
|
|||
|
||||
#include <linux/rh_kabi.h>
|
||||
|
||||
/**
|
||||
* struct netdev_config - queue-related configuration for a netdev
|
||||
* @hds_thresh: HDS Threshold value.
|
||||
* @hds_config: HDS value from userspace.
|
||||
*/
|
||||
struct netdev_config {
|
||||
u32 hds_thresh;
|
||||
u8 hds_config;
|
||||
};
|
||||
|
||||
/* See the netdev.yaml spec for definition of each statistic */
|
||||
struct netdev_queue_stats_rx {
|
||||
u64 bytes;
|
||||
|
|
|
@ -681,6 +681,8 @@ enum ethtool_link_ext_substate_module {
|
|||
* @ETH_SS_STATS_ETH_MAC: names of IEEE 802.3 MAC statistics
|
||||
* @ETH_SS_STATS_ETH_CTRL: names of IEEE 802.3 MAC Control statistics
|
||||
* @ETH_SS_STATS_RMON: names of RMON statistics
|
||||
* @ETH_SS_STATS_PHY: names of PHY(dev) statistics
|
||||
* @ETH_SS_TS_FLAGS: hardware timestamping flags
|
||||
*
|
||||
* @ETH_SS_COUNT: number of defined string sets
|
||||
*/
|
||||
|
@ -706,6 +708,8 @@ enum ethtool_stringset {
|
|||
ETH_SS_STATS_ETH_MAC,
|
||||
ETH_SS_STATS_ETH_CTRL,
|
||||
ETH_SS_STATS_RMON,
|
||||
ETH_SS_STATS_PHY,
|
||||
ETH_SS_TS_FLAGS,
|
||||
|
||||
/* add new constants above here */
|
||||
ETH_SS_COUNT
|
||||
|
@ -2055,6 +2059,24 @@ enum ethtool_link_mode_bit_indices {
|
|||
ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100,
|
||||
ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101,
|
||||
ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT = 102,
|
||||
ETHTOOL_LINK_MODE_200000baseCR_Full_BIT = 103,
|
||||
ETHTOOL_LINK_MODE_200000baseKR_Full_BIT = 104,
|
||||
ETHTOOL_LINK_MODE_200000baseDR_Full_BIT = 105,
|
||||
ETHTOOL_LINK_MODE_200000baseDR_2_Full_BIT = 106,
|
||||
ETHTOOL_LINK_MODE_200000baseSR_Full_BIT = 107,
|
||||
ETHTOOL_LINK_MODE_200000baseVR_Full_BIT = 108,
|
||||
ETHTOOL_LINK_MODE_400000baseCR2_Full_BIT = 109,
|
||||
ETHTOOL_LINK_MODE_400000baseKR2_Full_BIT = 110,
|
||||
ETHTOOL_LINK_MODE_400000baseDR2_Full_BIT = 111,
|
||||
ETHTOOL_LINK_MODE_400000baseDR2_2_Full_BIT = 112,
|
||||
ETHTOOL_LINK_MODE_400000baseSR2_Full_BIT = 113,
|
||||
ETHTOOL_LINK_MODE_400000baseVR2_Full_BIT = 114,
|
||||
ETHTOOL_LINK_MODE_800000baseCR4_Full_BIT = 115,
|
||||
ETHTOOL_LINK_MODE_800000baseKR4_Full_BIT = 116,
|
||||
ETHTOOL_LINK_MODE_800000baseDR4_Full_BIT = 117,
|
||||
ETHTOOL_LINK_MODE_800000baseDR4_2_Full_BIT = 118,
|
||||
ETHTOOL_LINK_MODE_800000baseSR4_Full_BIT = 119,
|
||||
ETHTOOL_LINK_MODE_800000baseVR4_Full_BIT = 120,
|
||||
|
||||
/* must be last entry */
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS
|
||||
|
@ -2267,6 +2289,10 @@ static inline int ethtool_validate_duplex(__u8 duplex)
|
|||
* be exploited to reduce the RSS queue spread.
|
||||
*/
|
||||
#define RXH_XFRM_SYM_XOR (1 << 0)
|
||||
/* Similar to SYM_XOR, except that one copy of the XOR'ed fields is replaced by
|
||||
* an OR of the same fields
|
||||
*/
|
||||
#define RXH_XFRM_SYM_OR_XOR (1 << 1)
|
||||
#define RXH_XFRM_NO_CHANGE 0xff
|
||||
|
||||
/* L2-L4 network traffic flow types */
|
||||
|
@ -2526,12 +2552,19 @@ struct ethtool_link_settings {
|
|||
__u8 master_slave_state;
|
||||
__u8 rate_matching;
|
||||
__u32 reserved[7];
|
||||
#ifndef __KERNEL__
|
||||
/* Linux builds with -Wflex-array-member-not-at-end but does
|
||||
* not use the "link_mode_masks" member. Leave it defined for
|
||||
* userspace for now, and when userspace wants to start using
|
||||
* -Wfamnae, we'll need a new solution.
|
||||
*/
|
||||
__u32 link_mode_masks[];
|
||||
/* layout of link_mode_masks fields:
|
||||
* __u32 map_supported[link_mode_masks_nwords];
|
||||
* __u32 map_advertising[link_mode_masks_nwords];
|
||||
* __u32 map_lp_advertising[link_mode_masks_nwords];
|
||||
*/
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,545 +10,12 @@
|
|||
#define _UAPI_LINUX_ETHTOOL_NETLINK_H_
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
/* message types - userspace to kernel */
|
||||
enum {
|
||||
ETHTOOL_MSG_USER_NONE,
|
||||
ETHTOOL_MSG_STRSET_GET,
|
||||
ETHTOOL_MSG_LINKINFO_GET,
|
||||
ETHTOOL_MSG_LINKINFO_SET,
|
||||
ETHTOOL_MSG_LINKMODES_GET,
|
||||
ETHTOOL_MSG_LINKMODES_SET,
|
||||
ETHTOOL_MSG_LINKSTATE_GET,
|
||||
ETHTOOL_MSG_DEBUG_GET,
|
||||
ETHTOOL_MSG_DEBUG_SET,
|
||||
ETHTOOL_MSG_WOL_GET,
|
||||
ETHTOOL_MSG_WOL_SET,
|
||||
ETHTOOL_MSG_FEATURES_GET,
|
||||
ETHTOOL_MSG_FEATURES_SET,
|
||||
ETHTOOL_MSG_PRIVFLAGS_GET,
|
||||
ETHTOOL_MSG_PRIVFLAGS_SET,
|
||||
ETHTOOL_MSG_RINGS_GET,
|
||||
ETHTOOL_MSG_RINGS_SET,
|
||||
ETHTOOL_MSG_CHANNELS_GET,
|
||||
ETHTOOL_MSG_CHANNELS_SET,
|
||||
ETHTOOL_MSG_COALESCE_GET,
|
||||
ETHTOOL_MSG_COALESCE_SET,
|
||||
ETHTOOL_MSG_PAUSE_GET,
|
||||
ETHTOOL_MSG_PAUSE_SET,
|
||||
ETHTOOL_MSG_EEE_GET,
|
||||
ETHTOOL_MSG_EEE_SET,
|
||||
ETHTOOL_MSG_TSINFO_GET,
|
||||
ETHTOOL_MSG_CABLE_TEST_ACT,
|
||||
ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
|
||||
ETHTOOL_MSG_TUNNEL_INFO_GET,
|
||||
ETHTOOL_MSG_FEC_GET,
|
||||
ETHTOOL_MSG_FEC_SET,
|
||||
ETHTOOL_MSG_MODULE_EEPROM_GET,
|
||||
ETHTOOL_MSG_STATS_GET,
|
||||
ETHTOOL_MSG_PHC_VCLOCKS_GET,
|
||||
ETHTOOL_MSG_MODULE_GET,
|
||||
ETHTOOL_MSG_MODULE_SET,
|
||||
ETHTOOL_MSG_PSE_GET,
|
||||
ETHTOOL_MSG_PSE_SET,
|
||||
ETHTOOL_MSG_RSS_GET,
|
||||
ETHTOOL_MSG_PLCA_GET_CFG,
|
||||
ETHTOOL_MSG_PLCA_SET_CFG,
|
||||
ETHTOOL_MSG_PLCA_GET_STATUS,
|
||||
ETHTOOL_MSG_MM_GET,
|
||||
ETHTOOL_MSG_MM_SET,
|
||||
ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
|
||||
ETHTOOL_MSG_PHY_GET,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_MSG_USER_CNT,
|
||||
ETHTOOL_MSG_USER_MAX = __ETHTOOL_MSG_USER_CNT - 1
|
||||
};
|
||||
|
||||
/* message types - kernel to userspace */
|
||||
enum {
|
||||
ETHTOOL_MSG_KERNEL_NONE,
|
||||
ETHTOOL_MSG_STRSET_GET_REPLY,
|
||||
ETHTOOL_MSG_LINKINFO_GET_REPLY,
|
||||
ETHTOOL_MSG_LINKINFO_NTF,
|
||||
ETHTOOL_MSG_LINKMODES_GET_REPLY,
|
||||
ETHTOOL_MSG_LINKMODES_NTF,
|
||||
ETHTOOL_MSG_LINKSTATE_GET_REPLY,
|
||||
ETHTOOL_MSG_DEBUG_GET_REPLY,
|
||||
ETHTOOL_MSG_DEBUG_NTF,
|
||||
ETHTOOL_MSG_WOL_GET_REPLY,
|
||||
ETHTOOL_MSG_WOL_NTF,
|
||||
ETHTOOL_MSG_FEATURES_GET_REPLY,
|
||||
ETHTOOL_MSG_FEATURES_SET_REPLY,
|
||||
ETHTOOL_MSG_FEATURES_NTF,
|
||||
ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
|
||||
ETHTOOL_MSG_PRIVFLAGS_NTF,
|
||||
ETHTOOL_MSG_RINGS_GET_REPLY,
|
||||
ETHTOOL_MSG_RINGS_NTF,
|
||||
ETHTOOL_MSG_CHANNELS_GET_REPLY,
|
||||
ETHTOOL_MSG_CHANNELS_NTF,
|
||||
ETHTOOL_MSG_COALESCE_GET_REPLY,
|
||||
ETHTOOL_MSG_COALESCE_NTF,
|
||||
ETHTOOL_MSG_PAUSE_GET_REPLY,
|
||||
ETHTOOL_MSG_PAUSE_NTF,
|
||||
ETHTOOL_MSG_EEE_GET_REPLY,
|
||||
ETHTOOL_MSG_EEE_NTF,
|
||||
ETHTOOL_MSG_TSINFO_GET_REPLY,
|
||||
ETHTOOL_MSG_CABLE_TEST_NTF,
|
||||
ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
|
||||
ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
|
||||
ETHTOOL_MSG_FEC_GET_REPLY,
|
||||
ETHTOOL_MSG_FEC_NTF,
|
||||
ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
|
||||
ETHTOOL_MSG_STATS_GET_REPLY,
|
||||
ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
|
||||
ETHTOOL_MSG_MODULE_GET_REPLY,
|
||||
ETHTOOL_MSG_MODULE_NTF,
|
||||
ETHTOOL_MSG_PSE_GET_REPLY,
|
||||
ETHTOOL_MSG_RSS_GET_REPLY,
|
||||
ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
|
||||
ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
|
||||
ETHTOOL_MSG_PLCA_NTF,
|
||||
ETHTOOL_MSG_MM_GET_REPLY,
|
||||
ETHTOOL_MSG_MM_NTF,
|
||||
ETHTOOL_MSG_MODULE_FW_FLASH_NTF,
|
||||
ETHTOOL_MSG_PHY_GET_REPLY,
|
||||
ETHTOOL_MSG_PHY_NTF,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_MSG_KERNEL_CNT,
|
||||
ETHTOOL_MSG_KERNEL_MAX = __ETHTOOL_MSG_KERNEL_CNT - 1
|
||||
};
|
||||
|
||||
/* request header */
|
||||
|
||||
enum ethtool_header_flags {
|
||||
ETHTOOL_FLAG_COMPACT_BITSETS = 1 << 0, /* use compact bitsets in reply */
|
||||
ETHTOOL_FLAG_OMIT_REPLY = 1 << 1, /* provide optional reply for SET or ACT requests */
|
||||
ETHTOOL_FLAG_STATS = 1 << 2, /* request statistics, if supported by the driver */
|
||||
};
|
||||
#include <linux/ethtool_netlink_generated.h>
|
||||
|
||||
#define ETHTOOL_FLAG_ALL (ETHTOOL_FLAG_COMPACT_BITSETS | \
|
||||
ETHTOOL_FLAG_OMIT_REPLY | \
|
||||
ETHTOOL_FLAG_STATS)
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_HEADER_UNSPEC,
|
||||
ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */
|
||||
ETHTOOL_A_HEADER_DEV_NAME, /* string */
|
||||
ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */
|
||||
ETHTOOL_A_HEADER_PHY_INDEX, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_HEADER_CNT,
|
||||
ETHTOOL_A_HEADER_MAX = __ETHTOOL_A_HEADER_CNT - 1
|
||||
};
|
||||
|
||||
/* bit sets */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_BITSET_BIT_UNSPEC,
|
||||
ETHTOOL_A_BITSET_BIT_INDEX, /* u32 */
|
||||
ETHTOOL_A_BITSET_BIT_NAME, /* string */
|
||||
ETHTOOL_A_BITSET_BIT_VALUE, /* flag */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_BITSET_BIT_CNT,
|
||||
ETHTOOL_A_BITSET_BIT_MAX = __ETHTOOL_A_BITSET_BIT_CNT - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_BITSET_BITS_UNSPEC,
|
||||
ETHTOOL_A_BITSET_BITS_BIT, /* nest - _A_BITSET_BIT_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_BITSET_BITS_CNT,
|
||||
ETHTOOL_A_BITSET_BITS_MAX = __ETHTOOL_A_BITSET_BITS_CNT - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_BITSET_UNSPEC,
|
||||
ETHTOOL_A_BITSET_NOMASK, /* flag */
|
||||
ETHTOOL_A_BITSET_SIZE, /* u32 */
|
||||
ETHTOOL_A_BITSET_BITS, /* nest - _A_BITSET_BITS_* */
|
||||
ETHTOOL_A_BITSET_VALUE, /* binary */
|
||||
ETHTOOL_A_BITSET_MASK, /* binary */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_BITSET_CNT,
|
||||
ETHTOOL_A_BITSET_MAX = __ETHTOOL_A_BITSET_CNT - 1
|
||||
};
|
||||
|
||||
/* string sets */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRING_UNSPEC,
|
||||
ETHTOOL_A_STRING_INDEX, /* u32 */
|
||||
ETHTOOL_A_STRING_VALUE, /* string */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STRING_CNT,
|
||||
ETHTOOL_A_STRING_MAX = __ETHTOOL_A_STRING_CNT - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRINGS_UNSPEC,
|
||||
ETHTOOL_A_STRINGS_STRING, /* nest - _A_STRINGS_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STRINGS_CNT,
|
||||
ETHTOOL_A_STRINGS_MAX = __ETHTOOL_A_STRINGS_CNT - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRINGSET_UNSPEC,
|
||||
ETHTOOL_A_STRINGSET_ID, /* u32 */
|
||||
ETHTOOL_A_STRINGSET_COUNT, /* u32 */
|
||||
ETHTOOL_A_STRINGSET_STRINGS, /* nest - _A_STRINGS_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STRINGSET_CNT,
|
||||
ETHTOOL_A_STRINGSET_MAX = __ETHTOOL_A_STRINGSET_CNT - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRINGSETS_UNSPEC,
|
||||
ETHTOOL_A_STRINGSETS_STRINGSET, /* nest - _A_STRINGSET_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STRINGSETS_CNT,
|
||||
ETHTOOL_A_STRINGSETS_MAX = __ETHTOOL_A_STRINGSETS_CNT - 1
|
||||
};
|
||||
|
||||
/* STRSET */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRSET_UNSPEC,
|
||||
ETHTOOL_A_STRSET_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_STRSET_STRINGSETS, /* nest - _A_STRINGSETS_* */
|
||||
ETHTOOL_A_STRSET_COUNTS_ONLY, /* flag */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STRSET_CNT,
|
||||
ETHTOOL_A_STRSET_MAX = __ETHTOOL_A_STRSET_CNT - 1
|
||||
};
|
||||
|
||||
/* LINKINFO */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_LINKINFO_UNSPEC,
|
||||
ETHTOOL_A_LINKINFO_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_LINKINFO_PORT, /* u8 */
|
||||
ETHTOOL_A_LINKINFO_PHYADDR, /* u8 */
|
||||
ETHTOOL_A_LINKINFO_TP_MDIX, /* u8 */
|
||||
ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, /* u8 */
|
||||
ETHTOOL_A_LINKINFO_TRANSCEIVER, /* u8 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_LINKINFO_CNT,
|
||||
ETHTOOL_A_LINKINFO_MAX = __ETHTOOL_A_LINKINFO_CNT - 1
|
||||
};
|
||||
|
||||
/* LINKMODES */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_LINKMODES_UNSPEC,
|
||||
ETHTOOL_A_LINKMODES_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_LINKMODES_AUTONEG, /* u8 */
|
||||
ETHTOOL_A_LINKMODES_OURS, /* bitset */
|
||||
ETHTOOL_A_LINKMODES_PEER, /* bitset */
|
||||
ETHTOOL_A_LINKMODES_SPEED, /* u32 */
|
||||
ETHTOOL_A_LINKMODES_DUPLEX, /* u8 */
|
||||
ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, /* u8 */
|
||||
ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, /* u8 */
|
||||
ETHTOOL_A_LINKMODES_LANES, /* u32 */
|
||||
ETHTOOL_A_LINKMODES_RATE_MATCHING, /* u8 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_LINKMODES_CNT,
|
||||
ETHTOOL_A_LINKMODES_MAX = __ETHTOOL_A_LINKMODES_CNT - 1
|
||||
};
|
||||
|
||||
/* LINKSTATE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_LINKSTATE_UNSPEC,
|
||||
ETHTOOL_A_LINKSTATE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_LINKSTATE_LINK, /* u8 */
|
||||
ETHTOOL_A_LINKSTATE_SQI, /* u32 */
|
||||
ETHTOOL_A_LINKSTATE_SQI_MAX, /* u32 */
|
||||
ETHTOOL_A_LINKSTATE_EXT_STATE, /* u8 */
|
||||
ETHTOOL_A_LINKSTATE_EXT_SUBSTATE, /* u8 */
|
||||
ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_LINKSTATE_CNT,
|
||||
ETHTOOL_A_LINKSTATE_MAX = __ETHTOOL_A_LINKSTATE_CNT - 1
|
||||
};
|
||||
|
||||
/* DEBUG */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_DEBUG_UNSPEC,
|
||||
ETHTOOL_A_DEBUG_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_DEBUG_MSGMASK, /* bitset */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_DEBUG_CNT,
|
||||
ETHTOOL_A_DEBUG_MAX = __ETHTOOL_A_DEBUG_CNT - 1
|
||||
};
|
||||
|
||||
/* WOL */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_WOL_UNSPEC,
|
||||
ETHTOOL_A_WOL_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_WOL_MODES, /* bitset */
|
||||
ETHTOOL_A_WOL_SOPASS, /* binary */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_WOL_CNT,
|
||||
ETHTOOL_A_WOL_MAX = __ETHTOOL_A_WOL_CNT - 1
|
||||
};
|
||||
|
||||
/* FEATURES */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_FEATURES_UNSPEC,
|
||||
ETHTOOL_A_FEATURES_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_FEATURES_HW, /* bitset */
|
||||
ETHTOOL_A_FEATURES_WANTED, /* bitset */
|
||||
ETHTOOL_A_FEATURES_ACTIVE, /* bitset */
|
||||
ETHTOOL_A_FEATURES_NOCHANGE, /* bitset */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_FEATURES_CNT,
|
||||
ETHTOOL_A_FEATURES_MAX = __ETHTOOL_A_FEATURES_CNT - 1
|
||||
};
|
||||
|
||||
/* PRIVFLAGS */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PRIVFLAGS_UNSPEC,
|
||||
ETHTOOL_A_PRIVFLAGS_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PRIVFLAGS_FLAGS, /* bitset */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PRIVFLAGS_CNT,
|
||||
ETHTOOL_A_PRIVFLAGS_MAX = __ETHTOOL_A_PRIVFLAGS_CNT - 1
|
||||
};
|
||||
|
||||
/* RINGS */
|
||||
|
||||
enum {
|
||||
ETHTOOL_TCP_DATA_SPLIT_UNKNOWN = 0,
|
||||
ETHTOOL_TCP_DATA_SPLIT_DISABLED,
|
||||
ETHTOOL_TCP_DATA_SPLIT_ENABLED,
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_RINGS_UNSPEC,
|
||||
ETHTOOL_A_RINGS_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_RINGS_RX_MAX, /* u32 */
|
||||
ETHTOOL_A_RINGS_RX_MINI_MAX, /* u32 */
|
||||
ETHTOOL_A_RINGS_RX_JUMBO_MAX, /* u32 */
|
||||
ETHTOOL_A_RINGS_TX_MAX, /* u32 */
|
||||
ETHTOOL_A_RINGS_RX, /* u32 */
|
||||
ETHTOOL_A_RINGS_RX_MINI, /* u32 */
|
||||
ETHTOOL_A_RINGS_RX_JUMBO, /* u32 */
|
||||
ETHTOOL_A_RINGS_TX, /* u32 */
|
||||
ETHTOOL_A_RINGS_RX_BUF_LEN, /* u32 */
|
||||
ETHTOOL_A_RINGS_TCP_DATA_SPLIT, /* u8 */
|
||||
ETHTOOL_A_RINGS_CQE_SIZE, /* u32 */
|
||||
ETHTOOL_A_RINGS_TX_PUSH, /* u8 */
|
||||
ETHTOOL_A_RINGS_RX_PUSH, /* u8 */
|
||||
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN, /* u32 */
|
||||
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_RINGS_CNT,
|
||||
ETHTOOL_A_RINGS_MAX = (__ETHTOOL_A_RINGS_CNT - 1)
|
||||
};
|
||||
|
||||
/* CHANNELS */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CHANNELS_UNSPEC,
|
||||
ETHTOOL_A_CHANNELS_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_CHANNELS_RX_MAX, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_TX_MAX, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_OTHER_MAX, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_COMBINED_MAX, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_RX_COUNT, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_TX_COUNT, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_OTHER_COUNT, /* u32 */
|
||||
ETHTOOL_A_CHANNELS_COMBINED_COUNT, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_CHANNELS_CNT,
|
||||
ETHTOOL_A_CHANNELS_MAX = (__ETHTOOL_A_CHANNELS_CNT - 1)
|
||||
};
|
||||
|
||||
/* COALESCE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_COALESCE_UNSPEC,
|
||||
ETHTOOL_A_COALESCE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_COALESCE_RX_USECS, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_USECS_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, /* u32 */
|
||||
ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, /* u32 */
|
||||
ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, /* u8 */
|
||||
ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, /* u8 */
|
||||
ETHTOOL_A_COALESCE_PKT_RATE_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_USECS_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, /* u32 */
|
||||
ETHTOOL_A_COALESCE_PKT_RATE_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_USECS_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_USECS_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, /* u32 */
|
||||
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, /* u32 */
|
||||
ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, /* u8 */
|
||||
ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, /* u8 */
|
||||
ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, /* u32 */
|
||||
ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, /* u32 */
|
||||
/* nest - _A_PROFILE_IRQ_MODERATION */
|
||||
ETHTOOL_A_COALESCE_RX_PROFILE,
|
||||
/* nest - _A_PROFILE_IRQ_MODERATION */
|
||||
ETHTOOL_A_COALESCE_TX_PROFILE,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_COALESCE_CNT,
|
||||
ETHTOOL_A_COALESCE_MAX = (__ETHTOOL_A_COALESCE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PROFILE_UNSPEC,
|
||||
/* nest, _A_IRQ_MODERATION_* */
|
||||
ETHTOOL_A_PROFILE_IRQ_MODERATION,
|
||||
__ETHTOOL_A_PROFILE_CNT,
|
||||
ETHTOOL_A_PROFILE_MAX = (__ETHTOOL_A_PROFILE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_IRQ_MODERATION_UNSPEC,
|
||||
ETHTOOL_A_IRQ_MODERATION_USEC, /* u32 */
|
||||
ETHTOOL_A_IRQ_MODERATION_PKTS, /* u32 */
|
||||
ETHTOOL_A_IRQ_MODERATION_COMPS, /* u32 */
|
||||
|
||||
__ETHTOOL_A_IRQ_MODERATION_CNT,
|
||||
ETHTOOL_A_IRQ_MODERATION_MAX = (__ETHTOOL_A_IRQ_MODERATION_CNT - 1)
|
||||
};
|
||||
|
||||
/* PAUSE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PAUSE_UNSPEC,
|
||||
ETHTOOL_A_PAUSE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PAUSE_AUTONEG, /* u8 */
|
||||
ETHTOOL_A_PAUSE_RX, /* u8 */
|
||||
ETHTOOL_A_PAUSE_TX, /* u8 */
|
||||
ETHTOOL_A_PAUSE_STATS, /* nest - _PAUSE_STAT_* */
|
||||
ETHTOOL_A_PAUSE_STATS_SRC, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PAUSE_CNT,
|
||||
ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PAUSE_STAT_UNSPEC,
|
||||
ETHTOOL_A_PAUSE_STAT_PAD,
|
||||
|
||||
ETHTOOL_A_PAUSE_STAT_TX_FRAMES,
|
||||
ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
|
||||
|
||||
/* add new constants above here
|
||||
* adjust ETHTOOL_PAUSE_STAT_CNT if adding non-stats!
|
||||
*/
|
||||
__ETHTOOL_A_PAUSE_STAT_CNT,
|
||||
ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
/* EEE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_EEE_UNSPEC,
|
||||
ETHTOOL_A_EEE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_EEE_MODES_OURS, /* bitset */
|
||||
ETHTOOL_A_EEE_MODES_PEER, /* bitset */
|
||||
ETHTOOL_A_EEE_ACTIVE, /* u8 */
|
||||
ETHTOOL_A_EEE_ENABLED, /* u8 */
|
||||
ETHTOOL_A_EEE_TX_LPI_ENABLED, /* u8 */
|
||||
ETHTOOL_A_EEE_TX_LPI_TIMER, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_EEE_CNT,
|
||||
ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1)
|
||||
};
|
||||
|
||||
/* TSINFO */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TSINFO_UNSPEC,
|
||||
ETHTOOL_A_TSINFO_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_TSINFO_TIMESTAMPING, /* bitset */
|
||||
ETHTOOL_A_TSINFO_TX_TYPES, /* bitset */
|
||||
ETHTOOL_A_TSINFO_RX_FILTERS, /* bitset */
|
||||
ETHTOOL_A_TSINFO_PHC_INDEX, /* u32 */
|
||||
ETHTOOL_A_TSINFO_STATS, /* nest - _A_TSINFO_STAT */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TSINFO_CNT,
|
||||
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TS_STAT_UNSPEC,
|
||||
|
||||
ETHTOOL_A_TS_STAT_TX_PKTS, /* uint */
|
||||
ETHTOOL_A_TS_STAT_TX_LOST, /* uint */
|
||||
ETHTOOL_A_TS_STAT_TX_ERR, /* uint */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TS_STAT_CNT,
|
||||
ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)
|
||||
|
||||
};
|
||||
|
||||
/* PHC VCLOCKS */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PHC_VCLOCKS_UNSPEC,
|
||||
ETHTOOL_A_PHC_VCLOCKS_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PHC_VCLOCKS_NUM, /* u32 */
|
||||
ETHTOOL_A_PHC_VCLOCKS_INDEX, /* array, s32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PHC_VCLOCKS_CNT,
|
||||
ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1)
|
||||
};
|
||||
|
||||
/* CABLE TEST */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_HEADER, /* nest - _A_HEADER_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_CABLE_TEST_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_MAX = __ETHTOOL_A_CABLE_TEST_CNT - 1
|
||||
};
|
||||
|
||||
/* CABLE TEST NOTIFY */
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC,
|
||||
|
@ -582,74 +49,12 @@ enum {
|
|||
ETHTOOL_A_CABLE_INF_SRC_ALCD,
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_RESULT_UNSPEC,
|
||||
ETHTOOL_A_CABLE_RESULT_PAIR, /* u8 ETHTOOL_A_CABLE_PAIR_ */
|
||||
ETHTOOL_A_CABLE_RESULT_CODE, /* u8 ETHTOOL_A_CABLE_RESULT_CODE_ */
|
||||
ETHTOOL_A_CABLE_RESULT_SRC, /* u32 ETHTOOL_A_CABLE_INF_SRC_ */
|
||||
|
||||
__ETHTOOL_A_CABLE_RESULT_CNT,
|
||||
ETHTOOL_A_CABLE_RESULT_MAX = (__ETHTOOL_A_CABLE_RESULT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC,
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR, /* u8 ETHTOOL_A_CABLE_PAIR_ */
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_CM, /* u32 */
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_SRC, /* u32 ETHTOOL_A_CABLE_INF_SRC_ */
|
||||
|
||||
__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT,
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = (__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_NTF_STATUS_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_STATUS_STARTED,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_STATUS_COMPLETED
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_NEST_UNSPEC,
|
||||
ETHTOOL_A_CABLE_NEST_RESULT, /* nest - ETHTOOL_A_CABLE_RESULT_ */
|
||||
ETHTOOL_A_CABLE_NEST_FAULT_LENGTH, /* nest - ETHTOOL_A_CABLE_FAULT_LENGTH_ */
|
||||
__ETHTOOL_A_CABLE_NEST_CNT,
|
||||
ETHTOOL_A_CABLE_NEST_MAX = (__ETHTOOL_A_CABLE_NEST_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_NTF_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_HEADER, /* nest - ETHTOOL_A_HEADER_* */
|
||||
ETHTOOL_A_CABLE_TEST_NTF_STATUS, /* u8 - _STARTED/_COMPLETE */
|
||||
ETHTOOL_A_CABLE_TEST_NTF_NEST, /* nest - of results: */
|
||||
|
||||
__ETHTOOL_A_CABLE_TEST_NTF_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_NTF_CNT - 1)
|
||||
};
|
||||
|
||||
/* CABLE TEST TDR */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST, /* u32 */
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST, /* u32 */
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP, /* u32 */
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR, /* u8 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = __ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT - 1
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_TDR_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG, /* nest - *_TDR_CFG_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_CABLE_TEST_TDR_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_MAX = __ETHTOOL_A_CABLE_TEST_TDR_CNT - 1
|
||||
};
|
||||
|
||||
/* CABLE TEST TDR NOTIFY */
|
||||
|
||||
enum {
|
||||
|
@ -689,163 +94,17 @@ enum {
|
|||
ETHTOOL_A_CABLE_TDR_NEST_MAX = (__ETHTOOL_A_CABLE_TDR_NEST_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER, /* nest - ETHTOOL_A_HEADER_* */
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS, /* u8 - _STARTED/_COMPLETE */
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST, /* nest - of results: */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX = __ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT - 1
|
||||
};
|
||||
|
||||
/* TUNNEL INFO */
|
||||
|
||||
enum {
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_GENEVE,
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE,
|
||||
|
||||
__ETHTOOL_UDP_TUNNEL_TYPE_CNT
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC,
|
||||
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT, /* be16 */
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT,
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = (__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC,
|
||||
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE, /* u32 */
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES, /* bitset */
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY, /* nest - _UDP_ENTRY_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT,
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_MAX = (__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_UDP_UNSPEC,
|
||||
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE, /* nest - _UDP_TABLE_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TUNNEL_UDP_CNT,
|
||||
ETHTOOL_A_TUNNEL_UDP_MAX = (__ETHTOOL_A_TUNNEL_UDP_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_INFO_UNSPEC,
|
||||
ETHTOOL_A_TUNNEL_INFO_HEADER, /* nest - _A_HEADER_* */
|
||||
|
||||
ETHTOOL_A_TUNNEL_INFO_UDP_PORTS, /* nest - _UDP_TABLE */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_TUNNEL_INFO_CNT,
|
||||
ETHTOOL_A_TUNNEL_INFO_MAX = (__ETHTOOL_A_TUNNEL_INFO_CNT - 1)
|
||||
};
|
||||
|
||||
/* FEC */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_FEC_UNSPEC,
|
||||
ETHTOOL_A_FEC_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_FEC_MODES, /* bitset */
|
||||
ETHTOOL_A_FEC_AUTO, /* u8 */
|
||||
ETHTOOL_A_FEC_ACTIVE, /* u32 */
|
||||
ETHTOOL_A_FEC_STATS, /* nest - _A_FEC_STAT */
|
||||
|
||||
__ETHTOOL_A_FEC_CNT,
|
||||
ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_FEC_STAT_UNSPEC,
|
||||
ETHTOOL_A_FEC_STAT_PAD,
|
||||
|
||||
ETHTOOL_A_FEC_STAT_CORRECTED, /* array, u64 */
|
||||
ETHTOOL_A_FEC_STAT_UNCORR, /* array, u64 */
|
||||
ETHTOOL_A_FEC_STAT_CORR_BITS, /* array, u64 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_FEC_STAT_CNT,
|
||||
ETHTOOL_A_FEC_STAT_MAX = (__ETHTOOL_A_FEC_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
/* MODULE EEPROM */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MODULE_EEPROM_UNSPEC,
|
||||
ETHTOOL_A_MODULE_EEPROM_HEADER, /* nest - _A_HEADER_* */
|
||||
|
||||
ETHTOOL_A_MODULE_EEPROM_OFFSET, /* u32 */
|
||||
ETHTOOL_A_MODULE_EEPROM_LENGTH, /* u32 */
|
||||
ETHTOOL_A_MODULE_EEPROM_PAGE, /* u8 */
|
||||
ETHTOOL_A_MODULE_EEPROM_BANK, /* u8 */
|
||||
ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS, /* u8 */
|
||||
ETHTOOL_A_MODULE_EEPROM_DATA, /* binary */
|
||||
|
||||
__ETHTOOL_A_MODULE_EEPROM_CNT,
|
||||
ETHTOOL_A_MODULE_EEPROM_MAX = (__ETHTOOL_A_MODULE_EEPROM_CNT - 1)
|
||||
};
|
||||
|
||||
/* STATS */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STATS_UNSPEC,
|
||||
ETHTOOL_A_STATS_PAD,
|
||||
ETHTOOL_A_STATS_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_STATS_GROUPS, /* bitset */
|
||||
|
||||
ETHTOOL_A_STATS_GRP, /* nest - _A_STATS_GRP_* */
|
||||
|
||||
ETHTOOL_A_STATS_SRC, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STATS_CNT,
|
||||
ETHTOOL_A_STATS_MAX = (__ETHTOOL_A_STATS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_STATS_ETH_PHY,
|
||||
ETHTOOL_STATS_ETH_MAC,
|
||||
ETHTOOL_STATS_ETH_CTRL,
|
||||
ETHTOOL_STATS_RMON,
|
||||
ETHTOOL_STATS_PHY,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_STATS_CNT
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STATS_GRP_UNSPEC,
|
||||
ETHTOOL_A_STATS_GRP_PAD,
|
||||
|
||||
ETHTOOL_A_STATS_GRP_ID, /* u32 */
|
||||
ETHTOOL_A_STATS_GRP_SS_ID, /* u32 */
|
||||
|
||||
ETHTOOL_A_STATS_GRP_STAT, /* nest */
|
||||
|
||||
ETHTOOL_A_STATS_GRP_HIST_RX, /* nest */
|
||||
ETHTOOL_A_STATS_GRP_HIST_TX, /* nest */
|
||||
|
||||
ETHTOOL_A_STATS_GRP_HIST_BKT_LOW, /* u32 */
|
||||
ETHTOOL_A_STATS_GRP_HIST_BKT_HI, /* u32 */
|
||||
ETHTOOL_A_STATS_GRP_HIST_VAL, /* u64 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_STATS_GRP_CNT,
|
||||
ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_GRP_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 30.3.2.1.5 aSymbolErrorDuringCarrier */
|
||||
ETHTOOL_A_STATS_ETH_PHY_5_SYM_ERR,
|
||||
|
@ -935,160 +194,20 @@ enum {
|
|||
ETHTOOL_A_STATS_RMON_MAX = (__ETHTOOL_A_STATS_RMON_CNT - 1)
|
||||
};
|
||||
|
||||
/* MODULE */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MODULE_UNSPEC,
|
||||
ETHTOOL_A_MODULE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_MODULE_POWER_MODE_POLICY, /* u8 */
|
||||
ETHTOOL_A_MODULE_POWER_MODE, /* u8 */
|
||||
/* Basic packet counters if PHY has separate counters from the MAC */
|
||||
ETHTOOL_A_STATS_PHY_RX_PKTS,
|
||||
ETHTOOL_A_STATS_PHY_RX_BYTES,
|
||||
ETHTOOL_A_STATS_PHY_RX_ERRORS,
|
||||
ETHTOOL_A_STATS_PHY_TX_PKTS,
|
||||
ETHTOOL_A_STATS_PHY_TX_BYTES,
|
||||
ETHTOOL_A_STATS_PHY_TX_ERRORS,
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_MODULE_CNT,
|
||||
ETHTOOL_A_MODULE_MAX = (__ETHTOOL_A_MODULE_CNT - 1)
|
||||
__ETHTOOL_A_STATS_PHY_CNT,
|
||||
ETHTOOL_A_STATS_PHY_MAX = (__ETHTOOL_A_STATS_PHY_CNT - 1)
|
||||
};
|
||||
|
||||
/* Power Sourcing Equipment */
|
||||
enum {
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_UNSPEC,
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_MIN, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_MAX, /* u32 */
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PSE_UNSPEC,
|
||||
ETHTOOL_A_PSE_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PODL_PSE_ADMIN_STATE, /* u32 */
|
||||
ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, /* u32 */
|
||||
ETHTOOL_A_PODL_PSE_PW_D_STATUS, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_ADMIN_STATE, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_ADMIN_CONTROL, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_PW_D_STATUS, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_PW_CLASS, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_ACTUAL_PW, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_EXT_STATE, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_EXT_SUBSTATE, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT, /* u32 */
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES, /* nest - _C33_PSE_PW_LIMIT_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PSE_CNT,
|
||||
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_RSS_UNSPEC,
|
||||
ETHTOOL_A_RSS_HEADER,
|
||||
ETHTOOL_A_RSS_CONTEXT, /* u32 */
|
||||
ETHTOOL_A_RSS_HFUNC, /* u32 */
|
||||
ETHTOOL_A_RSS_INDIR, /* binary */
|
||||
ETHTOOL_A_RSS_HKEY, /* binary */
|
||||
ETHTOOL_A_RSS_INPUT_XFRM, /* u32 */
|
||||
ETHTOOL_A_RSS_START_CONTEXT, /* u32 */
|
||||
|
||||
__ETHTOOL_A_RSS_CNT,
|
||||
ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1),
|
||||
};
|
||||
|
||||
/* PLCA */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PLCA_UNSPEC,
|
||||
ETHTOOL_A_PLCA_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PLCA_VERSION, /* u16 */
|
||||
ETHTOOL_A_PLCA_ENABLED, /* u8 */
|
||||
ETHTOOL_A_PLCA_STATUS, /* u8 */
|
||||
ETHTOOL_A_PLCA_NODE_CNT, /* u32 */
|
||||
ETHTOOL_A_PLCA_NODE_ID, /* u32 */
|
||||
ETHTOOL_A_PLCA_TO_TMR, /* u32 */
|
||||
ETHTOOL_A_PLCA_BURST_CNT, /* u32 */
|
||||
ETHTOOL_A_PLCA_BURST_TMR, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PLCA_CNT,
|
||||
ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
|
||||
};
|
||||
|
||||
/* MAC Merge (802.3) */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MM_STAT_UNSPEC,
|
||||
ETHTOOL_A_MM_STAT_PAD,
|
||||
|
||||
/* aMACMergeFrameAssErrorCount */
|
||||
ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS, /* u64 */
|
||||
/* aMACMergeFrameSmdErrorCount */
|
||||
ETHTOOL_A_MM_STAT_SMD_ERRORS, /* u64 */
|
||||
/* aMACMergeFrameAssOkCount */
|
||||
ETHTOOL_A_MM_STAT_REASSEMBLY_OK, /* u64 */
|
||||
/* aMACMergeFragCountRx */
|
||||
ETHTOOL_A_MM_STAT_RX_FRAG_COUNT, /* u64 */
|
||||
/* aMACMergeFragCountTx */
|
||||
ETHTOOL_A_MM_STAT_TX_FRAG_COUNT, /* u64 */
|
||||
/* aMACMergeHoldCount */
|
||||
ETHTOOL_A_MM_STAT_HOLD_COUNT, /* u64 */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_MM_STAT_CNT,
|
||||
ETHTOOL_A_MM_STAT_MAX = (__ETHTOOL_A_MM_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MM_UNSPEC,
|
||||
ETHTOOL_A_MM_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_MM_PMAC_ENABLED, /* u8 */
|
||||
ETHTOOL_A_MM_TX_ENABLED, /* u8 */
|
||||
ETHTOOL_A_MM_TX_ACTIVE, /* u8 */
|
||||
ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, /* u32 */
|
||||
ETHTOOL_A_MM_RX_MIN_FRAG_SIZE, /* u32 */
|
||||
ETHTOOL_A_MM_VERIFY_ENABLED, /* u8 */
|
||||
ETHTOOL_A_MM_VERIFY_STATUS, /* u8 */
|
||||
ETHTOOL_A_MM_VERIFY_TIME, /* u32 */
|
||||
ETHTOOL_A_MM_MAX_VERIFY_TIME, /* u32 */
|
||||
ETHTOOL_A_MM_STATS, /* nest - _A_MM_STAT_* */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_MM_CNT,
|
||||
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
|
||||
};
|
||||
|
||||
/* MODULE_FW_FLASH */
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MODULE_FW_FLASH_UNSPEC,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME, /* string */
|
||||
ETHTOOL_A_MODULE_FW_FLASH_PASSWORD, /* u32 */
|
||||
ETHTOOL_A_MODULE_FW_FLASH_STATUS, /* u32 */
|
||||
ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG, /* string */
|
||||
ETHTOOL_A_MODULE_FW_FLASH_DONE, /* uint */
|
||||
ETHTOOL_A_MODULE_FW_FLASH_TOTAL, /* uint */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_MODULE_FW_FLASH_CNT,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_MAX = (__ETHTOOL_A_MODULE_FW_FLASH_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PHY_UNSPEC,
|
||||
ETHTOOL_A_PHY_HEADER, /* nest - _A_HEADER_* */
|
||||
ETHTOOL_A_PHY_INDEX, /* u32 */
|
||||
ETHTOOL_A_PHY_DRVNAME, /* string */
|
||||
ETHTOOL_A_PHY_NAME, /* string */
|
||||
ETHTOOL_A_PHY_UPSTREAM_TYPE, /* u32 */
|
||||
ETHTOOL_A_PHY_UPSTREAM_INDEX, /* u32 */
|
||||
ETHTOOL_A_PHY_UPSTREAM_SFP_NAME, /* string */
|
||||
ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME, /* string */
|
||||
|
||||
/* add new constants above here */
|
||||
__ETHTOOL_A_PHY_CNT,
|
||||
ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1)
|
||||
};
|
||||
|
||||
/* generic netlink info */
|
||||
#define ETHTOOL_GENL_NAME "ethtool"
|
||||
#define ETHTOOL_GENL_VERSION 1
|
||||
|
||||
#define ETHTOOL_MCGRP_MONITOR_NAME "monitor"
|
||||
|
||||
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
|
||||
|
|
|
@ -0,0 +1,816 @@
|
|||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/ethtool.yaml */
|
||||
/* YNL-GEN uapi header */
|
||||
|
||||
#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
||||
#define _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
||||
|
||||
#define ETHTOOL_GENL_NAME "ethtool"
|
||||
#define ETHTOOL_GENL_VERSION 1
|
||||
|
||||
enum {
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_GENEVE,
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN_GPE,
|
||||
|
||||
/* private: */
|
||||
__ETHTOOL_UDP_TUNNEL_TYPE_CNT,
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_MAX = (__ETHTOOL_UDP_TUNNEL_TYPE_CNT - 1)
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ethtool_header_flags - common ethtool header flags
|
||||
* @ETHTOOL_FLAG_COMPACT_BITSETS: use compact bitsets in reply
|
||||
* @ETHTOOL_FLAG_OMIT_REPLY: provide optional reply for SET or ACT requests
|
||||
* @ETHTOOL_FLAG_STATS: request statistics, if supported by the driver
|
||||
*/
|
||||
enum ethtool_header_flags {
|
||||
ETHTOOL_FLAG_COMPACT_BITSETS = 1,
|
||||
ETHTOOL_FLAG_OMIT_REPLY = 2,
|
||||
ETHTOOL_FLAG_STATS = 4,
|
||||
};
|
||||
|
||||
enum ethtool_tcp_data_split {
|
||||
ETHTOOL_TCP_DATA_SPLIT_UNKNOWN,
|
||||
ETHTOOL_TCP_DATA_SPLIT_DISABLED,
|
||||
ETHTOOL_TCP_DATA_SPLIT_ENABLED,
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_HEADER_UNSPEC,
|
||||
ETHTOOL_A_HEADER_DEV_INDEX,
|
||||
ETHTOOL_A_HEADER_DEV_NAME,
|
||||
ETHTOOL_A_HEADER_FLAGS,
|
||||
ETHTOOL_A_HEADER_PHY_INDEX,
|
||||
|
||||
__ETHTOOL_A_HEADER_CNT,
|
||||
ETHTOOL_A_HEADER_MAX = (__ETHTOOL_A_HEADER_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_BITSET_BIT_UNSPEC,
|
||||
ETHTOOL_A_BITSET_BIT_INDEX,
|
||||
ETHTOOL_A_BITSET_BIT_NAME,
|
||||
ETHTOOL_A_BITSET_BIT_VALUE,
|
||||
|
||||
__ETHTOOL_A_BITSET_BIT_CNT,
|
||||
ETHTOOL_A_BITSET_BIT_MAX = (__ETHTOOL_A_BITSET_BIT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_BITSET_BITS_UNSPEC,
|
||||
ETHTOOL_A_BITSET_BITS_BIT,
|
||||
|
||||
__ETHTOOL_A_BITSET_BITS_CNT,
|
||||
ETHTOOL_A_BITSET_BITS_MAX = (__ETHTOOL_A_BITSET_BITS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_BITSET_UNSPEC,
|
||||
ETHTOOL_A_BITSET_NOMASK,
|
||||
ETHTOOL_A_BITSET_SIZE,
|
||||
ETHTOOL_A_BITSET_BITS,
|
||||
ETHTOOL_A_BITSET_VALUE,
|
||||
ETHTOOL_A_BITSET_MASK,
|
||||
|
||||
__ETHTOOL_A_BITSET_CNT,
|
||||
ETHTOOL_A_BITSET_MAX = (__ETHTOOL_A_BITSET_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRING_UNSPEC,
|
||||
ETHTOOL_A_STRING_INDEX,
|
||||
ETHTOOL_A_STRING_VALUE,
|
||||
|
||||
__ETHTOOL_A_STRING_CNT,
|
||||
ETHTOOL_A_STRING_MAX = (__ETHTOOL_A_STRING_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRINGS_UNSPEC,
|
||||
ETHTOOL_A_STRINGS_STRING,
|
||||
|
||||
__ETHTOOL_A_STRINGS_CNT,
|
||||
ETHTOOL_A_STRINGS_MAX = (__ETHTOOL_A_STRINGS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRINGSET_UNSPEC,
|
||||
ETHTOOL_A_STRINGSET_ID,
|
||||
ETHTOOL_A_STRINGSET_COUNT,
|
||||
ETHTOOL_A_STRINGSET_STRINGS,
|
||||
|
||||
__ETHTOOL_A_STRINGSET_CNT,
|
||||
ETHTOOL_A_STRINGSET_MAX = (__ETHTOOL_A_STRINGSET_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRINGSETS_UNSPEC,
|
||||
ETHTOOL_A_STRINGSETS_STRINGSET,
|
||||
|
||||
__ETHTOOL_A_STRINGSETS_CNT,
|
||||
ETHTOOL_A_STRINGSETS_MAX = (__ETHTOOL_A_STRINGSETS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STRSET_UNSPEC,
|
||||
ETHTOOL_A_STRSET_HEADER,
|
||||
ETHTOOL_A_STRSET_STRINGSETS,
|
||||
ETHTOOL_A_STRSET_COUNTS_ONLY,
|
||||
|
||||
__ETHTOOL_A_STRSET_CNT,
|
||||
ETHTOOL_A_STRSET_MAX = (__ETHTOOL_A_STRSET_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PRIVFLAGS_UNSPEC,
|
||||
ETHTOOL_A_PRIVFLAGS_HEADER,
|
||||
ETHTOOL_A_PRIVFLAGS_FLAGS,
|
||||
|
||||
__ETHTOOL_A_PRIVFLAGS_CNT,
|
||||
ETHTOOL_A_PRIVFLAGS_MAX = (__ETHTOOL_A_PRIVFLAGS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_RINGS_UNSPEC,
|
||||
ETHTOOL_A_RINGS_HEADER,
|
||||
ETHTOOL_A_RINGS_RX_MAX,
|
||||
ETHTOOL_A_RINGS_RX_MINI_MAX,
|
||||
ETHTOOL_A_RINGS_RX_JUMBO_MAX,
|
||||
ETHTOOL_A_RINGS_TX_MAX,
|
||||
ETHTOOL_A_RINGS_RX,
|
||||
ETHTOOL_A_RINGS_RX_MINI,
|
||||
ETHTOOL_A_RINGS_RX_JUMBO,
|
||||
ETHTOOL_A_RINGS_TX,
|
||||
ETHTOOL_A_RINGS_RX_BUF_LEN,
|
||||
ETHTOOL_A_RINGS_TCP_DATA_SPLIT,
|
||||
ETHTOOL_A_RINGS_CQE_SIZE,
|
||||
ETHTOOL_A_RINGS_TX_PUSH,
|
||||
ETHTOOL_A_RINGS_RX_PUSH,
|
||||
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN,
|
||||
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX,
|
||||
ETHTOOL_A_RINGS_HDS_THRESH,
|
||||
ETHTOOL_A_RINGS_HDS_THRESH_MAX,
|
||||
|
||||
__ETHTOOL_A_RINGS_CNT,
|
||||
ETHTOOL_A_RINGS_MAX = (__ETHTOOL_A_RINGS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MM_STAT_UNSPEC,
|
||||
ETHTOOL_A_MM_STAT_PAD,
|
||||
ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS,
|
||||
ETHTOOL_A_MM_STAT_SMD_ERRORS,
|
||||
ETHTOOL_A_MM_STAT_REASSEMBLY_OK,
|
||||
ETHTOOL_A_MM_STAT_RX_FRAG_COUNT,
|
||||
ETHTOOL_A_MM_STAT_TX_FRAG_COUNT,
|
||||
ETHTOOL_A_MM_STAT_HOLD_COUNT,
|
||||
|
||||
__ETHTOOL_A_MM_STAT_CNT,
|
||||
ETHTOOL_A_MM_STAT_MAX = (__ETHTOOL_A_MM_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MM_UNSPEC,
|
||||
ETHTOOL_A_MM_HEADER,
|
||||
ETHTOOL_A_MM_PMAC_ENABLED,
|
||||
ETHTOOL_A_MM_TX_ENABLED,
|
||||
ETHTOOL_A_MM_TX_ACTIVE,
|
||||
ETHTOOL_A_MM_TX_MIN_FRAG_SIZE,
|
||||
ETHTOOL_A_MM_RX_MIN_FRAG_SIZE,
|
||||
ETHTOOL_A_MM_VERIFY_ENABLED,
|
||||
ETHTOOL_A_MM_VERIFY_STATUS,
|
||||
ETHTOOL_A_MM_VERIFY_TIME,
|
||||
ETHTOOL_A_MM_MAX_VERIFY_TIME,
|
||||
ETHTOOL_A_MM_STATS,
|
||||
|
||||
__ETHTOOL_A_MM_CNT,
|
||||
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_LINKINFO_UNSPEC,
|
||||
ETHTOOL_A_LINKINFO_HEADER,
|
||||
ETHTOOL_A_LINKINFO_PORT,
|
||||
ETHTOOL_A_LINKINFO_PHYADDR,
|
||||
ETHTOOL_A_LINKINFO_TP_MDIX,
|
||||
ETHTOOL_A_LINKINFO_TP_MDIX_CTRL,
|
||||
ETHTOOL_A_LINKINFO_TRANSCEIVER,
|
||||
|
||||
__ETHTOOL_A_LINKINFO_CNT,
|
||||
ETHTOOL_A_LINKINFO_MAX = (__ETHTOOL_A_LINKINFO_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_LINKMODES_UNSPEC,
|
||||
ETHTOOL_A_LINKMODES_HEADER,
|
||||
ETHTOOL_A_LINKMODES_AUTONEG,
|
||||
ETHTOOL_A_LINKMODES_OURS,
|
||||
ETHTOOL_A_LINKMODES_PEER,
|
||||
ETHTOOL_A_LINKMODES_SPEED,
|
||||
ETHTOOL_A_LINKMODES_DUPLEX,
|
||||
ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG,
|
||||
ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE,
|
||||
ETHTOOL_A_LINKMODES_LANES,
|
||||
ETHTOOL_A_LINKMODES_RATE_MATCHING,
|
||||
|
||||
__ETHTOOL_A_LINKMODES_CNT,
|
||||
ETHTOOL_A_LINKMODES_MAX = (__ETHTOOL_A_LINKMODES_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_LINKSTATE_UNSPEC,
|
||||
ETHTOOL_A_LINKSTATE_HEADER,
|
||||
ETHTOOL_A_LINKSTATE_LINK,
|
||||
ETHTOOL_A_LINKSTATE_SQI,
|
||||
ETHTOOL_A_LINKSTATE_SQI_MAX,
|
||||
ETHTOOL_A_LINKSTATE_EXT_STATE,
|
||||
ETHTOOL_A_LINKSTATE_EXT_SUBSTATE,
|
||||
ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT,
|
||||
|
||||
__ETHTOOL_A_LINKSTATE_CNT,
|
||||
ETHTOOL_A_LINKSTATE_MAX = (__ETHTOOL_A_LINKSTATE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_DEBUG_UNSPEC,
|
||||
ETHTOOL_A_DEBUG_HEADER,
|
||||
ETHTOOL_A_DEBUG_MSGMASK,
|
||||
|
||||
__ETHTOOL_A_DEBUG_CNT,
|
||||
ETHTOOL_A_DEBUG_MAX = (__ETHTOOL_A_DEBUG_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_WOL_UNSPEC,
|
||||
ETHTOOL_A_WOL_HEADER,
|
||||
ETHTOOL_A_WOL_MODES,
|
||||
ETHTOOL_A_WOL_SOPASS,
|
||||
|
||||
__ETHTOOL_A_WOL_CNT,
|
||||
ETHTOOL_A_WOL_MAX = (__ETHTOOL_A_WOL_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_FEATURES_UNSPEC,
|
||||
ETHTOOL_A_FEATURES_HEADER,
|
||||
ETHTOOL_A_FEATURES_HW,
|
||||
ETHTOOL_A_FEATURES_WANTED,
|
||||
ETHTOOL_A_FEATURES_ACTIVE,
|
||||
ETHTOOL_A_FEATURES_NOCHANGE,
|
||||
|
||||
__ETHTOOL_A_FEATURES_CNT,
|
||||
ETHTOOL_A_FEATURES_MAX = (__ETHTOOL_A_FEATURES_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CHANNELS_UNSPEC,
|
||||
ETHTOOL_A_CHANNELS_HEADER,
|
||||
ETHTOOL_A_CHANNELS_RX_MAX,
|
||||
ETHTOOL_A_CHANNELS_TX_MAX,
|
||||
ETHTOOL_A_CHANNELS_OTHER_MAX,
|
||||
ETHTOOL_A_CHANNELS_COMBINED_MAX,
|
||||
ETHTOOL_A_CHANNELS_RX_COUNT,
|
||||
ETHTOOL_A_CHANNELS_TX_COUNT,
|
||||
ETHTOOL_A_CHANNELS_OTHER_COUNT,
|
||||
ETHTOOL_A_CHANNELS_COMBINED_COUNT,
|
||||
|
||||
__ETHTOOL_A_CHANNELS_CNT,
|
||||
ETHTOOL_A_CHANNELS_MAX = (__ETHTOOL_A_CHANNELS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_IRQ_MODERATION_UNSPEC,
|
||||
ETHTOOL_A_IRQ_MODERATION_USEC,
|
||||
ETHTOOL_A_IRQ_MODERATION_PKTS,
|
||||
ETHTOOL_A_IRQ_MODERATION_COMPS,
|
||||
|
||||
__ETHTOOL_A_IRQ_MODERATION_CNT,
|
||||
ETHTOOL_A_IRQ_MODERATION_MAX = (__ETHTOOL_A_IRQ_MODERATION_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PROFILE_UNSPEC,
|
||||
ETHTOOL_A_PROFILE_IRQ_MODERATION,
|
||||
|
||||
__ETHTOOL_A_PROFILE_CNT,
|
||||
ETHTOOL_A_PROFILE_MAX = (__ETHTOOL_A_PROFILE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_COALESCE_UNSPEC,
|
||||
ETHTOOL_A_COALESCE_HEADER,
|
||||
ETHTOOL_A_COALESCE_RX_USECS,
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES,
|
||||
ETHTOOL_A_COALESCE_RX_USECS_IRQ,
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,
|
||||
ETHTOOL_A_COALESCE_TX_USECS,
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES,
|
||||
ETHTOOL_A_COALESCE_TX_USECS_IRQ,
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,
|
||||
ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,
|
||||
ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,
|
||||
ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,
|
||||
ETHTOOL_A_COALESCE_PKT_RATE_LOW,
|
||||
ETHTOOL_A_COALESCE_RX_USECS_LOW,
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,
|
||||
ETHTOOL_A_COALESCE_TX_USECS_LOW,
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,
|
||||
ETHTOOL_A_COALESCE_PKT_RATE_HIGH,
|
||||
ETHTOOL_A_COALESCE_RX_USECS_HIGH,
|
||||
ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,
|
||||
ETHTOOL_A_COALESCE_TX_USECS_HIGH,
|
||||
ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
|
||||
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
|
||||
ETHTOOL_A_COALESCE_USE_CQE_MODE_TX,
|
||||
ETHTOOL_A_COALESCE_USE_CQE_MODE_RX,
|
||||
ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES,
|
||||
ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES,
|
||||
ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS,
|
||||
ETHTOOL_A_COALESCE_RX_PROFILE,
|
||||
ETHTOOL_A_COALESCE_TX_PROFILE,
|
||||
|
||||
__ETHTOOL_A_COALESCE_CNT,
|
||||
ETHTOOL_A_COALESCE_MAX = (__ETHTOOL_A_COALESCE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PAUSE_STAT_UNSPEC,
|
||||
ETHTOOL_A_PAUSE_STAT_PAD,
|
||||
ETHTOOL_A_PAUSE_STAT_TX_FRAMES,
|
||||
ETHTOOL_A_PAUSE_STAT_RX_FRAMES,
|
||||
|
||||
__ETHTOOL_A_PAUSE_STAT_CNT,
|
||||
ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PAUSE_UNSPEC,
|
||||
ETHTOOL_A_PAUSE_HEADER,
|
||||
ETHTOOL_A_PAUSE_AUTONEG,
|
||||
ETHTOOL_A_PAUSE_RX,
|
||||
ETHTOOL_A_PAUSE_TX,
|
||||
ETHTOOL_A_PAUSE_STATS,
|
||||
ETHTOOL_A_PAUSE_STATS_SRC,
|
||||
|
||||
__ETHTOOL_A_PAUSE_CNT,
|
||||
ETHTOOL_A_PAUSE_MAX = (__ETHTOOL_A_PAUSE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_EEE_UNSPEC,
|
||||
ETHTOOL_A_EEE_HEADER,
|
||||
ETHTOOL_A_EEE_MODES_OURS,
|
||||
ETHTOOL_A_EEE_MODES_PEER,
|
||||
ETHTOOL_A_EEE_ACTIVE,
|
||||
ETHTOOL_A_EEE_ENABLED,
|
||||
ETHTOOL_A_EEE_TX_LPI_ENABLED,
|
||||
ETHTOOL_A_EEE_TX_LPI_TIMER,
|
||||
|
||||
__ETHTOOL_A_EEE_CNT,
|
||||
ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TS_STAT_UNSPEC,
|
||||
ETHTOOL_A_TS_STAT_TX_PKTS,
|
||||
ETHTOOL_A_TS_STAT_TX_LOST,
|
||||
ETHTOOL_A_TS_STAT_TX_ERR,
|
||||
ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED,
|
||||
|
||||
__ETHTOOL_A_TS_STAT_CNT,
|
||||
ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_UNSPEC,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
|
||||
|
||||
__ETHTOOL_A_TS_HWTSTAMP_PROVIDER_CNT,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX = (__ETHTOOL_A_TS_HWTSTAMP_PROVIDER_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TSINFO_UNSPEC,
|
||||
ETHTOOL_A_TSINFO_HEADER,
|
||||
ETHTOOL_A_TSINFO_TIMESTAMPING,
|
||||
ETHTOOL_A_TSINFO_TX_TYPES,
|
||||
ETHTOOL_A_TSINFO_RX_FILTERS,
|
||||
ETHTOOL_A_TSINFO_PHC_INDEX,
|
||||
ETHTOOL_A_TSINFO_STATS,
|
||||
ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER,
|
||||
|
||||
__ETHTOOL_A_TSINFO_CNT,
|
||||
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_RESULT_UNSPEC,
|
||||
ETHTOOL_A_CABLE_RESULT_PAIR,
|
||||
ETHTOOL_A_CABLE_RESULT_CODE,
|
||||
ETHTOOL_A_CABLE_RESULT_SRC,
|
||||
|
||||
__ETHTOOL_A_CABLE_RESULT_CNT,
|
||||
ETHTOOL_A_CABLE_RESULT_MAX = (__ETHTOOL_A_CABLE_RESULT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_UNSPEC,
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR,
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_CM,
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_SRC,
|
||||
|
||||
__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT,
|
||||
ETHTOOL_A_CABLE_FAULT_LENGTH_MAX = (__ETHTOOL_A_CABLE_FAULT_LENGTH_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_NEST_UNSPEC,
|
||||
ETHTOOL_A_CABLE_NEST_RESULT,
|
||||
ETHTOOL_A_CABLE_NEST_FAULT_LENGTH,
|
||||
|
||||
__ETHTOOL_A_CABLE_NEST_CNT,
|
||||
ETHTOOL_A_CABLE_NEST_MAX = (__ETHTOOL_A_CABLE_NEST_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_HEADER,
|
||||
|
||||
__ETHTOOL_A_CABLE_TEST_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_MAX = (__ETHTOOL_A_CABLE_TEST_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_NTF_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_HEADER,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_STATUS,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_NEST,
|
||||
|
||||
__ETHTOOL_A_CABLE_TEST_NTF_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_NTF_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR,
|
||||
|
||||
__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX = (__ETHTOOL_A_CABLE_TEST_TDR_CFG_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST,
|
||||
|
||||
__ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX = (__ETHTOOL_A_CABLE_TEST_TDR_NTF_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_CABLE_TEST_TDR_UNSPEC,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_HEADER,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_CFG,
|
||||
|
||||
__ETHTOOL_A_CABLE_TEST_TDR_CNT,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_MAX = (__ETHTOOL_A_CABLE_TEST_TDR_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_UNSPEC,
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT,
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE,
|
||||
|
||||
__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT,
|
||||
ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX = (__ETHTOOL_A_TUNNEL_UDP_ENTRY_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_UNSPEC,
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE,
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES,
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY,
|
||||
|
||||
__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT,
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE_MAX = (__ETHTOOL_A_TUNNEL_UDP_TABLE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_UDP_UNSPEC,
|
||||
ETHTOOL_A_TUNNEL_UDP_TABLE,
|
||||
|
||||
__ETHTOOL_A_TUNNEL_UDP_CNT,
|
||||
ETHTOOL_A_TUNNEL_UDP_MAX = (__ETHTOOL_A_TUNNEL_UDP_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TUNNEL_INFO_UNSPEC,
|
||||
ETHTOOL_A_TUNNEL_INFO_HEADER,
|
||||
ETHTOOL_A_TUNNEL_INFO_UDP_PORTS,
|
||||
|
||||
__ETHTOOL_A_TUNNEL_INFO_CNT,
|
||||
ETHTOOL_A_TUNNEL_INFO_MAX = (__ETHTOOL_A_TUNNEL_INFO_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_FEC_STAT_UNSPEC,
|
||||
ETHTOOL_A_FEC_STAT_PAD,
|
||||
ETHTOOL_A_FEC_STAT_CORRECTED,
|
||||
ETHTOOL_A_FEC_STAT_UNCORR,
|
||||
ETHTOOL_A_FEC_STAT_CORR_BITS,
|
||||
|
||||
__ETHTOOL_A_FEC_STAT_CNT,
|
||||
ETHTOOL_A_FEC_STAT_MAX = (__ETHTOOL_A_FEC_STAT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_FEC_UNSPEC,
|
||||
ETHTOOL_A_FEC_HEADER,
|
||||
ETHTOOL_A_FEC_MODES,
|
||||
ETHTOOL_A_FEC_AUTO,
|
||||
ETHTOOL_A_FEC_ACTIVE,
|
||||
ETHTOOL_A_FEC_STATS,
|
||||
|
||||
__ETHTOOL_A_FEC_CNT,
|
||||
ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MODULE_EEPROM_UNSPEC,
|
||||
ETHTOOL_A_MODULE_EEPROM_HEADER,
|
||||
ETHTOOL_A_MODULE_EEPROM_OFFSET,
|
||||
ETHTOOL_A_MODULE_EEPROM_LENGTH,
|
||||
ETHTOOL_A_MODULE_EEPROM_PAGE,
|
||||
ETHTOOL_A_MODULE_EEPROM_BANK,
|
||||
ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,
|
||||
ETHTOOL_A_MODULE_EEPROM_DATA,
|
||||
|
||||
__ETHTOOL_A_MODULE_EEPROM_CNT,
|
||||
ETHTOOL_A_MODULE_EEPROM_MAX = (__ETHTOOL_A_MODULE_EEPROM_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STATS_GRP_UNSPEC,
|
||||
ETHTOOL_A_STATS_GRP_PAD,
|
||||
ETHTOOL_A_STATS_GRP_ID,
|
||||
ETHTOOL_A_STATS_GRP_SS_ID,
|
||||
ETHTOOL_A_STATS_GRP_STAT,
|
||||
ETHTOOL_A_STATS_GRP_HIST_RX,
|
||||
ETHTOOL_A_STATS_GRP_HIST_TX,
|
||||
ETHTOOL_A_STATS_GRP_HIST_BKT_LOW,
|
||||
ETHTOOL_A_STATS_GRP_HIST_BKT_HI,
|
||||
ETHTOOL_A_STATS_GRP_HIST_VAL,
|
||||
|
||||
__ETHTOOL_A_STATS_GRP_CNT,
|
||||
ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_GRP_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_STATS_UNSPEC,
|
||||
ETHTOOL_A_STATS_PAD,
|
||||
ETHTOOL_A_STATS_HEADER,
|
||||
ETHTOOL_A_STATS_GROUPS,
|
||||
ETHTOOL_A_STATS_GRP,
|
||||
ETHTOOL_A_STATS_SRC,
|
||||
|
||||
__ETHTOOL_A_STATS_CNT,
|
||||
ETHTOOL_A_STATS_MAX = (__ETHTOOL_A_STATS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PHC_VCLOCKS_UNSPEC,
|
||||
ETHTOOL_A_PHC_VCLOCKS_HEADER,
|
||||
ETHTOOL_A_PHC_VCLOCKS_NUM,
|
||||
ETHTOOL_A_PHC_VCLOCKS_INDEX,
|
||||
|
||||
__ETHTOOL_A_PHC_VCLOCKS_CNT,
|
||||
ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MODULE_UNSPEC,
|
||||
ETHTOOL_A_MODULE_HEADER,
|
||||
ETHTOOL_A_MODULE_POWER_MODE_POLICY,
|
||||
ETHTOOL_A_MODULE_POWER_MODE,
|
||||
|
||||
__ETHTOOL_A_MODULE_CNT,
|
||||
ETHTOOL_A_MODULE_MAX = (__ETHTOOL_A_MODULE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_UNSPEC,
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_MIN,
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_MAX,
|
||||
|
||||
__ETHTOOL_A_C33_PSE_PW_LIMIT_CNT,
|
||||
__ETHTOOL_A_C33_PSE_PW_LIMIT_MAX = (__ETHTOOL_A_C33_PSE_PW_LIMIT_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PSE_UNSPEC,
|
||||
ETHTOOL_A_PSE_HEADER,
|
||||
ETHTOOL_A_PODL_PSE_ADMIN_STATE,
|
||||
ETHTOOL_A_PODL_PSE_ADMIN_CONTROL,
|
||||
ETHTOOL_A_PODL_PSE_PW_D_STATUS,
|
||||
ETHTOOL_A_C33_PSE_ADMIN_STATE,
|
||||
ETHTOOL_A_C33_PSE_ADMIN_CONTROL,
|
||||
ETHTOOL_A_C33_PSE_PW_D_STATUS,
|
||||
ETHTOOL_A_C33_PSE_PW_CLASS,
|
||||
ETHTOOL_A_C33_PSE_ACTUAL_PW,
|
||||
ETHTOOL_A_C33_PSE_EXT_STATE,
|
||||
ETHTOOL_A_C33_PSE_EXT_SUBSTATE,
|
||||
ETHTOOL_A_C33_PSE_AVAIL_PW_LIMIT,
|
||||
ETHTOOL_A_C33_PSE_PW_LIMIT_RANGES,
|
||||
|
||||
__ETHTOOL_A_PSE_CNT,
|
||||
ETHTOOL_A_PSE_MAX = (__ETHTOOL_A_PSE_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_RSS_UNSPEC,
|
||||
ETHTOOL_A_RSS_HEADER,
|
||||
ETHTOOL_A_RSS_CONTEXT,
|
||||
ETHTOOL_A_RSS_HFUNC,
|
||||
ETHTOOL_A_RSS_INDIR,
|
||||
ETHTOOL_A_RSS_HKEY,
|
||||
ETHTOOL_A_RSS_INPUT_XFRM,
|
||||
ETHTOOL_A_RSS_START_CONTEXT,
|
||||
|
||||
__ETHTOOL_A_RSS_CNT,
|
||||
ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PLCA_UNSPEC,
|
||||
ETHTOOL_A_PLCA_HEADER,
|
||||
ETHTOOL_A_PLCA_VERSION,
|
||||
ETHTOOL_A_PLCA_ENABLED,
|
||||
ETHTOOL_A_PLCA_STATUS,
|
||||
ETHTOOL_A_PLCA_NODE_CNT,
|
||||
ETHTOOL_A_PLCA_NODE_ID,
|
||||
ETHTOOL_A_PLCA_TO_TMR,
|
||||
ETHTOOL_A_PLCA_BURST_CNT,
|
||||
ETHTOOL_A_PLCA_BURST_TMR,
|
||||
|
||||
__ETHTOOL_A_PLCA_CNT,
|
||||
ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_MODULE_FW_FLASH_UNSPEC,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_HEADER,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_FILE_NAME,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_PASSWORD,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_STATUS,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_STATUS_MSG,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_DONE,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_TOTAL,
|
||||
|
||||
__ETHTOOL_A_MODULE_FW_FLASH_CNT,
|
||||
ETHTOOL_A_MODULE_FW_FLASH_MAX = (__ETHTOOL_A_MODULE_FW_FLASH_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_PHY_UNSPEC,
|
||||
ETHTOOL_A_PHY_HEADER,
|
||||
ETHTOOL_A_PHY_INDEX,
|
||||
ETHTOOL_A_PHY_DRVNAME,
|
||||
ETHTOOL_A_PHY_NAME,
|
||||
ETHTOOL_A_PHY_UPSTREAM_TYPE,
|
||||
ETHTOOL_A_PHY_UPSTREAM_INDEX,
|
||||
ETHTOOL_A_PHY_UPSTREAM_SFP_NAME,
|
||||
ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME,
|
||||
|
||||
__ETHTOOL_A_PHY_CNT,
|
||||
ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_A_TSCONFIG_UNSPEC,
|
||||
ETHTOOL_A_TSCONFIG_HEADER,
|
||||
ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER,
|
||||
ETHTOOL_A_TSCONFIG_TX_TYPES,
|
||||
ETHTOOL_A_TSCONFIG_RX_FILTERS,
|
||||
ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS,
|
||||
|
||||
__ETHTOOL_A_TSCONFIG_CNT,
|
||||
ETHTOOL_A_TSCONFIG_MAX = (__ETHTOOL_A_TSCONFIG_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_MSG_USER_NONE = 0,
|
||||
ETHTOOL_MSG_STRSET_GET = 1,
|
||||
ETHTOOL_MSG_LINKINFO_GET,
|
||||
ETHTOOL_MSG_LINKINFO_SET,
|
||||
ETHTOOL_MSG_LINKMODES_GET,
|
||||
ETHTOOL_MSG_LINKMODES_SET,
|
||||
ETHTOOL_MSG_LINKSTATE_GET,
|
||||
ETHTOOL_MSG_DEBUG_GET,
|
||||
ETHTOOL_MSG_DEBUG_SET,
|
||||
ETHTOOL_MSG_WOL_GET,
|
||||
ETHTOOL_MSG_WOL_SET,
|
||||
ETHTOOL_MSG_FEATURES_GET,
|
||||
ETHTOOL_MSG_FEATURES_SET,
|
||||
ETHTOOL_MSG_PRIVFLAGS_GET,
|
||||
ETHTOOL_MSG_PRIVFLAGS_SET,
|
||||
ETHTOOL_MSG_RINGS_GET,
|
||||
ETHTOOL_MSG_RINGS_SET,
|
||||
ETHTOOL_MSG_CHANNELS_GET,
|
||||
ETHTOOL_MSG_CHANNELS_SET,
|
||||
ETHTOOL_MSG_COALESCE_GET,
|
||||
ETHTOOL_MSG_COALESCE_SET,
|
||||
ETHTOOL_MSG_PAUSE_GET,
|
||||
ETHTOOL_MSG_PAUSE_SET,
|
||||
ETHTOOL_MSG_EEE_GET,
|
||||
ETHTOOL_MSG_EEE_SET,
|
||||
ETHTOOL_MSG_TSINFO_GET,
|
||||
ETHTOOL_MSG_CABLE_TEST_ACT,
|
||||
ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
|
||||
ETHTOOL_MSG_TUNNEL_INFO_GET,
|
||||
ETHTOOL_MSG_FEC_GET,
|
||||
ETHTOOL_MSG_FEC_SET,
|
||||
ETHTOOL_MSG_MODULE_EEPROM_GET,
|
||||
ETHTOOL_MSG_STATS_GET,
|
||||
ETHTOOL_MSG_PHC_VCLOCKS_GET,
|
||||
ETHTOOL_MSG_MODULE_GET,
|
||||
ETHTOOL_MSG_MODULE_SET,
|
||||
ETHTOOL_MSG_PSE_GET,
|
||||
ETHTOOL_MSG_PSE_SET,
|
||||
ETHTOOL_MSG_RSS_GET,
|
||||
ETHTOOL_MSG_PLCA_GET_CFG,
|
||||
ETHTOOL_MSG_PLCA_SET_CFG,
|
||||
ETHTOOL_MSG_PLCA_GET_STATUS,
|
||||
ETHTOOL_MSG_MM_GET,
|
||||
ETHTOOL_MSG_MM_SET,
|
||||
ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
|
||||
ETHTOOL_MSG_PHY_GET,
|
||||
ETHTOOL_MSG_TSCONFIG_GET,
|
||||
ETHTOOL_MSG_TSCONFIG_SET,
|
||||
|
||||
__ETHTOOL_MSG_USER_CNT,
|
||||
ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
ETHTOOL_MSG_KERNEL_NONE = 0,
|
||||
ETHTOOL_MSG_STRSET_GET_REPLY = 1,
|
||||
ETHTOOL_MSG_LINKINFO_GET_REPLY,
|
||||
ETHTOOL_MSG_LINKINFO_NTF,
|
||||
ETHTOOL_MSG_LINKMODES_GET_REPLY,
|
||||
ETHTOOL_MSG_LINKMODES_NTF,
|
||||
ETHTOOL_MSG_LINKSTATE_GET_REPLY,
|
||||
ETHTOOL_MSG_DEBUG_GET_REPLY,
|
||||
ETHTOOL_MSG_DEBUG_NTF,
|
||||
ETHTOOL_MSG_WOL_GET_REPLY,
|
||||
ETHTOOL_MSG_WOL_NTF,
|
||||
ETHTOOL_MSG_FEATURES_GET_REPLY,
|
||||
ETHTOOL_MSG_FEATURES_SET_REPLY,
|
||||
ETHTOOL_MSG_FEATURES_NTF,
|
||||
ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
|
||||
ETHTOOL_MSG_PRIVFLAGS_NTF,
|
||||
ETHTOOL_MSG_RINGS_GET_REPLY,
|
||||
ETHTOOL_MSG_RINGS_NTF,
|
||||
ETHTOOL_MSG_CHANNELS_GET_REPLY,
|
||||
ETHTOOL_MSG_CHANNELS_NTF,
|
||||
ETHTOOL_MSG_COALESCE_GET_REPLY,
|
||||
ETHTOOL_MSG_COALESCE_NTF,
|
||||
ETHTOOL_MSG_PAUSE_GET_REPLY,
|
||||
ETHTOOL_MSG_PAUSE_NTF,
|
||||
ETHTOOL_MSG_EEE_GET_REPLY,
|
||||
ETHTOOL_MSG_EEE_NTF,
|
||||
ETHTOOL_MSG_TSINFO_GET_REPLY,
|
||||
ETHTOOL_MSG_CABLE_TEST_NTF,
|
||||
ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
|
||||
ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
|
||||
ETHTOOL_MSG_FEC_GET_REPLY,
|
||||
ETHTOOL_MSG_FEC_NTF,
|
||||
ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
|
||||
ETHTOOL_MSG_STATS_GET_REPLY,
|
||||
ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
|
||||
ETHTOOL_MSG_MODULE_GET_REPLY,
|
||||
ETHTOOL_MSG_MODULE_NTF,
|
||||
ETHTOOL_MSG_PSE_GET_REPLY,
|
||||
ETHTOOL_MSG_RSS_GET_REPLY,
|
||||
ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
|
||||
ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
|
||||
ETHTOOL_MSG_PLCA_NTF,
|
||||
ETHTOOL_MSG_MM_GET_REPLY,
|
||||
ETHTOOL_MSG_MM_NTF,
|
||||
ETHTOOL_MSG_MODULE_FW_FLASH_NTF,
|
||||
ETHTOOL_MSG_PHY_GET_REPLY,
|
||||
ETHTOOL_MSG_PHY_NTF,
|
||||
ETHTOOL_MSG_TSCONFIG_GET_REPLY,
|
||||
ETHTOOL_MSG_TSCONFIG_SET_REPLY,
|
||||
|
||||
__ETHTOOL_MSG_KERNEL_CNT,
|
||||
ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H */
|
|
@ -13,6 +13,17 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/socket.h> /* for SO_TIMESTAMPING */
|
||||
|
||||
/*
|
||||
* Possible type of hwtstamp provider. Mainly "precise" the default one
|
||||
* is for IEEE 1588 quality and "approx" is for NICs DMA point.
|
||||
*/
|
||||
enum hwtstamp_provider_qualifier {
|
||||
HWTSTAMP_PROVIDER_QUALIFIER_PRECISE,
|
||||
HWTSTAMP_PROVIDER_QUALIFIER_APPROX,
|
||||
|
||||
HWTSTAMP_PROVIDER_QUALIFIER_CNT,
|
||||
};
|
||||
|
||||
/* SO_TIMESTAMPING flags */
|
||||
enum {
|
||||
SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
|
||||
|
@ -32,8 +43,9 @@ enum {
|
|||
SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
|
||||
SOF_TIMESTAMPING_BIND_PHC = (1 << 15),
|
||||
SOF_TIMESTAMPING_OPT_ID_TCP = (1 << 16),
|
||||
SOF_TIMESTAMPING_OPT_RX_FILTER = (1 << 17),
|
||||
|
||||
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID_TCP,
|
||||
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_RX_FILTER,
|
||||
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
|
||||
SOF_TIMESTAMPING_LAST
|
||||
};
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/bpf.h>
|
||||
|
@ -104,6 +105,7 @@
|
|||
#include <net/dst.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/gro.h>
|
||||
#include <net/netdev_queues.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/checksum.h>
|
||||
|
@ -9426,6 +9428,18 @@ u8 dev_xdp_prog_count(struct net_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dev_xdp_prog_count);
|
||||
|
||||
u8 dev_xdp_sb_prog_count(struct net_device *dev)
|
||||
{
|
||||
u8 count = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < __MAX_XDP_MODE; i++)
|
||||
if (dev->xdp_state[i].prog &&
|
||||
!dev->xdp_state[i].prog->aux->xdp_has_frags)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
|
||||
{
|
||||
struct bpf_prog *prog = dev_xdp_prog(dev, mode);
|
||||
|
@ -9454,6 +9468,12 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
|
|||
struct netdev_bpf xdp;
|
||||
int err;
|
||||
|
||||
if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
|
||||
prog && !prog->aux->xdp_has_frags) {
|
||||
NL_SET_ERR_MSG(extack, "unable to install XDP to device using tcp-data-split");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
memset(&xdp, 0, sizeof(xdp));
|
||||
xdp.command = mode == XDP_MODE_HW ? XDP_SETUP_PROG_HW : XDP_SETUP_PROG;
|
||||
xdp.extack = extack;
|
||||
|
@ -11156,6 +11176,11 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
|||
if (!dev->ethtool)
|
||||
goto free_all;
|
||||
|
||||
dev->cfg = kzalloc(sizeof(*dev->cfg), GFP_KERNEL_ACCOUNT);
|
||||
if (!dev->cfg)
|
||||
goto free_all;
|
||||
dev->cfg_pending = dev->cfg;
|
||||
|
||||
napi_config_sz = array_size(maxqs, sizeof(*dev->napi_config));
|
||||
dev->napi_config = kvzalloc(napi_config_sz, GFP_KERNEL_ACCOUNT);
|
||||
if (!dev->napi_config)
|
||||
|
@ -11212,6 +11237,8 @@ void free_netdev(struct net_device *dev)
|
|||
|
||||
mutex_destroy(&dev->lock);
|
||||
|
||||
WARN_ON(dev->cfg != dev->cfg_pending);
|
||||
kfree(dev->cfg);
|
||||
kfree(dev->ethtool);
|
||||
netif_free_tx_queues(dev);
|
||||
netif_free_rx_queues(dev);
|
||||
|
|
|
@ -245,6 +245,12 @@ static inline void netdev_set_gro_flush_timeout(struct net_device *netdev,
|
|||
}
|
||||
|
||||
int rps_cpumask_housekeeping(struct cpumask *mask);
|
||||
int dev_set_hwtstamp_phylib(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *cfg,
|
||||
struct netlink_ext_ack *extack);
|
||||
int dev_get_hwtstamp_phylib(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *cfg);
|
||||
int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg);
|
||||
|
||||
/* Best effort check that NAPI is not idle (can't be scheduled to run) */
|
||||
static inline void napi_assert_will_not_race(const struct napi_struct *napi)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/phylib_stubs.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <net/dsa_stubs.h>
|
||||
|
@ -184,7 +185,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm
|
|||
return err;
|
||||
}
|
||||
|
||||
static int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
|
||||
int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
|
||||
{
|
||||
enum hwtstamp_tx_types tx_type;
|
||||
enum hwtstamp_rx_filters rx_filter;
|
||||
|
@ -266,9 +267,24 @@ static int dev_eth_ioctl(struct net_device *dev,
|
|||
* -EOPNOTSUPP for phylib for now, which is still more accurate than letting
|
||||
* the netdev handle the GET request.
|
||||
*/
|
||||
static int dev_get_hwtstamp_phylib(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *cfg)
|
||||
int dev_get_hwtstamp_phylib(struct net_device *dev,
|
||||
struct kernel_hwtstamp_config *cfg)
|
||||
{
|
||||
struct hwtstamp_provider *hwprov;
|
||||
|
||||
hwprov = rtnl_dereference(dev->hwprov);
|
||||
if (hwprov) {
|
||||
cfg->qualifier = hwprov->desc.qualifier;
|
||||
if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
|
||||
hwprov->phydev)
|
||||
return phy_hwtstamp_get(hwprov->phydev, cfg);
|
||||
|
||||
if (hwprov->source == HWTSTAMP_SOURCE_NETDEV)
|
||||
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (phy_is_default_hwtstamp(dev->phydev))
|
||||
return phy_hwtstamp_get(dev->phydev, cfg);
|
||||
|
||||
|
@ -324,11 +340,32 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
bool phy_ts = phy_is_default_hwtstamp(dev->phydev);
|
||||
struct kernel_hwtstamp_config old_cfg = {};
|
||||
struct hwtstamp_provider *hwprov;
|
||||
struct phy_device *phydev;
|
||||
bool changed = false;
|
||||
bool phy_ts;
|
||||
int err;
|
||||
|
||||
hwprov = rtnl_dereference(dev->hwprov);
|
||||
if (hwprov) {
|
||||
if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
|
||||
hwprov->phydev) {
|
||||
phy_ts = true;
|
||||
phydev = hwprov->phydev;
|
||||
} else if (hwprov->source == HWTSTAMP_SOURCE_NETDEV) {
|
||||
phy_ts = false;
|
||||
} else {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
cfg->qualifier = hwprov->desc.qualifier;
|
||||
} else {
|
||||
phy_ts = phy_is_default_hwtstamp(dev->phydev);
|
||||
if (phy_ts)
|
||||
phydev = dev->phydev;
|
||||
}
|
||||
|
||||
cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
|
||||
|
||||
if (phy_ts && dev->see_all_hwtstamp_requests) {
|
||||
|
@ -350,7 +387,7 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
|
|||
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
|
||||
|
||||
if (phy_ts) {
|
||||
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
|
||||
err = phy_hwtstamp_set(phydev, cfg, extack);
|
||||
if (err) {
|
||||
if (changed)
|
||||
ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);
|
||||
|
@ -360,7 +397,6 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_set_hwtstamp_phylib);
|
||||
|
||||
static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/ptp_classify.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
static unsigned int classify(const struct sk_buff *skb)
|
||||
{
|
||||
|
@ -21,19 +22,39 @@ static unsigned int classify(const struct sk_buff *skb)
|
|||
|
||||
void skb_clone_tx_timestamp(struct sk_buff *skb)
|
||||
{
|
||||
struct hwtstamp_provider *hwprov;
|
||||
struct mii_timestamper *mii_ts;
|
||||
struct phy_device *phydev;
|
||||
struct sk_buff *clone;
|
||||
unsigned int type;
|
||||
|
||||
if (!skb->sk || !skb->dev ||
|
||||
!phy_is_default_hwtstamp(skb->dev->phydev))
|
||||
if (!skb->sk || !skb->dev)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
hwprov = rcu_dereference(skb->dev->hwprov);
|
||||
if (hwprov) {
|
||||
if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB ||
|
||||
!hwprov->phydev) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
phydev = hwprov->phydev;
|
||||
} else {
|
||||
phydev = skb->dev->phydev;
|
||||
if (!phy_is_default_hwtstamp(phydev)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
type = classify(skb);
|
||||
if (type == PTP_CLASS_NONE)
|
||||
return;
|
||||
|
||||
mii_ts = skb->dev->phydev->mii_ts;
|
||||
mii_ts = phydev->mii_ts;
|
||||
if (likely(mii_ts->txtstamp)) {
|
||||
clone = skb_clone_sk(skb);
|
||||
if (!clone)
|
||||
|
@ -45,12 +66,33 @@ EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
|
|||
|
||||
bool skb_defer_rx_timestamp(struct sk_buff *skb)
|
||||
{
|
||||
struct hwtstamp_provider *hwprov;
|
||||
struct mii_timestamper *mii_ts;
|
||||
struct phy_device *phydev;
|
||||
unsigned int type;
|
||||
|
||||
if (!skb->dev || !phy_is_default_hwtstamp(skb->dev->phydev))
|
||||
if (!skb->dev)
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
hwprov = rcu_dereference(skb->dev->hwprov);
|
||||
if (hwprov) {
|
||||
if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB ||
|
||||
!hwprov->phydev) {
|
||||
rcu_read_unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
phydev = hwprov->phydev;
|
||||
} else {
|
||||
phydev = skb->dev->phydev;
|
||||
if (!phy_is_default_hwtstamp(phydev)) {
|
||||
rcu_read_unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (skb_headroom(skb) < ETH_HLEN)
|
||||
return false;
|
||||
|
||||
|
@ -63,7 +105,7 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb)
|
|||
if (type == PTP_CLASS_NONE)
|
||||
return false;
|
||||
|
||||
mii_ts = skb->dev->phydev->mii_ts;
|
||||
mii_ts = phydev->mii_ts;
|
||||
if (likely(mii_ts->rxtstamp))
|
||||
return mii_ts->rxtstamp(mii_ts, skb, type);
|
||||
|
||||
|
|
|
@ -9,4 +9,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
|
|||
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
|
||||
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
|
||||
module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o mm.o \
|
||||
phy.o
|
||||
phy.o tsconfig.o
|
||||
|
|
|
@ -425,12 +425,32 @@ static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ethnl_bitmap32_equal() - Compare two bitmaps
|
||||
* @map1: first bitmap
|
||||
* @map2: second bitmap
|
||||
* @nbits: bit size to compare
|
||||
*
|
||||
* Return: true if first @nbits are equal, false if not
|
||||
*/
|
||||
static bool ethnl_bitmap32_equal(const u32 *map1, const u32 *map2,
|
||||
unsigned int nbits)
|
||||
{
|
||||
if (memcmp(map1, map2, nbits / 32 * sizeof(u32)))
|
||||
return false;
|
||||
if (nbits % 32 == 0)
|
||||
return true;
|
||||
return !((map1[nbits / 32] ^ map2[nbits / 32]) &
|
||||
ethnl_lower_bits(nbits % 32));
|
||||
}
|
||||
|
||||
static int
|
||||
ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
|
||||
const struct nlattr *attr, struct nlattr **tb,
|
||||
ethnl_string_array_t names,
|
||||
struct netlink_ext_ack *extack, bool *mod)
|
||||
{
|
||||
u32 *saved_bitmap = NULL;
|
||||
struct nlattr *bit_attr;
|
||||
bool no_mask;
|
||||
int rem;
|
||||
|
@ -448,8 +468,20 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
|
|||
}
|
||||
|
||||
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
|
||||
if (no_mask)
|
||||
ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
|
||||
if (no_mask) {
|
||||
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
|
||||
unsigned int nbytes = nwords * sizeof(u32);
|
||||
bool dummy;
|
||||
|
||||
/* The bitmap size is only the size of the map part without
|
||||
* its mask part.
|
||||
*/
|
||||
saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL);
|
||||
if (!saved_bitmap)
|
||||
return -ENOMEM;
|
||||
memcpy(saved_bitmap, bitmap, nbytes);
|
||||
ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
|
||||
}
|
||||
|
||||
nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
|
||||
bool old_val, new_val;
|
||||
|
@ -458,22 +490,30 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
|
|||
if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
|
||||
"only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
|
||||
kfree(saved_bitmap);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
|
||||
names, extack);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
kfree(saved_bitmap);
|
||||
return ret;
|
||||
}
|
||||
old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
|
||||
if (new_val != old_val) {
|
||||
if (new_val)
|
||||
bitmap[idx / 32] |= ((u32)1 << (idx % 32));
|
||||
else
|
||||
bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
|
||||
*mod = true;
|
||||
if (!no_mask)
|
||||
*mod = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (no_mask && !ethnl_bitmap32_equal(saved_bitmap, bitmap, nbits))
|
||||
*mod = true;
|
||||
|
||||
kfree(saved_bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
|
|||
dev = req_info.dev;
|
||||
|
||||
rtnl_lock();
|
||||
phydev = ethnl_req_get_phydev(&req_info,
|
||||
tb[ETHTOOL_A_CABLE_TEST_HEADER],
|
||||
phydev = ethnl_req_get_phydev(&req_info, tb,
|
||||
ETHTOOL_A_CABLE_TEST_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
|
@ -339,8 +339,8 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
|
|||
goto out_dev_put;
|
||||
|
||||
rtnl_lock();
|
||||
phydev = ethnl_req_get_phydev(&req_info,
|
||||
tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
|
||||
phydev = ethnl_req_get_phydev(&req_info, tb,
|
||||
ETHTOOL_A_CABLE_TEST_TDR_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#define ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH 120
|
||||
#define ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH 2048
|
||||
#define ETHTOOL_CMIS_CDB_CMD_PAGE 0x9F
|
||||
#define ETHTOOL_CMIS_CDB_PAGE_I2C_ADDR 0x50
|
||||
|
||||
|
@ -23,6 +24,7 @@ enum ethtool_cmis_cdb_cmd_id {
|
|||
ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES = 0x0041,
|
||||
ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD = 0x0101,
|
||||
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL = 0x0103,
|
||||
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL = 0x0104,
|
||||
ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD = 0x0107,
|
||||
ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE = 0x0109,
|
||||
ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE = 0x010A,
|
||||
|
@ -38,6 +40,7 @@ enum ethtool_cmis_cdb_cmd_id {
|
|||
* @resv1: Added to match the CMIS standard request continuity.
|
||||
* @resv2: Added to match the CMIS standard request continuity.
|
||||
* @payload: Payload for the CDB commands.
|
||||
* @epl: Extended payload for the CDB commands.
|
||||
*/
|
||||
struct ethtool_cmis_cdb_request {
|
||||
__be16 id;
|
||||
|
@ -49,6 +52,7 @@ struct ethtool_cmis_cdb_request {
|
|||
u8 resv2;
|
||||
u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
|
||||
);
|
||||
u8 *epl; /* Everything above this field checksummed. */
|
||||
};
|
||||
|
||||
#define CDB_F_COMPLETION_VALID BIT(0)
|
||||
|
@ -96,13 +100,14 @@ struct ethtool_cmis_cdb_rpl {
|
|||
u8 payload[ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH];
|
||||
};
|
||||
|
||||
u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs);
|
||||
u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs);
|
||||
|
||||
void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
|
||||
enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl,
|
||||
u8 lpl_len, u16 max_duration,
|
||||
u8 read_write_len_ext, u16 msleep_pre_rpl,
|
||||
u8 rpl_exp_len, u8 flags);
|
||||
enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl,
|
||||
u8 lpl_len, u8 *epl, u16 epl_len,
|
||||
u16 max_duration, u8 read_write_len_ext,
|
||||
u16 msleep_pre_rpl, u8 rpl_exp_len,
|
||||
u8 flags);
|
||||
|
||||
void ethtool_cmis_cdb_check_completion_flag(u8 cmis_rev, u8 *flags);
|
||||
|
||||
|
|
|
@ -11,25 +11,29 @@
|
|||
* min(i, 15) byte octets where i specifies the allowable additional number of
|
||||
* byte octets in a READ or a WRITE.
|
||||
*/
|
||||
u32 ethtool_cmis_get_max_payload_size(u8 num_of_byte_octs)
|
||||
u32 ethtool_cmis_get_max_lpl_size(u8 num_of_byte_octs)
|
||||
{
|
||||
return 8 * (1 + min_t(u8, num_of_byte_octs, 15));
|
||||
}
|
||||
|
||||
void ethtool_cmis_cdb_compose_args(struct ethtool_cmis_cdb_cmd_args *args,
|
||||
enum ethtool_cmis_cdb_cmd_id cmd, u8 *pl,
|
||||
u8 lpl_len, u16 max_duration,
|
||||
u8 read_write_len_ext, u16 msleep_pre_rpl,
|
||||
u8 rpl_exp_len, u8 flags)
|
||||
enum ethtool_cmis_cdb_cmd_id cmd, u8 *lpl,
|
||||
u8 lpl_len, u8 *epl, u16 epl_len,
|
||||
u16 max_duration, u8 read_write_len_ext,
|
||||
u16 msleep_pre_rpl, u8 rpl_exp_len, u8 flags)
|
||||
{
|
||||
args->req.id = cpu_to_be16(cmd);
|
||||
args->req.lpl_len = lpl_len;
|
||||
if (pl)
|
||||
memcpy(args->req.payload, pl, args->req.lpl_len);
|
||||
if (lpl)
|
||||
memcpy(args->req.payload, lpl, args->req.lpl_len);
|
||||
if (epl) {
|
||||
args->req.epl_len = cpu_to_be16(epl_len);
|
||||
args->req.epl = epl;
|
||||
}
|
||||
|
||||
args->max_duration = max_duration;
|
||||
args->read_write_len_ext =
|
||||
ethtool_cmis_get_max_payload_size(read_write_len_ext);
|
||||
ethtool_cmis_get_max_lpl_size(read_write_len_ext);
|
||||
args->msleep_pre_rpl = msleep_pre_rpl;
|
||||
args->rpl_exp_len = rpl_exp_len;
|
||||
args->flags = flags;
|
||||
|
@ -183,7 +187,7 @@ cmis_cdb_validate_password(struct ethtool_cmis_cdb *cdb,
|
|||
}
|
||||
|
||||
ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_QUERY_STATUS,
|
||||
(u8 *)&qs_pl, sizeof(qs_pl), 0,
|
||||
(u8 *)&qs_pl, sizeof(qs_pl), NULL, 0, 0,
|
||||
cdb->read_write_len_ext, 1000,
|
||||
sizeof(*rpl),
|
||||
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
|
||||
|
@ -245,8 +249,9 @@ static int cmis_cdb_module_features_get(struct ethtool_cmis_cdb *cdb,
|
|||
ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_MODULE_FEATURES,
|
||||
NULL, 0, 0, cdb->read_write_len_ext,
|
||||
1000, sizeof(*rpl), flags);
|
||||
NULL, 0, NULL, 0, 0,
|
||||
cdb->read_write_len_ext, 1000,
|
||||
sizeof(*rpl), flags);
|
||||
|
||||
err = ethtool_cmis_cdb_execute_cmd(dev, &args);
|
||||
if (err < 0) {
|
||||
|
@ -346,7 +351,7 @@ ethtool_cmis_module_poll(struct net_device *dev,
|
|||
struct netlink_ext_ack extack = {};
|
||||
int err;
|
||||
|
||||
ethtool_cmis_page_init(&page_data, 0, offset, sizeof(rpl));
|
||||
ethtool_cmis_page_init(&page_data, 0, offset, sizeof(*rpl));
|
||||
page_data.data = (u8 *)rpl;
|
||||
|
||||
err = ops->get_module_eeprom_by_page(dev, &page_data, &extack);
|
||||
|
@ -546,6 +551,49 @@ __ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
|
|||
return err;
|
||||
}
|
||||
|
||||
#define CMIS_CDB_EPL_PAGE_START 0xA0
|
||||
#define CMIS_CDB_EPL_PAGE_END 0xAF
|
||||
#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_START 128
|
||||
#define CMIS_CDB_EPL_FW_BLOCK_OFFSET_END 255
|
||||
|
||||
static int
|
||||
ethtool_cmis_cdb_execute_epl_cmd(struct net_device *dev,
|
||||
struct ethtool_cmis_cdb_cmd_args *args,
|
||||
struct ethtool_module_eeprom *page_data)
|
||||
{
|
||||
u16 epl_len = be16_to_cpu(args->req.epl_len);
|
||||
u32 bytes_written = 0;
|
||||
u8 page;
|
||||
int err;
|
||||
|
||||
for (page = CMIS_CDB_EPL_PAGE_START;
|
||||
page <= CMIS_CDB_EPL_PAGE_END && bytes_written < epl_len; page++) {
|
||||
u16 offset = CMIS_CDB_EPL_FW_BLOCK_OFFSET_START;
|
||||
|
||||
while (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
|
||||
bytes_written < epl_len) {
|
||||
u32 bytes_left = epl_len - bytes_written;
|
||||
u16 space_left, bytes_to_write;
|
||||
|
||||
space_left = CMIS_CDB_EPL_FW_BLOCK_OFFSET_END - offset + 1;
|
||||
bytes_to_write = min_t(u16, bytes_left,
|
||||
min_t(u16, space_left,
|
||||
args->read_write_len_ext));
|
||||
|
||||
err = __ethtool_cmis_cdb_execute_cmd(dev, page_data,
|
||||
page, offset,
|
||||
bytes_to_write,
|
||||
args->req.epl + bytes_written);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
offset += bytes_to_write;
|
||||
bytes_written += bytes_to_write;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 cmis_cdb_calc_checksum(const void *data, size_t size)
|
||||
{
|
||||
const u8 *bytes = (const u8 *)data;
|
||||
|
@ -567,7 +615,9 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
|
|||
int err;
|
||||
|
||||
args->req.chk_code =
|
||||
cmis_cdb_calc_checksum(&args->req, sizeof(args->req));
|
||||
cmis_cdb_calc_checksum(&args->req,
|
||||
offsetof(struct ethtool_cmis_cdb_request,
|
||||
epl));
|
||||
|
||||
if (args->req.lpl_len > args->read_write_len_ext) {
|
||||
args->err_msg = "LPL length is longer than CDB read write length extension allows";
|
||||
|
@ -589,6 +639,12 @@ int ethtool_cmis_cdb_execute_cmd(struct net_device *dev,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (args->req.epl_len) {
|
||||
err = ethtool_cmis_cdb_execute_epl_cmd(dev, args, &page_data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
offset = CMIS_CDB_CMD_ID_OFFSET +
|
||||
offsetof(struct ethtool_cmis_cdb_request, id);
|
||||
err = __ethtool_cmis_cdb_execute_cmd(dev, &page_data,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
struct cmis_fw_update_fw_mng_features {
|
||||
u8 start_cmd_payload_size;
|
||||
u8 write_mechanism;
|
||||
u16 max_duration_start;
|
||||
u16 max_duration_write;
|
||||
u16 max_duration_complete;
|
||||
|
@ -36,7 +37,9 @@ struct cmis_cdb_fw_mng_features_rpl {
|
|||
};
|
||||
|
||||
enum cmis_cdb_fw_write_mechanism {
|
||||
CMIS_CDB_FW_WRITE_MECHANISM_NONE = 0x00,
|
||||
CMIS_CDB_FW_WRITE_MECHANISM_LPL = 0x01,
|
||||
CMIS_CDB_FW_WRITE_MECHANISM_EPL = 0x10,
|
||||
CMIS_CDB_FW_WRITE_MECHANISM_BOTH = 0x11,
|
||||
};
|
||||
|
||||
|
@ -54,7 +57,8 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
|
|||
ethtool_cmis_cdb_check_completion_flag(cdb->cmis_rev, &flags);
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_FW_MANAGMENT_FEATURES,
|
||||
NULL, 0, cdb->max_completion_time,
|
||||
NULL, 0, NULL, 0,
|
||||
cdb->max_completion_time,
|
||||
cdb->read_write_len_ext, 1000,
|
||||
sizeof(*rpl), flags);
|
||||
|
||||
|
@ -67,10 +71,9 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
|
|||
}
|
||||
|
||||
rpl = (struct cmis_cdb_fw_mng_features_rpl *)args.req.payload;
|
||||
if (!(rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ||
|
||||
rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_BOTH)) {
|
||||
if (rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_NONE) {
|
||||
ethnl_module_fw_flash_ntf_err(dev, ntf_params,
|
||||
"Write LPL is not supported",
|
||||
"CDB write mechanism is not supported",
|
||||
NULL);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -82,6 +85,10 @@ cmis_fw_update_fw_mng_features_get(struct ethtool_cmis_cdb *cdb,
|
|||
*/
|
||||
cdb->read_write_len_ext = rpl->read_write_len_ext;
|
||||
fw_mng->start_cmd_payload_size = rpl->start_cmd_payload_size;
|
||||
fw_mng->write_mechanism =
|
||||
rpl->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL ?
|
||||
CMIS_CDB_FW_WRITE_MECHANISM_LPL :
|
||||
CMIS_CDB_FW_WRITE_MECHANISM_EPL;
|
||||
fw_mng->max_duration_start = be16_to_cpu(rpl->max_duration_start);
|
||||
fw_mng->max_duration_write = be16_to_cpu(rpl->max_duration_write);
|
||||
fw_mng->max_duration_complete = be16_to_cpu(rpl->max_duration_complete);
|
||||
|
@ -122,7 +129,7 @@ cmis_fw_update_start_download(struct ethtool_cmis_cdb *cdb,
|
|||
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_START_FW_DOWNLOAD,
|
||||
(u8 *)&pl, lpl_len,
|
||||
(u8 *)&pl, lpl_len, NULL, 0,
|
||||
fw_mng->max_duration_start,
|
||||
cdb->read_write_len_ext, 1000, 0,
|
||||
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
|
||||
|
@ -148,9 +155,9 @@ struct cmis_cdb_write_fw_block_lpl_pl {
|
|||
};
|
||||
|
||||
static int
|
||||
cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
|
||||
struct ethtool_cmis_fw_update_params *fw_update,
|
||||
struct cmis_fw_update_fw_mng_features *fw_mng)
|
||||
cmis_fw_update_write_image_lpl(struct ethtool_cmis_cdb *cdb,
|
||||
struct ethtool_cmis_fw_update_params *fw_update,
|
||||
struct cmis_fw_update_fw_mng_features *fw_mng)
|
||||
{
|
||||
u8 start = fw_mng->start_cmd_payload_size;
|
||||
u32 offset, max_block_size, max_lpl_len;
|
||||
|
@ -158,7 +165,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
|
|||
int err;
|
||||
|
||||
max_lpl_len = min_t(u32,
|
||||
ethtool_cmis_get_max_payload_size(cdb->read_write_len_ext),
|
||||
ethtool_cmis_get_max_lpl_size(cdb->read_write_len_ext),
|
||||
ETHTOOL_CMIS_CDB_LPL_MAX_PL_LENGTH);
|
||||
max_block_size =
|
||||
max_lpl_len - sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
|
||||
|
@ -183,7 +190,7 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
|
|||
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_LPL,
|
||||
(u8 *)&pl, lpl_len,
|
||||
(u8 *)&pl, lpl_len, NULL, 0,
|
||||
fw_mng->max_duration_write,
|
||||
cdb->read_write_len_ext, 1, 0,
|
||||
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
|
||||
|
@ -201,6 +208,67 @@ cmis_fw_update_write_image(struct ethtool_cmis_cdb *cdb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct cmis_cdb_write_fw_block_epl_pl {
|
||||
u8 fw_block[ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH];
|
||||
};
|
||||
|
||||
static int
|
||||
cmis_fw_update_write_image_epl(struct ethtool_cmis_cdb *cdb,
|
||||
struct ethtool_cmis_fw_update_params *fw_update,
|
||||
struct cmis_fw_update_fw_mng_features *fw_mng)
|
||||
{
|
||||
u8 start = fw_mng->start_cmd_payload_size;
|
||||
u32 image_size = fw_update->fw->size;
|
||||
u32 offset, lpl_len;
|
||||
int err;
|
||||
|
||||
lpl_len = sizeof_field(struct cmis_cdb_write_fw_block_lpl_pl,
|
||||
block_address);
|
||||
|
||||
for (offset = start; offset < image_size;
|
||||
offset += ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH) {
|
||||
struct cmis_cdb_write_fw_block_lpl_pl lpl = {
|
||||
.block_address = cpu_to_be32(offset - start),
|
||||
};
|
||||
struct cmis_cdb_write_fw_block_epl_pl *epl;
|
||||
struct ethtool_cmis_cdb_cmd_args args = {};
|
||||
u32 epl_len;
|
||||
|
||||
ethnl_module_fw_flash_ntf_in_progress(fw_update->dev,
|
||||
&fw_update->ntf_params,
|
||||
offset - start,
|
||||
image_size);
|
||||
|
||||
epl_len = min_t(u32, ETHTOOL_CMIS_CDB_EPL_MAX_PL_LENGTH,
|
||||
image_size - offset);
|
||||
epl = kmalloc_array(epl_len, sizeof(u8), GFP_KERNEL);
|
||||
if (!epl)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(epl->fw_block, &fw_update->fw->data[offset], epl_len);
|
||||
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_WRITE_FW_BLOCK_EPL,
|
||||
(u8 *)&lpl, lpl_len, (u8 *)epl,
|
||||
epl_len,
|
||||
fw_mng->max_duration_write,
|
||||
cdb->read_write_len_ext, 1, 0,
|
||||
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
|
||||
|
||||
err = ethtool_cmis_cdb_execute_cmd(fw_update->dev, &args);
|
||||
kfree(epl);
|
||||
if (err < 0) {
|
||||
ethnl_module_fw_flash_ntf_err(fw_update->dev,
|
||||
&fw_update->ntf_params,
|
||||
"Write FW block EPL command failed",
|
||||
args.err_msg);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
|
||||
struct net_device *dev,
|
||||
|
@ -212,7 +280,8 @@ cmis_fw_update_complete_download(struct ethtool_cmis_cdb *cdb,
|
|||
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_COMPLETE_FW_DOWNLOAD,
|
||||
NULL, 0, fw_mng->max_duration_complete,
|
||||
NULL, 0, NULL, 0,
|
||||
fw_mng->max_duration_complete,
|
||||
cdb->read_write_len_ext, 1000, 0,
|
||||
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
|
||||
|
||||
|
@ -236,9 +305,15 @@ cmis_fw_update_download_image(struct ethtool_cmis_cdb *cdb,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = cmis_fw_update_write_image(cdb, fw_update, fw_mng);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (fw_mng->write_mechanism == CMIS_CDB_FW_WRITE_MECHANISM_LPL) {
|
||||
err = cmis_fw_update_write_image_lpl(cdb, fw_update, fw_mng);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
err = cmis_fw_update_write_image_epl(cdb, fw_update, fw_mng);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = cmis_fw_update_complete_download(cdb, fw_update->dev, fw_mng,
|
||||
&fw_update->ntf_params);
|
||||
|
@ -294,7 +369,7 @@ cmis_fw_update_run_image(struct ethtool_cmis_cdb *cdb, struct net_device *dev,
|
|||
int err;
|
||||
|
||||
ethtool_cmis_cdb_compose_args(&args, ETHTOOL_CMIS_CDB_CMD_RUN_FW_IMAGE,
|
||||
(u8 *)&pl, sizeof(pl),
|
||||
(u8 *)&pl, sizeof(pl), NULL, 0,
|
||||
cdb->max_completion_time,
|
||||
cdb->read_write_len_ext, 1000, 0,
|
||||
CDB_F_MODULE_STATE_VALID);
|
||||
|
@ -326,7 +401,8 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb,
|
|||
|
||||
ethtool_cmis_cdb_compose_args(&args,
|
||||
ETHTOOL_CMIS_CDB_CMD_COMMIT_FW_IMAGE,
|
||||
NULL, 0, cdb->max_completion_time,
|
||||
NULL, 0, NULL, 0,
|
||||
cdb->max_completion_time,
|
||||
cdb->read_write_len_ext, 1000, 0,
|
||||
CDB_F_COMPLETION_VALID | CDB_F_STATUS_VALID);
|
||||
|
||||
|
|
|
@ -5,9 +5,13 @@
|
|||
#include <linux/phy.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/phy_link_topology.h>
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "../core/dev.h"
|
||||
|
||||
|
||||
const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
|
||||
[NETIF_F_SG_BIT] = "tx-scatter-gather",
|
||||
|
@ -210,6 +214,24 @@ const char link_mode_names[][ETH_GSTRING_LEN] = {
|
|||
__DEFINE_LINK_MODE_NAME(10, T1S, Half),
|
||||
__DEFINE_LINK_MODE_NAME(10, T1S_P2MP, Half),
|
||||
__DEFINE_LINK_MODE_NAME(10, T1BRR, Full),
|
||||
__DEFINE_LINK_MODE_NAME(200000, CR, Full),
|
||||
__DEFINE_LINK_MODE_NAME(200000, KR, Full),
|
||||
__DEFINE_LINK_MODE_NAME(200000, DR, Full),
|
||||
__DEFINE_LINK_MODE_NAME(200000, DR_2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(200000, SR, Full),
|
||||
__DEFINE_LINK_MODE_NAME(200000, VR, Full),
|
||||
__DEFINE_LINK_MODE_NAME(400000, CR2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(400000, KR2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(400000, DR2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(400000, DR2_2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(400000, SR2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(400000, VR2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(800000, CR4, Full),
|
||||
__DEFINE_LINK_MODE_NAME(800000, KR4, Full),
|
||||
__DEFINE_LINK_MODE_NAME(800000, DR4, Full),
|
||||
__DEFINE_LINK_MODE_NAME(800000, DR4_2, Full),
|
||||
__DEFINE_LINK_MODE_NAME(800000, SR4, Full),
|
||||
__DEFINE_LINK_MODE_NAME(800000, VR4, Full),
|
||||
};
|
||||
static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
|
||||
|
@ -218,8 +240,11 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
|||
#define __LINK_MODE_LANES_CR4 4
|
||||
#define __LINK_MODE_LANES_CR8 8
|
||||
#define __LINK_MODE_LANES_DR 1
|
||||
#define __LINK_MODE_LANES_DR_2 1
|
||||
#define __LINK_MODE_LANES_DR2 2
|
||||
#define __LINK_MODE_LANES_DR2_2 2
|
||||
#define __LINK_MODE_LANES_DR4 4
|
||||
#define __LINK_MODE_LANES_DR4_2 4
|
||||
#define __LINK_MODE_LANES_DR8 8
|
||||
#define __LINK_MODE_LANES_KR 1
|
||||
#define __LINK_MODE_LANES_KR2 2
|
||||
|
@ -248,6 +273,9 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
|||
#define __LINK_MODE_LANES_T1L 1
|
||||
#define __LINK_MODE_LANES_T1S 1
|
||||
#define __LINK_MODE_LANES_T1S_P2MP 1
|
||||
#define __LINK_MODE_LANES_VR 1
|
||||
#define __LINK_MODE_LANES_VR2 2
|
||||
#define __LINK_MODE_LANES_VR4 4
|
||||
#define __LINK_MODE_LANES_VR8 8
|
||||
#define __LINK_MODE_LANES_DR8_2 8
|
||||
#define __LINK_MODE_LANES_T1BRR 1
|
||||
|
@ -375,8 +403,27 @@ const struct link_mode_info link_mode_params[] = {
|
|||
__DEFINE_LINK_MODE_PARAMS(10, T1S, Half),
|
||||
__DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half),
|
||||
__DEFINE_LINK_MODE_PARAMS(10, T1BRR, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(200000, CR, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(200000, KR, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(200000, DR, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(200000, DR_2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(200000, SR, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(200000, VR, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(400000, CR2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(400000, KR2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(400000, DR2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(400000, DR2_2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(400000, SR2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(400000, VR2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(800000, CR4, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(800000, KR4, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(800000, DR4, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(800000, DR4_2, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(800000, SR4, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(800000, VR4, Full),
|
||||
};
|
||||
static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
EXPORT_SYMBOL_GPL(link_mode_params);
|
||||
|
||||
const char netif_msg_class_names[][ETH_GSTRING_LEN] = {
|
||||
[NETIF_MSG_DRV_BIT] = "drv",
|
||||
|
@ -427,6 +474,7 @@ const char sof_timestamping_names[][ETH_GSTRING_LEN] = {
|
|||
[const_ilog2(SOF_TIMESTAMPING_OPT_TX_SWHW)] = "option-tx-swhw",
|
||||
[const_ilog2(SOF_TIMESTAMPING_BIND_PHC)] = "bind-phc",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_ID_TCP)] = "option-id-tcp",
|
||||
[const_ilog2(SOF_TIMESTAMPING_OPT_RX_FILTER)] = "option-rx-filter",
|
||||
};
|
||||
static_assert(ARRAY_SIZE(sof_timestamping_names) == __SOF_TIMESTAMPING_CNT);
|
||||
|
||||
|
@ -458,6 +506,11 @@ const char ts_rx_filter_names[][ETH_GSTRING_LEN] = {
|
|||
};
|
||||
static_assert(ARRAY_SIZE(ts_rx_filter_names) == __HWTSTAMP_FILTER_CNT);
|
||||
|
||||
const char ts_flags_names[][ETH_GSTRING_LEN] = {
|
||||
[const_ilog2(HWTSTAMP_FLAG_BONDED_PHC_INDEX)] = "bonded-phc-index",
|
||||
};
|
||||
static_assert(ARRAY_SIZE(ts_flags_names) == __HWTSTAMP_FLAG_CNT);
|
||||
|
||||
const char udp_tunnel_type_names[][ETH_GSTRING_LEN] = {
|
||||
[ETHTOOL_UDP_TUNNEL_TYPE_VXLAN] = "vxlan",
|
||||
[ETHTOOL_UDP_TUNNEL_TYPE_GENEVE] = "geneve",
|
||||
|
@ -537,6 +590,20 @@ static int ethtool_get_rxnfc_rule_count(struct net_device *dev)
|
|||
return info.rule_cnt;
|
||||
}
|
||||
|
||||
/* Max offset for one RSS context */
|
||||
static u32 ethtool_get_rss_ctx_max_channel(struct ethtool_rxfh_context *ctx)
|
||||
{
|
||||
u32 max_ring = 0;
|
||||
u32 i, *tbl;
|
||||
|
||||
if (WARN_ON_ONCE(!ctx))
|
||||
return 0;
|
||||
tbl = ethtool_rxfh_context_indir(ctx);
|
||||
for (i = 0; i < ctx->indir_size; i++)
|
||||
max_ring = max(max_ring, tbl[i]);
|
||||
return max_ring;
|
||||
}
|
||||
|
||||
static int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
|
@ -573,10 +640,18 @@ static int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max)
|
|||
|
||||
if (rule_info.fs.ring_cookie != RX_CLS_FLOW_DISC &&
|
||||
rule_info.fs.ring_cookie != RX_CLS_FLOW_WAKE &&
|
||||
!(rule_info.flow_type & FLOW_RSS) &&
|
||||
!ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie))
|
||||
max_ring =
|
||||
max_t(u64, max_ring, rule_info.fs.ring_cookie);
|
||||
!ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie)) {
|
||||
u64 ring = rule_info.fs.ring_cookie;
|
||||
|
||||
if (rule_info.flow_type & FLOW_RSS) {
|
||||
struct ethtool_rxfh_context *ctx;
|
||||
|
||||
ctx = xa_load(&dev->ethtool->rss_ctx,
|
||||
rule_info.rss_context);
|
||||
ring += ethtool_get_rss_ctx_max_channel(ctx);
|
||||
}
|
||||
max_ring = max_t(u64, max_ring, ring);
|
||||
}
|
||||
}
|
||||
|
||||
kvfree(info);
|
||||
|
@ -588,6 +663,7 @@ err_free_info:
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Max offset across all of a device's RSS contexts */
|
||||
static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
|
||||
{
|
||||
struct ethtool_rxfh_context *ctx;
|
||||
|
@ -595,13 +671,8 @@ static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
|
|||
u32 max_ring = 0;
|
||||
|
||||
mutex_lock(&dev->ethtool->rss_lock);
|
||||
xa_for_each(&dev->ethtool->rss_ctx, context, ctx) {
|
||||
u32 i, *tbl;
|
||||
|
||||
tbl = ethtool_rxfh_context_indir(ctx);
|
||||
for (i = 0; i < ctx->indir_size; i++)
|
||||
max_ring = max(max_ring, tbl[i]);
|
||||
}
|
||||
xa_for_each(&dev->ethtool->rss_ctx, context, ctx)
|
||||
max_ring = max(max_ring, ethtool_get_rss_ctx_max_channel(ctx));
|
||||
mutex_unlock(&dev->ethtool->rss_lock);
|
||||
|
||||
return max_ring;
|
||||
|
@ -610,7 +681,7 @@ static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
|
|||
static u32 ethtool_get_max_rxfh_channel(struct net_device *dev)
|
||||
{
|
||||
struct ethtool_rxfh_param rxfh = {};
|
||||
u32 dev_size, current_max;
|
||||
u32 dev_size, current_max = 0;
|
||||
int ret;
|
||||
|
||||
/* While we do track whether RSS context has an indirection
|
||||
|
@ -675,6 +746,54 @@ int ethtool_check_max_channel(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct ethtool_rxnfc *info;
|
||||
int rc, i, rule_cnt;
|
||||
|
||||
if (!ops->get_rxnfc)
|
||||
return 0;
|
||||
|
||||
rule_cnt = ethtool_get_rxnfc_rule_count(dev);
|
||||
if (!rule_cnt)
|
||||
return 0;
|
||||
|
||||
if (rule_cnt < 0)
|
||||
return -EINVAL;
|
||||
|
||||
info = kvzalloc(struct_size(info, rule_locs, rule_cnt), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->cmd = ETHTOOL_GRXCLSRLALL;
|
||||
info->rule_cnt = rule_cnt;
|
||||
rc = ops->get_rxnfc(dev, info, info->rule_locs);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
for (i = 0; i < rule_cnt; i++) {
|
||||
struct ethtool_rxnfc rule_info = {
|
||||
.cmd = ETHTOOL_GRXCLSRULE,
|
||||
.fs.location = info->rule_locs[i],
|
||||
};
|
||||
|
||||
rc = ops->get_rxnfc(dev, &rule_info, NULL);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
if (rule_info.fs.flow_type & FLOW_RSS &&
|
||||
rule_info.rss_context == rss_context) {
|
||||
rc = -EBUSY;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
out_free:
|
||||
kvfree(info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ethtool_check_ops(const struct ethtool_ops *ops)
|
||||
{
|
||||
if (WARN_ON(ops->set_coalesce && !ops->supported_coalesce_params))
|
||||
|
@ -688,20 +807,114 @@ int ethtool_check_ops(const struct ethtool_ops *ops)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
|
||||
void ethtool_ringparam_get_cfg(struct net_device *dev,
|
||||
struct ethtool_ringparam *param,
|
||||
struct kernel_ethtool_ringparam *kparam,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
int err = 0;
|
||||
memset(param, 0, sizeof(*param));
|
||||
memset(kparam, 0, sizeof(*kparam));
|
||||
|
||||
param->cmd = ETHTOOL_GRINGPARAM;
|
||||
dev->ethtool_ops->get_ringparam(dev, param, kparam, extack);
|
||||
|
||||
/* Driver gives us current state, we want to return current config */
|
||||
kparam->tcp_data_split = dev->cfg->hds_config;
|
||||
kparam->hds_thresh = dev->cfg->hds_thresh;
|
||||
}
|
||||
|
||||
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->cmd = ETHTOOL_GET_TS_INFO;
|
||||
info->phc_index = -1;
|
||||
}
|
||||
|
||||
if (phy_is_default_hwtstamp(phydev) && phy_has_tsinfo(phydev))
|
||||
err = phy_ts_info(phydev, info);
|
||||
else if (ops->get_ts_info)
|
||||
err = ops->get_ts_info(dev, info);
|
||||
int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
int err;
|
||||
|
||||
if (!ops->get_ts_info)
|
||||
return -ENODEV;
|
||||
|
||||
/* Does ptp comes from netdev */
|
||||
ethtool_init_tsinfo(info);
|
||||
info->phc_qualifier = hwprov_desc->qualifier;
|
||||
err = ops->get_ts_info(dev, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (info->phc_index == hwprov_desc->index &&
|
||||
net_support_hwtstamp_qualifier(dev, hwprov_desc->qualifier))
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
struct phy_device *
|
||||
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Only precise qualifier is supported in phydev */
|
||||
if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
/* Look in the phy topology */
|
||||
if (dev->link_topo) {
|
||||
struct phy_device_node *pdn;
|
||||
unsigned long phy_index;
|
||||
|
||||
xa_for_each(&dev->link_topo->phys, phy_index, pdn) {
|
||||
if (!phy_has_tsinfo(pdn->phy))
|
||||
continue;
|
||||
|
||||
ethtool_init_tsinfo(info);
|
||||
err = phy_ts_info(pdn->phy, info);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (info->phc_index == hwprov_desc->index)
|
||||
return pdn->phy;
|
||||
}
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
/* Look on the dev->phydev */
|
||||
if (phy_has_tsinfo(dev->phydev)) {
|
||||
ethtool_init_tsinfo(info);
|
||||
err = phy_ts_info(dev->phydev, info);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (info->phc_index == hwprov_desc->index)
|
||||
return dev->phydev;
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
int ethtool_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc);
|
||||
if (err == -ENODEV) {
|
||||
struct phy_device *phy;
|
||||
|
||||
phy = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc);
|
||||
if (IS_ERR(phy))
|
||||
err = PTR_ERR(phy);
|
||||
else
|
||||
err = 0;
|
||||
}
|
||||
|
||||
info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
|
@ -709,6 +922,59 @@ int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info
|
|||
return err;
|
||||
}
|
||||
|
||||
int __ethtool_get_ts_info(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info)
|
||||
{
|
||||
struct hwtstamp_provider *hwprov;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
hwprov = rcu_dereference(dev->hwprov);
|
||||
/* No provider specified, use default behavior */
|
||||
if (!hwprov) {
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
|
||||
ethtool_init_tsinfo(info);
|
||||
if (phy_is_default_hwtstamp(phydev) &&
|
||||
phy_has_tsinfo(phydev))
|
||||
err = phy_ts_info(phydev, info);
|
||||
else if (ops->get_ts_info)
|
||||
err = ops->get_ts_info(dev, info);
|
||||
|
||||
info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ethtool_get_ts_info_by_phc(dev, info, &hwprov->desc);
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
bool net_support_hwtstamp_qualifier(struct net_device *dev,
|
||||
enum hwtstamp_provider_qualifier qualifier)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
|
||||
if (!ops)
|
||||
return false;
|
||||
|
||||
/* Return true with precise qualifier and with NIC without
|
||||
* qualifier description to not break the old behavior.
|
||||
*/
|
||||
if (!ops->supported_hwtstamp_qualifiers &&
|
||||
qualifier == HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
|
||||
return true;
|
||||
|
||||
if (ops->supported_hwtstamp_qualifiers & BIT(qualifier))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index)
|
||||
{
|
||||
struct kernel_ethtool_ts_info info = { };
|
||||
|
|
|
@ -13,14 +13,10 @@
|
|||
ETHTOOL_LINK_MODE_ ## speed ## base ## type ## _ ## duplex ## _BIT
|
||||
|
||||
#define __SOF_TIMESTAMPING_CNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1)
|
||||
|
||||
struct link_mode_info {
|
||||
int speed;
|
||||
u8 lanes;
|
||||
u8 duplex;
|
||||
};
|
||||
#define __HWTSTAMP_FLAG_CNT (const_ilog2(HWTSTAMP_FLAG_LAST) + 1)
|
||||
|
||||
struct genl_info;
|
||||
struct hwtstamp_provider_desc;
|
||||
|
||||
extern const char
|
||||
netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
|
||||
|
@ -31,12 +27,12 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
|
|||
extern const char
|
||||
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
|
||||
extern const char link_mode_names[][ETH_GSTRING_LEN];
|
||||
extern const struct link_mode_info link_mode_params[];
|
||||
extern const char netif_msg_class_names[][ETH_GSTRING_LEN];
|
||||
extern const char wol_mode_names[][ETH_GSTRING_LEN];
|
||||
extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
|
||||
extern const char ts_tx_type_names[][ETH_GSTRING_LEN];
|
||||
extern const char ts_rx_filter_names[][ETH_GSTRING_LEN];
|
||||
extern const char ts_flags_names[][ETH_GSTRING_LEN];
|
||||
extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN];
|
||||
|
||||
int __ethtool_get_link(struct net_device *dev);
|
||||
|
@ -47,7 +43,26 @@ bool convert_legacy_settings_to_link_ksettings(
|
|||
int ethtool_check_max_channel(struct net_device *dev,
|
||||
struct ethtool_channels channels,
|
||||
struct genl_info *info);
|
||||
int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context);
|
||||
|
||||
void ethtool_ringparam_get_cfg(struct net_device *dev,
|
||||
struct ethtool_ringparam *param,
|
||||
struct kernel_ethtool_ringparam *kparam,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info);
|
||||
int ethtool_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc);
|
||||
int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc);
|
||||
struct phy_device *
|
||||
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc);
|
||||
bool net_support_hwtstamp_qualifier(struct net_device *dev,
|
||||
enum hwtstamp_provider_qualifier qualifier);
|
||||
|
||||
extern const struct ethtool_phy_ops *ethtool_phy_ops;
|
||||
extern const struct ethtool_pse_ops *ethtool_pse_ops;
|
||||
|
|
|
@ -992,18 +992,31 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (ops->get_rxfh) {
|
||||
if (cmd == ETHTOOL_SRXCLSRLINS && info.fs.flow_type & FLOW_RSS) {
|
||||
/* Nonzero ring with RSS only makes sense
|
||||
* if NIC adds them together
|
||||
*/
|
||||
if (!ops->cap_rss_rxnfc_adds &&
|
||||
ethtool_get_flow_spec_ring(info.fs.ring_cookie))
|
||||
return -EINVAL;
|
||||
|
||||
if (info.rss_context &&
|
||||
!xa_load(&dev->ethtool->rss_ctx, info.rss_context))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cmd == ETHTOOL_SRXFH && ops->get_rxfh) {
|
||||
struct ethtool_rxfh_param rxfh = {};
|
||||
|
||||
rc = ops->get_rxfh(dev, &rxfh);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Sanity check: if symmetric-xor is set, then:
|
||||
/* Sanity check: if symmetric-xor/symmetric-or-xor is set, then:
|
||||
* 1 - no other fields besides IP src/dst and/or L4 src/dst
|
||||
* 2 - If src is set, dst must also be set
|
||||
*/
|
||||
if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) &&
|
||||
if ((rxfh.input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) &&
|
||||
((info.data & ~(RXH_IP_SRC | RXH_IP_DST |
|
||||
RXH_L4_B_0_1 | RXH_L4_B_2_3)) ||
|
||||
(!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) ||
|
||||
|
@ -1376,11 +1389,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
|
|||
return -EOPNOTSUPP;
|
||||
/* Check input data transformation capabilities */
|
||||
if (rxfh.input_xfrm && rxfh.input_xfrm != RXH_XFRM_SYM_XOR &&
|
||||
rxfh.input_xfrm != RXH_XFRM_SYM_OR_XOR &&
|
||||
rxfh.input_xfrm != RXH_XFRM_NO_CHANGE)
|
||||
return -EINVAL;
|
||||
if (rxfh.input_xfrm != RXH_XFRM_NO_CHANGE &&
|
||||
(rxfh.input_xfrm & RXH_XFRM_SYM_XOR) &&
|
||||
!ops->cap_rss_sym_xor_supported)
|
||||
rxfh.input_xfrm & ~ops->supported_input_xfrm)
|
||||
return -EOPNOTSUPP;
|
||||
create = rxfh.rss_context == ETH_RXFH_CONTEXT_ALLOC;
|
||||
|
||||
|
@ -1462,6 +1475,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
|
|||
mutex_lock(&dev->ethtool->rss_lock);
|
||||
locked = true;
|
||||
}
|
||||
|
||||
if (rxfh.rss_context && rxfh_dev.rss_delete) {
|
||||
ret = ethtool_check_rss_ctx_busy(dev, rxfh.rss_context);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (create) {
|
||||
if (rxfh_dev.rss_delete) {
|
||||
ret = -EINVAL;
|
||||
|
@ -1505,6 +1525,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
|
|||
extack);
|
||||
/* Make sure driver populates defaults */
|
||||
WARN_ON_ONCE(!ret && !rxfh_dev.key &&
|
||||
ops->rxfh_per_ctx_key &&
|
||||
!memchr_inv(ethtool_rxfh_context_key(ctx),
|
||||
0, ctx->key_size));
|
||||
} else if (rxfh_dev.rss_delete) {
|
||||
|
@ -2045,8 +2066,8 @@ static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
|
|||
|
||||
static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
|
||||
struct kernel_ethtool_ringparam kernel_ringparam;
|
||||
struct ethtool_ringparam ringparam, max;
|
||||
int ret;
|
||||
|
||||
if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
|
||||
|
@ -2055,7 +2076,7 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
|
|||
if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
|
||||
return -EFAULT;
|
||||
|
||||
dev->ethtool_ops->get_ringparam(dev, &max, &kernel_ringparam, NULL);
|
||||
ethtool_ringparam_get_cfg(dev, &max, &kernel_ringparam, NULL);
|
||||
|
||||
/* ensure new ring parameters are within the maximums */
|
||||
if (ringparam.rx_pending > max.rx_max_pending ||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phylib_stubs.h>
|
||||
|
||||
struct linkstate_req_info {
|
||||
struct ethnl_req_info base;
|
||||
|
@ -26,9 +27,8 @@ const struct nla_policy ethnl_linkstate_get_policy[] = {
|
|||
NLA_POLICY_NESTED(ethnl_header_policy_stats),
|
||||
};
|
||||
|
||||
static int linkstate_get_sqi(struct net_device *dev)
|
||||
static int linkstate_get_sqi(struct phy_device *phydev)
|
||||
{
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
int ret;
|
||||
|
||||
if (!phydev)
|
||||
|
@ -46,9 +46,8 @@ static int linkstate_get_sqi(struct net_device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int linkstate_get_sqi_max(struct net_device *dev)
|
||||
static int linkstate_get_sqi_max(struct phy_device *phydev)
|
||||
{
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
int ret;
|
||||
|
||||
if (!phydev)
|
||||
|
@ -100,19 +99,28 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
|
|||
{
|
||||
struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
struct nlattr **tb = info->attrs;
|
||||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_LINKSTATE_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR(phydev)) {
|
||||
ret = PTR_ERR(phydev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->link = __ethtool_get_link(dev);
|
||||
|
||||
ret = linkstate_get_sqi(dev);
|
||||
ret = linkstate_get_sqi(phydev);
|
||||
if (linkstate_sqi_critical_error(ret))
|
||||
goto out;
|
||||
data->sqi = ret;
|
||||
|
||||
ret = linkstate_get_sqi_max(dev);
|
||||
ret = linkstate_get_sqi_max(phydev);
|
||||
if (linkstate_sqi_critical_error(ret))
|
||||
goto out;
|
||||
data->sqi_max = ret;
|
||||
|
@ -127,9 +135,9 @@ static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
|
|||
sizeof(data->link_stats) / 8);
|
||||
|
||||
if (req_base->flags & ETHTOOL_FLAG_STATS) {
|
||||
if (dev->phydev)
|
||||
data->link_stats.link_down_events =
|
||||
READ_ONCE(dev->phydev->link_down_events);
|
||||
if (phydev)
|
||||
phy_ethtool_get_link_ext_stats(phydev,
|
||||
&data->link_stats);
|
||||
|
||||
if (dev->ethtool_ops->get_link_ext_stats)
|
||||
dev->ethtool_ops->get_link_ext_stats(dev,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <net/netdev_queues.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/ethtool_netlink.h>
|
||||
#include <linux/phy_link_topology.h>
|
||||
|
@ -90,7 +91,7 @@ int ethnl_ops_begin(struct net_device *dev)
|
|||
pm_runtime_get_sync(dev->dev.parent);
|
||||
|
||||
if (!netif_device_present(dev) ||
|
||||
dev->reg_state == NETREG_UNREGISTERING) {
|
||||
dev->reg_state >= NETREG_UNREGISTERING) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
@ -210,7 +211,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
|
|||
}
|
||||
|
||||
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
|
||||
const struct nlattr *header,
|
||||
struct nlattr **tb, unsigned int header,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
|
@ -224,8 +225,8 @@ struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
|
|||
return req_info->dev->phydev;
|
||||
|
||||
phydev = phy_link_topo_get_phy(req_info->dev, req_info->phy_index);
|
||||
if (!phydev) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, header,
|
||||
if (!phydev && tb) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, tb[header],
|
||||
"no phy matching phyindex");
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
@ -394,6 +395,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
|
|||
[ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops,
|
||||
[ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops,
|
||||
[ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops,
|
||||
[ETHTOOL_MSG_TSCONFIG_GET] = ðnl_tsconfig_request_ops,
|
||||
[ETHTOOL_MSG_TSCONFIG_SET] = ðnl_tsconfig_request_ops,
|
||||
};
|
||||
|
||||
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
|
||||
|
@ -490,7 +493,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
|
|||
ret = ops->prepare_data(req_info, reply_data, info);
|
||||
rtnl_unlock();
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
goto err_dev;
|
||||
ret = ops->reply_size(req_info, reply_data);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
@ -548,7 +551,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
|
|||
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
|
||||
rtnl_unlock();
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out_cancel;
|
||||
ret = ethnl_fill_reply_header(skb, dev, ctx->ops->hdr_attr);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -557,6 +560,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
|
|||
out:
|
||||
if (ctx->ops->cleanup_data)
|
||||
ctx->ops->cleanup_data(ctx->reply_data);
|
||||
out_cancel:
|
||||
ctx->reply_data->dev = NULL;
|
||||
if (ret < 0)
|
||||
genlmsg_cancel(skb, ehdr);
|
||||
|
@ -665,6 +669,7 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|||
const struct ethnl_request_ops *ops;
|
||||
struct ethnl_req_info req_info = {};
|
||||
const u8 cmd = info->genlhdr->cmd;
|
||||
struct net_device *dev;
|
||||
int ret;
|
||||
|
||||
ops = ethnl_default_requests[cmd];
|
||||
|
@ -686,20 +691,36 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
|
|||
goto out_dev;
|
||||
}
|
||||
|
||||
dev = req_info.dev;
|
||||
|
||||
rtnl_lock();
|
||||
ret = ethnl_ops_begin(req_info.dev);
|
||||
dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
|
||||
GFP_KERNEL_ACCOUNT);
|
||||
if (!dev->cfg_pending) {
|
||||
ret = -ENOMEM;
|
||||
goto out_tie_cfg;
|
||||
}
|
||||
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
goto out_rtnl;
|
||||
goto out_free_cfg;
|
||||
|
||||
ret = ops->set(&req_info, info);
|
||||
if (ret <= 0)
|
||||
if (ret < 0)
|
||||
goto out_ops;
|
||||
ethtool_notify(req_info.dev, ops->set_ntf_cmd, NULL);
|
||||
|
||||
swap(dev->cfg, dev->cfg_pending);
|
||||
if (!ret)
|
||||
goto out_ops;
|
||||
ethtool_notify(dev, ops->set_ntf_cmd, NULL);
|
||||
|
||||
ret = 0;
|
||||
out_ops:
|
||||
ethnl_ops_complete(req_info.dev);
|
||||
out_rtnl:
|
||||
ethnl_ops_complete(dev);
|
||||
out_free_cfg:
|
||||
kfree(dev->cfg_pending);
|
||||
out_tie_cfg:
|
||||
dev->cfg_pending = dev->cfg;
|
||||
rtnl_unlock();
|
||||
out_dev:
|
||||
ethnl_parse_header_dev_put(&req_info);
|
||||
|
@ -760,7 +781,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
|
|||
ethnl_init_reply_data(reply_data, ops, dev);
|
||||
ret = ops->prepare_data(req_info, reply_data, &info);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
goto err_rep;
|
||||
ret = ops->reply_size(req_info, reply_data);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
@ -795,6 +816,7 @@ err_skb:
|
|||
err_cleanup:
|
||||
if (ops->cleanup_data)
|
||||
ops->cleanup_data(reply_data);
|
||||
err_rep:
|
||||
kfree(reply_data);
|
||||
kfree(req_info);
|
||||
return;
|
||||
|
@ -1074,9 +1096,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
|
|||
{
|
||||
.cmd = ETHTOOL_MSG_TSINFO_GET,
|
||||
.doit = ethnl_default_doit,
|
||||
.start = ethnl_default_start,
|
||||
.dumpit = ethnl_default_dumpit,
|
||||
.done = ethnl_default_done,
|
||||
.start = ethnl_tsinfo_start,
|
||||
.dumpit = ethnl_tsinfo_dumpit,
|
||||
.done = ethnl_tsinfo_done,
|
||||
.policy = ethnl_tsinfo_get_policy,
|
||||
.maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1,
|
||||
},
|
||||
|
@ -1243,6 +1265,22 @@ static const struct genl_ops ethtool_genl_ops[] = {
|
|||
.policy = ethnl_phy_get_policy,
|
||||
.maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_TSCONFIG_GET,
|
||||
.doit = ethnl_default_doit,
|
||||
.start = ethnl_default_start,
|
||||
.dumpit = ethnl_default_dumpit,
|
||||
.done = ethnl_default_done,
|
||||
.policy = ethnl_tsconfig_get_policy,
|
||||
.maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1,
|
||||
},
|
||||
{
|
||||
.cmd = ETHTOOL_MSG_TSCONFIG_SET,
|
||||
.flags = GENL_UNS_ADMIN_PERM,
|
||||
.doit = ethnl_default_set_doit,
|
||||
.policy = ethnl_tsconfig_set_policy,
|
||||
.maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
|
||||
|
|
|
@ -275,7 +275,8 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
|
|||
* ethnl_req_get_phydev() - Gets the phy_device targeted by this request,
|
||||
* if any. Must be called under rntl_lock().
|
||||
* @req_info: The ethnl request to get the phy from.
|
||||
* @header: The netlink header, used for error reporting.
|
||||
* @tb: The netlink attributes array, for error reporting.
|
||||
* @header: The netlink header index, used for error reporting.
|
||||
* @extack: The netlink extended ACK, for error reporting.
|
||||
*
|
||||
* The caller must hold RTNL, until it's done interacting with the returned
|
||||
|
@ -289,7 +290,7 @@ static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
|
|||
* is returned.
|
||||
*/
|
||||
struct phy_device *ethnl_req_get_phydev(const struct ethnl_req_info *req_info,
|
||||
const struct nlattr *header,
|
||||
struct nlattr **tb, unsigned int header,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
/**
|
||||
|
@ -435,6 +436,7 @@ extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
|
|||
extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_mm_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_phy_request_ops;
|
||||
extern const struct ethnl_request_ops ethnl_tsconfig_request_ops;
|
||||
|
||||
extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
|
||||
extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
|
||||
|
@ -455,7 +457,7 @@ extern const struct nla_policy ethnl_features_set_policy[ETHTOOL_A_FEATURES_WANT
|
|||
extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_privflags_set_policy[ETHTOOL_A_PRIVFLAGS_FLAGS + 1];
|
||||
extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX + 1];
|
||||
extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_HDS_THRESH_MAX + 1];
|
||||
extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_channels_set_policy[ETHTOOL_A_CHANNELS_COMBINED_COUNT + 1];
|
||||
extern const struct nla_policy ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_HEADER + 1];
|
||||
|
@ -464,7 +466,7 @@ extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_STATS_SRC
|
|||
extern const struct nla_policy ethnl_pause_set_policy[ETHTOOL_A_PAUSE_TX + 1];
|
||||
extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_eee_set_policy[ETHTOOL_A_EEE_TX_LPI_TIMER + 1];
|
||||
extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1];
|
||||
extern const struct nla_policy ethnl_cable_test_act_policy[ETHTOOL_A_CABLE_TEST_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG + 1];
|
||||
extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_HEADER + 1];
|
||||
|
@ -485,6 +487,8 @@ extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
|
|||
extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
|
||||
extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1];
|
||||
extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1];
|
||||
extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1];
|
||||
|
||||
int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
|
||||
int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
|
||||
|
@ -499,11 +503,15 @@ int ethnl_phy_start(struct netlink_callback *cb);
|
|||
int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int ethnl_phy_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int ethnl_phy_done(struct netlink_callback *cb);
|
||||
int ethnl_tsinfo_start(struct netlink_callback *cb);
|
||||
int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int ethnl_tsinfo_done(struct netlink_callback *cb);
|
||||
|
||||
extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
|
||||
extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
|
||||
extern const char stats_eth_mac_names[__ETHTOOL_A_STATS_ETH_MAC_CNT][ETH_GSTRING_LEN];
|
||||
extern const char stats_eth_ctrl_names[__ETHTOOL_A_STATS_ETH_CTRL_CNT][ETH_GSTRING_LEN];
|
||||
extern const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN];
|
||||
extern const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN];
|
||||
|
||||
#endif /* _NET_ETHTOOL_NETLINK_H */
|
||||
|
|
|
@ -125,7 +125,7 @@ static int ethnl_phy_parse_request(struct ethnl_req_info *req_base,
|
|||
struct phy_req_info *req_info = PHY_REQINFO(req_base);
|
||||
struct phy_device *phydev;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PHY_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PHY_HEADER,
|
||||
extack);
|
||||
if (!phydev)
|
||||
return 0;
|
||||
|
|
|
@ -62,7 +62,7 @@ static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
|
||||
info->extack);
|
||||
// check that the PHY device is available and connected
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
|
@ -152,7 +152,7 @@ ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
bool mod = false;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PLCA_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PLCA_HEADER,
|
||||
info->extack);
|
||||
// check that the PHY device is available and connected
|
||||
if (IS_ERR_OR_NULL(phydev))
|
||||
|
@ -211,7 +211,7 @@ static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PLCA_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PLCA_HEADER,
|
||||
info->extack);
|
||||
// check that the PHY device is available and connected
|
||||
if (IS_ERR_OR_NULL(phydev)) {
|
||||
|
|
|
@ -64,7 +64,7 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_PSE_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_PSE_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR(phydev))
|
||||
return -ENODEV;
|
||||
|
@ -261,7 +261,7 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_info, tb[ETHTOOL_A_PSE_HEADER],
|
||||
phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PSE_HEADER,
|
||||
info->extack);
|
||||
ret = ethnl_set_pse_validate(phydev, info);
|
||||
if (ret)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
|
||||
|
@ -37,6 +39,10 @@ static int rings_prepare_data(const struct ethnl_req_info *req_base,
|
|||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->kernel_ringparam.tcp_data_split = dev->cfg->hds_config;
|
||||
data->kernel_ringparam.hds_thresh = dev->cfg->hds_thresh;
|
||||
|
||||
dev->ethtool_ops->get_ringparam(dev, &data->ringparam,
|
||||
&data->kernel_ringparam, info->extack);
|
||||
ethnl_ops_complete(dev);
|
||||
|
@ -61,7 +67,9 @@ static int rings_reply_size(const struct ethnl_req_info *req_base,
|
|||
nla_total_size(sizeof(u8)) + /* _RINGS_TX_PUSH */
|
||||
nla_total_size(sizeof(u8))) + /* _RINGS_RX_PUSH */
|
||||
nla_total_size(sizeof(u32)) + /* _RINGS_TX_PUSH_BUF_LEN */
|
||||
nla_total_size(sizeof(u32)); /* _RINGS_TX_PUSH_BUF_LEN_MAX */
|
||||
nla_total_size(sizeof(u32)) + /* _RINGS_TX_PUSH_BUF_LEN_MAX */
|
||||
nla_total_size(sizeof(u32)) + /* _RINGS_HDS_THRESH */
|
||||
nla_total_size(sizeof(u32)); /* _RINGS_HDS_THRESH_MAX*/
|
||||
}
|
||||
|
||||
static int rings_fill_reply(struct sk_buff *skb,
|
||||
|
@ -108,7 +116,12 @@ static int rings_fill_reply(struct sk_buff *skb,
|
|||
(nla_put_u32(skb, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX,
|
||||
kr->tx_push_buf_max_len) ||
|
||||
nla_put_u32(skb, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN,
|
||||
kr->tx_push_buf_len))))
|
||||
kr->tx_push_buf_len))) ||
|
||||
((supported_ring_params & ETHTOOL_RING_USE_HDS_THRS) &&
|
||||
(nla_put_u32(skb, ETHTOOL_A_RINGS_HDS_THRESH,
|
||||
kr->hds_thresh) ||
|
||||
nla_put_u32(skb, ETHTOOL_A_RINGS_HDS_THRESH_MAX,
|
||||
kr->hds_thresh_max))))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
|
@ -130,6 +143,7 @@ const struct nla_policy ethnl_rings_set_policy[] = {
|
|||
[ETHTOOL_A_RINGS_TX_PUSH] = NLA_POLICY_MAX(NLA_U8, 1),
|
||||
[ETHTOOL_A_RINGS_RX_PUSH] = NLA_POLICY_MAX(NLA_U8, 1),
|
||||
[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_RINGS_HDS_THRESH] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -155,6 +169,14 @@ ethnl_set_rings_validate(struct ethnl_req_info *req_info,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (tb[ETHTOOL_A_RINGS_HDS_THRESH] &&
|
||||
!(ops->supported_ring_params & ETHTOOL_RING_USE_HDS_THRS)) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[ETHTOOL_A_RINGS_HDS_THRESH],
|
||||
"setting hds-thresh is not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (tb[ETHTOOL_A_RINGS_CQE_SIZE] &&
|
||||
!(ops->supported_ring_params & ETHTOOL_RING_USE_CQE_SIZE)) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
|
@ -193,16 +215,16 @@ ethnl_set_rings_validate(struct ethnl_req_info *req_info,
|
|||
static int
|
||||
ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
|
||||
{
|
||||
struct kernel_ethtool_ringparam kernel_ringparam = {};
|
||||
struct ethtool_ringparam ringparam = {};
|
||||
struct kernel_ethtool_ringparam kernel_ringparam;
|
||||
struct net_device *dev = req_info->dev;
|
||||
struct ethtool_ringparam ringparam;
|
||||
struct nlattr **tb = info->attrs;
|
||||
const struct nlattr *err_attr;
|
||||
bool mod = false;
|
||||
int ret;
|
||||
|
||||
dev->ethtool_ops->get_ringparam(dev, &ringparam,
|
||||
&kernel_ringparam, info->extack);
|
||||
ethtool_ringparam_get_cfg(dev, &ringparam, &kernel_ringparam,
|
||||
info->extack);
|
||||
|
||||
ethnl_update_u32(&ringparam.rx_pending, tb[ETHTOOL_A_RINGS_RX], &mod);
|
||||
ethnl_update_u32(&ringparam.rx_mini_pending,
|
||||
|
@ -222,9 +244,19 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
tb[ETHTOOL_A_RINGS_RX_PUSH], &mod);
|
||||
ethnl_update_u32(&kernel_ringparam.tx_push_buf_len,
|
||||
tb[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN], &mod);
|
||||
ethnl_update_u32(&kernel_ringparam.hds_thresh,
|
||||
tb[ETHTOOL_A_RINGS_HDS_THRESH], &mod);
|
||||
if (!mod)
|
||||
return 0;
|
||||
|
||||
if (kernel_ringparam.tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
|
||||
dev_xdp_sb_prog_count(dev)) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[ETHTOOL_A_RINGS_TCP_DATA_SPLIT],
|
||||
"tcp-data-split can not be enabled with single buffer XDP");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* ensure new ring parameters are within limits */
|
||||
if (ringparam.rx_pending > ringparam.rx_max_pending)
|
||||
err_attr = tb[ETHTOOL_A_RINGS_RX];
|
||||
|
@ -234,6 +266,8 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
err_attr = tb[ETHTOOL_A_RINGS_RX_JUMBO];
|
||||
else if (ringparam.tx_pending > ringparam.tx_max_pending)
|
||||
err_attr = tb[ETHTOOL_A_RINGS_TX];
|
||||
else if (kernel_ringparam.hds_thresh > kernel_ringparam.hds_thresh_max)
|
||||
err_attr = tb[ETHTOOL_A_RINGS_HDS_THRESH];
|
||||
else
|
||||
err_attr = NULL;
|
||||
if (err_attr) {
|
||||
|
@ -250,6 +284,9 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->cfg_pending->hds_config = kernel_ringparam.tcp_data_split;
|
||||
dev->cfg_pending->hds_thresh = kernel_ringparam.hds_thresh;
|
||||
|
||||
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
|
||||
&kernel_ringparam, info->extack);
|
||||
return ret < 0 ? ret : 1;
|
||||
|
|
|
@ -107,6 +107,8 @@ rss_prepare_ctx(const struct rss_req_info *request, struct net_device *dev,
|
|||
u32 total_size, indir_bytes;
|
||||
u8 *rss_config;
|
||||
|
||||
data->no_key_fields = !dev->ethtool_ops->rxfh_per_ctx_key;
|
||||
|
||||
ctx = xa_load(&dev->ethtool->rss_ctx, request->rss_context);
|
||||
if (!ctx)
|
||||
return -ENOENT;
|
||||
|
@ -153,7 +155,6 @@ rss_prepare_data(const struct ethnl_req_info *req_base,
|
|||
if (!ops->cap_rss_ctx_supported && !ops->create_rxfh_context)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data->no_key_fields = !ops->rxfh_per_ctx_key;
|
||||
return rss_prepare_ctx(request, dev, data, info);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phylib_stubs.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "bitset.h"
|
||||
|
@ -20,6 +23,7 @@ struct stats_reply_data {
|
|||
struct ethtool_eth_mac_stats mac_stats;
|
||||
struct ethtool_eth_ctrl_stats ctrl_stats;
|
||||
struct ethtool_rmon_stats rmon_stats;
|
||||
struct ethtool_phy_stats phydev_stats;
|
||||
);
|
||||
const struct ethtool_rmon_hist_range *rmon_ranges;
|
||||
};
|
||||
|
@ -32,6 +36,7 @@ const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN] = {
|
|||
[ETHTOOL_STATS_ETH_MAC] = "eth-mac",
|
||||
[ETHTOOL_STATS_ETH_CTRL] = "eth-ctrl",
|
||||
[ETHTOOL_STATS_RMON] = "rmon",
|
||||
[ETHTOOL_STATS_PHY] = "phydev",
|
||||
};
|
||||
|
||||
const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN] = {
|
||||
|
@ -76,6 +81,15 @@ const char stats_rmon_names[__ETHTOOL_A_STATS_RMON_CNT][ETH_GSTRING_LEN] = {
|
|||
[ETHTOOL_A_STATS_RMON_JABBER] = "etherStatsJabbers",
|
||||
};
|
||||
|
||||
const char stats_phy_names[__ETHTOOL_A_STATS_PHY_CNT][ETH_GSTRING_LEN] = {
|
||||
[ETHTOOL_A_STATS_PHY_RX_PKTS] = "RxFrames",
|
||||
[ETHTOOL_A_STATS_PHY_RX_BYTES] = "RxOctets",
|
||||
[ETHTOOL_A_STATS_PHY_RX_ERRORS] = "RxErrors",
|
||||
[ETHTOOL_A_STATS_PHY_TX_PKTS] = "TxFrames",
|
||||
[ETHTOOL_A_STATS_PHY_TX_BYTES] = "TxOctets",
|
||||
[ETHTOOL_A_STATS_PHY_TX_ERRORS] = "TxErrors",
|
||||
};
|
||||
|
||||
const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_SRC + 1] = {
|
||||
[ETHTOOL_A_STATS_HEADER] =
|
||||
NLA_POLICY_NESTED(ethnl_header_policy),
|
||||
|
@ -120,8 +134,15 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
|
|||
struct stats_reply_data *data = STATS_REPDATA(reply_base);
|
||||
enum ethtool_mac_stats_src src = req_info->src;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
struct nlattr **tb = info->attrs;
|
||||
struct phy_device *phydev;
|
||||
int ret;
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_STATS_HEADER,
|
||||
info->extack);
|
||||
if (IS_ERR(phydev))
|
||||
return PTR_ERR(phydev);
|
||||
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -145,6 +166,14 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
|
|||
data->ctrl_stats.src = src;
|
||||
data->rmon_stats.src = src;
|
||||
|
||||
if ((test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask) ||
|
||||
test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask)) &&
|
||||
src == ETHTOOL_MAC_STATS_SRC_AGGREGATE) {
|
||||
if (phydev)
|
||||
phy_ethtool_get_phy_stats(phydev, &data->phy_stats,
|
||||
&data->phydev_stats);
|
||||
}
|
||||
|
||||
if (test_bit(ETHTOOL_STATS_ETH_PHY, req_info->stat_mask) &&
|
||||
dev->ethtool_ops->get_eth_phy_stats)
|
||||
dev->ethtool_ops->get_eth_phy_stats(dev, &data->phy_stats);
|
||||
|
@ -194,6 +223,10 @@ static int stats_reply_size(const struct ethnl_req_info *req_base,
|
|||
nla_total_size(4)) * /* _A_STATS_GRP_HIST_BKT_HI */
|
||||
ETHTOOL_RMON_HIST_MAX * 2;
|
||||
}
|
||||
if (test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask)) {
|
||||
n_stats += sizeof(struct ethtool_phy_stats) / sizeof(u64);
|
||||
n_grps++;
|
||||
}
|
||||
|
||||
len += n_grps * (nla_total_size(0) + /* _A_STATS_GRP */
|
||||
nla_total_size(4) + /* _A_STATS_GRP_ID */
|
||||
|
@ -247,6 +280,25 @@ static int stats_put_phy_stats(struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stats_put_phydev_stats(struct sk_buff *skb,
|
||||
const struct stats_reply_data *data)
|
||||
{
|
||||
if (stat_put(skb, ETHTOOL_A_STATS_PHY_RX_PKTS,
|
||||
data->phydev_stats.rx_packets) ||
|
||||
stat_put(skb, ETHTOOL_A_STATS_PHY_RX_BYTES,
|
||||
data->phydev_stats.rx_bytes) ||
|
||||
stat_put(skb, ETHTOOL_A_STATS_PHY_RX_ERRORS,
|
||||
data->phydev_stats.rx_errors) ||
|
||||
stat_put(skb, ETHTOOL_A_STATS_PHY_TX_PKTS,
|
||||
data->phydev_stats.tx_packets) ||
|
||||
stat_put(skb, ETHTOOL_A_STATS_PHY_TX_BYTES,
|
||||
data->phydev_stats.tx_bytes) ||
|
||||
stat_put(skb, ETHTOOL_A_STATS_PHY_TX_ERRORS,
|
||||
data->phydev_stats.tx_errors))
|
||||
return -EMSGSIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stats_put_mac_stats(struct sk_buff *skb,
|
||||
const struct stats_reply_data *data)
|
||||
{
|
||||
|
@ -423,6 +475,9 @@ static int stats_fill_reply(struct sk_buff *skb,
|
|||
if (!ret && test_bit(ETHTOOL_STATS_RMON, req_info->stat_mask))
|
||||
ret = stats_put_stats(skb, data, ETHTOOL_STATS_RMON,
|
||||
ETH_SS_STATS_RMON, stats_put_rmon_stats);
|
||||
if (!ret && test_bit(ETHTOOL_STATS_PHY, req_info->stat_mask))
|
||||
ret = stats_put_stats(skb, data, ETHTOOL_STATS_PHY,
|
||||
ETH_SS_STATS_PHY, stats_put_phydev_stats);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,11 @@ static const struct strset_info info_template[] = {
|
|||
.count = __HWTSTAMP_FILTER_CNT,
|
||||
.strings = ts_rx_filter_names,
|
||||
},
|
||||
[ETH_SS_TS_FLAGS] = {
|
||||
.per_dev = false,
|
||||
.count = __HWTSTAMP_FLAG_CNT,
|
||||
.strings = ts_flags_names,
|
||||
},
|
||||
[ETH_SS_UDP_TUNNEL_TYPES] = {
|
||||
.per_dev = false,
|
||||
.count = __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
|
||||
|
@ -105,6 +110,11 @@ static const struct strset_info info_template[] = {
|
|||
.count = __ETHTOOL_A_STATS_RMON_CNT,
|
||||
.strings = stats_rmon_names,
|
||||
},
|
||||
[ETH_SS_STATS_PHY] = {
|
||||
.per_dev = false,
|
||||
.count = __ETHTOOL_A_STATS_PHY_CNT,
|
||||
.strings = stats_phy_names,
|
||||
},
|
||||
};
|
||||
|
||||
struct strset_req_info {
|
||||
|
@ -299,7 +309,7 @@ static int strset_prepare_data(const struct ethnl_req_info *req_base,
|
|||
return 0;
|
||||
}
|
||||
|
||||
phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS],
|
||||
phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS,
|
||||
info->extack);
|
||||
|
||||
/* phydev can be NULL, check for errors only */
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef _NET_ETHTOOL_TS_H
|
||||
#define _NET_ETHTOOL_TS_H
|
||||
|
||||
#include "netlink.h"
|
||||
|
||||
static const struct nla_policy
|
||||
ethnl_ts_hwtst_prov_policy[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX + 1] = {
|
||||
[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX] = { .type = NLA_U32 },
|
||||
[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER] =
|
||||
NLA_POLICY_MAX(NLA_U32, HWTSTAMP_PROVIDER_QUALIFIER_CNT - 1)
|
||||
};
|
||||
|
||||
int ts_parse_hwtst_provider(const struct nlattr *nest,
|
||||
struct hwtstamp_provider_desc *hwprov_desc,
|
||||
struct netlink_ext_ack *extack,
|
||||
bool *mod);
|
||||
|
||||
#endif /* _NET_ETHTOOL_TS_H */
|
|
@ -0,0 +1,457 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "bitset.h"
|
||||
#include "../core/dev.h"
|
||||
#include "ts.h"
|
||||
|
||||
struct tsconfig_req_info {
|
||||
struct ethnl_req_info base;
|
||||
};
|
||||
|
||||
struct tsconfig_reply_data {
|
||||
struct ethnl_reply_data base;
|
||||
struct hwtstamp_provider_desc hwprov_desc;
|
||||
struct {
|
||||
u32 tx_type;
|
||||
u32 rx_filter;
|
||||
u32 flags;
|
||||
} hwtst_config;
|
||||
};
|
||||
|
||||
#define TSCONFIG_REPDATA(__reply_base) \
|
||||
container_of(__reply_base, struct tsconfig_reply_data, base)
|
||||
|
||||
const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1] = {
|
||||
[ETHTOOL_A_TSCONFIG_HEADER] =
|
||||
NLA_POLICY_NESTED(ethnl_header_policy),
|
||||
};
|
||||
|
||||
static int tsconfig_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
|
||||
struct hwtstamp_provider *hwprov = NULL;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
struct kernel_hwtstamp_config cfg = {};
|
||||
int ret;
|
||||
|
||||
if (!dev->netdev_ops->ndo_hwtstamp_get)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = dev_get_hwtstamp_phylib(dev, &cfg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
data->hwtst_config.tx_type = BIT(cfg.tx_type);
|
||||
data->hwtst_config.rx_filter = BIT(cfg.rx_filter);
|
||||
data->hwtst_config.flags = cfg.flags;
|
||||
|
||||
data->hwprov_desc.index = -1;
|
||||
hwprov = rtnl_dereference(dev->hwprov);
|
||||
if (hwprov) {
|
||||
data->hwprov_desc.index = hwprov->desc.index;
|
||||
data->hwprov_desc.qualifier = hwprov->desc.qualifier;
|
||||
} else {
|
||||
struct kernel_ethtool_ts_info ts_info = {};
|
||||
|
||||
ts_info.phc_index = -1;
|
||||
ret = __ethtool_get_ts_info(dev, &ts_info);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (ts_info.phc_index == -1)
|
||||
return -ENODEV;
|
||||
|
||||
data->hwprov_desc.index = ts_info.phc_index;
|
||||
data->hwprov_desc.qualifier = ts_info.phc_qualifier;
|
||||
}
|
||||
|
||||
out:
|
||||
ethnl_ops_complete(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tsconfig_reply_size(const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
|
||||
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
int len = 0;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32);
|
||||
BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32);
|
||||
BUILD_BUG_ON(__HWTSTAMP_FLAG_CNT > 32);
|
||||
|
||||
if (data->hwtst_config.flags) {
|
||||
ret = ethnl_bitset32_size(&data->hwtst_config.flags,
|
||||
NULL, __HWTSTAMP_FLAG_CNT,
|
||||
ts_flags_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret; /* _TSCONFIG_HWTSTAMP_FLAGS */
|
||||
}
|
||||
|
||||
if (data->hwtst_config.tx_type) {
|
||||
ret = ethnl_bitset32_size(&data->hwtst_config.tx_type,
|
||||
NULL, __HWTSTAMP_TX_CNT,
|
||||
ts_tx_type_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret; /* _TSCONFIG_TX_TYPES */
|
||||
}
|
||||
if (data->hwtst_config.rx_filter) {
|
||||
ret = ethnl_bitset32_size(&data->hwtst_config.rx_filter,
|
||||
NULL, __HWTSTAMP_FILTER_CNT,
|
||||
ts_rx_filter_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len += ret; /* _TSCONFIG_RX_FILTERS */
|
||||
}
|
||||
|
||||
if (data->hwprov_desc.index >= 0)
|
||||
/* _TSCONFIG_HWTSTAMP_PROVIDER */
|
||||
len += nla_total_size(0) +
|
||||
2 * nla_total_size(sizeof(u32));
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int tsconfig_fill_reply(struct sk_buff *skb,
|
||||
const struct ethnl_req_info *req_base,
|
||||
const struct ethnl_reply_data *reply_base)
|
||||
{
|
||||
const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base);
|
||||
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
int ret;
|
||||
|
||||
if (data->hwtst_config.flags) {
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS,
|
||||
&data->hwtst_config.flags, NULL,
|
||||
__HWTSTAMP_FLAG_CNT,
|
||||
ts_flags_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data->hwtst_config.tx_type) {
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_TX_TYPES,
|
||||
&data->hwtst_config.tx_type, NULL,
|
||||
__HWTSTAMP_TX_CNT,
|
||||
ts_tx_type_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data->hwtst_config.rx_filter) {
|
||||
ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_RX_FILTERS,
|
||||
&data->hwtst_config.rx_filter,
|
||||
NULL, __HWTSTAMP_FILTER_CNT,
|
||||
ts_rx_filter_names, compact);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data->hwprov_desc.index >= 0) {
|
||||
struct nlattr *nest;
|
||||
|
||||
nest = nla_nest_start(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER);
|
||||
if (!nest)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
|
||||
data->hwprov_desc.index) ||
|
||||
nla_put_u32(skb,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
|
||||
data->hwprov_desc.qualifier)) {
|
||||
nla_nest_cancel(skb, nest);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TSCONFIG_SET */
|
||||
const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1] = {
|
||||
[ETHTOOL_A_TSCONFIG_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
|
||||
[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER] =
|
||||
NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy),
|
||||
[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_TSCONFIG_RX_FILTERS] = { .type = NLA_NESTED },
|
||||
[ETHTOOL_A_TSCONFIG_TX_TYPES] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct tsconfig_reply_data *reply_data;
|
||||
struct tsconfig_req_info *req_info;
|
||||
struct sk_buff *rskb;
|
||||
void *reply_payload;
|
||||
int reply_len = 0;
|
||||
int ret;
|
||||
|
||||
req_info = kzalloc(sizeof(*req_info), GFP_KERNEL);
|
||||
if (!req_info)
|
||||
return -ENOMEM;
|
||||
reply_data = kmalloc(sizeof(*reply_data), GFP_KERNEL);
|
||||
if (!reply_data) {
|
||||
kfree(req_info);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ASSERT_RTNL();
|
||||
reply_data->base.dev = dev;
|
||||
ret = tsconfig_prepare_data(&req_info->base, &reply_data->base, info);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
||||
ret = tsconfig_reply_size(&req_info->base, &reply_data->base);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
||||
reply_len = ret + ethnl_reply_header_size();
|
||||
rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY,
|
||||
ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload);
|
||||
if (!rskb)
|
||||
goto err_cleanup;
|
||||
|
||||
ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
||||
genlmsg_end(rskb, reply_payload);
|
||||
ret = genlmsg_reply(rskb, info);
|
||||
|
||||
err_cleanup:
|
||||
kfree(reply_data);
|
||||
kfree(req_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethnl_set_tsconfig_validate(struct ethnl_req_info *req_base,
|
||||
struct genl_info *info)
|
||||
{
|
||||
const struct net_device_ops *ops = req_base->dev->netdev_ops;
|
||||
|
||||
if (!ops->ndo_hwtstamp_set || !ops->ndo_hwtstamp_get)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct hwtstamp_provider *
|
||||
tsconfig_set_hwprov_from_desc(struct net_device *dev,
|
||||
struct genl_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
struct kernel_ethtool_ts_info ts_info;
|
||||
struct hwtstamp_provider *hwprov;
|
||||
struct nlattr **tb = info->attrs;
|
||||
struct phy_device *phy = NULL;
|
||||
enum hwtstamp_source source;
|
||||
int ret;
|
||||
|
||||
ret = ethtool_net_get_ts_info_by_phc(dev, &ts_info, hwprov_desc);
|
||||
if (!ret) {
|
||||
/* Found */
|
||||
source = HWTSTAMP_SOURCE_NETDEV;
|
||||
} else {
|
||||
phy = ethtool_phy_get_ts_info_by_phc(dev, &ts_info, hwprov_desc);
|
||||
if (IS_ERR(phy)) {
|
||||
if (PTR_ERR(phy) == -ENODEV)
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER],
|
||||
"phc not in this net device topology");
|
||||
return ERR_CAST(phy);
|
||||
}
|
||||
|
||||
source = HWTSTAMP_SOURCE_PHYLIB;
|
||||
}
|
||||
|
||||
hwprov = kzalloc(sizeof(*hwprov), GFP_KERNEL);
|
||||
if (!hwprov)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hwprov->desc.index = hwprov_desc->index;
|
||||
hwprov->desc.qualifier = hwprov_desc->qualifier;
|
||||
hwprov->source = source;
|
||||
hwprov->phydev = phy;
|
||||
|
||||
return hwprov;
|
||||
}
|
||||
|
||||
static int ethnl_set_tsconfig(struct ethnl_req_info *req_base,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct kernel_hwtstamp_config hwtst_config = {0};
|
||||
bool hwprov_mod = false, config_mod = false;
|
||||
struct hwtstamp_provider *hwprov = NULL;
|
||||
struct net_device *dev = req_base->dev;
|
||||
struct nlattr **tb = info->attrs;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(__HWTSTAMP_TX_CNT >= 32);
|
||||
BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT >= 32);
|
||||
BUILD_BUG_ON(__HWTSTAMP_FLAG_CNT > 32);
|
||||
|
||||
if (!netif_device_present(dev))
|
||||
return -ENODEV;
|
||||
|
||||
if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER]) {
|
||||
struct hwtstamp_provider_desc __hwprov_desc = {.index = -1};
|
||||
struct hwtstamp_provider *__hwprov;
|
||||
|
||||
__hwprov = rtnl_dereference(dev->hwprov);
|
||||
if (__hwprov) {
|
||||
__hwprov_desc.index = __hwprov->desc.index;
|
||||
__hwprov_desc.qualifier = __hwprov->desc.qualifier;
|
||||
}
|
||||
|
||||
ret = ts_parse_hwtst_provider(tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER],
|
||||
&__hwprov_desc, info->extack,
|
||||
&hwprov_mod);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (hwprov_mod) {
|
||||
hwprov = tsconfig_set_hwprov_from_desc(dev, info,
|
||||
&__hwprov_desc);
|
||||
if (IS_ERR(hwprov))
|
||||
return PTR_ERR(hwprov);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get current hwtstamp config if we are not changing the
|
||||
* hwtstamp source. It will be zeroed in the other case.
|
||||
*/
|
||||
if (!hwprov_mod) {
|
||||
ret = dev_get_hwtstamp_phylib(dev, &hwtst_config);
|
||||
if (ret < 0 && ret != -EOPNOTSUPP)
|
||||
goto err_free_hwprov;
|
||||
}
|
||||
|
||||
/* Get the hwtstamp config from netlink */
|
||||
if (tb[ETHTOOL_A_TSCONFIG_TX_TYPES]) {
|
||||
u32 req_tx_type;
|
||||
|
||||
req_tx_type = BIT(hwtst_config.tx_type);
|
||||
ret = ethnl_update_bitset32(&req_tx_type,
|
||||
__HWTSTAMP_TX_CNT,
|
||||
tb[ETHTOOL_A_TSCONFIG_TX_TYPES],
|
||||
ts_tx_type_names, info->extack,
|
||||
&config_mod);
|
||||
if (ret < 0)
|
||||
goto err_free_hwprov;
|
||||
|
||||
/* Select only one tx type at a time */
|
||||
if (ffs(req_tx_type) != fls(req_tx_type)) {
|
||||
ret = -EINVAL;
|
||||
goto err_free_hwprov;
|
||||
}
|
||||
|
||||
hwtst_config.tx_type = ffs(req_tx_type) - 1;
|
||||
}
|
||||
|
||||
if (tb[ETHTOOL_A_TSCONFIG_RX_FILTERS]) {
|
||||
u32 req_rx_filter;
|
||||
|
||||
req_rx_filter = BIT(hwtst_config.rx_filter);
|
||||
ret = ethnl_update_bitset32(&req_rx_filter,
|
||||
__HWTSTAMP_FILTER_CNT,
|
||||
tb[ETHTOOL_A_TSCONFIG_RX_FILTERS],
|
||||
ts_rx_filter_names, info->extack,
|
||||
&config_mod);
|
||||
if (ret < 0)
|
||||
goto err_free_hwprov;
|
||||
|
||||
/* Select only one rx filter at a time */
|
||||
if (ffs(req_rx_filter) != fls(req_rx_filter)) {
|
||||
ret = -EINVAL;
|
||||
goto err_free_hwprov;
|
||||
}
|
||||
|
||||
hwtst_config.rx_filter = ffs(req_rx_filter) - 1;
|
||||
}
|
||||
|
||||
if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS]) {
|
||||
ret = ethnl_update_bitset32(&hwtst_config.flags,
|
||||
__HWTSTAMP_FLAG_CNT,
|
||||
tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS],
|
||||
ts_flags_names, info->extack,
|
||||
&config_mod);
|
||||
if (ret < 0)
|
||||
goto err_free_hwprov;
|
||||
}
|
||||
|
||||
ret = net_hwtstamp_validate(&hwtst_config);
|
||||
if (ret)
|
||||
goto err_free_hwprov;
|
||||
|
||||
if (hwprov_mod) {
|
||||
struct kernel_hwtstamp_config zero_config = {0};
|
||||
struct hwtstamp_provider *__hwprov;
|
||||
|
||||
/* Disable current time stamping if we try to enable
|
||||
* another one
|
||||
*/
|
||||
ret = dev_set_hwtstamp_phylib(dev, &zero_config, info->extack);
|
||||
if (ret < 0)
|
||||
goto err_free_hwprov;
|
||||
|
||||
/* Change the selected hwtstamp source */
|
||||
__hwprov = rcu_replace_pointer_rtnl(dev->hwprov, hwprov);
|
||||
if (__hwprov)
|
||||
kfree_rcu(__hwprov, rcu_head);
|
||||
}
|
||||
|
||||
if (config_mod) {
|
||||
ret = dev_set_hwtstamp_phylib(dev, &hwtst_config,
|
||||
info->extack);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hwprov_mod || config_mod) {
|
||||
ret = tsconfig_send_reply(dev, info);
|
||||
if (ret && ret != -EOPNOTSUPP) {
|
||||
NL_SET_ERR_MSG(info->extack,
|
||||
"error while reading the new configuration set");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* tsconfig has no notification */
|
||||
return 0;
|
||||
|
||||
err_free_hwprov:
|
||||
kfree(hwprov);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct ethnl_request_ops ethnl_tsconfig_request_ops = {
|
||||
.request_cmd = ETHTOOL_MSG_TSCONFIG_GET,
|
||||
.reply_cmd = ETHTOOL_MSG_TSCONFIG_GET_REPLY,
|
||||
.hdr_attr = ETHTOOL_A_TSCONFIG_HEADER,
|
||||
.req_info_size = sizeof(struct tsconfig_req_info),
|
||||
.reply_data_size = sizeof(struct tsconfig_reply_data),
|
||||
|
||||
.prepare_data = tsconfig_prepare_data,
|
||||
.reply_size = tsconfig_reply_size,
|
||||
.fill_reply = tsconfig_fill_reply,
|
||||
|
||||
.set_validate = ethnl_set_tsconfig_validate,
|
||||
.set = ethnl_set_tsconfig,
|
||||
};
|
|
@ -1,13 +1,18 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_link_topology.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "bitset.h"
|
||||
#include "ts.h"
|
||||
|
||||
struct tsinfo_req_info {
|
||||
struct ethnl_req_info base;
|
||||
struct hwtstamp_provider_desc hwprov_desc;
|
||||
};
|
||||
|
||||
struct tsinfo_reply_data {
|
||||
|
@ -16,34 +21,96 @@ struct tsinfo_reply_data {
|
|||
struct ethtool_ts_stats stats;
|
||||
};
|
||||
|
||||
#define TSINFO_REQINFO(__req_base) \
|
||||
container_of(__req_base, struct tsinfo_req_info, base)
|
||||
|
||||
#define TSINFO_REPDATA(__reply_base) \
|
||||
container_of(__reply_base, struct tsinfo_reply_data, base)
|
||||
|
||||
#define ETHTOOL_TS_STAT_CNT \
|
||||
(__ETHTOOL_A_TS_STAT_CNT - (ETHTOOL_A_TS_STAT_UNSPEC + 1))
|
||||
|
||||
const struct nla_policy ethnl_tsinfo_get_policy[] = {
|
||||
const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1] = {
|
||||
[ETHTOOL_A_TSINFO_HEADER] =
|
||||
NLA_POLICY_NESTED(ethnl_header_policy_stats),
|
||||
[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER] =
|
||||
NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy),
|
||||
};
|
||||
|
||||
int ts_parse_hwtst_provider(const struct nlattr *nest,
|
||||
struct hwtstamp_provider_desc *hwprov_desc,
|
||||
struct netlink_ext_ack *extack,
|
||||
bool *mod)
|
||||
{
|
||||
struct nlattr *tb[ARRAY_SIZE(ethnl_ts_hwtst_prov_policy)];
|
||||
int ret;
|
||||
|
||||
ret = nla_parse_nested(tb,
|
||||
ARRAY_SIZE(ethnl_ts_hwtst_prov_policy) - 1,
|
||||
nest,
|
||||
ethnl_ts_hwtst_prov_policy, extack);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (NL_REQ_ATTR_CHECK(extack, nest, tb,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX) ||
|
||||
NL_REQ_ATTR_CHECK(extack, nest, tb,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER))
|
||||
return -EINVAL;
|
||||
|
||||
ethnl_update_u32(&hwprov_desc->index,
|
||||
tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX],
|
||||
mod);
|
||||
ethnl_update_u32(&hwprov_desc->qualifier,
|
||||
tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER],
|
||||
mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tsinfo_parse_request(struct ethnl_req_info *req_base, struct nlattr **tb,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct tsinfo_req_info *req = TSINFO_REQINFO(req_base);
|
||||
bool mod = false;
|
||||
|
||||
req->hwprov_desc.index = -1;
|
||||
|
||||
if (!tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER])
|
||||
return 0;
|
||||
|
||||
return ts_parse_hwtst_provider(tb[ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER],
|
||||
&req->hwprov_desc, extack, &mod);
|
||||
}
|
||||
|
||||
static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
|
||||
struct tsinfo_req_info *req = TSINFO_REQINFO(req_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
ret = ethnl_ops_begin(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (req->hwprov_desc.index != -1) {
|
||||
ret = ethtool_get_ts_info_by_phc(dev, &data->ts_info,
|
||||
&req->hwprov_desc);
|
||||
ethnl_ops_complete(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (req_base->flags & ETHTOOL_FLAG_STATS) {
|
||||
ethtool_stats_init((u64 *)&data->stats,
|
||||
sizeof(data->stats) / sizeof(u64));
|
||||
if (dev->ethtool_ops->get_ts_stats)
|
||||
dev->ethtool_ops->get_ts_stats(dev, &data->stats);
|
||||
}
|
||||
|
||||
ret = __ethtool_get_ts_info(dev, &data->ts_info);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
|
@ -87,8 +154,11 @@ static int tsinfo_reply_size(const struct ethnl_req_info *req_base,
|
|||
return ret;
|
||||
len += ret; /* _TSINFO_RX_FILTERS */
|
||||
}
|
||||
if (ts_info->phc_index >= 0)
|
||||
if (ts_info->phc_index >= 0) {
|
||||
len += nla_total_size(sizeof(u32)); /* _TSINFO_PHC_INDEX */
|
||||
/* _TSINFO_HWTSTAMP_PROVIDER */
|
||||
len += nla_total_size(0) + 2 * nla_total_size(sizeof(u32));
|
||||
}
|
||||
if (req_base->flags & ETHTOOL_FLAG_STATS)
|
||||
len += nla_total_size(0) + /* _TSINFO_STATS */
|
||||
nla_total_size_64bit(sizeof(u64)) * ETHTOOL_TS_STAT_CNT;
|
||||
|
@ -116,6 +186,8 @@ static int tsinfo_put_stats(struct sk_buff *skb,
|
|||
|
||||
if (tsinfo_put_stat(skb, stats->tx_stats.pkts,
|
||||
ETHTOOL_A_TS_STAT_TX_PKTS) ||
|
||||
tsinfo_put_stat(skb, stats->tx_stats.onestep_pkts_unconfirmed,
|
||||
ETHTOOL_A_TS_STAT_TX_ONESTEP_PKTS_UNCONFIRMED) ||
|
||||
tsinfo_put_stat(skb, stats->tx_stats.lost,
|
||||
ETHTOOL_A_TS_STAT_TX_LOST) ||
|
||||
tsinfo_put_stat(skb, stats->tx_stats.err,
|
||||
|
@ -163,9 +235,29 @@ static int tsinfo_fill_reply(struct sk_buff *skb,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ts_info->phc_index >= 0 &&
|
||||
nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX, ts_info->phc_index))
|
||||
return -EMSGSIZE;
|
||||
if (ts_info->phc_index >= 0) {
|
||||
struct nlattr *nest;
|
||||
|
||||
ret = nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX,
|
||||
ts_info->phc_index);
|
||||
if (ret)
|
||||
return -EMSGSIZE;
|
||||
|
||||
nest = nla_nest_start(skb, ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER);
|
||||
if (!nest)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
|
||||
ts_info->phc_index) ||
|
||||
nla_put_u32(skb,
|
||||
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
|
||||
ts_info->phc_qualifier)) {
|
||||
nla_nest_cancel(skb, nest);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
}
|
||||
if (req_base->flags & ETHTOOL_FLAG_STATS &&
|
||||
tsinfo_put_stats(skb, &data->stats))
|
||||
return -EMSGSIZE;
|
||||
|
@ -173,6 +265,264 @@ static int tsinfo_fill_reply(struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct ethnl_tsinfo_dump_ctx {
|
||||
struct tsinfo_req_info *req_info;
|
||||
struct tsinfo_reply_data *reply_data;
|
||||
unsigned long pos_ifindex;
|
||||
bool netdev_dump_done;
|
||||
unsigned long pos_phyindex;
|
||||
enum hwtstamp_provider_qualifier pos_phcqualifier;
|
||||
};
|
||||
|
||||
static void *ethnl_tsinfo_prepare_dump(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct tsinfo_reply_data *reply_data,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
void *ehdr = NULL;
|
||||
|
||||
ehdr = ethnl_dump_put(skb, cb,
|
||||
ETHTOOL_MSG_TSINFO_GET_REPLY);
|
||||
if (!ehdr)
|
||||
return ERR_PTR(-EMSGSIZE);
|
||||
|
||||
reply_data = ctx->reply_data;
|
||||
memset(reply_data, 0, sizeof(*reply_data));
|
||||
reply_data->base.dev = dev;
|
||||
reply_data->ts_info.cmd = ETHTOOL_GET_TS_INFO;
|
||||
reply_data->ts_info.phc_index = -1;
|
||||
|
||||
return ehdr;
|
||||
}
|
||||
|
||||
static int ethnl_tsinfo_end_dump(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct tsinfo_req_info *req_info,
|
||||
struct tsinfo_reply_data *reply_data,
|
||||
void *ehdr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
reply_data->ts_info.so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
|
||||
ret = ethnl_fill_reply_header(skb, dev, ETHTOOL_A_TSINFO_HEADER);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = tsinfo_fill_reply(skb, &req_info->base, &reply_data->base);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
reply_data->base.dev = NULL;
|
||||
genlmsg_end(skb, ehdr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethnl_tsinfo_dump_one_phydev(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct phy_device *phydev,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
struct tsinfo_reply_data *reply_data;
|
||||
struct tsinfo_req_info *req_info;
|
||||
void *ehdr = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!phy_has_tsinfo(phydev))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
reply_data = ctx->reply_data;
|
||||
req_info = ctx->req_info;
|
||||
ehdr = ethnl_tsinfo_prepare_dump(skb, dev, reply_data, cb);
|
||||
if (IS_ERR(ehdr))
|
||||
return PTR_ERR(ehdr);
|
||||
|
||||
ret = phy_ts_info(phydev, &reply_data->ts_info);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = ethnl_tsinfo_end_dump(skb, dev, req_info, reply_data, ehdr);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return ret;
|
||||
err:
|
||||
genlmsg_cancel(skb, ehdr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethnl_tsinfo_dump_one_netdev(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct tsinfo_reply_data *reply_data;
|
||||
struct tsinfo_req_info *req_info;
|
||||
void *ehdr = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!ops->get_ts_info)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
reply_data = ctx->reply_data;
|
||||
req_info = ctx->req_info;
|
||||
for (; ctx->pos_phcqualifier < HWTSTAMP_PROVIDER_QUALIFIER_CNT;
|
||||
ctx->pos_phcqualifier++) {
|
||||
if (!net_support_hwtstamp_qualifier(dev,
|
||||
ctx->pos_phcqualifier))
|
||||
continue;
|
||||
|
||||
ehdr = ethnl_tsinfo_prepare_dump(skb, dev, reply_data, cb);
|
||||
if (IS_ERR(ehdr)) {
|
||||
ret = PTR_ERR(ehdr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
reply_data->ts_info.phc_qualifier = ctx->pos_phcqualifier;
|
||||
ret = ops->get_ts_info(dev, &reply_data->ts_info);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = ethnl_tsinfo_end_dump(skb, dev, req_info, reply_data,
|
||||
ehdr);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
genlmsg_cancel(skb, ehdr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethnl_tsinfo_dump_one_net_topo(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
struct phy_device_node *pdn;
|
||||
int ret = 0;
|
||||
|
||||
if (!ctx->netdev_dump_done) {
|
||||
ret = ethnl_tsinfo_dump_one_netdev(skb, dev, cb);
|
||||
if (ret < 0 && ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
ctx->netdev_dump_done = true;
|
||||
}
|
||||
|
||||
if (!dev->link_topo) {
|
||||
if (phy_has_tsinfo(dev->phydev)) {
|
||||
ret = ethnl_tsinfo_dump_one_phydev(skb, dev,
|
||||
dev->phydev, cb);
|
||||
if (ret < 0 && ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
xa_for_each_start(&dev->link_topo->phys, ctx->pos_phyindex, pdn,
|
||||
ctx->pos_phyindex) {
|
||||
if (phy_has_tsinfo(pdn->phy)) {
|
||||
ret = ethnl_tsinfo_dump_one_phydev(skb, dev,
|
||||
pdn->phy, cb);
|
||||
if (ret < 0 && ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct net_device *dev;
|
||||
int ret = 0;
|
||||
|
||||
rtnl_lock();
|
||||
if (ctx->req_info->base.dev) {
|
||||
ret = ethnl_tsinfo_dump_one_net_topo(skb,
|
||||
ctx->req_info->base.dev,
|
||||
cb);
|
||||
} else {
|
||||
for_each_netdev_dump(net, dev, ctx->pos_ifindex) {
|
||||
ret = ethnl_tsinfo_dump_one_net_topo(skb, dev, cb);
|
||||
if (ret < 0 && ret != -EOPNOTSUPP)
|
||||
break;
|
||||
ctx->pos_phyindex = 0;
|
||||
ctx->netdev_dump_done = false;
|
||||
ctx->pos_phcqualifier = HWTSTAMP_PROVIDER_QUALIFIER_PRECISE;
|
||||
}
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ethnl_tsinfo_start(struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
struct nlattr **tb = info->info.attrs;
|
||||
struct tsinfo_reply_data *reply_data;
|
||||
struct tsinfo_req_info *req_info;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
|
||||
|
||||
req_info = kzalloc(sizeof(*req_info), GFP_KERNEL);
|
||||
if (!req_info)
|
||||
return -ENOMEM;
|
||||
reply_data = kzalloc(sizeof(*reply_data), GFP_KERNEL);
|
||||
if (!reply_data) {
|
||||
ret = -ENOMEM;
|
||||
goto free_req_info;
|
||||
}
|
||||
|
||||
ret = ethnl_parse_header_dev_get(&req_info->base,
|
||||
tb[ETHTOOL_A_TSINFO_HEADER],
|
||||
sock_net(cb->skb->sk), cb->extack,
|
||||
false);
|
||||
if (ret < 0)
|
||||
goto free_reply_data;
|
||||
|
||||
ctx->req_info = req_info;
|
||||
ctx->reply_data = reply_data;
|
||||
ctx->pos_ifindex = 0;
|
||||
ctx->pos_phyindex = 0;
|
||||
ctx->netdev_dump_done = false;
|
||||
ctx->pos_phcqualifier = HWTSTAMP_PROVIDER_QUALIFIER_PRECISE;
|
||||
|
||||
return 0;
|
||||
|
||||
free_reply_data:
|
||||
kfree(reply_data);
|
||||
free_req_info:
|
||||
kfree(req_info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ethnl_tsinfo_done(struct netlink_callback *cb)
|
||||
{
|
||||
struct ethnl_tsinfo_dump_ctx *ctx = (void *)cb->ctx;
|
||||
struct tsinfo_req_info *req_info = ctx->req_info;
|
||||
|
||||
ethnl_parse_header_dev_put(&req_info->base);
|
||||
kfree(ctx->reply_data);
|
||||
kfree(ctx->req_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethnl_request_ops ethnl_tsinfo_request_ops = {
|
||||
.request_cmd = ETHTOOL_MSG_TSINFO_GET,
|
||||
.reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY,
|
||||
|
@ -180,6 +530,7 @@ const struct ethnl_request_ops ethnl_tsinfo_request_ops = {
|
|||
.req_info_size = sizeof(struct tsinfo_req_info),
|
||||
.reply_data_size = sizeof(struct tsinfo_reply_data),
|
||||
|
||||
.parse_request = tsinfo_parse_request,
|
||||
.prepare_data = tsinfo_prepare_data,
|
||||
.reply_size = tsinfo_reply_size,
|
||||
.fill_reply = tsinfo_fill_reply,
|
||||
|
|
|
@ -2391,6 +2391,7 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
|
|||
struct scm_timestamping_internal *tss)
|
||||
{
|
||||
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
|
||||
u32 tsflags = READ_ONCE(sk->sk_tsflags);
|
||||
bool has_timestamping = false;
|
||||
|
||||
if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) {
|
||||
|
@ -2430,14 +2431,18 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
|
|||
}
|
||||
}
|
||||
|
||||
if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
|
||||
if (tsflags & SOF_TIMESTAMPING_SOFTWARE &&
|
||||
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
|
||||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
|
||||
has_timestamping = true;
|
||||
else
|
||||
tss->ts[0] = (struct timespec64) {0};
|
||||
}
|
||||
|
||||
if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
|
||||
if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)
|
||||
if (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
|
||||
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
|
||||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
|
||||
has_timestamping = true;
|
||||
else
|
||||
tss->ts[2] = (struct timespec64) {0};
|
||||
|
|
12
net/socket.c
12
net/socket.c
|
@ -901,6 +901,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
|
|||
skb_hwtstamps(skb);
|
||||
int if_index;
|
||||
ktime_t hwtstamp;
|
||||
u32 tsflags;
|
||||
|
||||
/* Race occurred between timestamp enabling and packet
|
||||
receiving. Fill in the current time for now. */
|
||||
|
@ -942,11 +943,18 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
|
|||
}
|
||||
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
|
||||
tsflags = READ_ONCE(sk->sk_tsflags);
|
||||
if ((tsflags & SOF_TIMESTAMPING_SOFTWARE &&
|
||||
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
|
||||
skb_is_err_queue(skb) ||
|
||||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) &&
|
||||
ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0))
|
||||
empty = 0;
|
||||
if (shhwtstamps &&
|
||||
(sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
|
||||
(tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
|
||||
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
|
||||
skb_is_err_queue(skb) ||
|
||||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) &&
|
||||
!skb_is_swtx_tstamp(skb, false_tstamp)) {
|
||||
if_index = 0;
|
||||
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV)
|
||||
|
|
|
@ -17,7 +17,8 @@ get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2)
|
|||
CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h)
|
||||
CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H,dpll.h)
|
||||
CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_H,ethtool.h) \
|
||||
$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h)
|
||||
$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) \
|
||||
$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_GENERATED_H,ethtool_netlink_generated.h)
|
||||
CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h)
|
||||
CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H,mptcp_pm.h)
|
||||
CFLAGS_net_shaper:=$(call get_hdr_inc,_LINUX_NET_SHAPER_H,net_shaper.h)
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
|
||||
import argparse
|
||||
import json
|
||||
import pathlib
|
||||
import pprint
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
|
||||
from lib import YnlFamily, Netlink, NlError
|
||||
|
||||
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
import argparse
|
||||
import json
|
||||
import pathlib
|
||||
import pprint
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
|
||||
from lib import YnlFamily
|
||||
|
||||
def args_to_req(ynl, op_name, args, req):
|
||||
|
@ -337,16 +339,24 @@ def main():
|
|||
print('Capabilities:')
|
||||
[print(f'\t{v}') for v in bits_to_dict(tsinfo['timestamping'])]
|
||||
|
||||
print(f'PTP Hardware Clock: {tsinfo["phc-index"]}')
|
||||
print(f'PTP Hardware Clock: {tsinfo.get("phc-index", "none")}')
|
||||
|
||||
print('Hardware Transmit Timestamp Modes:')
|
||||
[print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])]
|
||||
if 'tx-types' in tsinfo:
|
||||
print('Hardware Transmit Timestamp Modes:')
|
||||
[print(f'\t{v}') for v in bits_to_dict(tsinfo['tx-types'])]
|
||||
else:
|
||||
print('Hardware Transmit Timestamp Modes: none')
|
||||
|
||||
print('Hardware Receive Filter Modes:')
|
||||
[print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])]
|
||||
if 'rx-filters' in tsinfo:
|
||||
print('Hardware Receive Filter Modes:')
|
||||
[print(f'\t{v}') for v in bits_to_dict(tsinfo['rx-filters'])]
|
||||
else:
|
||||
print('Hardware Receive Filter Modes: none')
|
||||
|
||||
if 'stats' in tsinfo and tsinfo['stats']:
|
||||
print('Statistics:')
|
||||
[print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()]
|
||||
|
||||
print('Statistics:')
|
||||
[print(f'\t{k}: {v}') for k, v in tsinfo['stats'].items()]
|
||||
return
|
||||
|
||||
print(f'Settings for {args.device}:')
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
import argparse
|
||||
import collections
|
||||
import filecmp
|
||||
import pathlib
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import yaml
|
||||
|
||||
sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
|
||||
from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
|
||||
|
||||
|
||||
|
@ -793,6 +796,8 @@ class EnumSet(SpecEnumSet):
|
|||
self.user_type = 'int'
|
||||
|
||||
self.value_pfx = yaml.get('name-prefix', f"{family.ident_name}-{yaml['name']}-")
|
||||
self.header = yaml.get('header', None)
|
||||
self.enum_cnt_name = yaml.get('enum-cnt-name', None)
|
||||
|
||||
super().__init__(family, yaml)
|
||||
|
||||
|
@ -2409,6 +2414,87 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'):
|
|||
cw.block_start(line=start_line)
|
||||
|
||||
|
||||
def render_uapi_unified(family, cw, max_by_define, separate_ntf):
|
||||
max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
|
||||
cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
|
||||
max_value = f"({cnt_name} - 1)"
|
||||
|
||||
uapi_enum_start(family, cw, family['operations'], 'enum-name')
|
||||
val = 0
|
||||
for op in family.msgs.values():
|
||||
if separate_ntf and ('notify' in op or 'event' in op):
|
||||
continue
|
||||
|
||||
suffix = ','
|
||||
if op.value != val:
|
||||
suffix = f" = {op.value},"
|
||||
val = op.value
|
||||
cw.p(op.enum_name + suffix)
|
||||
val += 1
|
||||
cw.nl()
|
||||
cw.p(cnt_name + ('' if max_by_define else ','))
|
||||
if not max_by_define:
|
||||
cw.p(f"{max_name} = {max_value}")
|
||||
cw.block_end(line=';')
|
||||
if max_by_define:
|
||||
cw.p(f"#define {max_name} {max_value}")
|
||||
cw.nl()
|
||||
|
||||
|
||||
def render_uapi_directional(family, cw, max_by_define):
|
||||
max_name = f"{family.op_prefix}USER_MAX"
|
||||
cnt_name = f"__{family.op_prefix}USER_CNT"
|
||||
max_value = f"({cnt_name} - 1)"
|
||||
|
||||
cw.block_start(line='enum')
|
||||
cw.p(c_upper(f'{family.name}_MSG_USER_NONE = 0,'))
|
||||
val = 0
|
||||
for op in family.msgs.values():
|
||||
if 'do' in op and 'event' not in op:
|
||||
suffix = ','
|
||||
if op.value and op.value != val:
|
||||
suffix = f" = {op.value},"
|
||||
val = op.value
|
||||
cw.p(op.enum_name + suffix)
|
||||
val += 1
|
||||
cw.nl()
|
||||
cw.p(cnt_name + ('' if max_by_define else ','))
|
||||
if not max_by_define:
|
||||
cw.p(f"{max_name} = {max_value}")
|
||||
cw.block_end(line=';')
|
||||
if max_by_define:
|
||||
cw.p(f"#define {max_name} {max_value}")
|
||||
cw.nl()
|
||||
|
||||
max_name = f"{family.op_prefix}KERNEL_MAX"
|
||||
cnt_name = f"__{family.op_prefix}KERNEL_CNT"
|
||||
max_value = f"({cnt_name} - 1)"
|
||||
|
||||
cw.block_start(line='enum')
|
||||
cw.p(c_upper(f'{family.name}_MSG_KERNEL_NONE = 0,'))
|
||||
val = 0
|
||||
for op in family.msgs.values():
|
||||
if ('do' in op and 'reply' in op['do']) or 'notify' in op or 'event' in op:
|
||||
enum_name = op.enum_name
|
||||
if 'event' not in op and 'notify' not in op:
|
||||
enum_name = f'{enum_name}_REPLY'
|
||||
|
||||
suffix = ','
|
||||
if op.value and op.value != val:
|
||||
suffix = f" = {op.value},"
|
||||
val = op.value
|
||||
cw.p(enum_name + suffix)
|
||||
val += 1
|
||||
cw.nl()
|
||||
cw.p(cnt_name + ('' if max_by_define else ','))
|
||||
if not max_by_define:
|
||||
cw.p(f"{max_name} = {max_value}")
|
||||
cw.block_end(line=';')
|
||||
if max_by_define:
|
||||
cw.p(f"#define {max_name} {max_value}")
|
||||
cw.nl()
|
||||
|
||||
|
||||
def render_uapi(family, cw):
|
||||
hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H"
|
||||
cw.p('#ifndef ' + hdr_prot)
|
||||
|
@ -2431,6 +2517,9 @@ def render_uapi(family, cw):
|
|||
if const['type'] == 'enum' or const['type'] == 'flags':
|
||||
enum = family.consts[const['name']]
|
||||
|
||||
if enum.header:
|
||||
continue
|
||||
|
||||
if enum.has_doc():
|
||||
if enum.has_entry_doc():
|
||||
cw.p('/**')
|
||||
|
@ -2463,9 +2552,12 @@ def render_uapi(family, cw):
|
|||
max_val = f' = {enum.get_mask()},'
|
||||
cw.p(max_name + max_val)
|
||||
else:
|
||||
cnt_name = enum.enum_cnt_name
|
||||
max_name = c_upper(name_pfx + 'max')
|
||||
cw.p('__' + max_name + ',')
|
||||
cw.p(max_name + ' = (__' + max_name + ' - 1)')
|
||||
if not cnt_name:
|
||||
cnt_name = '__' + name_pfx + 'max'
|
||||
cw.p(c_upper(cnt_name) + ',')
|
||||
cw.p(max_name + ' = (' + c_upper(cnt_name) + ' - 1)')
|
||||
cw.block_end(line=';')
|
||||
cw.nl()
|
||||
elif const['type'] == 'const':
|
||||
|
@ -2506,30 +2598,12 @@ def render_uapi(family, cw):
|
|||
# Commands
|
||||
separate_ntf = 'async-prefix' in family['operations']
|
||||
|
||||
max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
|
||||
cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
|
||||
max_value = f"({cnt_name} - 1)"
|
||||
|
||||
uapi_enum_start(family, cw, family['operations'], 'enum-name')
|
||||
val = 0
|
||||
for op in family.msgs.values():
|
||||
if separate_ntf and ('notify' in op or 'event' in op):
|
||||
continue
|
||||
|
||||
suffix = ','
|
||||
if op.value != val:
|
||||
suffix = f" = {op.value},"
|
||||
val = op.value
|
||||
cw.p(op.enum_name + suffix)
|
||||
val += 1
|
||||
cw.nl()
|
||||
cw.p(cnt_name + ('' if max_by_define else ','))
|
||||
if not max_by_define:
|
||||
cw.p(f"{max_name} = {max_value}")
|
||||
cw.block_end(line=';')
|
||||
if max_by_define:
|
||||
cw.p(f"#define {max_name} {max_value}")
|
||||
cw.nl()
|
||||
if family.msg_id_model == 'unified':
|
||||
render_uapi_unified(family, cw, max_by_define, separate_ntf)
|
||||
elif family.msg_id_model == 'directional':
|
||||
render_uapi_directional(family, cw, max_by_define)
|
||||
else:
|
||||
raise Exception(f'Unsupported message enum-model {family.msg_id_model}')
|
||||
|
||||
if separate_ntf:
|
||||
uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
|
||||
|
@ -2653,13 +2727,6 @@ def main():
|
|||
os.sys.exit(1)
|
||||
return
|
||||
|
||||
supported_models = ['unified']
|
||||
if args.mode in ['user', 'kernel']:
|
||||
supported_models += ['directional']
|
||||
if parsed.msg_id_model not in supported_models:
|
||||
print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
|
||||
os.sys.exit(1)
|
||||
|
||||
cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out))
|
||||
|
||||
_, spec_kernel = find_kernel_root(args.spec)
|
||||
|
@ -2709,12 +2776,17 @@ def main():
|
|||
else:
|
||||
cw.p(f'#include "{hdr_file}"')
|
||||
cw.p('#include "ynl.h"')
|
||||
headers = [parsed.uapi_header]
|
||||
headers = []
|
||||
for definition in parsed['definitions']:
|
||||
if 'header' in definition:
|
||||
headers.append(definition['header'])
|
||||
if args.mode == 'user':
|
||||
headers.append(parsed.uapi_header)
|
||||
seen_header = []
|
||||
for one in headers:
|
||||
cw.p(f"#include <{one}>")
|
||||
if one not in seen_header:
|
||||
cw.p(f"#include <{one}>")
|
||||
seen_header.append(one)
|
||||
cw.nl()
|
||||
|
||||
if args.mode == "user":
|
||||
|
|
|
@ -96,7 +96,7 @@ TARGETS_HOTPLUG = cpu-hotplug
|
|||
TARGETS_HOTPLUG += memory-hotplug
|
||||
|
||||
# Networking tests want the net/lib target, include it automatically
|
||||
ifneq ($(filter net drivers/net,$(TARGETS)),)
|
||||
ifneq ($(filter net drivers/net drivers/net/hw,$(TARGETS)),)
|
||||
ifeq ($(filter net/lib,$(TARGETS)),)
|
||||
INSTALL_DEP_TARGETS := net/lib
|
||||
endif
|
||||
|
|
|
@ -7,6 +7,7 @@ TEST_PROGS := \
|
|||
queues.py \
|
||||
stats.py \
|
||||
shaper.py \
|
||||
hds.py \
|
||||
# end of TEST_PROGS
|
||||
|
||||
include ../../lib.mk
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import errno
|
||||
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_raises, KsftSkipEx
|
||||
from lib.py import EthtoolFamily, NlError
|
||||
from lib.py import NetDrvEnv
|
||||
from lib.py import defer, ethtool, ip, random
|
||||
|
||||
def get_hds(cfg, netnl) -> None:
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'tcp-data-split' not in rings:
|
||||
raise KsftSkipEx('tcp-data-split not supported by device')
|
||||
|
||||
def get_hds_thresh(cfg, netnl) -> None:
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'hds-thresh' not in rings:
|
||||
raise KsftSkipEx('hds-thresh not supported by device')
|
||||
|
||||
def set_hds_enable(cfg, netnl) -> None:
|
||||
try:
|
||||
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'enabled'})
|
||||
except NlError as e:
|
||||
if e.error == errno.EINVAL:
|
||||
raise KsftSkipEx("disabling of HDS not supported by the device")
|
||||
elif e.error == errno.EOPNOTSUPP:
|
||||
raise KsftSkipEx("ring-set not supported by the device")
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'tcp-data-split' not in rings:
|
||||
raise KsftSkipEx('tcp-data-split not supported by device')
|
||||
|
||||
ksft_eq('enabled', rings['tcp-data-split'])
|
||||
|
||||
def set_hds_disable(cfg, netnl) -> None:
|
||||
try:
|
||||
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'tcp-data-split': 'disabled'})
|
||||
except NlError as e:
|
||||
if e.error == errno.EINVAL:
|
||||
raise KsftSkipEx("disabling of HDS not supported by the device")
|
||||
elif e.error == errno.EOPNOTSUPP:
|
||||
raise KsftSkipEx("ring-set not supported by the device")
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'tcp-data-split' not in rings:
|
||||
raise KsftSkipEx('tcp-data-split not supported by device')
|
||||
|
||||
ksft_eq('disabled', rings['tcp-data-split'])
|
||||
|
||||
def set_hds_thresh_zero(cfg, netnl) -> None:
|
||||
try:
|
||||
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': 0})
|
||||
except NlError as e:
|
||||
if e.error == errno.EINVAL:
|
||||
raise KsftSkipEx("hds-thresh-set not supported by the device")
|
||||
elif e.error == errno.EOPNOTSUPP:
|
||||
raise KsftSkipEx("ring-set not supported by the device")
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'hds-thresh' not in rings:
|
||||
raise KsftSkipEx('hds-thresh not supported by device')
|
||||
|
||||
ksft_eq(0, rings['hds-thresh'])
|
||||
|
||||
def set_hds_thresh_random(cfg, netnl) -> None:
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'hds-thresh' not in rings:
|
||||
raise KsftSkipEx('hds-thresh not supported by device')
|
||||
if 'hds-thresh-max' not in rings:
|
||||
raise KsftSkipEx('hds-thresh-max not defined by device')
|
||||
|
||||
if rings['hds-thresh-max'] < 2:
|
||||
raise KsftSkipEx('hds-thresh-max is too small')
|
||||
elif rings['hds-thresh-max'] == 2:
|
||||
hds_thresh = 1
|
||||
else:
|
||||
while True:
|
||||
hds_thresh = random.randint(1, rings['hds-thresh-max'] - 1)
|
||||
if hds_thresh != rings['hds-thresh']:
|
||||
break
|
||||
|
||||
try:
|
||||
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_thresh})
|
||||
except NlError as e:
|
||||
if e.error == errno.EINVAL:
|
||||
raise KsftSkipEx("hds-thresh-set not supported by the device")
|
||||
elif e.error == errno.EOPNOTSUPP:
|
||||
raise KsftSkipEx("ring-set not supported by the device")
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
ksft_eq(hds_thresh, rings['hds-thresh'])
|
||||
|
||||
def set_hds_thresh_max(cfg, netnl) -> None:
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'hds-thresh' not in rings:
|
||||
raise KsftSkipEx('hds-thresh not supported by device')
|
||||
try:
|
||||
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': rings['hds-thresh-max']})
|
||||
except NlError as e:
|
||||
if e.error == errno.EINVAL:
|
||||
raise KsftSkipEx("hds-thresh-set not supported by the device")
|
||||
elif e.error == errno.EOPNOTSUPP:
|
||||
raise KsftSkipEx("ring-set not supported by the device")
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
ksft_eq(rings['hds-thresh'], rings['hds-thresh-max'])
|
||||
|
||||
def set_hds_thresh_gt(cfg, netnl) -> None:
|
||||
try:
|
||||
rings = netnl.rings_get({'header': {'dev-index': cfg.ifindex}})
|
||||
except NlError as e:
|
||||
raise KsftSkipEx('ring-get not supported by device')
|
||||
if 'hds-thresh' not in rings:
|
||||
raise KsftSkipEx('hds-thresh not supported by device')
|
||||
if 'hds-thresh-max' not in rings:
|
||||
raise KsftSkipEx('hds-thresh-max not defined by device')
|
||||
hds_gt = rings['hds-thresh-max'] + 1
|
||||
with ksft_raises(NlError) as e:
|
||||
netnl.rings_set({'header': {'dev-index': cfg.ifindex}, 'hds-thresh': hds_gt})
|
||||
ksft_eq(e.exception.nl_msg.error, -errno.EINVAL)
|
||||
|
||||
def main() -> None:
|
||||
with NetDrvEnv(__file__, queue_count=3) as cfg:
|
||||
ksft_run([get_hds,
|
||||
get_hds_thresh,
|
||||
set_hds_disable,
|
||||
set_hds_enable,
|
||||
set_hds_thresh_random,
|
||||
set_hds_thresh_zero,
|
||||
set_hds_thresh_max,
|
||||
set_hds_thresh_gt],
|
||||
args=(cfg, EthtoolFamily()))
|
||||
ksft_exit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -9,6 +9,8 @@ TEST_PROGS = \
|
|||
hw_stats_l3.sh \
|
||||
hw_stats_l3_gre.sh \
|
||||
loopback.sh \
|
||||
rss_ctx.py \
|
||||
rss_input_xfrm.py \
|
||||
#
|
||||
|
||||
TEST_FILES := \
|
||||
|
@ -16,6 +18,7 @@ TEST_FILES := \
|
|||
#
|
||||
|
||||
TEST_INCLUDES := \
|
||||
$(wildcard lib/py/*.py ../lib/py/*.py) \
|
||||
../../../net/lib.sh \
|
||||
../../../net/forwarding/lib.sh \
|
||||
../../../net/forwarding/ipip_lib.sh \
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
KSFT_DIR = (Path(__file__).parent / "../../../../..").resolve()
|
||||
|
||||
try:
|
||||
sys.path.append(KSFT_DIR.as_posix())
|
||||
from net.lib.py import *
|
||||
from drivers.net.lib.py import *
|
||||
except ModuleNotFoundError as e:
|
||||
ksft_pr("Failed importing `net` library from kernel sources")
|
||||
ksft_pr(str(e))
|
||||
ktap_result(True, comment="SKIP")
|
||||
sys.exit(4)
|
|
@ -0,0 +1,817 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import datetime
|
||||
import random
|
||||
import re
|
||||
from lib.py import ksft_run, ksft_pr, ksft_exit
|
||||
from lib.py import ksft_eq, ksft_ne, ksft_ge, ksft_in, ksft_lt, ksft_true, ksft_raises
|
||||
from lib.py import NetDrvEpEnv
|
||||
from lib.py import EthtoolFamily, NetdevFamily
|
||||
from lib.py import KsftSkipEx, KsftFailEx
|
||||
from lib.py import rand_port
|
||||
from lib.py import ethtool, ip, defer, GenerateTraffic, CmdExitFailure
|
||||
|
||||
|
||||
def _rss_key_str(key):
|
||||
return ":".join(["{:02x}".format(x) for x in key])
|
||||
|
||||
|
||||
def _rss_key_rand(length):
|
||||
return [random.randint(0, 255) for _ in range(length)]
|
||||
|
||||
|
||||
def _rss_key_check(cfg, data=None, context=0):
|
||||
if data is None:
|
||||
data = get_rss(cfg, context=context)
|
||||
if 'rss-hash-key' not in data:
|
||||
return
|
||||
non_zero = [x for x in data['rss-hash-key'] if x != 0]
|
||||
ksft_eq(bool(non_zero), True, comment=f"RSS key is all zero {data['rss-hash-key']}")
|
||||
|
||||
|
||||
def get_rss(cfg, context=0):
|
||||
return ethtool(f"-x {cfg.ifname} context {context}", json=True)[0]
|
||||
|
||||
|
||||
def get_drop_err_sum(cfg):
|
||||
stats = ip("-s -s link show dev " + cfg.ifname, json=True)[0]
|
||||
cnt = 0
|
||||
for key in ['errors', 'dropped', 'over_errors', 'fifo_errors',
|
||||
'length_errors', 'crc_errors', 'missed_errors',
|
||||
'frame_errors']:
|
||||
cnt += stats["stats64"]["rx"][key]
|
||||
return cnt, stats["stats64"]["tx"]["carrier_changes"]
|
||||
|
||||
|
||||
def ethtool_create(cfg, act, opts):
|
||||
output = ethtool(f"{act} {cfg.ifname} {opts}").stdout
|
||||
# Output will be something like: "New RSS context is 1" or
|
||||
# "Added rule with ID 7", we want the integer from the end
|
||||
return int(output.split()[-1])
|
||||
|
||||
|
||||
def require_ntuple(cfg):
|
||||
features = ethtool(f"-k {cfg.ifname}", json=True)[0]
|
||||
if not features["ntuple-filters"]["active"]:
|
||||
# ntuple is more of a capability than a config knob, don't bother
|
||||
# trying to enable it (until some driver actually needs it).
|
||||
raise KsftSkipEx("Ntuple filters not enabled on the device: " + str(features["ntuple-filters"]))
|
||||
|
||||
|
||||
# Get Rx packet counts for all queues, as a simple list of integers
|
||||
# if @prev is specified the prev counts will be subtracted
|
||||
def _get_rx_cnts(cfg, prev=None):
|
||||
cfg.wait_hw_stats_settle()
|
||||
data = cfg.netdevnl.qstats_get({"ifindex": cfg.ifindex, "scope": ["queue"]}, dump=True)
|
||||
data = [x for x in data if x['queue-type'] == "rx"]
|
||||
max_q = max([x["queue-id"] for x in data])
|
||||
queue_stats = [0] * (max_q + 1)
|
||||
for q in data:
|
||||
queue_stats[q["queue-id"]] = q["rx-packets"]
|
||||
if prev and q["queue-id"] < len(prev):
|
||||
queue_stats[q["queue-id"]] -= prev[q["queue-id"]]
|
||||
return queue_stats
|
||||
|
||||
|
||||
def _send_traffic_check(cfg, port, name, params):
|
||||
# params is a dict with 3 possible keys:
|
||||
# - "target": required, which queues we expect to get iperf traffic
|
||||
# - "empty": optional, which queues should see no traffic at all
|
||||
# - "noise": optional, which queues we expect to see low traffic;
|
||||
# used for queues of the main context, since some background
|
||||
# OS activity may use those queues while we're testing
|
||||
# the value for each is a list, or some other iterable containing queue ids.
|
||||
|
||||
cnts = _get_rx_cnts(cfg)
|
||||
GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
|
||||
cnts = _get_rx_cnts(cfg, prev=cnts)
|
||||
|
||||
directed = sum(cnts[i] for i in params['target'])
|
||||
|
||||
ksft_ge(directed, 20000, f"traffic on {name}: " + str(cnts))
|
||||
if params.get('noise'):
|
||||
ksft_lt(sum(cnts[i] for i in params['noise']), directed / 2,
|
||||
f"traffic on other queues ({name})':" + str(cnts))
|
||||
if params.get('empty'):
|
||||
ksft_eq(sum(cnts[i] for i in params['empty']), 0,
|
||||
f"traffic on inactive queues ({name}): " + str(cnts))
|
||||
|
||||
|
||||
def _ntuple_rule_check(cfg, rule_id, ctx_id):
|
||||
"""Check that ntuple rule references RSS context ID"""
|
||||
text = ethtool(f"-n {cfg.ifname} rule {rule_id}").stdout
|
||||
pattern = f"RSS Context (ID: )?{ctx_id}"
|
||||
ksft_true(re.search(pattern, text), "RSS context not referenced in ntuple rule")
|
||||
|
||||
|
||||
def test_rss_key_indir(cfg):
|
||||
"""Test basics like updating the main RSS key and indirection table."""
|
||||
|
||||
qcnt = len(_get_rx_cnts(cfg))
|
||||
if qcnt < 3:
|
||||
KsftSkipEx("Device has fewer than 3 queues (or doesn't support queue stats)")
|
||||
|
||||
data = get_rss(cfg)
|
||||
want_keys = ['rss-hash-key', 'rss-hash-function', 'rss-indirection-table']
|
||||
for k in want_keys:
|
||||
if k not in data:
|
||||
raise KsftFailEx("ethtool results missing key: " + k)
|
||||
if not data[k]:
|
||||
raise KsftFailEx(f"ethtool results empty for '{k}': {data[k]}")
|
||||
|
||||
_rss_key_check(cfg, data=data)
|
||||
key_len = len(data['rss-hash-key'])
|
||||
|
||||
# Set the key
|
||||
key = _rss_key_rand(key_len)
|
||||
ethtool(f"-X {cfg.ifname} hkey " + _rss_key_str(key))
|
||||
|
||||
data = get_rss(cfg)
|
||||
ksft_eq(key, data['rss-hash-key'])
|
||||
|
||||
# Set the indirection table and the key together
|
||||
key = _rss_key_rand(key_len)
|
||||
ethtool(f"-X {cfg.ifname} equal 3 hkey " + _rss_key_str(key))
|
||||
reset_indir = defer(ethtool, f"-X {cfg.ifname} default")
|
||||
|
||||
data = get_rss(cfg)
|
||||
_rss_key_check(cfg, data=data)
|
||||
ksft_eq(0, min(data['rss-indirection-table']))
|
||||
ksft_eq(2, max(data['rss-indirection-table']))
|
||||
|
||||
# Reset indirection table and set the key
|
||||
key = _rss_key_rand(key_len)
|
||||
ethtool(f"-X {cfg.ifname} default hkey " + _rss_key_str(key))
|
||||
data = get_rss(cfg)
|
||||
_rss_key_check(cfg, data=data)
|
||||
ksft_eq(0, min(data['rss-indirection-table']))
|
||||
ksft_eq(qcnt - 1, max(data['rss-indirection-table']))
|
||||
|
||||
# Set the indirection table
|
||||
ethtool(f"-X {cfg.ifname} equal 2")
|
||||
data = get_rss(cfg)
|
||||
ksft_eq(0, min(data['rss-indirection-table']))
|
||||
ksft_eq(1, max(data['rss-indirection-table']))
|
||||
|
||||
# Check we only get traffic on the first 2 queues
|
||||
cnts = _get_rx_cnts(cfg)
|
||||
GenerateTraffic(cfg).wait_pkts_and_stop(20000)
|
||||
cnts = _get_rx_cnts(cfg, prev=cnts)
|
||||
# 2 queues, 20k packets, must be at least 5k per queue
|
||||
ksft_ge(cnts[0], 5000, "traffic on main context (1/2): " + str(cnts))
|
||||
ksft_ge(cnts[1], 5000, "traffic on main context (2/2): " + str(cnts))
|
||||
# The other queues should be unused
|
||||
ksft_eq(sum(cnts[2:]), 0, "traffic on unused queues: " + str(cnts))
|
||||
|
||||
# Restore, and check traffic gets spread again
|
||||
reset_indir.exec()
|
||||
|
||||
cnts = _get_rx_cnts(cfg)
|
||||
GenerateTraffic(cfg).wait_pkts_and_stop(20000)
|
||||
cnts = _get_rx_cnts(cfg, prev=cnts)
|
||||
# First two queues get less traffic than all the rest
|
||||
ksft_lt(sum(cnts[:2]), sum(cnts[2:]), "traffic distributed: " + str(cnts))
|
||||
|
||||
|
||||
def test_rss_queue_reconfigure(cfg, main_ctx=True):
|
||||
"""Make sure queue changes can't override requested RSS config.
|
||||
|
||||
By default main RSS table should change to include all queues.
|
||||
When user sets a specific RSS config the driver should preserve it,
|
||||
even when queue count changes. Driver should refuse to deactivate
|
||||
queues used in the user-set RSS config.
|
||||
"""
|
||||
|
||||
if not main_ctx:
|
||||
require_ntuple(cfg)
|
||||
|
||||
# Start with 4 queues, an arbitrary known number.
|
||||
try:
|
||||
qcnt = len(_get_rx_cnts(cfg))
|
||||
ethtool(f"-L {cfg.ifname} combined 4")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
|
||||
except:
|
||||
raise KsftSkipEx("Not enough queues for the test or qstat not supported")
|
||||
|
||||
if main_ctx:
|
||||
ctx_id = 0
|
||||
ctx_ref = ""
|
||||
else:
|
||||
ctx_id = ethtool_create(cfg, "-X", "context new")
|
||||
ctx_ref = f"context {ctx_id}"
|
||||
defer(ethtool, f"-X {cfg.ifname} {ctx_ref} delete")
|
||||
|
||||
# Indirection table should be distributing to all queues.
|
||||
data = get_rss(cfg, context=ctx_id)
|
||||
ksft_eq(0, min(data['rss-indirection-table']))
|
||||
ksft_eq(3, max(data['rss-indirection-table']))
|
||||
|
||||
# Increase queues, indirection table should be distributing to all queues.
|
||||
# It's unclear whether tables of additional contexts should be reset, too.
|
||||
if main_ctx:
|
||||
ethtool(f"-L {cfg.ifname} combined 5")
|
||||
data = get_rss(cfg)
|
||||
ksft_eq(0, min(data['rss-indirection-table']))
|
||||
ksft_eq(4, max(data['rss-indirection-table']))
|
||||
ethtool(f"-L {cfg.ifname} combined 4")
|
||||
|
||||
# Configure the table explicitly
|
||||
port = rand_port()
|
||||
ethtool(f"-X {cfg.ifname} {ctx_ref} weight 1 0 0 1")
|
||||
if main_ctx:
|
||||
other_key = 'empty'
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
else:
|
||||
other_key = 'noise'
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
|
||||
ntuple = ethtool_create(cfg, "-N", flow)
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
|
||||
|
||||
_send_traffic_check(cfg, port, ctx_ref, { 'target': (0, 3),
|
||||
other_key: (1, 2) })
|
||||
|
||||
# We should be able to increase queues, but table should be left untouched
|
||||
ethtool(f"-L {cfg.ifname} combined 5")
|
||||
data = get_rss(cfg, context=ctx_id)
|
||||
ksft_eq({0, 3}, set(data['rss-indirection-table']))
|
||||
|
||||
_send_traffic_check(cfg, port, ctx_ref, { 'target': (0, 3),
|
||||
other_key: (1, 2, 4) })
|
||||
|
||||
# Setting queue count to 3 should fail, queue 3 is used
|
||||
try:
|
||||
ethtool(f"-L {cfg.ifname} combined 3")
|
||||
except CmdExitFailure:
|
||||
pass
|
||||
else:
|
||||
raise Exception(f"Driver didn't prevent us from deactivating a used queue (context {ctx_id})")
|
||||
|
||||
if not main_ctx:
|
||||
ethtool(f"-L {cfg.ifname} combined 4")
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id} action 1"
|
||||
try:
|
||||
# this targets queue 4, which doesn't exist
|
||||
ntuple2 = ethtool_create(cfg, "-N", flow)
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple2}")
|
||||
except CmdExitFailure:
|
||||
pass
|
||||
else:
|
||||
raise Exception(f"Driver didn't prevent us from targeting a nonexistent queue (context {ctx_id})")
|
||||
# change the table to target queues 0 and 2
|
||||
ethtool(f"-X {cfg.ifname} {ctx_ref} weight 1 0 1 0")
|
||||
# ntuple rule therefore targets queues 1 and 3
|
||||
try:
|
||||
ntuple2 = ethtool_create(cfg, "-N", flow)
|
||||
except CmdExitFailure:
|
||||
ksft_pr("Driver does not support rss + queue offset")
|
||||
return
|
||||
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple2}")
|
||||
# should replace existing filter
|
||||
ksft_eq(ntuple, ntuple2)
|
||||
_send_traffic_check(cfg, port, ctx_ref, { 'target': (1, 3),
|
||||
'noise' : (0, 2) })
|
||||
# Setting queue count to 3 should fail, queue 3 is used
|
||||
try:
|
||||
ethtool(f"-L {cfg.ifname} combined 3")
|
||||
except CmdExitFailure:
|
||||
pass
|
||||
else:
|
||||
raise Exception(f"Driver didn't prevent us from deactivating a used queue (context {ctx_id})")
|
||||
|
||||
|
||||
def test_rss_resize(cfg):
|
||||
"""Test resizing of the RSS table.
|
||||
|
||||
Some devices dynamically increase and decrease the size of the RSS
|
||||
indirection table based on the number of enabled queues.
|
||||
When that happens driver must maintain the balance of entries
|
||||
(preferably duplicating the smaller table).
|
||||
"""
|
||||
|
||||
channels = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}})
|
||||
ch_max = channels['combined-max']
|
||||
qcnt = channels['combined-count']
|
||||
|
||||
if ch_max < 2:
|
||||
raise KsftSkipEx(f"Not enough queues for the test: {ch_max}")
|
||||
|
||||
ethtool(f"-L {cfg.ifname} combined 2")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
|
||||
|
||||
ethtool(f"-X {cfg.ifname} weight 1 7")
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
|
||||
ethtool(f"-L {cfg.ifname} combined {ch_max}")
|
||||
data = get_rss(cfg)
|
||||
ksft_eq(0, min(data['rss-indirection-table']))
|
||||
ksft_eq(1, max(data['rss-indirection-table']))
|
||||
|
||||
ksft_eq(7,
|
||||
data['rss-indirection-table'].count(1) /
|
||||
data['rss-indirection-table'].count(0),
|
||||
f"Table imbalance after resize: {data['rss-indirection-table']}")
|
||||
|
||||
|
||||
def test_hitless_key_update(cfg):
|
||||
"""Test that flows may be rehashed without impacting traffic.
|
||||
|
||||
Some workloads may want to rehash the flows in response to an imbalance.
|
||||
Most effective way to do that is changing the RSS key. Check that changing
|
||||
the key does not cause link flaps or traffic disruption.
|
||||
|
||||
Disrupting traffic for key update is not a bug, but makes the key
|
||||
update unusable for rehashing under load.
|
||||
"""
|
||||
data = get_rss(cfg)
|
||||
key_len = len(data['rss-hash-key'])
|
||||
|
||||
key = _rss_key_rand(key_len)
|
||||
|
||||
tgen = GenerateTraffic(cfg)
|
||||
try:
|
||||
errors0, carrier0 = get_drop_err_sum(cfg)
|
||||
t0 = datetime.datetime.now()
|
||||
ethtool(f"-X {cfg.ifname} hkey " + _rss_key_str(key))
|
||||
t1 = datetime.datetime.now()
|
||||
errors1, carrier1 = get_drop_err_sum(cfg)
|
||||
finally:
|
||||
tgen.wait_pkts_and_stop(5000)
|
||||
|
||||
ksft_lt((t1 - t0).total_seconds(), 0.2)
|
||||
ksft_eq(errors1 - errors1, 0)
|
||||
ksft_eq(carrier1 - carrier0, 0)
|
||||
|
||||
|
||||
def test_rss_context_dump(cfg):
|
||||
"""
|
||||
Test dumping RSS contexts. This tests mostly exercises the kernel APIs.
|
||||
"""
|
||||
|
||||
# Get a random key of the right size
|
||||
data = get_rss(cfg)
|
||||
if 'rss-hash-key' in data:
|
||||
key_data = _rss_key_rand(len(data['rss-hash-key']))
|
||||
key = _rss_key_str(key_data)
|
||||
else:
|
||||
key_data = []
|
||||
key = "ba:ad"
|
||||
|
||||
ids = []
|
||||
try:
|
||||
ids.append(ethtool_create(cfg, "-X", f"context new"))
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ids[-1]} delete")
|
||||
|
||||
ids.append(ethtool_create(cfg, "-X", f"context new weight 1 1"))
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ids[-1]} delete")
|
||||
|
||||
ids.append(ethtool_create(cfg, "-X", f"context new hkey {key}"))
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ids[-1]} delete")
|
||||
except CmdExitFailure:
|
||||
if not ids:
|
||||
raise KsftSkipEx("Unable to add any contexts")
|
||||
ksft_pr(f"Added only {len(ids)} out of 3 contexts")
|
||||
|
||||
expect_tuples = set([(cfg.ifname, -1)] + [(cfg.ifname, ctx_id) for ctx_id in ids])
|
||||
|
||||
# Dump all
|
||||
ctxs = cfg.ethnl.rss_get({}, dump=True)
|
||||
tuples = [(c['header']['dev-name'], c.get('context', -1)) for c in ctxs]
|
||||
ksft_eq(len(tuples), len(set(tuples)), "duplicates in context dump")
|
||||
ctx_tuples = set([ctx for ctx in tuples if ctx[0] == cfg.ifname])
|
||||
ksft_eq(expect_tuples, ctx_tuples)
|
||||
|
||||
# Sanity-check the results
|
||||
for data in ctxs:
|
||||
ksft_ne(set(data['indir']), {0}, "indir table is all zero")
|
||||
ksft_ne(set(data.get('hkey', [1])), {0}, "key is all zero")
|
||||
|
||||
# More specific checks
|
||||
if len(ids) > 1 and data.get('context') == ids[1]:
|
||||
ksft_eq(set(data['indir']), {0, 1},
|
||||
"ctx1 - indir table mismatch")
|
||||
if len(ids) > 2 and data.get('context') == ids[2]:
|
||||
ksft_eq(data['hkey'], bytes(key_data), "ctx2 - key mismatch")
|
||||
|
||||
# Ifindex filter
|
||||
ctxs = cfg.ethnl.rss_get({'header': {'dev-name': cfg.ifname}}, dump=True)
|
||||
tuples = [(c['header']['dev-name'], c.get('context', -1)) for c in ctxs]
|
||||
ctx_tuples = set(tuples)
|
||||
ksft_eq(len(tuples), len(ctx_tuples), "duplicates in context dump")
|
||||
ksft_eq(expect_tuples, ctx_tuples)
|
||||
|
||||
# Skip ctx 0
|
||||
expect_tuples.remove((cfg.ifname, -1))
|
||||
|
||||
ctxs = cfg.ethnl.rss_get({'start-context': 1}, dump=True)
|
||||
tuples = [(c['header']['dev-name'], c.get('context', -1)) for c in ctxs]
|
||||
ksft_eq(len(tuples), len(set(tuples)), "duplicates in context dump")
|
||||
ctx_tuples = set([ctx for ctx in tuples if ctx[0] == cfg.ifname])
|
||||
ksft_eq(expect_tuples, ctx_tuples)
|
||||
|
||||
# And finally both with ifindex and skip main
|
||||
ctxs = cfg.ethnl.rss_get({'header': {'dev-name': cfg.ifname}, 'start-context': 1}, dump=True)
|
||||
ctx_tuples = set([(c['header']['dev-name'], c.get('context', -1)) for c in ctxs])
|
||||
ksft_eq(expect_tuples, ctx_tuples)
|
||||
|
||||
|
||||
def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
|
||||
"""
|
||||
Test separating traffic into RSS contexts.
|
||||
The queues will be allocated 2 for each context:
|
||||
ctx0 ctx1 ctx2 ctx3
|
||||
[0 1] [2 3] [4 5] [6 7] ...
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
requested_ctx_cnt = ctx_cnt
|
||||
|
||||
# Try to allocate more queues when necessary
|
||||
qcnt = len(_get_rx_cnts(cfg))
|
||||
if qcnt < 2 + 2 * ctx_cnt:
|
||||
try:
|
||||
ksft_pr(f"Increasing queue count {qcnt} -> {2 + 2 * ctx_cnt}")
|
||||
ethtool(f"-L {cfg.ifname} combined {2 + 2 * ctx_cnt}")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
|
||||
except:
|
||||
raise KsftSkipEx("Not enough queues for the test")
|
||||
|
||||
ports = []
|
||||
|
||||
# Use queues 0 and 1 for normal traffic
|
||||
ethtool(f"-X {cfg.ifname} equal 2")
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
|
||||
for i in range(ctx_cnt):
|
||||
want_cfg = f"start {2 + i * 2} equal 2"
|
||||
create_cfg = want_cfg if create_with_cfg else ""
|
||||
|
||||
try:
|
||||
ctx_id = ethtool_create(cfg, "-X", f"context new {create_cfg}")
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
|
||||
except CmdExitFailure:
|
||||
# try to carry on and skip at the end
|
||||
if i == 0:
|
||||
raise
|
||||
ksft_pr(f"Failed to create context {i + 1}, trying to test what we got")
|
||||
ctx_cnt = i
|
||||
break
|
||||
|
||||
_rss_key_check(cfg, context=ctx_id)
|
||||
|
||||
if not create_with_cfg:
|
||||
ethtool(f"-X {cfg.ifname} context {ctx_id} {want_cfg}")
|
||||
_rss_key_check(cfg, context=ctx_id)
|
||||
|
||||
# Sanity check the context we just created
|
||||
data = get_rss(cfg, ctx_id)
|
||||
ksft_eq(min(data['rss-indirection-table']), 2 + i * 2, "Unexpected context cfg: " + str(data))
|
||||
ksft_eq(max(data['rss-indirection-table']), 2 + i * 2 + 1, "Unexpected context cfg: " + str(data))
|
||||
|
||||
ports.append(rand_port())
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
|
||||
ntuple = ethtool_create(cfg, "-N", flow)
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
|
||||
|
||||
_ntuple_rule_check(cfg, ntuple, ctx_id)
|
||||
|
||||
for i in range(ctx_cnt):
|
||||
_send_traffic_check(cfg, ports[i], f"context {i}",
|
||||
{ 'target': (2+i*2, 3+i*2),
|
||||
'noise': (0, 1),
|
||||
'empty': list(range(2, 2+i*2)) + list(range(4+i*2, 2+2*ctx_cnt)) })
|
||||
|
||||
if requested_ctx_cnt != ctx_cnt:
|
||||
raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}")
|
||||
|
||||
|
||||
def test_rss_context4(cfg):
|
||||
test_rss_context(cfg, 4)
|
||||
|
||||
|
||||
def test_rss_context32(cfg):
|
||||
test_rss_context(cfg, 32)
|
||||
|
||||
|
||||
def test_rss_context4_create_with_cfg(cfg):
|
||||
test_rss_context(cfg, 4, create_with_cfg=True)
|
||||
|
||||
|
||||
def test_rss_context_queue_reconfigure(cfg):
|
||||
test_rss_queue_reconfigure(cfg, main_ctx=False)
|
||||
|
||||
|
||||
def test_rss_context_out_of_order(cfg, ctx_cnt=4):
|
||||
"""
|
||||
Test separating traffic into RSS contexts.
|
||||
Contexts are removed in semi-random order, and steering re-tested
|
||||
to make sure removal doesn't break steering to surviving contexts.
|
||||
Test requires 3 contexts to work.
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
requested_ctx_cnt = ctx_cnt
|
||||
|
||||
# Try to allocate more queues when necessary
|
||||
qcnt = len(_get_rx_cnts(cfg))
|
||||
if qcnt < 2 + 2 * ctx_cnt:
|
||||
try:
|
||||
ksft_pr(f"Increasing queue count {qcnt} -> {2 + 2 * ctx_cnt}")
|
||||
ethtool(f"-L {cfg.ifname} combined {2 + 2 * ctx_cnt}")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
|
||||
except:
|
||||
raise KsftSkipEx("Not enough queues for the test")
|
||||
|
||||
ntuple = []
|
||||
ctx = []
|
||||
ports = []
|
||||
|
||||
def remove_ctx(idx):
|
||||
ntuple[idx].exec()
|
||||
ntuple[idx] = None
|
||||
ctx[idx].exec()
|
||||
ctx[idx] = None
|
||||
|
||||
def check_traffic():
|
||||
for i in range(ctx_cnt):
|
||||
if ctx[i]:
|
||||
expected = {
|
||||
'target': (2+i*2, 3+i*2),
|
||||
'noise': (0, 1),
|
||||
'empty': list(range(2, 2+i*2)) + list(range(4+i*2, 2+2*ctx_cnt))
|
||||
}
|
||||
else:
|
||||
expected = {
|
||||
'target': (0, 1),
|
||||
'empty': range(2, 2+2*ctx_cnt)
|
||||
}
|
||||
|
||||
_send_traffic_check(cfg, ports[i], f"context {i}", expected)
|
||||
|
||||
# Use queues 0 and 1 for normal traffic
|
||||
ethtool(f"-X {cfg.ifname} equal 2")
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
|
||||
for i in range(ctx_cnt):
|
||||
ctx_id = ethtool_create(cfg, "-X", f"context new start {2 + i * 2} equal 2")
|
||||
ctx.append(defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete"))
|
||||
|
||||
ports.append(rand_port())
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
|
||||
ntuple_id = ethtool_create(cfg, "-N", flow)
|
||||
ntuple.append(defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}"))
|
||||
|
||||
check_traffic()
|
||||
|
||||
# Remove middle context
|
||||
remove_ctx(ctx_cnt // 2)
|
||||
check_traffic()
|
||||
|
||||
# Remove first context
|
||||
remove_ctx(0)
|
||||
check_traffic()
|
||||
|
||||
# Remove last context
|
||||
remove_ctx(-1)
|
||||
check_traffic()
|
||||
|
||||
if requested_ctx_cnt != ctx_cnt:
|
||||
raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}")
|
||||
|
||||
|
||||
def test_rss_context_overlap(cfg, other_ctx=0):
|
||||
"""
|
||||
Test contexts overlapping with each other.
|
||||
Use 4 queues for the main context, but only queues 2 and 3 for context 1.
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
queue_cnt = len(_get_rx_cnts(cfg))
|
||||
if queue_cnt < 4:
|
||||
try:
|
||||
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
|
||||
ethtool(f"-L {cfg.ifname} combined 4")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
|
||||
except:
|
||||
raise KsftSkipEx("Not enough queues for the test")
|
||||
|
||||
if other_ctx == 0:
|
||||
ethtool(f"-X {cfg.ifname} equal 4")
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
else:
|
||||
other_ctx = ethtool_create(cfg, "-X", "context new")
|
||||
ethtool(f"-X {cfg.ifname} context {other_ctx} equal 4")
|
||||
defer(ethtool, f"-X {cfg.ifname} context {other_ctx} delete")
|
||||
|
||||
ctx_id = ethtool_create(cfg, "-X", "context new")
|
||||
ethtool(f"-X {cfg.ifname} context {ctx_id} start 2 equal 2")
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
|
||||
|
||||
port = rand_port()
|
||||
if other_ctx:
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {other_ctx}"
|
||||
ntuple_id = ethtool_create(cfg, "-N", flow)
|
||||
ntuple = defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
|
||||
|
||||
# Test the main context
|
||||
cnts = _get_rx_cnts(cfg)
|
||||
GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
|
||||
cnts = _get_rx_cnts(cfg, prev=cnts)
|
||||
|
||||
ksft_ge(sum(cnts[ :4]), 20000, "traffic on main context: " + str(cnts))
|
||||
ksft_ge(sum(cnts[ :2]), 7000, "traffic on main context (1/2): " + str(cnts))
|
||||
ksft_ge(sum(cnts[2:4]), 7000, "traffic on main context (2/2): " + str(cnts))
|
||||
if other_ctx == 0:
|
||||
ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
|
||||
|
||||
# Now create a rule for context 1 and make sure traffic goes to a subset
|
||||
if other_ctx:
|
||||
ntuple.exec()
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
|
||||
ntuple_id = ethtool_create(cfg, "-N", flow)
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
|
||||
|
||||
cnts = _get_rx_cnts(cfg)
|
||||
GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
|
||||
cnts = _get_rx_cnts(cfg, prev=cnts)
|
||||
|
||||
directed = sum(cnts[2:4])
|
||||
ksft_lt(sum(cnts[ :2]), directed / 2, "traffic on main context: " + str(cnts))
|
||||
ksft_ge(directed, 20000, "traffic on extra context: " + str(cnts))
|
||||
if other_ctx == 0:
|
||||
ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
|
||||
|
||||
|
||||
def test_rss_context_overlap2(cfg):
|
||||
test_rss_context_overlap(cfg, True)
|
||||
|
||||
|
||||
def test_flow_add_context_missing(cfg):
|
||||
"""
|
||||
Test that we are not allowed to add a rule pointing to an RSS context
|
||||
which was never created.
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
# Find a context which doesn't exist
|
||||
for ctx_id in range(1, 100):
|
||||
try:
|
||||
get_rss(cfg, context=ctx_id)
|
||||
except CmdExitFailure:
|
||||
break
|
||||
|
||||
with ksft_raises(CmdExitFailure) as cm:
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port 1234 context {ctx_id}"
|
||||
ntuple_id = ethtool_create(cfg, "-N", flow)
|
||||
ethtool(f"-N {cfg.ifname} delete {ntuple_id}")
|
||||
if cm.exception:
|
||||
ksft_in('Invalid argument', cm.exception.cmd.stderr)
|
||||
|
||||
|
||||
def test_delete_rss_context_busy(cfg):
|
||||
"""
|
||||
Test that deletion returns -EBUSY when an rss context is being used
|
||||
by an ntuple filter.
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
# create additional rss context
|
||||
ctx_id = ethtool_create(cfg, "-X", "context new")
|
||||
ctx_deleter = defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
|
||||
|
||||
# utilize context from ntuple filter
|
||||
port = rand_port()
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
|
||||
ntuple_id = ethtool_create(cfg, "-N", flow)
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
|
||||
|
||||
# attempt to delete in-use context
|
||||
try:
|
||||
ctx_deleter.exec_only()
|
||||
ctx_deleter.cancel()
|
||||
raise KsftFailEx(f"deleted context {ctx_id} used by rule {ntuple_id}")
|
||||
except CmdExitFailure:
|
||||
pass
|
||||
|
||||
|
||||
def test_rss_ntuple_addition(cfg):
|
||||
"""
|
||||
Test that the queue offset (ring_cookie) of an ntuple rule is added
|
||||
to the queue number read from the indirection table.
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
queue_cnt = len(_get_rx_cnts(cfg))
|
||||
if queue_cnt < 4:
|
||||
try:
|
||||
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
|
||||
ethtool(f"-L {cfg.ifname} combined 4")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
|
||||
except:
|
||||
raise KsftSkipEx("Not enough queues for the test")
|
||||
|
||||
# Use queue 0 for normal traffic
|
||||
ethtool(f"-X {cfg.ifname} equal 1")
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
|
||||
# create additional rss context
|
||||
ctx_id = ethtool_create(cfg, "-X", "context new equal 2")
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
|
||||
|
||||
# utilize context from ntuple filter
|
||||
port = rand_port()
|
||||
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id} action 2"
|
||||
try:
|
||||
ntuple_id = ethtool_create(cfg, "-N", flow)
|
||||
except CmdExitFailure:
|
||||
raise KsftSkipEx("Ntuple filter with RSS and nonzero action not supported")
|
||||
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
|
||||
|
||||
_send_traffic_check(cfg, port, f"context {ctx_id}", { 'target': (2, 3),
|
||||
'empty' : (1,),
|
||||
'noise' : (0,) })
|
||||
|
||||
|
||||
def test_rss_default_context_rule(cfg):
|
||||
"""
|
||||
Allocate a port, direct this port to context 0, then create a new RSS
|
||||
context and steer all TCP traffic to it (context 1). Verify that:
|
||||
* Traffic to the specific port continues to use queues of the main
|
||||
context (0/1).
|
||||
* Traffic to any other TCP port is redirected to the new context
|
||||
(queues 2/3).
|
||||
"""
|
||||
|
||||
require_ntuple(cfg)
|
||||
|
||||
queue_cnt = len(_get_rx_cnts(cfg))
|
||||
if queue_cnt < 4:
|
||||
try:
|
||||
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
|
||||
ethtool(f"-L {cfg.ifname} combined 4")
|
||||
defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
|
||||
except Exception as exc:
|
||||
raise KsftSkipEx("Not enough queues for the test") from exc
|
||||
|
||||
# Use queues 0 and 1 for the main context
|
||||
ethtool(f"-X {cfg.ifname} equal 2")
|
||||
defer(ethtool, f"-X {cfg.ifname} default")
|
||||
|
||||
# Create a new RSS context that uses queues 2 and 3
|
||||
ctx_id = ethtool_create(cfg, "-X", "context new start 2 equal 2")
|
||||
defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
|
||||
|
||||
# Generic low-priority rule: redirect all TCP traffic to the new context.
|
||||
# Give it an explicit higher location number (lower priority).
|
||||
flow_generic = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} context {ctx_id} loc 1"
|
||||
ethtool(f"-N {cfg.ifname} {flow_generic}")
|
||||
defer(ethtool, f"-N {cfg.ifname} delete 1")
|
||||
|
||||
# Specific high-priority rule for a random port that should stay on context 0.
|
||||
# Assign loc 0 so it is evaluated before the generic rule.
|
||||
port_main = rand_port()
|
||||
flow_main = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port_main} context 0 loc 0"
|
||||
ethtool(f"-N {cfg.ifname} {flow_main}")
|
||||
defer(ethtool, f"-N {cfg.ifname} delete 0")
|
||||
|
||||
_ntuple_rule_check(cfg, 1, ctx_id)
|
||||
|
||||
# Verify that traffic matching the specific rule still goes to queues 0/1
|
||||
_send_traffic_check(cfg, port_main, "context 0",
|
||||
{ 'target': (0, 1),
|
||||
'empty' : (2, 3) })
|
||||
|
||||
# And that traffic for any other port is steered to the new context
|
||||
port_other = rand_port()
|
||||
_send_traffic_check(cfg, port_other, f"context {ctx_id}",
|
||||
{ 'target': (2, 3),
|
||||
'noise' : (0, 1) })
|
||||
|
||||
|
||||
def main() -> None:
|
||||
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
|
||||
cfg.ethnl = EthtoolFamily()
|
||||
cfg.netdevnl = NetdevFamily()
|
||||
|
||||
ksft_run([test_rss_key_indir, test_rss_queue_reconfigure,
|
||||
test_rss_resize, test_hitless_key_update,
|
||||
test_rss_context, test_rss_context4, test_rss_context32,
|
||||
test_rss_context_dump, test_rss_context_queue_reconfigure,
|
||||
test_rss_context_overlap, test_rss_context_overlap2,
|
||||
test_rss_context_out_of_order, test_rss_context4_create_with_cfg,
|
||||
test_flow_add_context_missing,
|
||||
test_delete_rss_context_busy, test_rss_ntuple_addition,
|
||||
test_rss_default_context_rule],
|
||||
args=(cfg, ))
|
||||
ksft_exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import multiprocessing
|
||||
import socket
|
||||
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, cmd, fd_read_timeout
|
||||
from lib.py import NetDrvEpEnv
|
||||
from lib.py import EthtoolFamily, NetdevFamily
|
||||
from lib.py import KsftSkipEx, KsftFailEx
|
||||
from lib.py import rand_port
|
||||
|
||||
|
||||
def traffic(cfg, local_port, remote_port, ipver):
|
||||
af_inet = socket.AF_INET if ipver == "4" else socket.AF_INET6
|
||||
sock = socket.socket(af_inet, socket.SOCK_DGRAM)
|
||||
sock.bind(("", local_port))
|
||||
sock.connect((cfg.remote_addr_v[ipver], remote_port))
|
||||
tgt = f"{ipver}:[{cfg.addr_v[ipver]}]:{local_port},sourceport={remote_port}"
|
||||
cmd("echo a | socat - UDP" + tgt, host=cfg.remote)
|
||||
fd_read_timeout(sock.fileno(), 5)
|
||||
return sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU)
|
||||
|
||||
|
||||
def test_rss_input_xfrm(cfg, ipver):
|
||||
"""
|
||||
Test symmetric input_xfrm.
|
||||
If symmetric RSS hash is configured, send traffic twice, swapping the
|
||||
src/dst UDP ports, and verify that the same queue is receiving the traffic
|
||||
in both cases (IPs are constant).
|
||||
"""
|
||||
|
||||
if multiprocessing.cpu_count() < 2:
|
||||
raise KsftSkipEx("Need at least two CPUs to test symmetric RSS hash")
|
||||
|
||||
input_xfrm = cfg.ethnl.rss_get(
|
||||
{'header': {'dev-name': cfg.ifname}}).get('input_xfrm')
|
||||
|
||||
# Check for symmetric xor/or-xor
|
||||
if not input_xfrm or (input_xfrm != 1 and input_xfrm != 2):
|
||||
raise KsftSkipEx("Symmetric RSS hash not requested")
|
||||
|
||||
cpus = set()
|
||||
successful = 0
|
||||
for _ in range(100):
|
||||
try:
|
||||
port1 = rand_port(socket.SOCK_DGRAM)
|
||||
port2 = rand_port(socket.SOCK_DGRAM)
|
||||
cpu1 = traffic(cfg, port1, port2, ipver)
|
||||
cpu2 = traffic(cfg, port2, port1, ipver)
|
||||
cpus.update([cpu1, cpu2])
|
||||
ksft_eq(
|
||||
cpu1, cpu2, comment=f"Received traffic on different cpus with ports ({port1 = }, {port2 = }) while symmetric hash is configured")
|
||||
|
||||
successful += 1
|
||||
if successful == 10:
|
||||
break
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
raise KsftFailEx("Failed to run traffic")
|
||||
|
||||
ksft_ge(len(cpus), 2,
|
||||
comment=f"Received traffic on less than two cpus {cpus = }")
|
||||
|
||||
|
||||
def test_rss_input_xfrm_ipv4(cfg):
|
||||
cfg.require_ipver("4")
|
||||
test_rss_input_xfrm(cfg, "4")
|
||||
|
||||
|
||||
def test_rss_input_xfrm_ipv6(cfg):
|
||||
cfg.require_ipver("6")
|
||||
test_rss_input_xfrm(cfg, "6")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
|
||||
cfg.ethnl = EthtoolFamily()
|
||||
cfg.netdevnl = NetdevFamily()
|
||||
|
||||
ksft_run([test_rss_input_xfrm_ipv4, test_rss_input_xfrm_ipv6],
|
||||
args=(cfg, ))
|
||||
ksft_exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -15,4 +15,5 @@ except ModuleNotFoundError as e:
|
|||
sys.exit(4)
|
||||
|
||||
from .env import *
|
||||
from .load import *
|
||||
from .remote import Remote
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import os
|
||||
import shlex
|
||||
from pathlib import Path
|
||||
from lib.py import KsftSkipEx
|
||||
from lib.py import KsftSkipEx, KsftXfailEx
|
||||
from lib.py import cmd, ip
|
||||
from lib.py import NetNS, NetdevSimDev
|
||||
from .remote import Remote
|
||||
|
@ -76,7 +76,7 @@ class NetDrvEpEnv:
|
|||
nsim_v4_pfx = "192.0.2."
|
||||
nsim_v6_pfx = "2001:db8::"
|
||||
|
||||
def __init__(self, src_path):
|
||||
def __init__(self, src_path, nsim_test=None):
|
||||
|
||||
self.env = _load_env_file(src_path)
|
||||
|
||||
|
@ -88,6 +88,8 @@ class NetDrvEpEnv:
|
|||
self._ns_peer = None
|
||||
|
||||
if "NETIF" in self.env:
|
||||
if nsim_test is True:
|
||||
raise KsftXfailEx("Test only works on netdevsim")
|
||||
self.dev = ip("link show dev " + self.env['NETIF'], json=True)[0]
|
||||
|
||||
self.v4 = self.env.get("LOCAL_V4")
|
||||
|
@ -97,6 +99,9 @@ class NetDrvEpEnv:
|
|||
kind = self.env["REMOTE_TYPE"]
|
||||
args = self.env["REMOTE_ARGS"]
|
||||
else:
|
||||
if nsim_test is False:
|
||||
raise KsftXfailEx("Test does not work on netdevsim")
|
||||
|
||||
self.create_local()
|
||||
|
||||
self.dev = self._ns.nsims[0].dev
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import time
|
||||
|
||||
from lib.py import ksft_pr, cmd, ip, rand_port, wait_port_listen
|
||||
|
||||
class GenerateTraffic:
|
||||
def __init__(self, env, port=None):
|
||||
env.require_cmd("iperf3", remote=True)
|
||||
|
||||
self.env = env
|
||||
|
||||
if port is None:
|
||||
port = rand_port()
|
||||
self._iperf_server = cmd(f"iperf3 -s -1 -p {port}", background=True)
|
||||
wait_port_listen(port)
|
||||
time.sleep(0.1)
|
||||
self._iperf_client = cmd(f"iperf3 -c {env.addr} -P 16 -p {port} -t 86400",
|
||||
background=True, host=env.remote)
|
||||
|
||||
# Wait for traffic to ramp up
|
||||
pkt = ip("-s link show dev " + env.ifname, json=True)[0]["stats64"]["rx"]["packets"]
|
||||
for _ in range(50):
|
||||
time.sleep(0.1)
|
||||
now = ip("-s link show dev " + env.ifname, json=True)[0]["stats64"]["rx"]["packets"]
|
||||
if now - pkt > 1000:
|
||||
return
|
||||
pkt = now
|
||||
self.stop(verbose=True)
|
||||
raise Exception("iperf3 traffic did not ramp up")
|
||||
|
||||
def stop(self, verbose=None):
|
||||
self._iperf_client.process(terminate=True)
|
||||
if verbose:
|
||||
ksft_pr(">> Client:")
|
||||
ksft_pr(self._iperf_client.stdout)
|
||||
ksft_pr(self._iperf_client.stderr)
|
||||
self._iperf_server.process(terminate=True)
|
||||
if verbose:
|
||||
ksft_pr(">> Server:")
|
||||
ksft_pr(self._iperf_server.stdout)
|
||||
ksft_pr(self._iperf_server.stderr)
|
|
@ -6,11 +6,16 @@ import sys
|
|||
import time
|
||||
import traceback
|
||||
from .consts import KSFT_MAIN_NAME
|
||||
from .utils import global_defer_queue
|
||||
|
||||
KSFT_RESULT = None
|
||||
KSFT_RESULT_ALL = True
|
||||
|
||||
|
||||
class KsftFailEx(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class KsftSkipEx(Exception):
|
||||
pass
|
||||
|
||||
|
@ -38,6 +43,12 @@ def ksft_eq(a, b, comment=""):
|
|||
_fail("Check failed", a, "!=", b, comment)
|
||||
|
||||
|
||||
def ksft_ne(a, b, comment=""):
|
||||
global KSFT_RESULT
|
||||
if a == b:
|
||||
_fail("Check failed", a, "==", b, comment)
|
||||
|
||||
|
||||
def ksft_true(a, comment=""):
|
||||
if not a:
|
||||
_fail("Check failed", a, "does not eval to True", comment)
|
||||
|
@ -53,6 +64,11 @@ def ksft_ge(a, b, comment=""):
|
|||
_fail("Check failed", a, "<", b, comment)
|
||||
|
||||
|
||||
def ksft_lt(a, b, comment=""):
|
||||
if a >= b:
|
||||
_fail("Check failed", a, ">=", b, comment)
|
||||
|
||||
|
||||
class ksft_raises:
|
||||
def __init__(self, expected_type):
|
||||
self.exception = None
|
||||
|
@ -99,6 +115,24 @@ def ktap_result(ok, cnt=1, case="", comment=""):
|
|||
print(res)
|
||||
|
||||
|
||||
def ksft_flush_defer():
|
||||
global KSFT_RESULT
|
||||
|
||||
i = 0
|
||||
qlen_start = len(global_defer_queue)
|
||||
while global_defer_queue:
|
||||
i += 1
|
||||
entry = global_defer_queue.pop()
|
||||
try:
|
||||
entry.exec_only()
|
||||
except:
|
||||
ksft_pr(f"Exception while handling defer / cleanup (callback {i} of {qlen_start})!")
|
||||
tb = traceback.format_exc()
|
||||
for line in tb.strip().split('\n'):
|
||||
ksft_pr("Defer Exception|", line)
|
||||
KSFT_RESULT = False
|
||||
|
||||
|
||||
def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
|
||||
cases = cases or []
|
||||
|
||||
|
@ -121,29 +155,31 @@ def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
|
|||
for case in cases:
|
||||
KSFT_RESULT = True
|
||||
cnt += 1
|
||||
comment = ""
|
||||
cnt_key = ""
|
||||
|
||||
try:
|
||||
case(*args)
|
||||
except KsftSkipEx as e:
|
||||
ktap_result(True, cnt, case, comment="SKIP " + str(e))
|
||||
totals['skip'] += 1
|
||||
continue
|
||||
comment = "SKIP " + str(e)
|
||||
cnt_key = 'skip'
|
||||
except KsftXfailEx as e:
|
||||
ktap_result(True, cnt, case, comment="XFAIL " + str(e))
|
||||
totals['xfail'] += 1
|
||||
continue
|
||||
comment = "XFAIL " + str(e)
|
||||
cnt_key = 'xfail'
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
for line in tb.strip().split('\n'):
|
||||
ksft_pr("Exception|", line)
|
||||
ktap_result(False, cnt, case)
|
||||
totals['fail'] += 1
|
||||
continue
|
||||
KSFT_RESULT = False
|
||||
cnt_key = 'fail'
|
||||
|
||||
ktap_result(KSFT_RESULT, cnt, case)
|
||||
if KSFT_RESULT:
|
||||
totals['pass'] += 1
|
||||
else:
|
||||
totals['fail'] += 1
|
||||
ksft_flush_defer()
|
||||
|
||||
if not cnt_key:
|
||||
cnt_key = 'pass' if KSFT_RESULT else 'fail'
|
||||
|
||||
ktap_result(KSFT_RESULT, cnt, case, comment=comment)
|
||||
totals[cnt_key] += 1
|
||||
|
||||
print(
|
||||
f"# Totals: pass:{totals['pass']} fail:{totals['fail']} xfail:{totals['xfail']} xpass:0 skip:{totals['skip']} error:0"
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import errno
|
||||
import json as _json
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import select
|
||||
import socket
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
class CmdExitFailure(Exception):
|
||||
pass
|
||||
|
||||
def fd_read_timeout(fd, timeout):
|
||||
rlist, _, _ = select.select([fd], [], [], timeout)
|
||||
if rlist:
|
||||
return os.read(fd, 1024)
|
||||
else:
|
||||
raise TimeoutError("Timeout waiting for fd read")
|
||||
|
||||
|
||||
class cmd:
|
||||
def __init__(self, comm, shell=True, fail=True, ns=None, background=False, host=None, timeout=5):
|
||||
if ns:
|
||||
|
@ -41,7 +56,8 @@ class cmd:
|
|||
if self.proc.returncode != 0 and fail:
|
||||
if len(stderr) > 0 and stderr[-1] == "\n":
|
||||
stderr = stderr[:-1]
|
||||
raise Exception("Command failed: %s\n%s" % (self.proc.args, stderr))
|
||||
raise CmdExitFailure("Command failed: %s\nSTDOUT: %s\nSTDERR: %s" %
|
||||
(self.proc.args, stdout, stderr))
|
||||
|
||||
|
||||
class bkg(cmd):
|
||||
|
@ -58,11 +74,45 @@ class bkg(cmd):
|
|||
def __exit__(self, ex_type, ex_value, ex_tb):
|
||||
return self.process(terminate=self.terminate, fail=self.check_fail)
|
||||
|
||||
global_defer_queue = []
|
||||
|
||||
def ip(args, json=None, ns=None, host=None):
|
||||
cmd_str = "ip "
|
||||
|
||||
class defer:
|
||||
def __init__(self, func, *args, **kwargs):
|
||||
global global_defer_queue
|
||||
|
||||
if not callable(func):
|
||||
raise Exception("defer created with un-callable object, did you call the function instead of passing its name?")
|
||||
|
||||
self.func = func
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
self._queue = global_defer_queue
|
||||
self._queue.append(self)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, ex_type, ex_value, ex_tb):
|
||||
return self.exec()
|
||||
|
||||
def exec_only(self):
|
||||
self.func(*self.args, **self.kwargs)
|
||||
|
||||
def cancel(self):
|
||||
self._queue.remove(self)
|
||||
|
||||
def exec(self):
|
||||
self.cancel()
|
||||
self.exec_only()
|
||||
|
||||
|
||||
|
||||
def tool(name, args, json=None, ns=None, host=None):
|
||||
cmd_str = name + ' '
|
||||
if json:
|
||||
cmd_str += '-j '
|
||||
cmd_str += '--json '
|
||||
cmd_str += args
|
||||
cmd_obj = cmd(cmd_str, ns=ns, host=host)
|
||||
if json:
|
||||
|
@ -70,11 +120,23 @@ def ip(args, json=None, ns=None, host=None):
|
|||
return cmd_obj
|
||||
|
||||
|
||||
def rand_port():
|
||||
def ip(args, json=None, ns=None, host=None):
|
||||
if ns:
|
||||
args = f'-netns {ns} ' + args
|
||||
return tool('ip', args, json=json, host=host)
|
||||
|
||||
|
||||
def ethtool(args, json=None, ns=None, host=None):
|
||||
return tool('ethtool', args, json=json, ns=ns, host=host)
|
||||
|
||||
|
||||
def rand_port(type=socket.SOCK_STREAM):
|
||||
"""
|
||||
Get unprivileged port, for now just random, one day we may decide to check if used.
|
||||
Get a random unprivileged port.
|
||||
"""
|
||||
return random.randint(1024, 65535)
|
||||
with socket.socket(socket.AF_INET6, type) as s:
|
||||
s.bind(("", 0))
|
||||
return s.getsockname()[1]
|
||||
|
||||
|
||||
def wait_port_listen(port, proto="tcp", ns=None, host=None, sleep=0.005, deadline=5):
|
||||
|
|
|
@ -57,6 +57,8 @@ static struct sof_flag sof_flags[] = {
|
|||
SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE),
|
||||
SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE),
|
||||
SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE),
|
||||
SOF_FLAG(SOF_TIMESTAMPING_OPT_RX_FILTER),
|
||||
SOF_FLAG(SOF_TIMESTAMPING_RAW_HARDWARE),
|
||||
};
|
||||
|
||||
static struct socket_type socket_types[] = {
|
||||
|
@ -97,6 +99,22 @@ static struct test_case test_cases[] = {
|
|||
| SOF_TIMESTAMPING_RX_HARDWARE },
|
||||
{}
|
||||
},
|
||||
{
|
||||
{ .so_timestamping = SOF_TIMESTAMPING_RAW_HARDWARE
|
||||
| SOF_TIMESTAMPING_OPT_RX_FILTER },
|
||||
{}
|
||||
},
|
||||
{
|
||||
{ .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
|
||||
| SOF_TIMESTAMPING_OPT_RX_FILTER },
|
||||
{}
|
||||
},
|
||||
{
|
||||
{ .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
|
||||
| SOF_TIMESTAMPING_RX_SOFTWARE
|
||||
| SOF_TIMESTAMPING_OPT_RX_FILTER },
|
||||
{ .swtstamp = true }
|
||||
},
|
||||
{
|
||||
{ .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
|
||||
| SOF_TIMESTAMPING_RX_SOFTWARE },
|
||||
|
|
Loading…
Reference in New Issue