From 0caab0a46d066f068952776cba64158c25be70d4 Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Mon, 11 Sep 2023 11:13:07 +0530 Subject: dt-bindings: net: Add compatible for AM64x in ICSSG Add compatible for AM64x in icssg-prueth dt bindings. AM64x supports ICSSG similar to AM65x SR2.0. Acked-by: Krzysztof Kozlowski Reviewed-by: Roger Quadros Signed-off-by: MD Danish Anwar Signed-off-by: Paolo Abeni --- Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml index 311c570165f9..836d2d60e87d 100644 --- a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +++ b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml @@ -19,6 +19,7 @@ allOf: properties: compatible: enum: + - ti,am642-icssg-prueth # for AM64x SoC family - ti,am654-icssg-prueth # for AM65x SoC family sram: -- cgit v1.2.3 From 133c4c0d37175f510a10fa9bed51e223936073fc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 11 Sep 2023 17:05:31 +0000 Subject: tcp: defer regular ACK while processing socket backlog This idea came after a particular workload requested the quickack attribute set on routes, and a performance drop was noticed for large bulk transfers. For high throughput flows, it is best to use one cpu running the user thread issuing socket system calls, and a separate cpu to process incoming packets from BH context. (With TSO/GRO, bottleneck is usually the 'user' cpu) Problem is the user thread can spend a lot of time while holding the socket lock, forcing BH handler to queue most of incoming packets in the socket backlog. Whenever the user thread releases the socket lock, it must first process all accumulated packets in the backlog, potentially adding latency spikes. Due to flood mitigation, having too many packets in the backlog increases chance of unexpected drops. Backlog processing unfortunately shifts a fair amount of cpu cycles from the BH cpu to the 'user' cpu, thus reducing max throughput. This patch takes advantage of the backlog processing, and the fact that ACK are mostly cumulative. The idea is to detect we are in the backlog processing and defer all eligible ACK into a single one, sent from tcp_release_cb(). This saves cpu cycles on both sides, and network resources. Performance of a single TCP flow on a 200Gbit NIC: - Throughput is increased by 20% (100Gbit -> 120Gbit). - Number of generated ACK per second shrinks from 240,000 to 40,000. - Number of backlog drops per second shrinks from 230 to 0. Benchmark context: - Regular netperf TCP_STREAM (no zerocopy) - Intel(R) Xeon(R) Platinum 8481C (Saphire Rapids) - MAX_SKB_FRAGS = 17 (~60KB per GRO packet) This feature is guarded by a new sysctl, and enabled by default: /proc/sys/net/ipv4/tcp_backlog_ack_defer Signed-off-by: Eric Dumazet Acked-by: Yuchung Cheng Acked-by: Neal Cardwell Acked-by: Soheil Hassas Yeganeh Acked-by: Dave Taht Signed-off-by: Paolo Abeni --- Documentation/networking/ip-sysctl.rst | 7 +++++++ include/linux/tcp.h | 14 ++++++++------ include/net/netns/ipv4.h | 1 + net/ipv4/sysctl_net_ipv4.c | 9 +++++++++ net/ipv4/tcp_input.c | 8 ++++++++ net/ipv4/tcp_ipv4.c | 1 + net/ipv4/tcp_output.c | 5 ++++- 7 files changed, 38 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index a66054d0763a..5bfa1837968c 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -745,6 +745,13 @@ tcp_comp_sack_nr - INTEGER Default : 44 +tcp_backlog_ack_defer - BOOLEAN + If set, user thread processing socket backlog tries sending + one ACK for the whole queue. This helps to avoid potential + long latencies at end of a TCP socket syscall. + + Default : true + tcp_slow_start_after_idle - BOOLEAN If set, provide RFC2861 behavior and time out the congestion window after an idle period. An idle period is defined at diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 3c5efeeb024f..44d946161d4a 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -463,15 +463,17 @@ enum tsq_enum { TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call * tcp_v{4|6}_mtu_reduced() */ + TCP_ACK_DEFERRED, /* TX pure ack is deferred */ }; enum tsq_flags { - TSQF_THROTTLED = (1UL << TSQ_THROTTLED), - TSQF_QUEUED = (1UL << TSQ_QUEUED), - TCPF_TSQ_DEFERRED = (1UL << TCP_TSQ_DEFERRED), - TCPF_WRITE_TIMER_DEFERRED = (1UL << TCP_WRITE_TIMER_DEFERRED), - TCPF_DELACK_TIMER_DEFERRED = (1UL << TCP_DELACK_TIMER_DEFERRED), - TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED), + TSQF_THROTTLED = BIT(TSQ_THROTTLED), + TSQF_QUEUED = BIT(TSQ_QUEUED), + TCPF_TSQ_DEFERRED = BIT(TCP_TSQ_DEFERRED), + TCPF_WRITE_TIMER_DEFERRED = BIT(TCP_WRITE_TIMER_DEFERRED), + TCPF_DELACK_TIMER_DEFERRED = BIT(TCP_DELACK_TIMER_DEFERRED), + TCPF_MTU_REDUCED_DEFERRED = BIT(TCP_MTU_REDUCED_DEFERRED), + TCPF_ACK_DEFERRED = BIT(TCP_ACK_DEFERRED), }; #define tcp_sk(ptr) container_of_const(ptr, struct tcp_sock, inet_conn.icsk_inet.sk) diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 7a41c4791536..d96d05b08819 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -132,6 +132,7 @@ struct netns_ipv4 { u8 sysctl_tcp_syncookies; u8 sysctl_tcp_migrate_req; u8 sysctl_tcp_comp_sack_nr; + u8 sysctl_tcp_backlog_ack_defer; int sysctl_tcp_reordering; u8 sysctl_tcp_retries1; u8 sysctl_tcp_retries2; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 6ac890b4073f..e7f024d93572 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1366,6 +1366,15 @@ static struct ctl_table ipv4_net_table[] = { .proc_handler = proc_dou8vec_minmax, .extra1 = SYSCTL_ZERO, }, + { + .procname = "tcp_backlog_ack_defer", + .data = &init_net.ipv4.sysctl_tcp_backlog_ack_defer, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, { .procname = "tcp_reflect_tos", .data = &init_net.ipv4.sysctl_tcp_reflect_tos, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 06fe1cf645d5..41b471748437 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5553,6 +5553,14 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) tcp_in_quickack_mode(sk) || /* Protocol state mandates a one-time immediate ACK */ inet_csk(sk)->icsk_ack.pending & ICSK_ACK_NOW) { + /* If we are running from __release_sock() in user context, + * Defer the ack until tcp_release_cb(). + */ + if (sock_owned_by_user_nocheck(sk) && + READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_backlog_ack_defer)) { + set_bit(TCP_ACK_DEFERRED, &sk->sk_tsq_flags); + return; + } send_now: tcp_send_ack(sk); return; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 27140e5cdc06..f13eb7e23d03 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3263,6 +3263,7 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.sysctl_tcp_comp_sack_delay_ns = NSEC_PER_MSEC; net->ipv4.sysctl_tcp_comp_sack_slack_ns = 100 * NSEC_PER_USEC; net->ipv4.sysctl_tcp_comp_sack_nr = 44; + net->ipv4.sysctl_tcp_backlog_ack_defer = 1; net->ipv4.sysctl_tcp_fastopen = TFO_CLIENT_ENABLE; net->ipv4.sysctl_tcp_fastopen_blackhole_timeout = 0; atomic_set(&net->ipv4.tfo_active_disable_times, 0); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b4cac12d0e63..1fc1f879cfd6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1077,7 +1077,8 @@ static void tcp_tasklet_func(struct tasklet_struct *t) #define TCP_DEFERRED_ALL (TCPF_TSQ_DEFERRED | \ TCPF_WRITE_TIMER_DEFERRED | \ TCPF_DELACK_TIMER_DEFERRED | \ - TCPF_MTU_REDUCED_DEFERRED) + TCPF_MTU_REDUCED_DEFERRED | \ + TCPF_ACK_DEFERRED) /** * tcp_release_cb - tcp release_sock() callback * @sk: socket @@ -1114,6 +1115,8 @@ void tcp_release_cb(struct sock *sk) inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); __sock_put(sk); } + if ((flags & TCPF_ACK_DEFERRED) && inet_csk_ack_scheduled(sk)) + tcp_send_ack(sk); } EXPORT_SYMBOL(tcp_release_cb); -- cgit v1.2.3 From 558c50cc3b135e00c9ed15df4c9159e84166f94c Mon Sep 17 00:00:00 2001 From: Quan Tian Date: Mon, 11 Sep 2023 15:23:53 +0000 Subject: docs/bpf: update out-of-date doc in BPF flow dissector Commit a5e2151ff9d5 ("net/ipv6: SKB symmetric hash should incorporate transport ports") removed the use of FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL in __skb_get_hash_symmetric(), making the doc out-of-date. Signed-off-by: Quan Tian Link: https://lore.kernel.org/r/20230911152353.8280-1-qtian@vmware.com Signed-off-by: Martin KaFai Lau --- Documentation/bpf/prog_flow_dissector.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/bpf/prog_flow_dissector.rst b/Documentation/bpf/prog_flow_dissector.rst index 4d86780ab0f1..f24270b8b034 100644 --- a/Documentation/bpf/prog_flow_dissector.rst +++ b/Documentation/bpf/prog_flow_dissector.rst @@ -113,7 +113,7 @@ Flags used by ``eth_get_headlen`` to estimate length of all headers for GRO. * ``BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL`` - tells BPF flow dissector to stop parsing as soon as it reaches IPv6 flow label; used by - ``___skb_get_hash`` and ``__skb_get_hash_symmetric`` to get flow hash. + ``___skb_get_hash`` to get flow hash. * ``BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP`` - tells BPF flow dissector to stop parsing as soon as it reaches encapsulated headers; used by routing infrastructure. -- cgit v1.2.3 From a251eee62133774cf35ff829041377e721ef9c8c Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Mon, 7 Aug 2023 17:34:16 -0700 Subject: idpf: add SRIOV support and other ndo_ops Add support for SRIOV: send the requested number of VFs to the device Control Plane, via the virtchnl message and then enable the VFs using 'pci_enable_sriov'. Add other ndo ops supported by the driver such as features_check, set_rx_mode, validate_addr, set_mac_address, change_mtu, get_stats64, set_features, and tx_timeout. Initialize the statistics task which requests the queue related statistics to the CP. Add loopback and promiscuous mode support and the respective virtchnl messages. Finally, add documentation and build support for the driver. Signed-off-by: Joshua Hay Co-developed-by: Alan Brady Signed-off-by: Alan Brady Co-developed-by: Madhu Chittim Signed-off-by: Madhu Chittim Co-developed-by: Phani Burra Signed-off-by: Phani Burra Reviewed-by: Sridhar Samudrala Reviewed-by: Willem de Bruijn Co-developed-by: Pavan Kumar Linga Signed-off-by: Pavan Kumar Linga Signed-off-by: Tony Nguyen --- .../networking/device_drivers/ethernet/index.rst | 1 + .../device_drivers/ethernet/intel/idpf.rst | 160 +++++ drivers/net/ethernet/intel/Kconfig | 12 + drivers/net/ethernet/intel/Makefile | 1 + drivers/net/ethernet/intel/idpf/idpf.h | 51 ++ drivers/net/ethernet/intel/idpf/idpf_lib.c | 644 ++++++++++++++++++++- drivers/net/ethernet/intel/idpf/idpf_main.c | 17 + drivers/net/ethernet/intel/idpf/idpf_txrx.c | 21 + drivers/net/ethernet/intel/idpf/idpf_txrx.h | 2 + drivers/net/ethernet/intel/idpf/idpf_virtchnl.c | 208 +++++++ 10 files changed, 1114 insertions(+), 3 deletions(-) create mode 100644 Documentation/networking/device_drivers/ethernet/intel/idpf.rst (limited to 'Documentation') diff --git a/Documentation/networking/device_drivers/ethernet/index.rst b/Documentation/networking/device_drivers/ethernet/index.rst index 9827e816084b..43de285b8a92 100644 --- a/Documentation/networking/device_drivers/ethernet/index.rst +++ b/Documentation/networking/device_drivers/ethernet/index.rst @@ -32,6 +32,7 @@ Contents: intel/e1000 intel/e1000e intel/fm10k + intel/idpf intel/igb intel/igbvf intel/ixgbe diff --git a/Documentation/networking/device_drivers/ethernet/intel/idpf.rst b/Documentation/networking/device_drivers/ethernet/intel/idpf.rst new file mode 100644 index 000000000000..adb16e2abd21 --- /dev/null +++ b/Documentation/networking/device_drivers/ethernet/intel/idpf.rst @@ -0,0 +1,160 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +========================================================================== +idpf Linux* Base Driver for the Intel(R) Infrastructure Data Path Function +========================================================================== + +Intel idpf Linux driver. +Copyright(C) 2023 Intel Corporation. + +.. contents:: + +The idpf driver serves as both the Physical Function (PF) and Virtual Function +(VF) driver for the Intel(R) Infrastructure Data Path Function. + +Driver information can be obtained using ethtool, lspci, and ip. + +For questions related to hardware requirements, refer to the documentation +supplied with your Intel adapter. All hardware requirements listed apply to use +with Linux. + + +Identifying Your Adapter +======================== +For information on how to identify your adapter, and for the latest Intel +network drivers, refer to the Intel Support website: +http://www.intel.com/support + + +Additional Features and Configurations +====================================== + +ethtool +------- +The driver utilizes the ethtool interface for driver configuration and +diagnostics, as well as displaying statistical information. The latest ethtool +version is required for this functionality. If you don't have one yet, you can +obtain it at: +https://kernel.org/pub/software/network/ethtool/ + + +Viewing Link Messages +--------------------- +Link messages will not be displayed to the console if the distribution is +restricting system messages. In order to see network driver link messages on +your console, set dmesg to eight by entering the following:: + + # dmesg -n 8 + +.. note:: + This setting is not saved across reboots. + + +Jumbo Frames +------------ +Jumbo Frames support is enabled by changing the Maximum Transmission Unit (MTU) +to a value larger than the default value of 1500. + +Use the ip command to increase the MTU size. For example, enter the following +where is the interface number:: + + # ip link set mtu 9000 dev + # ip link set up dev + +.. note:: + The maximum MTU setting for jumbo frames is 9706. This corresponds to the + maximum jumbo frame size of 9728 bytes. + +.. note:: + This driver will attempt to use multiple page sized buffers to receive + each jumbo packet. This should help to avoid buffer starvation issues when + allocating receive packets. + +.. note:: + Packet loss may have a greater impact on throughput when you use jumbo + frames. If you observe a drop in performance after enabling jumbo frames, + enabling flow control may mitigate the issue. + + +Performance Optimization +======================== +Driver defaults are meant to fit a wide variety of workloads, but if further +optimization is required, we recommend experimenting with the following +settings. + + +Interrupt Rate Limiting +----------------------- +This driver supports an adaptive interrupt throttle rate (ITR) mechanism that +is tuned for general workloads. The user can customize the interrupt rate +control for specific workloads, via ethtool, adjusting the number of +microseconds between interrupts. + +To set the interrupt rate manually, you must disable adaptive mode:: + + # ethtool -C adaptive-rx off adaptive-tx off + +For lower CPU utilization: + - Disable adaptive ITR and lower Rx and Tx interrupts. The examples below + affect every queue of the specified interface. + + - Setting rx-usecs and tx-usecs to 80 will limit interrupts to about + 12,500 interrupts per second per queue:: + + # ethtool -C adaptive-rx off adaptive-tx off rx-usecs 80 + tx-usecs 80 + +For reduced latency: + - Disable adaptive ITR and ITR by setting rx-usecs and tx-usecs to 0 + using ethtool:: + + # ethtool -C adaptive-rx off adaptive-tx off rx-usecs 0 + tx-usecs 0 + +Per-queue interrupt rate settings: + - The following examples are for queues 1 and 3, but you can adjust other + queues. + + - To disable Rx adaptive ITR and set static Rx ITR to 10 microseconds or + about 100,000 interrupts/second, for queues 1 and 3:: + + # ethtool --per-queue queue_mask 0xa --coalesce adaptive-rx off + rx-usecs 10 + + - To show the current coalesce settings for queues 1 and 3:: + + # ethtool --per-queue queue_mask 0xa --show-coalesce + + + +Virtualized Environments +------------------------ +In addition to the other suggestions in this section, the following may be +helpful to optimize performance in VMs. + + - Using the appropriate mechanism (vcpupin) in the VM, pin the CPUs to + individual LCPUs, making sure to use a set of CPUs included in the + device's local_cpulist: /sys/class/net//device/local_cpulist. + + - Configure as many Rx/Tx queues in the VM as available. (See the idpf driver + documentation for the number of queues supported.) For example:: + + # ethtool -L rx tx + + +Support +======= +For general information, go to the Intel support website at: +http://www.intel.com/support/ + +If an issue is identified with the released source code on a supported kernel +with a supported adapter, email the specific information related to the issue +to intel-wired-lan@lists.osuosl.org. + + +Trademarks +========== +Intel is a trademark or registered trademark of Intel Corporation or its +subsidiaries in the United States and/or other countries. + +* Other names and brands may be claimed as the property of others. diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 9bc0a9519899..d57f70d6e4d4 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -355,5 +355,17 @@ config IGC To compile this driver as a module, choose M here. The module will be called igc. +config IDPF + tristate "Intel(R) Infrastructure Data Path Function Support" + depends on PCI_MSI + select DIMLIB + select PAGE_POOL + select PAGE_POOL_STATS + help + This driver supports Intel(R) Infrastructure Data Path Function + devices. + + To compile this driver as a module, choose M here. The module + will be called idpf. endif # NET_VENDOR_INTEL diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile index d80d04132073..dacb481ee5b1 100644 --- a/drivers/net/ethernet/intel/Makefile +++ b/drivers/net/ethernet/intel/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_I40E) += i40e/ obj-$(CONFIG_IAVF) += iavf/ obj-$(CONFIG_FM10K) += fm10k/ obj-$(CONFIG_ICE) += ice/ +obj-$(CONFIG_IDPF) += idpf/ diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index e016a7db6b73..bee73353b56a 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -147,6 +147,8 @@ enum idpf_vport_state { * @vport_id: Vport identifier * @vport_idx: Relative vport index * @state: See enum idpf_vport_state + * @netstats: Packet and byte stats + * @stats_lock: Lock to protect stats update */ struct idpf_netdev_priv { struct idpf_adapter *adapter; @@ -154,6 +156,8 @@ struct idpf_netdev_priv { u32 vport_id; u16 vport_idx; enum idpf_vport_state state; + struct rtnl_link_stats64 netstats; + spinlock_t stats_lock; }; /** @@ -239,6 +243,8 @@ struct idpf_dev_ops { STATE(IDPF_VC_ALLOC_VECTORS_ERR) \ STATE(IDPF_VC_DEALLOC_VECTORS) \ STATE(IDPF_VC_DEALLOC_VECTORS_ERR) \ + STATE(IDPF_VC_SET_SRIOV_VFS) \ + STATE(IDPF_VC_SET_SRIOV_VFS_ERR) \ STATE(IDPF_VC_GET_RSS_LUT) \ STATE(IDPF_VC_GET_RSS_LUT_ERR) \ STATE(IDPF_VC_SET_RSS_LUT) \ @@ -247,12 +253,16 @@ struct idpf_dev_ops { STATE(IDPF_VC_GET_RSS_KEY_ERR) \ STATE(IDPF_VC_SET_RSS_KEY) \ STATE(IDPF_VC_SET_RSS_KEY_ERR) \ + STATE(IDPF_VC_GET_STATS) \ + STATE(IDPF_VC_GET_STATS_ERR) \ STATE(IDPF_VC_ADD_MAC_ADDR) \ STATE(IDPF_VC_ADD_MAC_ADDR_ERR) \ STATE(IDPF_VC_DEL_MAC_ADDR) \ STATE(IDPF_VC_DEL_MAC_ADDR_ERR) \ STATE(IDPF_VC_GET_PTYPE_INFO) \ STATE(IDPF_VC_GET_PTYPE_INFO_ERR) \ + STATE(IDPF_VC_LOOPBACK_STATE) \ + STATE(IDPF_VC_LOOPBACK_STATE_ERR) \ STATE(IDPF_VC_NBITS) #define IDPF_GEN_ENUM(ENUM) ENUM, @@ -268,10 +278,14 @@ extern const char * const idpf_vport_vc_state_str[]; * enum idpf_vport_reset_cause - Vport soft reset causes * @IDPF_SR_Q_CHANGE: Soft reset queue change * @IDPF_SR_Q_DESC_CHANGE: Soft reset descriptor change + * @IDPF_SR_MTU_CHANGE: Soft reset MTU change + * @IDPF_SR_RSC_CHANGE: Soft reset RSC change */ enum idpf_vport_reset_cause { IDPF_SR_Q_CHANGE, IDPF_SR_Q_DESC_CHANGE, + IDPF_SR_MTU_CHANGE, + IDPF_SR_RSC_CHANGE, }; /** @@ -402,6 +416,19 @@ struct idpf_vport { struct mutex vc_buf_lock; }; +/** + * enum idpf_user_flags + * @__IDPF_PROMISC_UC: Unicast promiscuous mode + * @__IDPF_PROMISC_MC: Multicast promiscuous mode + * @__IDPF_USER_FLAGS_NBITS: Must be last + */ +enum idpf_user_flags { + __IDPF_PROMISC_UC = 32, + __IDPF_PROMISC_MC, + + __IDPF_USER_FLAGS_NBITS, +}; + /** * struct idpf_rss_data - Associated RSS data * @rss_key_size: Size of RSS hash key @@ -428,6 +455,7 @@ struct idpf_rss_data { * ethtool * @num_req_rxq_desc: Number of user requested RX queue descriptors through * ethtool + * @user_flags: User toggled config flags * @mac_filter_list: List of MAC filters * * Used to restore configuration after a reset as the vport will get wiped. @@ -438,6 +466,7 @@ struct idpf_vport_user_config_data { u16 num_req_rx_qs; u32 num_req_txq_desc; u32 num_req_rxq_desc; + DECLARE_BITMAP(user_flags, __IDPF_USER_FLAGS_NBITS); struct list_head mac_filter_list; }; @@ -548,6 +577,7 @@ struct idpf_vport_config { * @mb_vector: Mailbox vector data * @vector_stack: Stack to store the msix vector indexes * @irq_mb_handler: Handler for hard interrupt for mailbox + * @tx_timeout_count: Number of TX timeouts that have occurred * @avail_queues: Device given queue limits * @vports: Array to store vports created by the driver * @netdevs: Associated Vport netdevs @@ -566,6 +596,8 @@ struct idpf_vport_config { * @mbx_wq: Workqueue for mailbox responses * @vc_event_task: Task to handle out of band virtchnl event notifications * @vc_event_wq: Workqueue for virtchnl events + * @stats_task: Periodic statistics retrieval task + * @stats_wq: Workqueue for statistics task * @caps: Negotiated capabilities with device * @vchnl_wq: Wait queue for virtchnl messages * @vc_state: Virtchnl message state @@ -601,6 +633,7 @@ struct idpf_adapter { struct idpf_vector_lifo vector_stack; irqreturn_t (*irq_mb_handler)(int irq, void *data); + u32 tx_timeout_count; struct idpf_avail_queue_info avail_queues; struct idpf_vport **vports; struct net_device **netdevs; @@ -621,6 +654,8 @@ struct idpf_adapter { struct workqueue_struct *mbx_wq; struct delayed_work vc_event_task; struct workqueue_struct *vc_event_wq; + struct delayed_work stats_task; + struct workqueue_struct *stats_wq; struct virtchnl2_get_capabilities caps; wait_queue_head_t vchnl_wq; @@ -825,6 +860,15 @@ static inline bool idpf_is_feature_ena(const struct idpf_vport *vport, return vport->netdev->features & feature; } +/** + * idpf_get_max_tx_hdr_size -- get the size of tx header + * @adapter: Driver specific private structure + */ +static inline u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter) +{ + return le16_to_cpu(adapter->caps.max_tx_hdr_size); +} + /** * idpf_vport_ctrl_lock - Acquire the vport control lock * @netdev: Network interface device structure @@ -850,6 +894,7 @@ static inline void idpf_vport_ctrl_unlock(struct net_device *netdev) mutex_unlock(&np->adapter->vport_ctrl_lock); } +void idpf_statistics_task(struct work_struct *work); void idpf_init_task(struct work_struct *work); void idpf_service_task(struct work_struct *work); void idpf_mbx_task(struct work_struct *work); @@ -865,6 +910,7 @@ int idpf_intr_req(struct idpf_adapter *adapter); void idpf_intr_rel(struct idpf_adapter *adapter); int idpf_get_reg_intr_vecs(struct idpf_vport *vport, struct idpf_vec_regs *reg_vals); +u16 idpf_get_max_tx_hdr_size(struct idpf_adapter *adapter); int idpf_send_delete_queues_msg(struct idpf_vport *vport); int idpf_send_add_queues_msg(const struct idpf_vport *vport, u16 num_tx_q, u16 num_complq, u16 num_rx_q, u16 num_rx_bufq); @@ -874,6 +920,7 @@ int idpf_send_enable_vport_msg(struct idpf_vport *vport); int idpf_send_disable_vport_msg(struct idpf_vport *vport); int idpf_send_destroy_vport_msg(struct idpf_vport *vport); int idpf_send_get_rx_ptype_msg(struct idpf_vport *vport); +int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport); int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get); int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get); int idpf_send_dealloc_vectors_msg(struct idpf_adapter *adapter); @@ -883,6 +930,7 @@ int idpf_req_rel_vector_indexes(struct idpf_adapter *adapter, u16 *q_vector_idxs, struct idpf_vector_info *vec_info); int idpf_vport_alloc_vec_indexes(struct idpf_vport *vport); +int idpf_send_get_stats_msg(struct idpf_vport *vport); int idpf_get_vec_ids(struct idpf_adapter *adapter, u16 *vecids, int num_vecids, struct virtchnl2_vector_chunks *chunks); @@ -898,6 +946,9 @@ void idpf_vport_dealloc_max_qs(struct idpf_adapter *adapter, int idpf_add_del_mac_filters(struct idpf_vport *vport, struct idpf_netdev_priv *np, bool add, bool async); +int idpf_set_promiscuous(struct idpf_adapter *adapter, + struct idpf_vport_user_config_data *config_data, + u32 vport_id); int idpf_send_disable_queues_msg(struct idpf_vport *vport); void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q); u32 idpf_get_vport_id(struct idpf_vport *vport); diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 2387dede6191..19809b0ddcd9 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -455,6 +455,70 @@ static struct idpf_mac_filter *idpf_find_mac_filter(struct idpf_vport_config *vc return NULL; } +/** + * __idpf_del_mac_filter - Delete a MAC filter from the filter list + * @vport_config: Vport config structure + * @macaddr: The MAC address + * + * Returns 0 on success, error value on failure + **/ +static int __idpf_del_mac_filter(struct idpf_vport_config *vport_config, + const u8 *macaddr) +{ + struct idpf_mac_filter *f; + + spin_lock_bh(&vport_config->mac_filter_list_lock); + f = idpf_find_mac_filter(vport_config, macaddr); + if (f) { + list_del(&f->list); + kfree(f); + } + spin_unlock_bh(&vport_config->mac_filter_list_lock); + + return 0; +} + +/** + * idpf_del_mac_filter - Delete a MAC filter from the filter list + * @vport: Main vport structure + * @np: Netdev private structure + * @macaddr: The MAC address + * @async: Don't wait for return message + * + * Removes filter from list and if interface is up, tells hardware about the + * removed filter. + **/ +static int idpf_del_mac_filter(struct idpf_vport *vport, + struct idpf_netdev_priv *np, + const u8 *macaddr, bool async) +{ + struct idpf_vport_config *vport_config; + struct idpf_mac_filter *f; + + vport_config = np->adapter->vport_config[np->vport_idx]; + + spin_lock_bh(&vport_config->mac_filter_list_lock); + f = idpf_find_mac_filter(vport_config, macaddr); + if (f) { + f->remove = true; + } else { + spin_unlock_bh(&vport_config->mac_filter_list_lock); + + return -EINVAL; + } + spin_unlock_bh(&vport_config->mac_filter_list_lock); + + if (np->state == __IDPF_VPORT_UP) { + int err; + + err = idpf_add_del_mac_filters(vport, np, false, async); + if (err) + return err; + } + + return __idpf_del_mac_filter(vport_config, macaddr); +} + /** * __idpf_add_mac_filter - Add mac filter helper function * @vport_config: Vport config structure @@ -521,6 +585,77 @@ static int idpf_add_mac_filter(struct idpf_vport *vport, return err; } +/** + * idpf_del_all_mac_filters - Delete all MAC filters in list + * @vport: main vport struct + * + * Takes mac_filter_list_lock spinlock. Deletes all filters + */ +static void idpf_del_all_mac_filters(struct idpf_vport *vport) +{ + struct idpf_vport_config *vport_config; + struct idpf_mac_filter *f, *ftmp; + + vport_config = vport->adapter->vport_config[vport->idx]; + spin_lock_bh(&vport_config->mac_filter_list_lock); + + list_for_each_entry_safe(f, ftmp, &vport_config->user_config.mac_filter_list, + list) { + list_del(&f->list); + kfree(f); + } + + spin_unlock_bh(&vport_config->mac_filter_list_lock); +} + +/** + * idpf_restore_mac_filters - Re-add all MAC filters in list + * @vport: main vport struct + * + * Takes mac_filter_list_lock spinlock. Sets add field to true for filters to + * resync filters back to HW. + */ +static void idpf_restore_mac_filters(struct idpf_vport *vport) +{ + struct idpf_vport_config *vport_config; + struct idpf_mac_filter *f; + + vport_config = vport->adapter->vport_config[vport->idx]; + spin_lock_bh(&vport_config->mac_filter_list_lock); + + list_for_each_entry(f, &vport_config->user_config.mac_filter_list, list) + f->add = true; + + spin_unlock_bh(&vport_config->mac_filter_list_lock); + + idpf_add_del_mac_filters(vport, netdev_priv(vport->netdev), + true, false); +} + +/** + * idpf_remove_mac_filters - Remove all MAC filters in list + * @vport: main vport struct + * + * Takes mac_filter_list_lock spinlock. Sets remove field to true for filters + * to remove filters in HW. + */ +static void idpf_remove_mac_filters(struct idpf_vport *vport) +{ + struct idpf_vport_config *vport_config; + struct idpf_mac_filter *f; + + vport_config = vport->adapter->vport_config[vport->idx]; + spin_lock_bh(&vport_config->mac_filter_list_lock); + + list_for_each_entry(f, &vport_config->user_config.mac_filter_list, list) + f->remove = true; + + spin_unlock_bh(&vport_config->mac_filter_list_lock); + + idpf_add_del_mac_filters(vport, netdev_priv(vport->netdev), + false, false); +} + /** * idpf_deinit_mac_addr - deinitialize mac address for vport * @vport: main vport structure @@ -629,6 +764,8 @@ static int idpf_cfg_netdev(struct idpf_vport *vport) np->vport_idx = vport->idx; np->vport_id = vport->vport_id; + spin_lock_init(&np->stats_lock); + err = idpf_init_mac_addr(vport, netdev); if (err) { free_netdev(vport->netdev); @@ -735,6 +872,18 @@ static int idpf_get_free_slot(struct idpf_adapter *adapter) return IDPF_NO_FREE_SLOT; } +/** + * idpf_remove_features - Turn off feature configs + * @vport: virtual port structure + */ +static void idpf_remove_features(struct idpf_vport *vport) +{ + struct idpf_adapter *adapter = vport->adapter; + + if (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_MACFILTER)) + idpf_remove_mac_filters(vport); +} + /** * idpf_vport_stop - Disable a vport * @vport: vport to disable @@ -752,13 +901,16 @@ static void idpf_vport_stop(struct idpf_vport *vport) idpf_send_disable_vport_msg(vport); idpf_send_disable_queues_msg(vport); idpf_send_map_unmap_queue_vector_msg(vport, false); - /* Normally we ask for queues in create_vport, but if we're changing - * number of requested queues we do a delete then add instead of - * deleting and reallocating the vport. + /* Normally we ask for queues in create_vport, but if the number of + * initially requested queues have changed, for example via ethtool + * set channels, we do delete queues and then add the queues back + * instead of deleting and reallocating the vport. */ if (test_and_clear_bit(IDPF_VPORT_DEL_QUEUES, vport->flags)) idpf_send_delete_queues_msg(vport); + idpf_remove_features(vport); + vport->link_up = false; idpf_vport_intr_deinit(vport); idpf_vport_intr_rel(vport); @@ -866,6 +1018,10 @@ static void idpf_vport_rel(struct idpf_vport *vport) adapter->vport_params_recvd[idx] = NULL; kfree(adapter->vport_params_reqd[idx]); adapter->vport_params_reqd[idx] = NULL; + if (adapter->vport_config[idx]) { + kfree(adapter->vport_config[idx]->req_qs_chunks); + adapter->vport_config[idx]->req_qs_chunks = NULL; + } kfree(vport); adapter->num_alloc_vports--; } @@ -886,6 +1042,8 @@ static void idpf_vport_dealloc(struct idpf_vport *vport) if (!test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) idpf_decfg_netdev(vport); + if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) + idpf_del_all_mac_filters(vport); if (adapter->netdevs[i]) { struct idpf_netdev_priv *np = netdev_priv(adapter->netdevs[i]); @@ -975,6 +1133,43 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter, return vport; } +/** + * idpf_get_stats64 - get statistics for network device structure + * @netdev: network interface device structure + * @stats: main device statistics structure + */ +static void idpf_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct idpf_netdev_priv *np = netdev_priv(netdev); + + spin_lock_bh(&np->stats_lock); + *stats = np->netstats; + spin_unlock_bh(&np->stats_lock); +} + +/** + * idpf_statistics_task - Delayed task to get statistics over mailbox + * @work: work_struct handle to our data + */ +void idpf_statistics_task(struct work_struct *work) +{ + struct idpf_adapter *adapter; + int i; + + adapter = container_of(work, struct idpf_adapter, stats_task.work); + + for (i = 0; i < adapter->max_vports; i++) { + struct idpf_vport *vport = adapter->vports[i]; + + if (vport && !test_bit(IDPF_HR_RESET_IN_PROG, adapter->flags)) + idpf_send_get_stats_msg(vport); + } + + queue_delayed_work(adapter->stats_wq, &adapter->stats_task, + msecs_to_jiffies(10000)); +} + /** * idpf_mbx_task - Delayed task to handle mailbox responses * @work: work_struct handle @@ -1019,6 +1214,18 @@ void idpf_service_task(struct work_struct *work) msecs_to_jiffies(300)); } +/** + * idpf_restore_features - Restore feature configs + * @vport: virtual port structure + */ +static void idpf_restore_features(struct idpf_vport *vport) +{ + struct idpf_adapter *adapter = vport->adapter; + + if (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_MACFILTER)) + idpf_restore_mac_filters(vport); +} + /** * idpf_set_real_num_queues - set number of queues for netdev * @vport: virtual port structure @@ -1175,6 +1382,8 @@ static int idpf_vport_open(struct idpf_vport *vport, bool alloc_res) goto disable_queues; } + idpf_restore_features(vport); + vport_config = adapter->vport_config[vport->idx]; if (vport_config->user_config.rss_data.rss_lut) err = idpf_config_rss(vport); @@ -1317,6 +1526,9 @@ void idpf_init_task(struct work_struct *work) * unconditionally here in case we were in reset and the link was down. */ clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); + /* Start the statistics task now */ + queue_delayed_work(adapter->stats_wq, &adapter->stats_task, + msecs_to_jiffies(10 * (pdev->devfn & 0x07))); return; @@ -1335,6 +1547,70 @@ unwind_vports: clear_bit(IDPF_HR_RESET_IN_PROG, adapter->flags); } +/** + * idpf_sriov_ena - Enable or change number of VFs + * @adapter: private data struct + * @num_vfs: number of VFs to allocate + */ +static int idpf_sriov_ena(struct idpf_adapter *adapter, int num_vfs) +{ + struct device *dev = &adapter->pdev->dev; + int err; + + err = idpf_send_set_sriov_vfs_msg(adapter, num_vfs); + if (err) { + dev_err(dev, "Failed to allocate VFs: %d\n", err); + + return err; + } + + err = pci_enable_sriov(adapter->pdev, num_vfs); + if (err) { + idpf_send_set_sriov_vfs_msg(adapter, 0); + dev_err(dev, "Failed to enable SR-IOV: %d\n", err); + + return err; + } + + adapter->num_vfs = num_vfs; + + return num_vfs; +} + +/** + * idpf_sriov_configure - Configure the requested VFs + * @pdev: pointer to a pci_dev structure + * @num_vfs: number of vfs to allocate + * + * Enable or change the number of VFs. Called when the user updates the number + * of VFs in sysfs. + **/ +int idpf_sriov_configure(struct pci_dev *pdev, int num_vfs) +{ + struct idpf_adapter *adapter = pci_get_drvdata(pdev); + + if (!idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_SRIOV)) { + dev_info(&pdev->dev, "SR-IOV is not supported on this device\n"); + + return -EOPNOTSUPP; + } + + if (num_vfs) + return idpf_sriov_ena(adapter, num_vfs); + + if (pci_vfs_assigned(pdev)) { + dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs\n"); + + return -EBUSY; + } + + pci_disable_sriov(adapter->pdev); + idpf_send_set_sriov_vfs_msg(adapter, 0); + adapter->num_vfs = 0; + + return 0; +} + /** * idpf_deinit_task - Device deinit routine * @adapter: Driver specific private structure @@ -1354,6 +1630,8 @@ void idpf_deinit_task(struct idpf_adapter *adapter) if (!adapter->vports) return; + cancel_delayed_work_sync(&adapter->stats_task); + for (i = 0; i < adapter->max_vports; i++) { if (adapter->vports[i]) idpf_vport_dealloc(adapter->vports[i]); @@ -1570,6 +1848,9 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport, /* Update queue parameters before allocating resources */ idpf_vport_calc_num_q_desc(new_vport); break; + case IDPF_SR_MTU_CHANGE: + case IDPF_SR_RSC_CHANGE: + break; default: dev_err(&adapter->pdev->dev, "Unhandled soft reset cause\n"); err = -EINVAL; @@ -1667,6 +1948,208 @@ free_vport: return err; } +/** + * idpf_addr_sync - Callback for dev_(mc|uc)_sync to add address + * @netdev: the netdevice + * @addr: address to add + * + * Called by __dev_(mc|uc)_sync when an address needs to be added. We call + * __dev_(uc|mc)_sync from .set_rx_mode. Kernel takes addr_list_lock spinlock + * meaning we cannot sleep in this context. Due to this, we have to add the + * filter and send the virtchnl message asynchronously without waiting for the + * response from the other side. We won't know whether or not the operation + * actually succeeded until we get the message back. Returns 0 on success, + * negative on failure. + */ +static int idpf_addr_sync(struct net_device *netdev, const u8 *addr) +{ + struct idpf_netdev_priv *np = netdev_priv(netdev); + + return idpf_add_mac_filter(np->vport, np, addr, true); +} + +/** + * idpf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address + * @netdev: the netdevice + * @addr: address to add + * + * Called by __dev_(mc|uc)_sync when an address needs to be added. We call + * __dev_(uc|mc)_sync from .set_rx_mode. Kernel takes addr_list_lock spinlock + * meaning we cannot sleep in this context. Due to this we have to delete the + * filter and send the virtchnl message asynchronously without waiting for the + * return from the other side. We won't know whether or not the operation + * actually succeeded until we get the message back. Returns 0 on success, + * negative on failure. + */ +static int idpf_addr_unsync(struct net_device *netdev, const u8 *addr) +{ + struct idpf_netdev_priv *np = netdev_priv(netdev); + + /* Under some circumstances, we might receive a request to delete + * our own device address from our uc list. Because we store the + * device address in the VSI's MAC filter list, we need to ignore + * such requests and not delete our device address from this list. + */ + if (ether_addr_equal(addr, netdev->dev_addr)) + return 0; + + idpf_del_mac_filter(np->vport, np, addr, true); + + return 0; +} + +/** + * idpf_set_rx_mode - NDO callback to set the netdev filters + * @netdev: network interface device structure + * + * Stack takes addr_list_lock spinlock before calling our .set_rx_mode. We + * cannot sleep in this context. + */ +static void idpf_set_rx_mode(struct net_device *netdev) +{ + struct idpf_netdev_priv *np = netdev_priv(netdev); + struct idpf_vport_user_config_data *config_data; + struct idpf_adapter *adapter; + bool changed = false; + struct device *dev; + int err; + + adapter = np->adapter; + dev = &adapter->pdev->dev; + + if (idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_MACFILTER)) { + __dev_uc_sync(netdev, idpf_addr_sync, idpf_addr_unsync); + __dev_mc_sync(netdev, idpf_addr_sync, idpf_addr_unsync); + } + + if (!idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_PROMISC)) + return; + + config_data = &adapter->vport_config[np->vport_idx]->user_config; + /* IFF_PROMISC enables both unicast and multicast promiscuous, + * while IFF_ALLMULTI only enables multicast such that: + * + * promisc + allmulti = unicast | multicast + * promisc + !allmulti = unicast | multicast + * !promisc + allmulti = multicast + */ + if ((netdev->flags & IFF_PROMISC) && + !test_and_set_bit(__IDPF_PROMISC_UC, config_data->user_flags)) { + changed = true; + dev_info(&adapter->pdev->dev, "Entering promiscuous mode\n"); + if (!test_and_set_bit(__IDPF_PROMISC_MC, adapter->flags)) + dev_info(dev, "Entering multicast promiscuous mode\n"); + } + + if (!(netdev->flags & IFF_PROMISC) && + test_and_clear_bit(__IDPF_PROMISC_UC, config_data->user_flags)) { + changed = true; + dev_info(dev, "Leaving promiscuous mode\n"); + } + + if (netdev->flags & IFF_ALLMULTI && + !test_and_set_bit(__IDPF_PROMISC_MC, config_data->user_flags)) { + changed = true; + dev_info(dev, "Entering multicast promiscuous mode\n"); + } + + if (!(netdev->flags & (IFF_ALLMULTI | IFF_PROMISC)) && + test_and_clear_bit(__IDPF_PROMISC_MC, config_data->user_flags)) { + changed = true; + dev_info(dev, "Leaving multicast promiscuous mode\n"); + } + + if (!changed) + return; + + err = idpf_set_promiscuous(adapter, config_data, np->vport_id); + if (err) + dev_err(dev, "Failed to set promiscuous mode: %d\n", err); +} + +/** + * idpf_vport_manage_rss_lut - disable/enable RSS + * @vport: the vport being changed + * + * In the event of disable request for RSS, this function will zero out RSS + * LUT, while in the event of enable request for RSS, it will reconfigure RSS + * LUT with the default LUT configuration. + */ +static int idpf_vport_manage_rss_lut(struct idpf_vport *vport) +{ + bool ena = idpf_is_feature_ena(vport, NETIF_F_RXHASH); + struct idpf_rss_data *rss_data; + u16 idx = vport->idx; + int lut_size; + + rss_data = &vport->adapter->vport_config[idx]->user_config.rss_data; + lut_size = rss_data->rss_lut_size * sizeof(u32); + + if (ena) { + /* This will contain the default or user configured LUT */ + memcpy(rss_data->rss_lut, rss_data->cached_lut, lut_size); + } else { + /* Save a copy of the current LUT to be restored later if + * requested. + */ + memcpy(rss_data->cached_lut, rss_data->rss_lut, lut_size); + + /* Zero out the current LUT to disable */ + memset(rss_data->rss_lut, 0, lut_size); + } + + return idpf_config_rss(vport); +} + +/** + * idpf_set_features - set the netdev feature flags + * @netdev: ptr to the netdev being adjusted + * @features: the feature set that the stack is suggesting + */ +static int idpf_set_features(struct net_device *netdev, + netdev_features_t features) +{ + netdev_features_t changed = netdev->features ^ features; + struct idpf_adapter *adapter; + struct idpf_vport *vport; + int err = 0; + + idpf_vport_ctrl_lock(netdev); + vport = idpf_netdev_to_vport(netdev); + + adapter = vport->adapter; + + if (idpf_is_reset_in_prog(adapter)) { + dev_err(&adapter->pdev->dev, "Device is resetting, changing netdev features temporarily unavailable.\n"); + err = -EBUSY; + goto unlock_mutex; + } + + if (changed & NETIF_F_RXHASH) { + netdev->features ^= NETIF_F_RXHASH; + err = idpf_vport_manage_rss_lut(vport); + if (err) + goto unlock_mutex; + } + + if (changed & NETIF_F_GRO_HW) { + netdev->features ^= NETIF_F_GRO_HW; + err = idpf_initiate_soft_reset(vport, IDPF_SR_RSC_CHANGE); + if (err) + goto unlock_mutex; + } + + if (changed & NETIF_F_LOOPBACK) { + netdev->features ^= NETIF_F_LOOPBACK; + err = idpf_send_ena_dis_loopback_msg(vport); + } + +unlock_mutex: + idpf_vport_ctrl_unlock(netdev); + + return err; +} + /** * idpf_open - Called when a network interface becomes active * @netdev: network interface device structure @@ -1694,6 +2177,145 @@ static int idpf_open(struct net_device *netdev) return err; } +/** + * idpf_change_mtu - NDO callback to change the MTU + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int idpf_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct idpf_vport *vport; + int err; + + idpf_vport_ctrl_lock(netdev); + vport = idpf_netdev_to_vport(netdev); + + netdev->mtu = new_mtu; + + err = idpf_initiate_soft_reset(vport, IDPF_SR_MTU_CHANGE); + + idpf_vport_ctrl_unlock(netdev); + + return err; +} + +/** + * idpf_features_check - Validate packet conforms to limits + * @skb: skb buffer + * @netdev: This port's netdev + * @features: Offload features that the stack believes apply + */ +static netdev_features_t idpf_features_check(struct sk_buff *skb, + struct net_device *netdev, + netdev_features_t features) +{ + struct idpf_vport *vport = idpf_netdev_to_vport(netdev); + struct idpf_adapter *adapter = vport->adapter; + size_t len; + + /* No point in doing any of this if neither checksum nor GSO are + * being requested for this frame. We can rule out both by just + * checking for CHECKSUM_PARTIAL + */ + if (skb->ip_summed != CHECKSUM_PARTIAL) + return features; + + /* We cannot support GSO if the MSS is going to be less than + * 88 bytes. If it is then we need to drop support for GSO. + */ + if (skb_is_gso(skb) && + (skb_shinfo(skb)->gso_size < IDPF_TX_TSO_MIN_MSS)) + features &= ~NETIF_F_GSO_MASK; + + /* Ensure MACLEN is <= 126 bytes (63 words) and not an odd size */ + len = skb_network_offset(skb); + if (unlikely(len & ~(126))) + goto unsupported; + + len = skb_network_header_len(skb); + if (unlikely(len > idpf_get_max_tx_hdr_size(adapter))) + goto unsupported; + + if (!skb->encapsulation) + return features; + + /* L4TUNLEN can support 127 words */ + len = skb_inner_network_header(skb) - skb_transport_header(skb); + if (unlikely(len & ~(127 * 2))) + goto unsupported; + + /* IPLEN can support at most 127 dwords */ + len = skb_inner_network_header_len(skb); + if (unlikely(len > idpf_get_max_tx_hdr_size(adapter))) + goto unsupported; + + /* No need to validate L4LEN as TCP is the only protocol with a + * a flexible value and we support all possible values supported + * by TCP, which is at most 15 dwords + */ + + return features; + +unsupported: + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); +} + +/** + * idpf_set_mac - NDO callback to set port mac address + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int idpf_set_mac(struct net_device *netdev, void *p) +{ + struct idpf_netdev_priv *np = netdev_priv(netdev); + struct idpf_vport_config *vport_config; + struct sockaddr *addr = p; + struct idpf_vport *vport; + int err = 0; + + idpf_vport_ctrl_lock(netdev); + vport = idpf_netdev_to_vport(netdev); + + if (!idpf_is_cap_ena(vport->adapter, IDPF_OTHER_CAPS, + VIRTCHNL2_CAP_MACFILTER)) { + dev_info(&vport->adapter->pdev->dev, "Setting MAC address is not supported\n"); + err = -EOPNOTSUPP; + goto unlock_mutex; + } + + if (!is_valid_ether_addr(addr->sa_data)) { + dev_info(&vport->adapter->pdev->dev, "Invalid MAC address: %pM\n", + addr->sa_data); + err = -EADDRNOTAVAIL; + goto unlock_mutex; + } + + if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) + goto unlock_mutex; + + vport_config = vport->adapter->vport_config[vport->idx]; + err = idpf_add_mac_filter(vport, np, addr->sa_data, false); + if (err) { + __idpf_del_mac_filter(vport_config, addr->sa_data); + goto unlock_mutex; + } + + if (is_valid_ether_addr(vport->default_mac_addr)) + idpf_del_mac_filter(vport, np, vport->default_mac_addr, false); + + ether_addr_copy(vport->default_mac_addr, addr->sa_data); + eth_hw_addr_set(netdev, addr->sa_data); + +unlock_mutex: + idpf_vport_ctrl_unlock(netdev); + + return err; +} + /** * idpf_alloc_dma_mem - Allocate dma memory * @hw: pointer to hw struct @@ -1732,10 +2354,26 @@ static const struct net_device_ops idpf_netdev_ops_splitq = { .ndo_open = idpf_open, .ndo_stop = idpf_stop, .ndo_start_xmit = idpf_tx_splitq_start, + .ndo_features_check = idpf_features_check, + .ndo_set_rx_mode = idpf_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = idpf_set_mac, + .ndo_change_mtu = idpf_change_mtu, + .ndo_get_stats64 = idpf_get_stats64, + .ndo_set_features = idpf_set_features, + .ndo_tx_timeout = idpf_tx_timeout, }; static const struct net_device_ops idpf_netdev_ops_singleq = { .ndo_open = idpf_open, .ndo_stop = idpf_stop, .ndo_start_xmit = idpf_tx_singleq_start, + .ndo_features_check = idpf_features_check, + .ndo_set_rx_mode = idpf_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = idpf_set_mac, + .ndo_change_mtu = idpf_change_mtu, + .ndo_get_stats64 = idpf_get_stats64, + .ndo_set_features = idpf_set_features, + .ndo_tx_timeout = idpf_tx_timeout, }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index 8f3a83fd3474..e1febc74cefd 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -26,6 +26,9 @@ static void idpf_remove(struct pci_dev *pdev) * end up in bad state. */ cancel_delayed_work_sync(&adapter->vc_event_task); + if (adapter->num_vfs) + idpf_sriov_configure(pdev, 0); + idpf_vc_core_deinit(adapter); /* Be a good citizen and leave the device clean on exit */ adapter->dev_ops.reg_ops.trigger_reset(adapter, IDPF_HR_FUNC_RESET); @@ -52,6 +55,7 @@ destroy_wqs: destroy_workqueue(adapter->init_wq); destroy_workqueue(adapter->serv_wq); destroy_workqueue(adapter->mbx_wq); + destroy_workqueue(adapter->stats_wq); destroy_workqueue(adapter->vc_event_wq); for (i = 0; i < adapter->max_vports; i++) { @@ -192,6 +196,15 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_mbx_wq_alloc; } + adapter->stats_wq = alloc_workqueue("%s-%s-stats", 0, 0, + dev_driver_string(dev), + dev_name(dev)); + if (!adapter->stats_wq) { + dev_err(dev, "Failed to allocate workqueue\n"); + err = -ENOMEM; + goto err_stats_wq_alloc; + } + adapter->vc_event_wq = alloc_workqueue("%s-%s-vc_event", 0, 0, dev_driver_string(dev), dev_name(dev)); @@ -221,6 +234,7 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_DELAYED_WORK(&adapter->init_task, idpf_init_task); INIT_DELAYED_WORK(&adapter->serv_task, idpf_service_task); INIT_DELAYED_WORK(&adapter->mbx_task, idpf_mbx_task); + INIT_DELAYED_WORK(&adapter->stats_task, idpf_statistics_task); INIT_DELAYED_WORK(&adapter->vc_event_task, idpf_vc_event_task); adapter->dev_ops.reg_ops.reset_reg_init(adapter); @@ -233,6 +247,8 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_cfg_hw: destroy_workqueue(adapter->vc_event_wq); err_vc_event_wq_alloc: + destroy_workqueue(adapter->stats_wq); +err_stats_wq_alloc: destroy_workqueue(adapter->mbx_wq); err_mbx_wq_alloc: destroy_workqueue(adapter->serv_wq); @@ -256,6 +272,7 @@ static struct pci_driver idpf_driver = { .name = KBUILD_MODNAME, .id_table = idpf_pci_tbl, .probe = idpf_probe, + .sriov_configure = idpf_sriov_configure, .remove = idpf_remove, .shutdown = idpf_shutdown, }; diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 425f00573a01..6fa79898c42c 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -33,6 +33,27 @@ static struct idpf_tx_stash *idpf_buf_lifo_pop(struct idpf_buf_lifo *stack) return stack->bufs[--stack->top]; } +/** + * idpf_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + * @txqueue: TX queue + */ +void idpf_tx_timeout(struct net_device *netdev, unsigned int txqueue) +{ + struct idpf_adapter *adapter = idpf_netdev_to_adapter(netdev); + + adapter->tx_timeout_count++; + + netdev_err(netdev, "Detected Tx timeout: Count %d, Queue %d\n", + adapter->tx_timeout_count, txqueue); + if (!idpf_is_reset_in_prog(adapter)) { + set_bit(IDPF_HR_FUNC_RESET, adapter->flags); + queue_delayed_work(adapter->vc_event_wq, + &adapter->vc_event_task, + msecs_to_jiffies(10)); + } +} + /** * idpf_tx_buf_rel - Release a Tx buffer * @tx_q: the queue that owns the buffer diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index 3e7f9e7338a5..df76493faa75 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -101,6 +101,7 @@ do { \ #define IDPF_HDR_BUF_SIZE 256 #define IDPF_PACKET_HDR_PAD \ (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN * 2) +#define IDPF_TX_TSO_MIN_MSS 88 /* Minimum number of descriptors between 2 descriptors with the RE bit set; * only relevant in flow scheduling mode @@ -1010,6 +1011,7 @@ unsigned int idpf_tx_desc_count_required(struct idpf_queue *txq, bool idpf_chk_linearize(struct sk_buff *skb, unsigned int max_bufs, unsigned int count); int idpf_tx_maybe_stop_common(struct idpf_queue *tx_q, unsigned int size); +void idpf_tx_timeout(struct net_device *netdev, unsigned int txqueue); netdev_tx_t idpf_tx_splitq_start(struct sk_buff *skb, struct net_device *netdev); netdev_tx_t idpf_tx_singleq_start(struct sk_buff *skb, diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index cf9508433fed..9bc85b2f1709 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -200,6 +200,7 @@ static int idpf_find_vport(struct idpf_adapter *adapter, case VIRTCHNL2_OP_VERSION: case VIRTCHNL2_OP_GET_CAPS: case VIRTCHNL2_OP_CREATE_VPORT: + case VIRTCHNL2_OP_SET_SRIOV_VFS: case VIRTCHNL2_OP_ALLOC_VECTORS: case VIRTCHNL2_OP_DEALLOC_VECTORS: case VIRTCHNL2_OP_GET_PTYPE_INFO: @@ -227,6 +228,9 @@ static int idpf_find_vport(struct idpf_adapter *adapter, case VIRTCHNL2_OP_UNMAP_QUEUE_VECTOR: v_id = le32_to_cpu(((struct virtchnl2_queue_vector_maps *)vc_msg)->vport_id); break; + case VIRTCHNL2_OP_GET_STATS: + v_id = le32_to_cpu(((struct virtchnl2_vport_stats *)vc_msg)->vport_id); + break; case VIRTCHNL2_OP_GET_RSS_LUT: case VIRTCHNL2_OP_SET_RSS_LUT: v_id = le32_to_cpu(((struct virtchnl2_rss_lut *)vc_msg)->vport_id); @@ -238,6 +242,12 @@ static int idpf_find_vport(struct idpf_adapter *adapter, case VIRTCHNL2_OP_EVENT: v_id = le32_to_cpu(((struct virtchnl2_event *)vc_msg)->vport_id); break; + case VIRTCHNL2_OP_LOOPBACK: + v_id = le32_to_cpu(((struct virtchnl2_loopback *)vc_msg)->vport_id); + break; + case VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE: + v_id = le32_to_cpu(((struct virtchnl2_promisc_info *)vc_msg)->vport_id); + break; case VIRTCHNL2_OP_ADD_MAC_ADDR: case VIRTCHNL2_OP_DEL_MAC_ADDR: v_id = le32_to_cpu(((struct virtchnl2_mac_addr_list *)vc_msg)->vport_id); @@ -491,6 +501,11 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, IDPF_VC_UNMAP_IRQ, IDPF_VC_UNMAP_IRQ_ERR); break; + case VIRTCHNL2_OP_GET_STATS: + idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, + IDPF_VC_GET_STATS, + IDPF_VC_GET_STATS_ERR); + break; case VIRTCHNL2_OP_GET_RSS_LUT: idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, IDPF_VC_GET_RSS_LUT, @@ -511,6 +526,11 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, IDPF_VC_SET_RSS_KEY, IDPF_VC_SET_RSS_KEY_ERR); break; + case VIRTCHNL2_OP_SET_SRIOV_VFS: + idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, + IDPF_VC_SET_SRIOV_VFS, + IDPF_VC_SET_SRIOV_VFS_ERR); + break; case VIRTCHNL2_OP_ALLOC_VECTORS: idpf_recv_vchnl_op(adapter, NULL, &ctlq_msg, IDPF_VC_ALLOC_VECTORS, @@ -526,6 +546,24 @@ int idpf_recv_mb_msg(struct idpf_adapter *adapter, u32 op, IDPF_VC_GET_PTYPE_INFO, IDPF_VC_GET_PTYPE_INFO_ERR); break; + case VIRTCHNL2_OP_LOOPBACK: + idpf_recv_vchnl_op(adapter, vport, &ctlq_msg, + IDPF_VC_LOOPBACK_STATE, + IDPF_VC_LOOPBACK_STATE_ERR); + break; + case VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE: + /* This message can only be sent asynchronously. As + * such we'll have lost the context in which it was + * called and thus can only really report if it looks + * like an error occurred. Don't bother setting ERR bit + * or waking chnl_wq since no work queue will be waiting + * to read the message. + */ + if (ctlq_msg.cookie.mbx.chnl_retval) { + dev_err(&adapter->pdev->dev, "Failed to set promiscuous mode: %d\n", + ctlq_msg.cookie.mbx.chnl_retval); + } + break; case VIRTCHNL2_OP_ADD_MAC_ADDR: vport_config = adapter->vport_config[vport->idx]; if (test_and_clear_bit(IDPF_VPORT_ADD_MAC_REQ, @@ -2310,6 +2348,110 @@ rel_lock: return err; } +/** + * idpf_get_max_vfs - Get max number of vfs supported + * @adapter: Driver specific private structure + * + * Returns max number of VFs + */ +static int idpf_get_max_vfs(struct idpf_adapter *adapter) +{ + return le16_to_cpu(adapter->caps.max_sriov_vfs); +} + +/** + * idpf_send_set_sriov_vfs_msg - Send virtchnl set sriov vfs message + * @adapter: Driver specific private structure + * @num_vfs: number of virtual functions to be created + * + * Returns 0 on success, negative on failure. + */ +int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs) +{ + struct virtchnl2_sriov_vfs_info svi = { }; + int err; + + svi.num_vfs = cpu_to_le16(num_vfs); + + mutex_lock(&adapter->vc_buf_lock); + + err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_SET_SRIOV_VFS, + sizeof(svi), (u8 *)&svi); + if (err) + goto rel_lock; + + err = idpf_wait_for_event(adapter, NULL, IDPF_VC_SET_SRIOV_VFS, + IDPF_VC_SET_SRIOV_VFS_ERR); + +rel_lock: + mutex_unlock(&adapter->vc_buf_lock); + + return err; +} + +/** + * idpf_send_get_stats_msg - Send virtchnl get statistics message + * @vport: vport to get stats for + * + * Returns 0 on success, negative on failure. + */ +int idpf_send_get_stats_msg(struct idpf_vport *vport) +{ + struct idpf_netdev_priv *np = netdev_priv(vport->netdev); + struct rtnl_link_stats64 *netstats = &np->netstats; + struct idpf_adapter *adapter = vport->adapter; + struct virtchnl2_vport_stats stats_msg = { }; + struct virtchnl2_vport_stats *stats; + int err; + + /* Don't send get_stats message if the link is down */ + if (np->state <= __IDPF_VPORT_DOWN) + return 0; + + stats_msg.vport_id = cpu_to_le32(vport->vport_id); + + mutex_lock(&vport->vc_buf_lock); + + err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_GET_STATS, + sizeof(struct virtchnl2_vport_stats), + (u8 *)&stats_msg); + if (err) + goto rel_lock; + + err = idpf_wait_for_event(adapter, vport, IDPF_VC_GET_STATS, + IDPF_VC_GET_STATS_ERR); + if (err) + goto rel_lock; + + stats = (struct virtchnl2_vport_stats *)vport->vc_msg; + + spin_lock_bh(&np->stats_lock); + + netstats->rx_packets = le64_to_cpu(stats->rx_unicast) + + le64_to_cpu(stats->rx_multicast) + + le64_to_cpu(stats->rx_broadcast); + netstats->rx_bytes = le64_to_cpu(stats->rx_bytes); + netstats->rx_dropped = le64_to_cpu(stats->rx_discards); + netstats->rx_over_errors = le64_to_cpu(stats->rx_overflow_drop); + netstats->rx_length_errors = le64_to_cpu(stats->rx_invalid_frame_length); + + netstats->tx_packets = le64_to_cpu(stats->tx_unicast) + + le64_to_cpu(stats->tx_multicast) + + le64_to_cpu(stats->tx_broadcast); + netstats->tx_bytes = le64_to_cpu(stats->tx_bytes); + netstats->tx_errors = le64_to_cpu(stats->tx_errors); + netstats->tx_dropped = le64_to_cpu(stats->tx_discards); + + vport->port_stats.vport_stats = *stats; + + spin_unlock_bh(&np->stats_lock); + +rel_lock: + mutex_unlock(&vport->vc_buf_lock); + + return err; +} + /** * idpf_send_get_set_rss_lut_msg - Send virtchnl get or set rss lut message * @vport: virtual port data structure @@ -2716,6 +2858,38 @@ vc_buf_unlock: return err; } +/** + * idpf_send_ena_dis_loopback_msg - Send virtchnl enable/disable loopback + * message + * @vport: virtual port data structure + * + * Returns 0 on success, negative on failure. + */ +int idpf_send_ena_dis_loopback_msg(struct idpf_vport *vport) +{ + struct virtchnl2_loopback loopback; + int err; + + loopback.vport_id = cpu_to_le32(vport->vport_id); + loopback.enable = idpf_is_feature_ena(vport, NETIF_F_LOOPBACK); + + mutex_lock(&vport->vc_buf_lock); + + err = idpf_send_mb_msg(vport->adapter, VIRTCHNL2_OP_LOOPBACK, + sizeof(loopback), (u8 *)&loopback); + if (err) + goto rel_lock; + + err = idpf_wait_for_event(vport->adapter, vport, + IDPF_VC_LOOPBACK_STATE, + IDPF_VC_LOOPBACK_STATE_ERR); + +rel_lock: + mutex_unlock(&vport->vc_buf_lock); + + return err; +} + /** * idpf_find_ctlq - Given a type and id, find ctlq info * @hw: hardware struct @@ -2914,6 +3088,7 @@ restart: msleep(task_delay); } + pci_sriov_set_totalvfs(adapter->pdev, idpf_get_max_vfs(adapter)); num_max_vports = idpf_get_max_vports(adapter); adapter->max_vports = num_max_vports; adapter->vports = kcalloc(num_max_vports, sizeof(*adapter->vports), @@ -3581,3 +3756,36 @@ error: return err; } + +/** + * idpf_set_promiscuous - set promiscuous and send message to mailbox + * @adapter: Driver specific private structure + * @config_data: Vport specific config data + * @vport_id: Vport identifier + * + * Request to enable promiscuous mode for the vport. Message is sent + * asynchronously and won't wait for response. Returns 0 on success, negative + * on failure; + */ +int idpf_set_promiscuous(struct idpf_adapter *adapter, + struct idpf_vport_user_config_data *config_data, + u32 vport_id) +{ + struct virtchnl2_promisc_info vpi; + u16 flags = 0; + int err; + + if (test_bit(__IDPF_PROMISC_UC, config_data->user_flags)) + flags |= VIRTCHNL2_UNICAST_PROMISC; + if (test_bit(__IDPF_PROMISC_MC, config_data->user_flags)) + flags |= VIRTCHNL2_MULTICAST_PROMISC; + + vpi.vport_id = cpu_to_le32(vport_id); + vpi.flags = cpu_to_le16(flags); + + err = idpf_send_mb_msg(adapter, VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE, + sizeof(struct virtchnl2_promisc_info), + (u8 *)&vpi); + + return err; +} -- cgit v1.2.3 From 927c568d62128f48d6646d6df801c1ae25cf139f Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Wed, 13 Sep 2023 14:40:10 +0530 Subject: dt-bindings: net: Add documentation for Half duplex support. In order to support half-duplex operation at 10M and 100M link speeds, the PHY collision detection signal (COL) should be routed to ICSSG GPIO pin (PRGx_PRU0/1_GPI10) so that firmware can detect collision signal and apply the CSMA/CD algorithm applicable for half duplex operation. A DT property, "ti,half-duplex-capable" is introduced for this purpose. If board has PHY COL pin conencted to PRGx_PRU1_GPIO10, this DT property can be added to eth node of ICSSG, MII port to support half duplex operation at that port. Reviewed-by: Roger Quadros Signed-off-by: MD Danish Anwar Reviewed-by: Andrew Lunn Acked-by: Conor Dooley Reviewed-by: Rob Herring Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml index 836d2d60e87d..229c8f32019f 100644 --- a/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml +++ b/Documentation/devicetree/bindings/net/ti,icssg-prueth.yaml @@ -107,6 +107,13 @@ properties: phandle to system controller node and register offset to ICSSG control register for RGMII transmit delay + ti,half-duplex-capable: + type: boolean + description: + Indicates that the PHY output pin COL is routed to ICSSG GPIO pin + (PRGx_PRU0/1_GPIO10) as input so that the ICSSG MII port is + capable of half duplex operations. + required: - reg anyOf: -- cgit v1.2.3 From a9c2a608549bb1a2363d289d63907640afcf22af Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 13 Sep 2023 10:13:49 -0700 Subject: bpf: expose information about supported xdp metadata kfunc Add new xdp-rx-metadata-features member to netdev netlink which exports a bitmask of supported kfuncs. Most of the patch is autogenerated (headers), the only relevant part is netdev.yaml and the changes in netdev-genl.c to marshal into netlink. Example output on veth: $ ip link add veth0 type veth peer name veth1 # ifndex == 12 $ ./tools/net/ynl/samples/netdev 12 Select ifc ($ifindex; or 0 = dump; or -2 ntf check): 12 veth1[12] xdp-features (23): basic redirect rx-sg xdp-rx-metadata-features (3): timestamp hash xdp-zc-max-segs=0 Cc: netdev@vger.kernel.org Cc: Willem de Bruijn Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230913171350.369987-3-sdf@google.com Signed-off-by: Martin KaFai Lau --- Documentation/netlink/specs/netdev.yaml | 21 +++++++++++++++++++++ Documentation/networking/xdp-rx-metadata.rst | 7 +++++++ include/net/xdp.h | 5 ++++- include/uapi/linux/netdev.h | 16 ++++++++++++++++ kernel/bpf/offload.c | 2 +- net/core/netdev-genl.c | 12 +++++++++++- net/core/xdp.c | 4 ++-- tools/include/uapi/linux/netdev.h | 16 ++++++++++++++++ 8 files changed, 78 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 1c7284fd535b..c46fcc78fc04 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -42,6 +42,19 @@ definitions: doc: This feature informs if netdev implements non-linear XDP buffer support in ndo_xdp_xmit callback. + - + type: flags + name: xdp-rx-metadata + render-max: true + entries: + - + name: timestamp + doc: + Device is capable of exposing receive HW timestamp via bpf_xdp_metadata_rx_timestamp(). + - + name: hash + doc: + Device is capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash(). attribute-sets: - @@ -68,6 +81,13 @@ attribute-sets: type: u32 checks: min: 1 + - + name: xdp-rx-metadata-features + doc: Bitmask of supported XDP receive metadata features. + See Documentation/networking/xdp-rx-metadata.rst for more details. + type: u64 + enum: xdp-rx-metadata + enum-as-flags: true operations: list: @@ -84,6 +104,7 @@ operations: - ifindex - xdp-features - xdp-zc-max-segs + - xdp-rx-metadata-features dump: reply: *dev-all - diff --git a/Documentation/networking/xdp-rx-metadata.rst b/Documentation/networking/xdp-rx-metadata.rst index 25ce72af81c2..205696780b78 100644 --- a/Documentation/networking/xdp-rx-metadata.rst +++ b/Documentation/networking/xdp-rx-metadata.rst @@ -105,6 +105,13 @@ bpf_tail_call Adding programs that access metadata kfuncs to the ``BPF_MAP_TYPE_PROG_ARRAY`` is currently not supported. +Supported Devices +================= + +It is possible to query which kfunc the particular netdev implements via +netlink. See ``xdp-rx-metadata-features`` attribute set in +``Documentation/netlink/specs/netdev.yaml``. + Example ======= diff --git a/include/net/xdp.h b/include/net/xdp.h index d59e12f8f311..349c36fb5fd8 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -386,19 +386,22 @@ void xdp_attachment_setup(struct xdp_attachment_info *info, /* Define the relationship between xdp-rx-metadata kfunc and * various other entities: * - xdp_rx_metadata enum + * - netdev netlink enum (Documentation/netlink/specs/netdev.yaml) * - kfunc name * - xdp_metadata_ops field */ #define XDP_METADATA_KFUNC_xxx \ XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_TIMESTAMP, \ + NETDEV_XDP_RX_METADATA_TIMESTAMP, \ bpf_xdp_metadata_rx_timestamp, \ xmo_rx_timestamp) \ XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_HASH, \ + NETDEV_XDP_RX_METADATA_HASH, \ bpf_xdp_metadata_rx_hash, \ xmo_rx_hash) \ enum xdp_rx_metadata { -#define XDP_METADATA_KFUNC(name, _, __) name, +#define XDP_METADATA_KFUNC(name, _, __, ___) name, XDP_METADATA_KFUNC_xxx #undef XDP_METADATA_KFUNC MAX_XDP_METADATA_KFUNC, diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h index c1634b95c223..2943a151d4f1 100644 --- a/include/uapi/linux/netdev.h +++ b/include/uapi/linux/netdev.h @@ -38,11 +38,27 @@ enum netdev_xdp_act { NETDEV_XDP_ACT_MASK = 127, }; +/** + * enum netdev_xdp_rx_metadata + * @NETDEV_XDP_RX_METADATA_TIMESTAMP: Device is capable of exposing receive HW + * timestamp via bpf_xdp_metadata_rx_timestamp(). + * @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet + * hash via bpf_xdp_metadata_rx_hash(). + */ +enum netdev_xdp_rx_metadata { + NETDEV_XDP_RX_METADATA_TIMESTAMP = 1, + NETDEV_XDP_RX_METADATA_HASH = 2, + + /* private: */ + NETDEV_XDP_RX_METADATA_MASK = 3, +}; + enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, NETDEV_A_DEV_XDP_ZC_MAX_SEGS, + NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c index 6aa6de8d715d..e7a1752b5a09 100644 --- a/kernel/bpf/offload.c +++ b/kernel/bpf/offload.c @@ -845,7 +845,7 @@ void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog, u32 func_id) if (!ops) goto out; -#define XDP_METADATA_KFUNC(name, _, xmo) \ +#define XDP_METADATA_KFUNC(name, _, __, xmo) \ if (func_id == bpf_xdp_metadata_kfunc_id(name)) p = ops->xmo; XDP_METADATA_KFUNC_xxx #undef XDP_METADATA_KFUNC diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index c1aea8b756b6..fe61f85bcf33 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "netdev-genl-gen.h" @@ -12,15 +13,24 @@ static int netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, const struct genl_info *info) { + u64 xdp_rx_meta = 0; void *hdr; hdr = genlmsg_iput(rsp, info); if (!hdr) return -EMSGSIZE; +#define XDP_METADATA_KFUNC(_, flag, __, xmo) \ + if (netdev->xdp_metadata_ops && netdev->xdp_metadata_ops->xmo) \ + xdp_rx_meta |= flag; +XDP_METADATA_KFUNC_xxx +#undef XDP_METADATA_KFUNC + if (nla_put_u32(rsp, NETDEV_A_DEV_IFINDEX, netdev->ifindex) || nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_FEATURES, - netdev->xdp_features, NETDEV_A_DEV_PAD)) { + netdev->xdp_features, NETDEV_A_DEV_PAD) || + nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, + xdp_rx_meta, NETDEV_A_DEV_PAD)) { genlmsg_cancel(rsp, hdr); return -EINVAL; } diff --git a/net/core/xdp.c b/net/core/xdp.c index bab563b2f812..df4789ab512d 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -741,7 +741,7 @@ __bpf_kfunc int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, u32 *hash, __diag_pop(); BTF_SET8_START(xdp_metadata_kfunc_ids) -#define XDP_METADATA_KFUNC(_, name, __) BTF_ID_FLAGS(func, name, KF_TRUSTED_ARGS) +#define XDP_METADATA_KFUNC(_, __, name, ___) BTF_ID_FLAGS(func, name, KF_TRUSTED_ARGS) XDP_METADATA_KFUNC_xxx #undef XDP_METADATA_KFUNC BTF_SET8_END(xdp_metadata_kfunc_ids) @@ -752,7 +752,7 @@ static const struct btf_kfunc_id_set xdp_metadata_kfunc_set = { }; BTF_ID_LIST(xdp_metadata_kfunc_ids_unsorted) -#define XDP_METADATA_KFUNC(name, str, _) BTF_ID(func, str) +#define XDP_METADATA_KFUNC(name, _, str, __) BTF_ID(func, str) XDP_METADATA_KFUNC_xxx #undef XDP_METADATA_KFUNC diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index c1634b95c223..2943a151d4f1 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -38,11 +38,27 @@ enum netdev_xdp_act { NETDEV_XDP_ACT_MASK = 127, }; +/** + * enum netdev_xdp_rx_metadata + * @NETDEV_XDP_RX_METADATA_TIMESTAMP: Device is capable of exposing receive HW + * timestamp via bpf_xdp_metadata_rx_timestamp(). + * @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet + * hash via bpf_xdp_metadata_rx_hash(). + */ +enum netdev_xdp_rx_metadata { + NETDEV_XDP_RX_METADATA_TIMESTAMP = 1, + NETDEV_XDP_RX_METADATA_HASH = 2, + + /* private: */ + NETDEV_XDP_RX_METADATA_MASK = 3, +}; + enum { NETDEV_A_DEV_IFINDEX = 1, NETDEV_A_DEV_PAD, NETDEV_A_DEV_XDP_FEATURES, NETDEV_A_DEV_XDP_ZC_MAX_SEGS, + NETDEV_A_DEV_XDP_RX_METADATA_FEATURES, __NETDEV_A_DEV_MAX, NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1) -- cgit v1.2.3 From 7e10088bc4e458493688a7aee08998479f541628 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Thu, 14 Sep 2023 19:44:33 +0800 Subject: dt-bindings: mfd: syscon: Add compatibles for Loongson-1 syscon Add Loongson LS1B and LS1C compatibles for system controller. Signed-off-by: Keguang Zhang Acked-by: Krzysztof Kozlowski Reviewed-by: Serge Semin Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/mfd/syscon.yaml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index 8103154bbb52..c77d7b155a4c 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -49,6 +49,8 @@ properties: - hisilicon,peri-subctrl - hpe,gxp-sysreg - intel,lgm-syscon + - loongson,ls1b-syscon + - loongson,ls1c-syscon - marvell,armada-3700-usb2-host-misc - mediatek,mt8135-pctl-a-syscfg - mediatek,mt8135-pctl-b-syscfg -- cgit v1.2.3 From 2af21077fa9f8aa7b2418bd3bb835d337d1caeab Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Thu, 14 Sep 2023 19:44:34 +0800 Subject: dt-bindings: net: Add Loongson-1 Ethernet Controller Add devicetree binding document for Loongson-1 Ethernet controller. And modify MAINTAINERS to add a new F: entry for Loongson1 dt-binding documents. Signed-off-by: Keguang Zhang Reviewed-by: Krzysztof Kozlowski Reviewed-by: Serge Semin Signed-off-by: David S. Miller --- .../bindings/net/loongson,ls1b-gmac.yaml | 114 +++++++++++++++++++++ .../bindings/net/loongson,ls1c-emac.yaml | 113 ++++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 228 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/loongson,ls1b-gmac.yaml create mode 100644 Documentation/devicetree/bindings/net/loongson,ls1c-emac.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/loongson,ls1b-gmac.yaml b/Documentation/devicetree/bindings/net/loongson,ls1b-gmac.yaml new file mode 100644 index 000000000000..c4f3224bad38 --- /dev/null +++ b/Documentation/devicetree/bindings/net/loongson,ls1b-gmac.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/loongson,ls1b-gmac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-1B Gigabit Ethernet MAC Controller + +maintainers: + - Keguang Zhang + +description: | + Loongson-1B Gigabit Ethernet MAC Controller is based on + Synopsys DesignWare MAC (version 3.50a). + + Main features + - Dual 10/100/1000Mbps GMAC controllers + - Full-duplex operation (IEEE 802.3x flow control automatic transmission) + - Half-duplex operation (CSMA/CD Protocol and back-pressure support) + - RX Checksum Offload + - TX Checksum insertion + - MII interface + - RGMII interface + +select: + properties: + compatible: + contains: + enum: + - loongson,ls1b-gmac + required: + - compatible + +properties: + compatible: + items: + - enum: + - loongson,ls1b-gmac + - const: snps,dwmac-3.50a + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: stmmaceth + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: macirq + + loongson,ls1-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon containing some extra configurations + including PHY interface mode. + + phy-mode: + enum: + - mii + - rgmii-id + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + - loongson,ls1-syscon + +allOf: + - $ref: snps,dwmac.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + gmac0: ethernet@1fe10000 { + compatible = "loongson,ls1b-gmac", "snps,dwmac-3.50a"; + reg = <0x1fe10000 0x10000>; + + clocks = <&clkc LS1X_CLKID_AHB>; + clock-names = "stmmaceth"; + + interrupt-parent = <&intc1>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + + loongson,ls1-syscon = <&syscon>; + + phy-handle = <&phy0>; + phy-mode = "mii"; + snps,pbl = <1>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@0 { + reg = <0x0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/loongson,ls1c-emac.yaml b/Documentation/devicetree/bindings/net/loongson,ls1c-emac.yaml new file mode 100644 index 000000000000..99001b940b83 --- /dev/null +++ b/Documentation/devicetree/bindings/net/loongson,ls1c-emac.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/loongson,ls1c-emac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-1C Ethernet MAC Controller + +maintainers: + - Keguang Zhang + +description: | + Loongson-1C Ethernet MAC Controller is based on + Synopsys DesignWare MAC (version 3.50a). + + Main features + - 10/100Mbps + - Full-duplex operation (IEEE 802.3x flow control automatic transmission) + - Half-duplex operation (CSMA/CD Protocol and back-pressure support) + - IEEE 802.1Q VLAN tag detection for reception frames + - MII interface + - RMII interface + +select: + properties: + compatible: + contains: + enum: + - loongson,ls1c-emac + required: + - compatible + +properties: + compatible: + items: + - enum: + - loongson,ls1c-emac + - const: snps,dwmac-3.50a + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: stmmaceth + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: macirq + + loongson,ls1-syscon: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon containing some extra configurations + including PHY interface mode. + + phy-mode: + enum: + - mii + - rmii + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + - loongson,ls1-syscon + +allOf: + - $ref: snps,dwmac.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + emac: ethernet@1fe10000 { + compatible = "loongson,ls1c-emac", "snps,dwmac-3.50a"; + reg = <0x1fe10000 0x10000>; + + clocks = <&clkc LS1X_CLKID_AHB>; + clock-names = "stmmaceth"; + + interrupt-parent = <&intc1>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + + loongson,ls1-syscon = <&syscon>; + + phy-handle = <&phy0>; + phy-mode = "mii"; + snps,pbl = <1>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@13 { + reg = <0x13>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3b32228356de..5e3e19960af2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14344,6 +14344,7 @@ MIPS/LOONGSON1 ARCHITECTURE M: Keguang Zhang L: linux-mips@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml F: arch/mips/include/asm/mach-loongson32/ F: arch/mips/loongson32/ F: drivers/*/*loongson1* -- cgit v1.2.3 From e26f40a60f17050040afcb8777f9aeac4f354a97 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 14 Sep 2023 09:51:06 +0200 Subject: dt-bindings: net: dsa: microchip: Update ksz device tree bindings for drive strength Extend device tree bindings to support drive strength configuration for the ksz* switches. Introduced properties: - microchip,hi-drive-strength-microamp: Controls the drive strength for high-speed interfaces like GMII/RGMII and more. - microchip,lo-drive-strength-microamp: Governs the drive strength for low-speed interfaces such as LEDs, PME_N, and others. - microchip,io-drive-strength-microamp: Controls the drive strength for for undocumented Pads on KSZ88xx variants. Signed-off-by: Oleksij Rempel Reviewed-by: Rob Herring Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- .../devicetree/bindings/net/dsa/microchip,ksz.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml index 03b5567be389..41014f5c01c4 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml @@ -49,6 +49,26 @@ properties: Set if the output SYNCLKO clock should be disabled. Do not mix with microchip,synclko-125. + microchip,io-drive-strength-microamp: + description: + IO Pad Drive Strength + enum: [8000, 16000] + default: 16000 + + microchip,hi-drive-strength-microamp: + description: + High Speed Drive Strength. Controls drive strength of GMII / RGMII / + MII / RMII (except TX_CLK/REFCLKI, COL and CRS) and CLKO_25_125 lines. + enum: [2000, 4000, 8000, 12000, 16000, 20000, 24000, 28000] + default: 24000 + + microchip,lo-drive-strength-microamp: + description: + Low Speed Drive Strength. Controls drive strength of TX_CLK / REFCLKI, + COL, CRS, LEDs, PME_N, NTRP_N, SDO and SDI/SDA/MDIO lines. + enum: [2000, 4000, 8000, 12000, 16000, 20000, 24000, 28000] + default: 8000 + interrupts: maxItems: 1 -- cgit v1.2.3 From dbb291f19393b628a1d15b94a78d471b9d94e532 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Wed, 13 Sep 2023 21:49:35 +0100 Subject: dpll: documentation on DPLL subsystem interface Add documentation explaining common netlink interface to configure DPLL devices and monitoring events. Common way to implement DPLL device in a driver is also covered. Co-developed-by: Bagas Sanjaya Signed-off-by: Bagas Sanjaya Signed-off-by: Vadim Fedorenko Signed-off-by: Arkadiusz Kubalewski Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/driver-api/dpll.rst | 497 +++++++++++++++++++++++++++++++++++++ Documentation/driver-api/index.rst | 1 + 2 files changed, 498 insertions(+) create mode 100644 Documentation/driver-api/dpll.rst (limited to 'Documentation') diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst new file mode 100644 index 000000000000..bb52f1b8c0be --- /dev/null +++ b/Documentation/driver-api/dpll.rst @@ -0,0 +1,497 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============================== +The Linux kernel dpll subsystem +=============================== + +DPLL +==== + +PLL - Phase Locked Loop is an electronic circuit which syntonizes clock +signal of a device with an external clock signal. Effectively enabling +device to run on the same clock signal beat as provided on a PLL input. + +DPLL - Digital Phase Locked Loop is an integrated circuit which in +addition to plain PLL behavior incorporates a digital phase detector +and may have digital divider in the loop. As a result, the frequency on +DPLL's input and output may be configurable. + +Subsystem +========= + +The main purpose of dpll subsystem is to provide general interface +to configure devices that use any kind of Digital PLL and could use +different sources of input signal to synchronize to, as well as +different types of outputs. +The main interface is NETLINK_GENERIC based protocol with an event +monitoring multicast group defined. + +Device object +============= + +Single dpll device object means single Digital PLL circuit and bunch of +connected pins. +It reports the supported modes of operation and current status to the +user in response to the `do` request of netlink command +``DPLL_CMD_DEVICE_GET`` and list of dplls registered in the subsystem +with `dump` netlink request of the same command. +Changing the configuration of dpll device is done with `do` request of +netlink ``DPLL_CMD_DEVICE_SET`` command. +A device handle is ``DPLL_A_ID``, it shall be provided to get or set +configuration of particular device in the system. It can be obtained +with a ``DPLL_CMD_DEVICE_GET`` `dump` request or +a ``DPLL_CMD_DEVICE_ID_GET`` `do` request, where the one must provide +attributes that result in single device match. + +Pin object +========== + +A pin is amorphic object which represents either input or output, it +could be internal component of the device, as well as externally +connected. +The number of pins per dpll vary, but usually multiple pins shall be +provided for a single dpll device. +Pin's properties, capabilities and status is provided to the user in +response to `do` request of netlink ``DPLL_CMD_PIN_GET`` command. +It is also possible to list all the pins that were registered in the +system with `dump` request of ``DPLL_CMD_PIN_GET`` command. +Configuration of a pin can be changed by `do` request of netlink +``DPLL_CMD_PIN_SET`` command. +Pin handle is a ``DPLL_A_PIN_ID``, it shall be provided to get or set +configuration of particular pin in the system. It can be obtained with +``DPLL_CMD_PIN_GET`` `dump` request or ``DPLL_CMD_PIN_ID_GET`` `do` +request, where user provides attributes that result in single pin match. + +Pin selection +============= + +In general, selected pin (the one which signal is driving the dpll +device) can be obtained from ``DPLL_A_PIN_STATE`` attribute, and only +one pin shall be in ``DPLL_PIN_STATE_CONNECTED`` state for any dpll +device. + +Pin selection can be done either manually or automatically, depending +on hardware capabilities and active dpll device work mode +(``DPLL_A_MODE`` attribute). The consequence is that there are +differences for each mode in terms of available pin states, as well as +for the states the user can request for a dpll device. + +In manual mode (``DPLL_MODE_MANUAL``) the user can request or receive +one of following pin states: + +- ``DPLL_PIN_STATE_CONNECTED`` - the pin is used to drive dpll device +- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin is not used to drive dpll + device + +In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can request or +receive one of following pin states: + +- ``DPLL_PIN_STATE_SELECTABLE`` - the pin shall be considered as valid + input for automatic selection algorithm +- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as + a valid input for automatic selection algorithm + +In automatic mode (``DPLL_MODE_AUTOMATIC``) the user can only receive +pin state ``DPLL_PIN_STATE_CONNECTED`` once automatic selection +algorithm locks a dpll device with one of the inputs. + +Shared pins +=========== + +A single pin object can be attached to multiple dpll devices. +Then there are two groups of configuration knobs: + +1) Set on a pin - the configuration affects all dpll devices pin is + registered to (i.e., ``DPLL_A_PIN_FREQUENCY``), +2) Set on a pin-dpll tuple - the configuration affects only selected + dpll device (i.e., ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE``, + ``DPLL_A_PIN_DIRECTION``). + +MUX-type pins +============= + +A pin can be MUX-type, it aggregates child pins and serves as a pin +multiplexer. One or more pins are registered with MUX-type instead of +being directly registered to a dpll device. +Pins registered with a MUX-type pin provide user with additional nested +attribute ``DPLL_A_PIN_PARENT_PIN`` for each parent they were registered +with. +If a pin was registered with multiple parent pins, they behave like a +multiple output multiplexer. In this case output of a +``DPLL_CMD_PIN_GET`` would contain multiple pin-parent nested +attributes with current state related to each parent, like: + +'pin': [{{ + 'clock-id': 282574471561216, + 'module-name': 'ice', + 'capabilities': 4, + 'id': 13, + 'parent-pin': [ + {'parent-id': 2, 'state': 'connected'}, + {'parent-id': 3, 'state': 'disconnected'} + ], + 'type': 'synce-eth-port' + }}] + +Only one child pin can provide its signal to the parent MUX-type pin at +a time, the selection is done by requesting change of a child pin state +on desired parent, with the use of ``DPLL_A_PIN_PARENT`` nested +attribute. Example of netlink `set state on parent pin` message format: + + ========================== ============================================= + ``DPLL_A_PIN_ID`` child pin id + ``DPLL_A_PIN_PARENT_PIN`` nested attribute for requesting configuration + related to parent pin + ``DPLL_A_PIN_PARENT_ID`` parent pin id + ``DPLL_A_PIN_STATE`` requested pin state on parent + ========================== ============================================= + +Pin priority +============ + +Some devices might offer a capability of automatic pin selection mode +(enum value ``DPLL_MODE_AUTOMATIC`` of ``DPLL_A_MODE`` attribute). +Usually, automatic selection is performed on the hardware level, which +means only pins directly connected to the dpll can be used for automatic +input pin selection. +In automatic selection mode, the user cannot manually select a input +pin for the device, instead the user shall provide all directly +connected pins with a priority ``DPLL_A_PIN_PRIO``, the device would +pick a highest priority valid signal and use it to control the DPLL +device. Example of netlink `set priority on parent pin` message format: + + ============================ ============================================= + ``DPLL_A_PIN_ID`` configured pin id + ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting configuration + related to parent dpll device + ``DPLL_A_PIN_PARENT_ID`` parent dpll device id + ``DPLL_A_PIN_PRIO`` requested pin prio on parent dpll + ============================ ============================================= + +Child pin of MUX-type pin is not capable of automatic input pin selection, +in order to configure active input of a MUX-type pin, the user needs to +request desired pin state of the child pin on the parent pin, +as described in the ``MUX-type pins`` chapter. + +Configuration commands group +============================ + +Configuration commands are used to get information about registered +dpll devices (and pins), as well as set configuration of device or pins. +As dpll devices must be abstracted and reflect real hardware, +there is no way to add new dpll device via netlink from user space and +each device should be registered by its driver. + +All netlink commands require ``GENL_ADMIN_PERM``. This is to prevent +any spamming/DoS from unauthorized userspace applications. + +List of netlink commands with possible attributes +================================================= + +Constants identifying command types for dpll device uses a +``DPLL_CMD_`` prefix and suffix according to command purpose. +The dpll device related attributes use a ``DPLL_A_`` prefix and +suffix according to attribute purpose. + + ==================================== ================================= + ``DPLL_CMD_DEVICE_ID_GET`` command to get device ID + ``DPLL_A_MODULE_NAME`` attr module name of registerer + ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier + (EUI-64), as defined by the + IEEE 1588 standard + ``DPLL_A_TYPE`` attr type of dpll device + ==================================== ================================= + + ==================================== ================================= + ``DPLL_CMD_DEVICE_GET`` command to get device info or + dump list of available devices + ``DPLL_A_ID`` attr unique dpll device ID + ``DPLL_A_MODULE_NAME`` attr module name of registerer + ``DPLL_A_CLOCK_ID`` attr Unique Clock Identifier + (EUI-64), as defined by the + IEEE 1588 standard + ``DPLL_A_MODE`` attr selection mode + ``DPLL_A_MODE_SUPPORTED`` attr available selection modes + ``DPLL_A_LOCK_STATUS`` attr dpll device lock status + ``DPLL_A_TEMP`` attr device temperature info + ``DPLL_A_TYPE`` attr type of dpll device + ==================================== ================================= + + ==================================== ================================= + ``DPLL_CMD_DEVICE_SET`` command to set dpll device config + ``DPLL_A_ID`` attr internal dpll device index + ``DPLL_A_MODE`` attr selection mode to configure + ==================================== ================================= + +Constants identifying command types for pins uses a +``DPLL_CMD_PIN_`` prefix and suffix according to command purpose. +The pin related attributes use a ``DPLL_A_PIN_`` prefix and suffix +according to attribute purpose. + + ==================================== ================================= + ``DPLL_CMD_PIN_ID_GET`` command to get pin ID + ``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer + ``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier + (EUI-64), as defined by the + IEEE 1588 standard + ``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided + by registerer + ``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided + by registerer + ``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided + by registerer + ``DPLL_A_PIN_TYPE`` attr type of a pin + ==================================== ================================= + + ==================================== ================================== + ``DPLL_CMD_PIN_GET`` command to get pin info or dump + list of available pins + ``DPLL_A_PIN_ID`` attr unique a pin ID + ``DPLL_A_PIN_MODULE_NAME`` attr module name of registerer + ``DPLL_A_PIN_CLOCK_ID`` attr Unique Clock Identifier + (EUI-64), as defined by the + IEEE 1588 standard + ``DPLL_A_PIN_BOARD_LABEL`` attr pin board label provided + by registerer + ``DPLL_A_PIN_PANEL_LABEL`` attr pin panel label provided + by registerer + ``DPLL_A_PIN_PACKAGE_LABEL`` attr pin package label provided + by registerer + ``DPLL_A_PIN_TYPE`` attr type of a pin + ``DPLL_A_PIN_FREQUENCY`` attr current frequency of a pin + ``DPLL_A_PIN_FREQUENCY_SUPPORTED`` nested attr provides supported + frequencies + ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency + ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency + ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device + the pin is connected with + ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id + ``DPLL_A_PIN_PRIO`` attr priority of pin on the + dpll device + ``DPLL_A_PIN_STATE`` attr state of pin on the parent + dpll device + ``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the + parent dpll device + ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin + the pin is connected with + ``DPLL_A_PIN_PARENT_ID`` attr parent pin id + ``DPLL_A_PIN_STATE`` attr state of pin on the parent + pin + ``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities + ==================================== ================================== + + ==================================== ================================= + ``DPLL_CMD_PIN_SET`` command to set pins configuration + ``DPLL_A_PIN_ID`` attr unique a pin ID + ``DPLL_A_PIN_FREQUENCY`` attr requested frequency of a pin + ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent dpll + device configuration request + ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id + ``DPLL_A_PIN_DIRECTION`` attr requested direction of a pin + ``DPLL_A_PIN_PRIO`` attr requested priority of pin on + the dpll device + ``DPLL_A_PIN_STATE`` attr requested state of pin on + the dpll device + ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin + configuration request + ``DPLL_A_PIN_PARENT_ID`` attr parent pin id + ``DPLL_A_PIN_STATE`` attr requested state of pin on + parent pin + ==================================== ================================= + +Netlink dump requests +===================== + +The ``DPLL_CMD_DEVICE_GET`` and ``DPLL_CMD_PIN_GET`` commands are +capable of dump type netlink requests, in which case the response is in +the same format as for their ``do`` request, but every device or pin +registered in the system is returned. + +SET commands format +=================== + +``DPLL_CMD_DEVICE_SET`` - to target a dpll device, the user provides +``DPLL_A_ID``, which is unique identifier of dpll device in the system, +as well as parameter being configured (``DPLL_A_MODE``). + +``DPLL_CMD_PIN_SET`` - to target a pin user must provide a +``DPLL_A_PIN_ID``, which is unique identifier of a pin in the system. +Also configured pin parameters must be added. +If ``DPLL_A_PIN_FREQUENCY`` is configured, this affects all the dpll +devices that are connected with the pin, that is why frequency attribute +shall not be enclosed in ``DPLL_A_PIN_PARENT_DEVICE``. +Other attributes: ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE`` or +``DPLL_A_PIN_DIRECTION`` must be enclosed in +``DPLL_A_PIN_PARENT_DEVICE`` as their configuration relates to only one +of parent dplls, targeted by ``DPLL_A_PIN_PARENT_ID`` attribute which is +also required inside that nest. +For MUX-type pins the ``DPLL_A_PIN_STATE`` attribute is configured in +similar way, by enclosing required state in ``DPLL_A_PIN_PARENT_PIN`` +nested attribute and targeted parent pin id in ``DPLL_A_PIN_PARENT_ID``. + +In general, it is possible to configure multiple parameters at once, but +internally each parameter change will be invoked separately, where order +of configuration is not guaranteed by any means. + +Configuration pre-defined enums +=============================== + +.. kernel-doc:: include/uapi/linux/dpll.h + +Notifications +============= + +dpll device can provide notifications regarding status changes of the +device, i.e. lock status changes, input/output changes or other alarms. +There is one multicast group that is used to notify user-space apps via +netlink socket: ``DPLL_MCGRP_MONITOR`` + +Notifications messages: + + ============================== ===================================== + ``DPLL_CMD_DEVICE_CREATE_NTF`` dpll device was created + ``DPLL_CMD_DEVICE_DELETE_NTF`` dpll device was deleted + ``DPLL_CMD_DEVICE_CHANGE_NTF`` dpll device has changed + ``DPLL_CMD_PIN_CREATE_NTF`` dpll pin was created + ``DPLL_CMD_PIN_DELETE_NTF`` dpll pin was deleted + ``DPLL_CMD_PIN_CHANGE_NTF`` dpll pin has changed + ============================== ===================================== + +Events format is the same as for the corresponding get command. +Format of ``DPLL_CMD_DEVICE_`` events is the same as response of +``DPLL_CMD_DEVICE_GET``. +Format of ``DPLL_CMD_PIN_`` events is same as response of +``DPLL_CMD_PIN_GET``. + +Device driver implementation +============================ + +Device is allocated by dpll_device_get() call. Second call with the +same arguments will not create new object but provides pointer to +previously created device for given arguments, it also increases +refcount of that object. +Device is deallocated by dpll_device_put() call, which first +decreases the refcount, once refcount is cleared the object is +destroyed. + +Device should implement set of operations and register device via +dpll_device_register() at which point it becomes available to the +users. Multiple driver instances can obtain reference to it with +dpll_device_get(), as well as register dpll device with their own +ops and priv. + +The pins are allocated separately with dpll_pin_get(), it works +similarly to dpll_device_get(). Function first creates object and then +for each call with the same arguments only the object refcount +increases. Also dpll_pin_put() works similarly to dpll_device_put(). + +A pin can be registered with parent dpll device or parent pin, depending +on hardware needs. Each registration requires registerer to provide set +of pin callbacks, and private data pointer for calling them: + +- dpll_pin_register() - register pin with a dpll device, +- dpll_pin_on_pin_register() - register pin with another MUX type pin. + +Notifications of adding or removing dpll devices are created within +subsystem itself. +Notifications about registering/deregistering pins are also invoked by +the subsystem. +Notifications about status changes either of dpll device or a pin are +invoked in two ways: + +- after successful change was requested on dpll subsystem, the subsystem + calls corresponding notification, +- requested by device driver with dpll_device_change_ntf() or + dpll_pin_change_ntf() when driver informs about the status change. + +The device driver using dpll interface is not required to implement all +the callback operation. Nevertheless, there are few required to be +implemented. +Required dpll device level callback operations: + +- ``.mode_get``, +- ``.lock_status_get``. + +Required pin level callback operations: + +- ``.state_on_dpll_get`` (pins registered with dpll device), +- ``.state_on_pin_get`` (pins registered with parent pin), +- ``.direction_get``. + +Every other operation handler is checked for existence and +``-EOPNOTSUPP`` is returned in case of absence of specific handler. + +The simplest implementation is in the OCP TimeCard driver. The ops +structures are defined like this: + +.. code-block:: c + static const struct dpll_device_ops dpll_ops = { + .lock_status_get = ptp_ocp_dpll_lock_status_get, + .mode_get = ptp_ocp_dpll_mode_get, + .mode_supported = ptp_ocp_dpll_mode_supported, + }; + + static const struct dpll_pin_ops dpll_pins_ops = { + .frequency_get = ptp_ocp_dpll_frequency_get, + .frequency_set = ptp_ocp_dpll_frequency_set, + .direction_get = ptp_ocp_dpll_direction_get, + .direction_set = ptp_ocp_dpll_direction_set, + .state_on_dpll_get = ptp_ocp_dpll_state_get, + }; + +The registration part is then looks like this part: + +.. code-block:: c + clkid = pci_get_dsn(pdev); + bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE); + if (IS_ERR(bp->dpll)) { + err = PTR_ERR(bp->dpll); + dev_err(&pdev->dev, "dpll_device_alloc failed\n"); + goto out; + } + + err = dpll_device_register(bp->dpll, DPLL_TYPE_PPS, &dpll_ops, bp); + if (err) + goto out; + + for (i = 0; i < OCP_SMA_NUM; i++) { + bp->sma[i].dpll_pin = dpll_pin_get(clkid, i, THIS_MODULE, &bp->sma[i].dpll_prop); + if (IS_ERR(bp->sma[i].dpll_pin)) { + err = PTR_ERR(bp->dpll); + goto out_dpll; + } + + err = dpll_pin_register(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, + &bp->sma[i]); + if (err) { + dpll_pin_put(bp->sma[i].dpll_pin); + goto out_dpll; + } + } + +In the error path we have to rewind every allocation in the reverse order: + +.. code-block:: c + while (i) { + --i; + dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); + dpll_pin_put(bp->sma[i].dpll_pin); + } + dpll_device_put(bp->dpll); + +More complex example can be found in Intel's ICE driver or nVidia's mlx5 driver. + +SyncE enablement +================ +For SyncE enablement it is required to allow control over dpll device +for a software application which monitors and configures the inputs of +dpll device in response to current state of a dpll device and its +inputs. +In such scenario, dpll device input signal shall be also configurable +to drive dpll with signal recovered from the PHY netdevice. +This is done by exposing a pin to the netdevice - attaching pin to the +netdevice itself with +``netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin)``. +Exposed pin id handle ``DPLL_A_PIN_ID`` is then identifiable by the user +as it is attached to rtnetlink respond to get ``RTM_NEWLINK`` command in +nested attribute ``IFLA_DPLL_PIN``. diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 1e16a40da3ba..f549a68951d7 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -114,6 +114,7 @@ available subsections can be seen below. zorro hte/index wmi + dpll .. only:: subproject and html -- cgit v1.2.3 From 3badff3a25d815e915d89565a0c82dec608a8d2b Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Wed, 13 Sep 2023 21:49:36 +0100 Subject: dpll: spec: Add Netlink spec in YAML Add a protocol spec for DPLL. Add code generated from the spec. Signed-off-by: Jakub Kicinski Signed-off-by: Michal Michalik Signed-off-by: Vadim Fedorenko Signed-off-by: Arkadiusz Kubalewski Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/netlink/specs/dpll.yaml | 488 ++++++++++++++++++++++++++++++++++ drivers/dpll/dpll_nl.c | 162 +++++++++++ drivers/dpll/dpll_nl.h | 51 ++++ include/uapi/linux/dpll.h | 201 ++++++++++++++ 4 files changed, 902 insertions(+) create mode 100644 Documentation/netlink/specs/dpll.yaml create mode 100644 drivers/dpll/dpll_nl.c create mode 100644 drivers/dpll/dpll_nl.h create mode 100644 include/uapi/linux/dpll.h (limited to 'Documentation') diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml new file mode 100644 index 000000000000..8b86b28b47a6 --- /dev/null +++ b/Documentation/netlink/specs/dpll.yaml @@ -0,0 +1,488 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: dpll + +doc: DPLL subsystem. + +definitions: + - + type: enum + name: mode + doc: | + working modes a dpll can support, differentiates if and how dpll selects + one of its inputs to syntonize with it, valid values for DPLL_A_MODE + attribute + entries: + - + name: manual + doc: input can be only selected by sending a request to dpll + value: 1 + - + name: automatic + doc: highest prio input pin auto selected by dpll + render-max: true + - + type: enum + name: lock-status + doc: | + provides information of dpll device lock status, valid values for + DPLL_A_LOCK_STATUS attribute + entries: + - + name: unlocked + doc: | + dpll was not yet locked to any valid input (or forced by setting + DPLL_A_MODE to DPLL_MODE_DETACHED) + value: 1 + - + name: locked + doc: | + dpll is locked to a valid signal, but no holdover available + - + name: locked-ho-acq + doc: | + dpll is locked and holdover acquired + - + name: holdover + doc: | + dpll is in holdover state - lost a valid lock or was forced + by disconnecting all the pins (latter possible only + when dpll lock-state was already DPLL_LOCK_STATUS_LOCKED_HO_ACQ, + if dpll lock-state was not DPLL_LOCK_STATUS_LOCKED_HO_ACQ, the + dpll's lock-state shall remain DPLL_LOCK_STATUS_UNLOCKED) + render-max: true + - + type: const + name: temp-divider + value: 1000 + doc: | + temperature divider allowing userspace to calculate the + temperature as float with three digit decimal precision. + Value of (DPLL_A_TEMP / DPLL_TEMP_DIVIDER) is integer part of + temperature value. + Value of (DPLL_A_TEMP % DPLL_TEMP_DIVIDER) is fractional part of + temperature value. + - + type: enum + name: type + doc: type of dpll, valid values for DPLL_A_TYPE attribute + entries: + - + name: pps + doc: dpll produces Pulse-Per-Second signal + value: 1 + - + name: eec + doc: dpll drives the Ethernet Equipment Clock + render-max: true + - + type: enum + name: pin-type + doc: | + defines possible types of a pin, valid values for DPLL_A_PIN_TYPE + attribute + entries: + - + name: mux + doc: aggregates another layer of selectable pins + value: 1 + - + name: ext + doc: external input + - + name: synce-eth-port + doc: ethernet port PHY's recovered clock + - + name: int-oscillator + doc: device internal oscillator + - + name: gnss + doc: GNSS recovered clock + render-max: true + - + type: enum + name: pin-direction + doc: | + defines possible direction of a pin, valid values for + DPLL_A_PIN_DIRECTION attribute + entries: + - + name: input + doc: pin used as a input of a signal + value: 1 + - + name: output + doc: pin used to output the signal + render-max: true + - + type: const + name: pin-frequency-1-hz + value: 1 + - + type: const + name: pin-frequency-10-khz + value: 10000 + - + type: const + name: pin-frequency-77_5-khz + value: 77500 + - + type: const + name: pin-frequency-10-mhz + value: 10000000 + - + type: enum + name: pin-state + doc: | + defines possible states of a pin, valid values for + DPLL_A_PIN_STATE attribute + entries: + - + name: connected + doc: pin connected, active input of phase locked loop + value: 1 + - + name: disconnected + doc: pin disconnected, not considered as a valid input + - + name: selectable + doc: pin enabled for automatic input selection + render-max: true + - + type: flags + name: pin-capabilities + doc: | + defines possible capabilities of a pin, valid flags on + DPLL_A_PIN_CAPABILITIES attribute + entries: + - + name: direction-can-change + doc: pin direction can be changed + - + name: priority-can-change + doc: pin priority can be changed + - + name: state-can-change + doc: pin state can be changed + +attribute-sets: + - + name: dpll + enum-name: dpll_a + attributes: + - + name: id + type: u32 + - + name: module-name + type: string + - + name: pad + type: pad + - + name: clock-id + type: u64 + - + name: mode + type: u32 + enum: mode + - + name: mode-supported + type: u32 + enum: mode + multi-attr: true + - + name: lock-status + type: u32 + enum: lock-status + - + name: temp + type: s32 + - + name: type + type: u32 + enum: type + - + name: pin + enum-name: dpll_a_pin + attributes: + - + name: id + type: u32 + - + name: parent-id + type: u32 + - + name: module-name + type: string + - + name: pad + type: pad + - + name: clock-id + type: u64 + - + name: board-label + type: string + - + name: panel-label + type: string + - + name: package-label + type: string + - + name: type + type: u32 + enum: pin-type + - + name: direction + type: u32 + enum: pin-direction + - + name: frequency + type: u64 + - + name: frequency-supported + type: nest + multi-attr: true + nested-attributes: frequency-range + - + name: frequency-min + type: u64 + - + name: frequency-max + type: u64 + - + name: prio + type: u32 + - + name: state + type: u32 + enum: pin-state + - + name: capabilities + type: u32 + - + name: parent-device + type: nest + multi-attr: true + nested-attributes: pin-parent-device + - + name: parent-pin + type: nest + multi-attr: true + nested-attributes: pin-parent-pin + - + name: pin-parent-device + subset-of: pin + attributes: + - + name: parent-id + type: u32 + - + name: direction + type: u32 + - + name: prio + type: u32 + - + name: state + type: u32 + - + name: pin-parent-pin + subset-of: pin + attributes: + - + name: parent-id + type: u32 + - + name: state + type: u32 + - + name: frequency-range + subset-of: pin + attributes: + - + name: frequency-min + type: u64 + - + name: frequency-max + type: u64 + +operations: + enum-name: dpll_cmd + list: + - + name: device-id-get + doc: | + Get id of dpll device that matches given attributes + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-lock-doit + post: dpll-unlock-doit + request: + attributes: + - module-name + - clock-id + - type + reply: + attributes: + - id + + - + name: device-get + doc: | + Get list of DPLL devices (dump) or attributes of a single dpll device + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-pre-doit + post: dpll-post-doit + request: + attributes: + - id + reply: &dev-attrs + attributes: + - id + - module-name + - mode + - mode-supported + - lock-status + - temp + - clock-id + - type + + dump: + pre: dpll-lock-dumpit + post: dpll-unlock-dumpit + reply: *dev-attrs + + - + name: device-set + doc: Set attributes for a DPLL device + attribute-set: dpll + flags: [ admin-perm ] + + do: + pre: dpll-pre-doit + post: dpll-post-doit + request: + attributes: + - id + - + name: device-create-ntf + doc: Notification about device appearing + notify: device-get + mcgrp: monitor + - + name: device-delete-ntf + doc: Notification about device disappearing + notify: device-get + mcgrp: monitor + - + name: device-change-ntf + doc: Notification about device configuration being changed + notify: device-get + mcgrp: monitor + - + name: pin-id-get + doc: | + Get id of a pin that matches given attributes + attribute-set: pin + flags: [ admin-perm ] + + do: + pre: dpll-lock-doit + post: dpll-unlock-doit + request: + attributes: + - module-name + - clock-id + - board-label + - panel-label + - package-label + - type + reply: + attributes: + - id + + - + name: pin-get + doc: | + Get list of pins and its attributes. + - dump request without any attributes given - list all the pins in the + system + - dump request with target dpll - list all the pins registered with + a given dpll device + - do request with target dpll and target pin - single pin attributes + attribute-set: pin + flags: [ admin-perm ] + + do: + pre: dpll-pin-pre-doit + post: dpll-pin-post-doit + request: + attributes: + - id + reply: &pin-attrs + attributes: + - id + - board-label + - panel-label + - package-label + - type + - frequency + - frequency-supported + - capabilities + - parent-device + - parent-pin + + dump: + pre: dpll-lock-dumpit + post: dpll-unlock-dumpit + request: + attributes: + - id + reply: *pin-attrs + + - + name: pin-set + doc: Set attributes of a target pin + attribute-set: pin + flags: [ admin-perm ] + + do: + pre: dpll-pin-pre-doit + post: dpll-pin-post-doit + request: + attributes: + - id + - frequency + - direction + - prio + - state + - parent-device + - parent-pin + - + name: pin-create-ntf + doc: Notification about pin appearing + notify: pin-get + mcgrp: monitor + - + name: pin-delete-ntf + doc: Notification about pin disappearing + notify: pin-get + mcgrp: monitor + - + name: pin-change-ntf + doc: Notification about pin configuration being changed + notify: pin-get + mcgrp: monitor + +mcast-groups: + list: + - + name: monitor diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c new file mode 100644 index 000000000000..14064c8c783b --- /dev/null +++ b/drivers/dpll/dpll_nl.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dpll.yaml */ +/* YNL-GEN kernel source */ + +#include +#include + +#include "dpll_nl.h" + +#include + +/* Common nested types */ +const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1] = { + [DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, }, + [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), + [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, + [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), +}; + +const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = { + [DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, }, + [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), +}; + +/* DPLL_CMD_DEVICE_ID_GET - do */ +static const struct nla_policy dpll_device_id_get_nl_policy[DPLL_A_TYPE + 1] = { + [DPLL_A_MODULE_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_CLOCK_ID] = { .type = NLA_U64, }, + [DPLL_A_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 2), +}; + +/* DPLL_CMD_DEVICE_GET - do */ +static const struct nla_policy dpll_device_get_nl_policy[DPLL_A_ID + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, +}; + +/* DPLL_CMD_DEVICE_SET - do */ +static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_ID + 1] = { + [DPLL_A_ID] = { .type = NLA_U32, }, +}; + +/* DPLL_CMD_PIN_ID_GET - do */ +static const struct nla_policy dpll_pin_id_get_nl_policy[DPLL_A_PIN_TYPE + 1] = { + [DPLL_A_PIN_MODULE_NAME] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_CLOCK_ID] = { .type = NLA_U64, }, + [DPLL_A_PIN_BOARD_LABEL] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_PANEL_LABEL] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_PACKAGE_LABEL] = { .type = NLA_NUL_STRING, }, + [DPLL_A_PIN_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 5), +}; + +/* DPLL_CMD_PIN_GET - do */ +static const struct nla_policy dpll_pin_get_do_nl_policy[DPLL_A_PIN_ID + 1] = { + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, +}; + +/* DPLL_CMD_PIN_GET - dump */ +static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] = { + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, +}; + +/* DPLL_CMD_PIN_SET - do */ +static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT_PIN + 1] = { + [DPLL_A_PIN_ID] = { .type = NLA_U32, }, + [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, + [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), + [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, + [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), + [DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy), + [DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy), +}; + +/* Ops table for dpll */ +static const struct genl_split_ops dpll_nl_ops[] = { + { + .cmd = DPLL_CMD_DEVICE_ID_GET, + .pre_doit = dpll_lock_doit, + .doit = dpll_nl_device_id_get_doit, + .post_doit = dpll_unlock_doit, + .policy = dpll_device_id_get_nl_policy, + .maxattr = DPLL_A_TYPE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_DEVICE_GET, + .pre_doit = dpll_pre_doit, + .doit = dpll_nl_device_get_doit, + .post_doit = dpll_post_doit, + .policy = dpll_device_get_nl_policy, + .maxattr = DPLL_A_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_DEVICE_GET, + .start = dpll_lock_dumpit, + .dumpit = dpll_nl_device_get_dumpit, + .done = dpll_unlock_dumpit, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = DPLL_CMD_DEVICE_SET, + .pre_doit = dpll_pre_doit, + .doit = dpll_nl_device_set_doit, + .post_doit = dpll_post_doit, + .policy = dpll_device_set_nl_policy, + .maxattr = DPLL_A_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_PIN_ID_GET, + .pre_doit = dpll_lock_doit, + .doit = dpll_nl_pin_id_get_doit, + .post_doit = dpll_unlock_doit, + .policy = dpll_pin_id_get_nl_policy, + .maxattr = DPLL_A_PIN_TYPE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_PIN_GET, + .pre_doit = dpll_pin_pre_doit, + .doit = dpll_nl_pin_get_doit, + .post_doit = dpll_pin_post_doit, + .policy = dpll_pin_get_do_nl_policy, + .maxattr = DPLL_A_PIN_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DPLL_CMD_PIN_GET, + .start = dpll_lock_dumpit, + .dumpit = dpll_nl_pin_get_dumpit, + .done = dpll_unlock_dumpit, + .policy = dpll_pin_get_dump_nl_policy, + .maxattr = DPLL_A_PIN_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = DPLL_CMD_PIN_SET, + .pre_doit = dpll_pin_pre_doit, + .doit = dpll_nl_pin_set_doit, + .post_doit = dpll_pin_post_doit, + .policy = dpll_pin_set_nl_policy, + .maxattr = DPLL_A_PIN_PARENT_PIN, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, +}; + +static const struct genl_multicast_group dpll_nl_mcgrps[] = { + [DPLL_NLGRP_MONITOR] = { "monitor", }, +}; + +struct genl_family dpll_nl_family __ro_after_init = { + .name = DPLL_FAMILY_NAME, + .version = DPLL_FAMILY_VERSION, + .netnsok = true, + .parallel_ops = true, + .module = THIS_MODULE, + .split_ops = dpll_nl_ops, + .n_split_ops = ARRAY_SIZE(dpll_nl_ops), + .mcgrps = dpll_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(dpll_nl_mcgrps), +}; diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h new file mode 100644 index 000000000000..1f67aaed4742 --- /dev/null +++ b/drivers/dpll/dpll_nl.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dpll.yaml */ +/* YNL-GEN kernel header */ + +#ifndef _LINUX_DPLL_GEN_H +#define _LINUX_DPLL_GEN_H + +#include +#include + +#include + +/* Common nested types */ +extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1]; +extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1]; + +int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +int dpll_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +dpll_unlock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +dpll_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +dpll_pin_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +int dpll_lock_dumpit(struct netlink_callback *cb); +int dpll_unlock_dumpit(struct netlink_callback *cb); + +int dpll_nl_device_id_get_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_device_get_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int dpll_nl_device_set_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_pin_get_doit(struct sk_buff *skb, struct genl_info *info); +int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int dpll_nl_pin_set_doit(struct sk_buff *skb, struct genl_info *info); + +enum { + DPLL_NLGRP_MONITOR, +}; + +extern struct genl_family dpll_nl_family; + +#endif /* _LINUX_DPLL_GEN_H */ diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h new file mode 100644 index 000000000000..20ef0718f8dc --- /dev/null +++ b/include/uapi/linux/dpll.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dpll.yaml */ +/* YNL-GEN uapi header */ + +#ifndef _UAPI_LINUX_DPLL_H +#define _UAPI_LINUX_DPLL_H + +#define DPLL_FAMILY_NAME "dpll" +#define DPLL_FAMILY_VERSION 1 + +/** + * enum dpll_mode - working modes a dpll can support, differentiates if and how + * dpll selects one of its inputs to syntonize with it, valid values for + * DPLL_A_MODE attribute + * @DPLL_MODE_MANUAL: input can be only selected by sending a request to dpll + * @DPLL_MODE_AUTOMATIC: highest prio input pin auto selected by dpll + */ +enum dpll_mode { + DPLL_MODE_MANUAL = 1, + DPLL_MODE_AUTOMATIC, + + /* private: */ + __DPLL_MODE_MAX, + DPLL_MODE_MAX = (__DPLL_MODE_MAX - 1) +}; + +/** + * enum dpll_lock_status - provides information of dpll device lock status, + * valid values for DPLL_A_LOCK_STATUS attribute + * @DPLL_LOCK_STATUS_UNLOCKED: dpll was not yet locked to any valid input (or + * forced by setting DPLL_A_MODE to DPLL_MODE_DETACHED) + * @DPLL_LOCK_STATUS_LOCKED: dpll is locked to a valid signal, but no holdover + * available + * @DPLL_LOCK_STATUS_LOCKED_HO_ACQ: dpll is locked and holdover acquired + * @DPLL_LOCK_STATUS_HOLDOVER: dpll is in holdover state - lost a valid lock or + * was forced by disconnecting all the pins (latter possible only when dpll + * lock-state was already DPLL_LOCK_STATUS_LOCKED_HO_ACQ, if dpll lock-state + * was not DPLL_LOCK_STATUS_LOCKED_HO_ACQ, the dpll's lock-state shall remain + * DPLL_LOCK_STATUS_UNLOCKED) + */ +enum dpll_lock_status { + DPLL_LOCK_STATUS_UNLOCKED = 1, + DPLL_LOCK_STATUS_LOCKED, + DPLL_LOCK_STATUS_LOCKED_HO_ACQ, + DPLL_LOCK_STATUS_HOLDOVER, + + /* private: */ + __DPLL_LOCK_STATUS_MAX, + DPLL_LOCK_STATUS_MAX = (__DPLL_LOCK_STATUS_MAX - 1) +}; + +#define DPLL_TEMP_DIVIDER 1000 + +/** + * enum dpll_type - type of dpll, valid values for DPLL_A_TYPE attribute + * @DPLL_TYPE_PPS: dpll produces Pulse-Per-Second signal + * @DPLL_TYPE_EEC: dpll drives the Ethernet Equipment Clock + */ +enum dpll_type { + DPLL_TYPE_PPS = 1, + DPLL_TYPE_EEC, + + /* private: */ + __DPLL_TYPE_MAX, + DPLL_TYPE_MAX = (__DPLL_TYPE_MAX - 1) +}; + +/** + * enum dpll_pin_type - defines possible types of a pin, valid values for + * DPLL_A_PIN_TYPE attribute + * @DPLL_PIN_TYPE_MUX: aggregates another layer of selectable pins + * @DPLL_PIN_TYPE_EXT: external input + * @DPLL_PIN_TYPE_SYNCE_ETH_PORT: ethernet port PHY's recovered clock + * @DPLL_PIN_TYPE_INT_OSCILLATOR: device internal oscillator + * @DPLL_PIN_TYPE_GNSS: GNSS recovered clock + */ +enum dpll_pin_type { + DPLL_PIN_TYPE_MUX = 1, + DPLL_PIN_TYPE_EXT, + DPLL_PIN_TYPE_SYNCE_ETH_PORT, + DPLL_PIN_TYPE_INT_OSCILLATOR, + DPLL_PIN_TYPE_GNSS, + + /* private: */ + __DPLL_PIN_TYPE_MAX, + DPLL_PIN_TYPE_MAX = (__DPLL_PIN_TYPE_MAX - 1) +}; + +/** + * enum dpll_pin_direction - defines possible direction of a pin, valid values + * for DPLL_A_PIN_DIRECTION attribute + * @DPLL_PIN_DIRECTION_INPUT: pin used as a input of a signal + * @DPLL_PIN_DIRECTION_OUTPUT: pin used to output the signal + */ +enum dpll_pin_direction { + DPLL_PIN_DIRECTION_INPUT = 1, + DPLL_PIN_DIRECTION_OUTPUT, + + /* private: */ + __DPLL_PIN_DIRECTION_MAX, + DPLL_PIN_DIRECTION_MAX = (__DPLL_PIN_DIRECTION_MAX - 1) +}; + +#define DPLL_PIN_FREQUENCY_1_HZ 1 +#define DPLL_PIN_FREQUENCY_10_KHZ 10000 +#define DPLL_PIN_FREQUENCY_77_5_KHZ 77500 +#define DPLL_PIN_FREQUENCY_10_MHZ 10000000 + +/** + * enum dpll_pin_state - defines possible states of a pin, valid values for + * DPLL_A_PIN_STATE attribute + * @DPLL_PIN_STATE_CONNECTED: pin connected, active input of phase locked loop + * @DPLL_PIN_STATE_DISCONNECTED: pin disconnected, not considered as a valid + * input + * @DPLL_PIN_STATE_SELECTABLE: pin enabled for automatic input selection + */ +enum dpll_pin_state { + DPLL_PIN_STATE_CONNECTED = 1, + DPLL_PIN_STATE_DISCONNECTED, + DPLL_PIN_STATE_SELECTABLE, + + /* private: */ + __DPLL_PIN_STATE_MAX, + DPLL_PIN_STATE_MAX = (__DPLL_PIN_STATE_MAX - 1) +}; + +/** + * enum dpll_pin_capabilities - defines possible capabilities of a pin, valid + * flags on DPLL_A_PIN_CAPABILITIES attribute + * @DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE: pin direction can be changed + * @DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE: pin priority can be changed + * @DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE: pin state can be changed + */ +enum dpll_pin_capabilities { + DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE = 1, + DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE = 2, + DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE = 4, +}; + +enum dpll_a { + DPLL_A_ID = 1, + DPLL_A_MODULE_NAME, + DPLL_A_PAD, + DPLL_A_CLOCK_ID, + DPLL_A_MODE, + DPLL_A_MODE_SUPPORTED, + DPLL_A_LOCK_STATUS, + DPLL_A_TEMP, + DPLL_A_TYPE, + + __DPLL_A_MAX, + DPLL_A_MAX = (__DPLL_A_MAX - 1) +}; + +enum dpll_a_pin { + DPLL_A_PIN_ID = 1, + DPLL_A_PIN_PARENT_ID, + DPLL_A_PIN_MODULE_NAME, + DPLL_A_PIN_PAD, + DPLL_A_PIN_CLOCK_ID, + DPLL_A_PIN_BOARD_LABEL, + DPLL_A_PIN_PANEL_LABEL, + DPLL_A_PIN_PACKAGE_LABEL, + DPLL_A_PIN_TYPE, + DPLL_A_PIN_DIRECTION, + DPLL_A_PIN_FREQUENCY, + DPLL_A_PIN_FREQUENCY_SUPPORTED, + DPLL_A_PIN_FREQUENCY_MIN, + DPLL_A_PIN_FREQUENCY_MAX, + DPLL_A_PIN_PRIO, + DPLL_A_PIN_STATE, + DPLL_A_PIN_CAPABILITIES, + DPLL_A_PIN_PARENT_DEVICE, + DPLL_A_PIN_PARENT_PIN, + + __DPLL_A_PIN_MAX, + DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) +}; + +enum dpll_cmd { + DPLL_CMD_DEVICE_ID_GET = 1, + DPLL_CMD_DEVICE_GET, + DPLL_CMD_DEVICE_SET, + DPLL_CMD_DEVICE_CREATE_NTF, + DPLL_CMD_DEVICE_DELETE_NTF, + DPLL_CMD_DEVICE_CHANGE_NTF, + DPLL_CMD_PIN_ID_GET, + DPLL_CMD_PIN_GET, + DPLL_CMD_PIN_SET, + DPLL_CMD_PIN_CREATE_NTF, + DPLL_CMD_PIN_DELETE_NTF, + DPLL_CMD_PIN_CHANGE_NTF, + + __DPLL_CMD_MAX, + DPLL_CMD_MAX = (__DPLL_CMD_MAX - 1) +}; + +#define DPLL_MCGRP_MONITOR "monitor" + +#endif /* _UAPI_LINUX_DPLL_H */ -- cgit v1.2.3 From 6fb8c20a04be234cf1cfd4bdd8cfb8860c9d2d3b Mon Sep 17 00:00:00 2001 From: Rohan G Thomas Date: Sat, 16 Sep 2023 14:33:11 +0800 Subject: dt-bindings: net: snps,dwmac: Tx coe unsupported Add dt-bindings for coe-unsupported property per tx queue. Some DWMAC IPs support tx checksum offloading(coe) only for a few tx queues. DW xGMAC IP can be synthesized such that it can support tx coe only for a few initial tx queues. Also as Serge pointed out, for the DW QoS IP tx coe can be individually configured for each tx queue. This property is added to have sw fallback for checksum calculation if a tx queue doesn't support tx coe. Signed-off-by: Rohan G Thomas Acked-by: Conor Dooley Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/snps,dwmac.yaml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index ddf9522a5dc2..5c2769dc689a 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -394,6 +394,11 @@ properties: When a PFC frame is received with priorities matching the bitmask, the queue is blocked from transmitting for the pause time specified in the PFC frame. + + snps,coe-unsupported: + type: boolean + description: TX checksum offload is unsupported by the TX queue. + allOf: - if: required: -- cgit v1.2.3 From 4518b25c63d4e47566be87b06ce4fb880b6d1186 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 18 Sep 2023 12:29:03 +0200 Subject: dt-bindings: soc: mediatek: mt7986-wo-ccif: add binding for MT7988 SoC Introduce MT7988 SoC compatibility string in mt7986-wo-ccif binding. Acked-by: Rob Herring Signed-off-by: Lorenzo Bianconi Signed-off-by: Paolo Abeni --- .../devicetree/bindings/soc/mediatek/mediatek,mt7986-wo-ccif.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt7986-wo-ccif.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt7986-wo-ccif.yaml index f0fa92b04b32..3b212f26abc5 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt7986-wo-ccif.yaml +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt7986-wo-ccif.yaml @@ -20,6 +20,7 @@ properties: items: - enum: - mediatek,mt7986-wo-ccif + - mediatek,mt7988-wo-ccif - const: syscon reg: -- cgit v1.2.3 From f881f27324483b59a47e34d58774d9bcc761626f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 18 Sep 2023 12:29:04 +0200 Subject: dt-bindings: arm: mediatek: mt7622-wed: add WED binding for MT7988 SoC Introduce MT7988 SoC compatibility string in mtk_wed binding. Acked-by: Rob Herring Signed-off-by: Lorenzo Bianconi Signed-off-by: Paolo Abeni --- Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-wed.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-wed.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-wed.yaml index 28ded09d72e3..e7720caf31b3 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-wed.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt7622-wed.yaml @@ -22,6 +22,7 @@ properties: - mediatek,mt7622-wed - mediatek,mt7981-wed - mediatek,mt7986-wed + - mediatek,mt7988-wed - const: syscon reg: -- cgit v1.2.3 From ac0691c75ab78cd240630c184ffbf09433de2d2e Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 19 Sep 2023 16:25:37 +0800 Subject: bpf, docs: Add loongarch64 as arch supporting BPF JIT As BPF JIT support for loongarch64 was added about one year ago with commit 5dc615520c4d ("LoongArch: Add BPF JIT support"), it is appropriate to add loongarch64 as arch supporting BPF JIT in bpf and sysctl docs as well. Signed-off-by: Tiezhu Yang Link: https://lore.kernel.org/r/1695111937-19697-1-git-send-email-yangtiezhu@loongson.cn Signed-off-by: Martin KaFai Lau --- Documentation/admin-guide/sysctl/net.rst | 1 + Documentation/networking/filter.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index 4877563241f3..c7525942f12c 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -71,6 +71,7 @@ two flavors of JITs, the newer eBPF JIT currently supported on: - s390x - riscv64 - riscv32 + - loongarch64 And the older cBPF JIT supported on the following archs: diff --git a/Documentation/networking/filter.rst b/Documentation/networking/filter.rst index f69da5074860..7d8c5380492f 100644 --- a/Documentation/networking/filter.rst +++ b/Documentation/networking/filter.rst @@ -650,8 +650,8 @@ before a conversion to the new layout is being done behind the scenes! Currently, the classic BPF format is being used for JITing on most 32-bit architectures, whereas x86-64, aarch64, s390x, powerpc64, -sparc64, arm32, riscv64, riscv32 perform JIT compilation from eBPF -instruction set. +sparc64, arm32, riscv64, riscv32, loongarch64 perform JIT compilation +from eBPF instruction set. Testing ------- -- cgit v1.2.3 From 7c7dd1d64910d07ab36b858d53d00e89b6d918d6 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Wed, 20 Sep 2023 20:56:58 +0800 Subject: pktgen: Introducing 'SHARED' flag for testing with non-shared skb Currently, skbs generated by pktgen always have their reference count incremented before transmission, causing their reference count to be always greater than 1, leading to two issues: 1. Only the code paths for shared skbs can be tested. 2. In certain situations, skbs can only be released by pktgen. To enhance testing comprehensiveness, we are introducing the "SHARED" flag to indicate whether an SKB is shared. This flag is enabled by default, aligning with the current behavior. However, disabling this flag allows skbs with a reference count of 1 to be transmitted. So we can test non-shared skbs and code paths where skbs are released within the stack. Signed-off-by: Liang Chen Reviewed-by: Benjamin Poirier Link: https://lore.kernel.org/r/20230920125658.46978-2-liangchen.linux@gmail.com Signed-off-by: Paolo Abeni --- Documentation/networking/pktgen.rst | 12 +++++++ net/core/pktgen.c | 64 +++++++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/pktgen.rst b/Documentation/networking/pktgen.rst index 1225f0f63ff0..c945218946e1 100644 --- a/Documentation/networking/pktgen.rst +++ b/Documentation/networking/pktgen.rst @@ -178,6 +178,7 @@ Examples:: IPSEC # IPsec encapsulation (needs CONFIG_XFRM) NODE_ALLOC # node specific memory allocation NO_TIMESTAMP # disable timestamping + SHARED # enable shared SKB pgset 'flag ![name]' Clear a flag to determine behaviour. Note that you might need to use single quote in interactive mode, so that your shell wouldn't expand @@ -288,6 +289,16 @@ To avoid breaking existing testbed scripts for using AH type and tunnel mode, you can use "pgset spi SPI_VALUE" to specify which transformation mode to employ. +Disable shared SKB +================== +By default, SKBs sent by pktgen are shared (user count > 1). +To test with non-shared SKBs, remove the "SHARED" flag by simply setting:: + + pg_set "flag !SHARED" + +However, if the "clone_skb" or "burst" parameters are configured, the skb +still needs to be held by pktgen for further access. Hence the skb must be +shared. Current commands and configuration options ========================================== @@ -357,6 +368,7 @@ Current commands and configuration options IPSEC NODE_ALLOC NO_TIMESTAMP + SHARED spi (ipsec) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 48306a101fd9..5e865af82e5b 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -200,6 +200,7 @@ pf(VID_RND) /* Random VLAN ID */ \ pf(SVID_RND) /* Random SVLAN ID */ \ pf(NODE) /* Node memory alloc*/ \ + pf(SHARED) /* Shared SKB */ \ #define pf(flag) flag##_SHIFT, enum pkt_flags { @@ -1198,7 +1199,8 @@ static ssize_t pktgen_if_write(struct file *file, ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) || !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))) return -ENOTSUPP; - if (value > 0 && pkt_dev->n_imix_entries > 0) + if (value > 0 && (pkt_dev->n_imix_entries > 0 || + !(pkt_dev->flags & F_SHARED))) return -EINVAL; i += len; @@ -1257,6 +1259,10 @@ static ssize_t pktgen_if_write(struct file *file, ((pkt_dev->xmit_mode == M_START_XMIT) && (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING))))) return -ENOTSUPP; + + if (value > 1 && !(pkt_dev->flags & F_SHARED)) + return -EINVAL; + pkt_dev->burst = value < 1 ? 1 : value; sprintf(pg_result, "OK: burst=%u", pkt_dev->burst); return count; @@ -1334,10 +1340,19 @@ static ssize_t pktgen_if_write(struct file *file, flag = pktgen_read_flag(f, &disable); if (flag) { - if (disable) + if (disable) { + /* If "clone_skb", or "burst" parameters are + * configured, it means that the skb still + * needs to be referenced by the pktgen, so + * the skb must be shared. + */ + if (flag == F_SHARED && (pkt_dev->clone_skb || + pkt_dev->burst > 1)) + return -EINVAL; pkt_dev->flags &= ~flag; - else + } else { pkt_dev->flags |= flag; + } sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); return count; @@ -3446,12 +3461,24 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) static void pktgen_xmit(struct pktgen_dev *pkt_dev) { - unsigned int burst = READ_ONCE(pkt_dev->burst); + bool skb_shared = !!(READ_ONCE(pkt_dev->flags) & F_SHARED); struct net_device *odev = pkt_dev->odev; struct netdev_queue *txq; + unsigned int burst = 1; struct sk_buff *skb; + int clone_skb = 0; int ret; + /* If 'skb_shared' is false, the read of possible + * new values (if any) for 'burst' and 'clone_skb' will be skipped to + * prevent some concurrent changes from slipping in. And the stabilized + * config will be read in during the next run of pktgen_xmit. + */ + if (skb_shared) { + burst = READ_ONCE(pkt_dev->burst); + clone_skb = READ_ONCE(pkt_dev->clone_skb); + } + /* If device is offline, then don't send */ if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { pktgen_stop_device(pkt_dev); @@ -3468,7 +3495,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) /* If no skb or clone count exhausted then get new one */ if (!pkt_dev->skb || (pkt_dev->last_ok && - ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { + ++pkt_dev->clone_count >= clone_skb)) { /* build a new pkt */ kfree_skb(pkt_dev->skb); @@ -3489,7 +3516,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) { skb = pkt_dev->skb; skb->protocol = eth_type_trans(skb, skb->dev); - refcount_add(burst, &skb->users); + if (skb_shared) + refcount_add(burst, &skb->users); local_bh_disable(); do { ret = netif_receive_skb(skb); @@ -3497,6 +3525,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->errors++; pkt_dev->sofar++; pkt_dev->seq_num++; + if (unlikely(!skb_shared)) { + pkt_dev->skb = NULL; + break; + } if (refcount_read(&skb->users) != burst) { /* skb was queued by rps/rfs or taps, * so cannot reuse this skb @@ -3515,9 +3547,14 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) goto out; /* Skips xmit_mode M_START_XMIT */ } else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) { local_bh_disable(); - refcount_inc(&pkt_dev->skb->users); + if (skb_shared) + refcount_inc(&pkt_dev->skb->users); ret = dev_queue_xmit(pkt_dev->skb); + + if (!skb_shared && dev_xmit_complete(ret)) + pkt_dev->skb = NULL; + switch (ret) { case NET_XMIT_SUCCESS: pkt_dev->sofar++; @@ -3555,11 +3592,15 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->last_ok = 0; goto unlock; } - refcount_add(burst, &pkt_dev->skb->users); + if (skb_shared) + refcount_add(burst, &pkt_dev->skb->users); xmit_more: ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); + if (!skb_shared && dev_xmit_complete(ret)) + pkt_dev->skb = NULL; + switch (ret) { case NETDEV_TX_OK: pkt_dev->last_ok = 1; @@ -3581,7 +3622,8 @@ xmit_more: fallthrough; case NETDEV_TX_BUSY: /* Retry it next time */ - refcount_dec(&(pkt_dev->skb->users)); + if (skb_shared) + refcount_dec(&pkt_dev->skb->users); pkt_dev->last_ok = 0; } if (unlikely(burst)) @@ -3594,7 +3636,8 @@ out: /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { - pktgen_wait_for_skb(pkt_dev); + if (pkt_dev->skb) + pktgen_wait_for_skb(pkt_dev); /* Done with this */ pktgen_stop_device(pkt_dev); @@ -3777,6 +3820,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) pkt_dev->svlan_id = 0xffff; pkt_dev->burst = 1; pkt_dev->node = NUMA_NO_NODE; + pkt_dev->flags = F_SHARED; /* SKB shared by default */ err = pktgen_setup_dev(t->net, pkt_dev, ifname); if (err) -- cgit v1.2.3 From a6b07a51b161ba1ad3d81919955fe77b697f9d48 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 21 Sep 2023 09:07:40 -0400 Subject: handshake: Fix sign of socket file descriptor fields Socket file descriptors are signed integers. Use nla_get/put_s32 for those to avoid implicit signed conversion in the netlink protocol. Signed-off-by: Chuck Lever Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/169530165057.8905.8650469415145814828.stgit@oracle-102.nfsv4bat.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/handshake.yaml | 4 ++-- net/handshake/genl.c | 2 +- net/handshake/netlink.c | 2 +- net/handshake/tlshd.c | 2 +- tools/net/ynl/generated/handshake-user.h | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml index 6d89e30f5fd5..a49b46b80e16 100644 --- a/Documentation/netlink/specs/handshake.yaml +++ b/Documentation/netlink/specs/handshake.yaml @@ -43,7 +43,7 @@ attribute-sets: attributes: - name: sockfd - type: u32 + type: s32 - name: handler-class type: u32 @@ -79,7 +79,7 @@ attribute-sets: type: u32 - name: sockfd - type: u32 + type: s32 - name: remote-auth type: u32 diff --git a/net/handshake/genl.c b/net/handshake/genl.c index 233be5cbfec9..f55d14d7b726 100644 --- a/net/handshake/genl.c +++ b/net/handshake/genl.c @@ -18,7 +18,7 @@ static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HAN /* HANDSHAKE_CMD_DONE - do */ static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_REMOTE_AUTH + 1] = { [HANDSHAKE_A_DONE_STATUS] = { .type = NLA_U32, }, - [HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_U32, }, + [HANDSHAKE_A_DONE_SOCKFD] = { .type = NLA_S32, }, [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .type = NLA_U32, }, }; diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c index d0bc1dd8e65a..64a0046dd611 100644 --- a/net/handshake/netlink.c +++ b/net/handshake/netlink.c @@ -163,7 +163,7 @@ int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info) if (GENL_REQ_ATTR_CHECK(info, HANDSHAKE_A_DONE_SOCKFD)) return -EINVAL; - fd = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_SOCKFD]); + fd = nla_get_s32(info->attrs[HANDSHAKE_A_DONE_SOCKFD]); sock = sockfd_lookup(fd, &err); if (!sock) diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c index bbfb4095ddd6..7ac80201aa1f 100644 --- a/net/handshake/tlshd.c +++ b/net/handshake/tlshd.c @@ -214,7 +214,7 @@ static int tls_handshake_accept(struct handshake_req *req, goto out_cancel; ret = -EMSGSIZE; - ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd); + ret = nla_put_s32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd); if (ret < 0) goto out_cancel; ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type); diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h index 47646bb91cea..f8e481fa9e09 100644 --- a/tools/net/ynl/generated/handshake-user.h +++ b/tools/net/ynl/generated/handshake-user.h @@ -65,7 +65,7 @@ struct handshake_accept_rsp { __u32 peername_len; } _present; - __u32 sockfd; + __s32 sockfd; enum handshake_msg_type message_type; __u32 timeout; enum handshake_auth auth_mode; @@ -104,7 +104,7 @@ struct handshake_done_req { } _present; __u32 status; - __u32 sockfd; + __s32 sockfd; unsigned int n_remote_auth; __u32 *remote_auth; }; @@ -122,7 +122,7 @@ handshake_done_req_set_status(struct handshake_done_req *req, __u32 status) req->status = status; } static inline void -handshake_done_req_set_sockfd(struct handshake_done_req *req, __u32 sockfd) +handshake_done_req_set_sockfd(struct handshake_done_req *req, __s32 sockfd) { req->_present.sockfd = 1; req->sockfd = sockfd; -- cgit v1.2.3 From 160f404495aa9282cac99b518d1b379e31ef1bdd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 21 Sep 2023 09:08:07 -0400 Subject: handshake: Fix sign of key_serial_t fields key_serial_t fields are signed integers. Use nla_get/put_s32 for those to avoid implicit signed conversion in the netlink protocol. Signed-off-by: Chuck Lever Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/169530167716.8905.645746457741372879.stgit@oracle-102.nfsv4bat.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/handshake.yaml | 4 ++-- net/handshake/tlshd.c | 4 ++-- tools/net/ynl/generated/handshake-user.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml index a49b46b80e16..b934cc513e3d 100644 --- a/Documentation/netlink/specs/handshake.yaml +++ b/Documentation/netlink/specs/handshake.yaml @@ -34,10 +34,10 @@ attribute-sets: attributes: - name: cert - type: u32 + type: s32 - name: privkey - type: u32 + type: s32 - name: accept attributes: diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c index 7ac80201aa1f..d697f68c598c 100644 --- a/net/handshake/tlshd.c +++ b/net/handshake/tlshd.c @@ -173,9 +173,9 @@ static int tls_handshake_put_certificate(struct sk_buff *msg, if (!entry_attr) return -EMSGSIZE; - if (nla_put_u32(msg, HANDSHAKE_A_X509_CERT, + if (nla_put_s32(msg, HANDSHAKE_A_X509_CERT, treq->th_certificate) || - nla_put_u32(msg, HANDSHAKE_A_X509_PRIVKEY, + nla_put_s32(msg, HANDSHAKE_A_X509_PRIVKEY, treq->th_privkey)) { nla_nest_cancel(msg, entry_attr); return -EMSGSIZE; diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h index f8e481fa9e09..2b34acc608de 100644 --- a/tools/net/ynl/generated/handshake-user.h +++ b/tools/net/ynl/generated/handshake-user.h @@ -28,8 +28,8 @@ struct handshake_x509 { __u32 privkey:1; } _present; - __u32 cert; - __u32 privkey; + __s32 cert; + __s32 privkey; }; /* ============== HANDSHAKE_CMD_ACCEPT ============== */ -- cgit v1.2.3 From 92425d08a60814b4a2e91626f1e24e4fd5fd5c7e Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Thu, 28 Sep 2023 12:27:07 +0700 Subject: Documentation: dpll: Fix code blocks kernel test robot and Stephen Rothwell report htmldocs warnings: Documentation/driver-api/dpll.rst:427: WARNING: Error in "code-block" directive: maximum 1 argument(s) allowed, 18 supplied. .. code-block:: c ... Documentation/driver-api/dpll.rst:444: WARNING: Error in "code-block" directive: maximum 1 argument(s) allowed, 21 supplied. .. code-block:: c ... Documentation/driver-api/dpll.rst:474: WARNING: Error in "code-block" directive: maximum 1 argument(s) allowed, 12 supplied. .. code-block:: c ... Fix these above by adding missing blank line separator after code-block directive. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202309180456.lOhxy9gS-lkp@intel.com/ Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/linux-next/20230918131521.155e9e63@canb.auug.org.au/ Fixes: dbb291f19393b6 ("dpll: documentation on DPLL subsystem interface") Signed-off-by: Bagas Sanjaya Acked-by: Randy Dunlap Tested-by: Randy Dunlap Reviewed-by: Vadim Fedorenko Link: https://lore.kernel.org/r/20230928052708.44820-2-bagasdotme@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/driver-api/dpll.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst index bb52f1b8c0be..01eb4de86703 100644 --- a/Documentation/driver-api/dpll.rst +++ b/Documentation/driver-api/dpll.rst @@ -425,6 +425,7 @@ The simplest implementation is in the OCP TimeCard driver. The ops structures are defined like this: .. code-block:: c + static const struct dpll_device_ops dpll_ops = { .lock_status_get = ptp_ocp_dpll_lock_status_get, .mode_get = ptp_ocp_dpll_mode_get, @@ -442,6 +443,7 @@ structures are defined like this: The registration part is then looks like this part: .. code-block:: c + clkid = pci_get_dsn(pdev); bp->dpll = dpll_device_get(clkid, 0, THIS_MODULE); if (IS_ERR(bp->dpll)) { @@ -472,6 +474,7 @@ The registration part is then looks like this part: In the error path we have to rewind every allocation in the reverse order: .. code-block:: c + while (i) { --i; dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]); -- cgit v1.2.3 From c8afdc01832943fab030103bd027ce021d26ddcf Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Thu, 28 Sep 2023 12:27:08 +0700 Subject: Documentation: dpll: wrap DPLL_CMD_PIN_GET output in a code block DPLL_CMD_PIN_GET netlink command output for mux-type pins looks ugly with normal paragraph formatting. Format it as a code block instead. Signed-off-by: Bagas Sanjaya Acked-by: Randy Dunlap Tested-by: Randy Dunlap Reviewed-by: Vadim Fedorenko Link: https://lore.kernel.org/r/20230928052708.44820-3-bagasdotme@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/driver-api/dpll.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst index 01eb4de86703..69670deb8c4e 100644 --- a/Documentation/driver-api/dpll.rst +++ b/Documentation/driver-api/dpll.rst @@ -119,19 +119,19 @@ with. If a pin was registered with multiple parent pins, they behave like a multiple output multiplexer. In this case output of a ``DPLL_CMD_PIN_GET`` would contain multiple pin-parent nested -attributes with current state related to each parent, like: - -'pin': [{{ - 'clock-id': 282574471561216, - 'module-name': 'ice', - 'capabilities': 4, - 'id': 13, - 'parent-pin': [ - {'parent-id': 2, 'state': 'connected'}, - {'parent-id': 3, 'state': 'disconnected'} - ], - 'type': 'synce-eth-port' - }}] +attributes with current state related to each parent, like:: + + 'pin': [{{ + 'clock-id': 282574471561216, + 'module-name': 'ice', + 'capabilities': 4, + 'id': 13, + 'parent-pin': [ + {'parent-id': 2, 'state': 'connected'}, + {'parent-id': 3, 'state': 'disconnected'} + ], + 'type': 'synce-eth-port' + }}] Only one child pin can provide its signal to the parent MUX-type pin at a time, the selection is done by requesting change of a child pin state -- cgit v1.2.3 From 473267a4911f2469722c74ca58087d951072f72a Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 25 Sep 2023 14:47:11 -0700 Subject: net: add sysctl to disable rfc4862 5.5.3e lifetime handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds a sysctl to opt-out of RFC4862 section 5.5.3e's valid lifetime derivation mechanism. RFC4862 section 5.5.3e prescribes that the valid lifetime in a Router Advertisement PIO shall be ignored if it less than 2 hours and to reset the lifetime of the corresponding address to 2 hours. An in-progress 6man draft (see draft-ietf-6man-slaac-renum-07 section 4.2) is currently looking to remove this mechanism. While this draft has not been moving particularly quickly for other reasons, there is widespread consensus on section 4.2 which updates RFC4862 section 5.5.3e. Cc: Maciej Żenczykowski Cc: Lorenzo Colitti Cc: Jen Linkova Signed-off-by: Patrick Rohr Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230925214711.959704-1-prohr@google.com Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 11 ++++++++++ include/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 38 ++++++++++++++++++++++------------ 3 files changed, 37 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 5bfa1837968c..f7dfde3b09a9 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2311,6 +2311,17 @@ accept_ra_pinfo - BOOLEAN - enabled if accept_ra is enabled. - disabled if accept_ra is disabled. +ra_honor_pio_life - BOOLEAN + Whether to use RFC4862 Section 5.5.3e to determine the valid + lifetime of an address matching a prefix sent in a Router + Advertisement Prefix Information Option. + + - If enabled, the PIO valid lifetime will always be honored. + - If disabled, RFC4862 section 5.5.3e is used to determine + the valid lifetime of the address. + + Default: 0 (disabled) + accept_ra_rt_info_min_plen - INTEGER Minimum prefix length of Route Information in RA. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index e400ff757f13..5e605e384aac 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -82,6 +82,7 @@ struct ipv6_devconf { __u32 ioam6_id_wide; __u8 ioam6_enabled; __u8 ndisc_evict_nocarrier; + __u8 ra_honor_pio_life; struct ctl_table_header *sysctl_header; }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0b6ee962c84e..c2d471ad7922 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .ioam6_id = IOAM6_DEFAULT_IF_ID, .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE, .ndisc_evict_nocarrier = 1, + .ra_honor_pio_life = 0, }; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { @@ -297,6 +298,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .ioam6_id = IOAM6_DEFAULT_IF_ID, .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE, .ndisc_evict_nocarrier = 1, + .ra_honor_pio_life = 0, }; /* Check if link is ready: is it up and is a valid qdisc available */ @@ -2657,22 +2659,23 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; else stored_lft = 0; - if (!create && stored_lft) { + + /* RFC4862 Section 5.5.3e: + * "Note that the preferred lifetime of the + * corresponding address is always reset to + * the Preferred Lifetime in the received + * Prefix Information option, regardless of + * whether the valid lifetime is also reset or + * ignored." + * + * So we should always update prefered_lft here. + */ + update_lft = !create && stored_lft; + + if (update_lft && !in6_dev->cnf.ra_honor_pio_life) { const u32 minimum_lft = min_t(u32, stored_lft, MIN_VALID_LIFETIME); valid_lft = max(valid_lft, minimum_lft); - - /* RFC4862 Section 5.5.3e: - * "Note that the preferred lifetime of the - * corresponding address is always reset to - * the Preferred Lifetime in the received - * Prefix Information option, regardless of - * whether the valid lifetime is also reset or - * ignored." - * - * So we should always update prefered_lft here. - */ - update_lft = 1; } if (update_lft) { @@ -6846,6 +6849,15 @@ static const struct ctl_table addrconf_sysctl[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "ra_honor_pio_life", + .data = &ipv6_devconf.ra_honor_pio_life, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, #ifdef CONFIG_IPV6_ROUTER_PREF { .procname = "accept_ra_rtr_pref", -- cgit v1.2.3 From ca6f5c2f94aa40028b3173967d3e5cb3a68aaa74 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 26 Sep 2023 08:10:17 -0300 Subject: dt-bindings: net: fec: Add imx8dxl description The imx8dl FEC has the same programming model as the one on the imx8qxp. Add the imx8dl compatible string. Signed-off-by: Fabio Estevam Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20230926111017.320409-1-festevam@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/fsl,fec.yaml | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/fsl,fec.yaml b/Documentation/devicetree/bindings/net/fsl,fec.yaml index b494e009326e..8948a11c994e 100644 --- a/Documentation/devicetree/bindings/net/fsl,fec.yaml +++ b/Documentation/devicetree/bindings/net/fsl,fec.yaml @@ -59,6 +59,7 @@ properties: - const: fsl,imx6sx-fec - items: - enum: + - fsl,imx8dxl-fec - fsl,imx8qxp-fec - const: fsl,imx8qm-fec - const: fsl,imx6sx-fec -- cgit v1.2.3 From 00f3696f7555d0890ae07b635e6ccbf39fd2eb3a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 27 Sep 2023 11:00:30 +0200 Subject: net: appletalk: remove cops support The COPS Appletalk support is very old, never said to actually work properly, and the firmware code for the devices are under a very suspect license. Remove it all to clear up the license issue, if it is still needed and actually used by anyone, we can add it back later once the license is cleared up. Reported-by: Prarit Bhargava Cc: jschlst@samba.org Signed-off-by: Greg Kroah-Hartman Acked-by: Christoph Hellwig Acked-by: Prarit Bhargava Reviewed-by: Vitaly Kuznetsov Link: https://lore.kernel.org/r/20230927090029.44704-2-gregkh@linuxfoundation.org Signed-off-by: Jakub Kicinski --- .../networking/device_drivers/appletalk/cops.rst | 80 -- .../networking/device_drivers/appletalk/index.rst | 18 - Documentation/networking/device_drivers/index.rst | 1 - drivers/net/Space.c | 6 - drivers/net/appletalk/Kconfig | 30 - drivers/net/appletalk/Makefile | 1 - drivers/net/appletalk/cops.c | 1005 -------------------- drivers/net/appletalk/cops.h | 61 -- drivers/net/appletalk/cops_ffdrv.h | 532 ----------- drivers/net/appletalk/cops_ltdrv.h | 241 ----- include/net/Space.h | 1 - 11 files changed, 1976 deletions(-) delete mode 100644 Documentation/networking/device_drivers/appletalk/cops.rst delete mode 100644 Documentation/networking/device_drivers/appletalk/index.rst delete mode 100644 drivers/net/appletalk/cops.c delete mode 100644 drivers/net/appletalk/cops.h delete mode 100644 drivers/net/appletalk/cops_ffdrv.h delete mode 100644 drivers/net/appletalk/cops_ltdrv.h (limited to 'Documentation') diff --git a/Documentation/networking/device_drivers/appletalk/cops.rst b/Documentation/networking/device_drivers/appletalk/cops.rst deleted file mode 100644 index 964ba80599a9..000000000000 --- a/Documentation/networking/device_drivers/appletalk/cops.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -======================================== -The COPS LocalTalk Linux driver (cops.c) -======================================== - -By Jay Schulist - -This driver has two modes and they are: Dayna mode and Tangent mode. -Each mode corresponds with the type of card. It has been found -that there are 2 main types of cards and all other cards are -the same and just have different names or only have minor differences -such as more IO ports. As this driver is tested it will -become more clear exactly what cards are supported. - -Right now these cards are known to work with the COPS driver. The -LT-200 cards work in a somewhat more limited capacity than the -DL200 cards, which work very well and are in use by many people. - -TANGENT driver mode: - - Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200 - -DAYNA driver mode: - - Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, - - Farallon PhoneNET PC III, Farallon PhoneNET PC II - -Other cards possibly supported mode unknown though: - - Dayna DL2000 (Full length) - -The COPS driver defaults to using Dayna mode. To change the driver's -mode if you built a driver with dual support use board_type=1 or -board_type=2 for Dayna or Tangent with insmod. - -Operation/loading of the driver -=============================== - -Use modprobe like this: /sbin/modprobe cops.o (IO #) (IRQ #) -If you do not specify any options the driver will try and use the IO = 0x240, -IRQ = 5. As of right now I would only use IRQ 5 for the card, if autoprobing. - -To load multiple COPS driver Localtalk cards you can do one of the following:: - - insmod cops io=0x240 irq=5 - insmod -o cops2 cops io=0x260 irq=3 - -Or in lilo.conf put something like this:: - - append="ether=5,0x240,lt0 ether=3,0x260,lt1" - -Then bring up the interface with ifconfig. It will look something like this:: - - lt0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-F7-00-00-00-00-00-00-00-00 - inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0 - UP BROADCAST RUNNING NOARP MULTICAST MTU:600 Metric:1 - RX packets:0 errors:0 dropped:0 overruns:0 frame:0 - TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 coll:0 - -Netatalk Configuration -====================== - -You will need to configure atalkd with something like the following to make -it work with the cops.c driver. - -* For single LTalk card use:: - - dummy -seed -phase 2 -net 2000 -addr 2000.10 -zone "1033" - lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033" - -* For multiple cards, Ethernet and LocalTalk:: - - eth0 -seed -phase 2 -net 3000 -addr 3000.20 -zone "1033" - lt0 -seed -phase 1 -net 1000 -addr 1000.50 -zone "1033" - -* For multiple LocalTalk cards, and an Ethernet card. - -* Order seems to matter here, Ethernet last:: - - lt0 -seed -phase 1 -net 1000 -addr 1000.10 -zone "LocalTalk1" - lt1 -seed -phase 1 -net 2000 -addr 2000.20 -zone "LocalTalk2" - eth0 -seed -phase 2 -net 3000 -addr 3000.30 -zone "EtherTalk" diff --git a/Documentation/networking/device_drivers/appletalk/index.rst b/Documentation/networking/device_drivers/appletalk/index.rst deleted file mode 100644 index c196baeb0856..000000000000 --- a/Documentation/networking/device_drivers/appletalk/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) - -AppleTalk Device Drivers -======================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - cops - -.. only:: subproject and html - - Indices - ======= - - * :ref:`genindex` diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst index 601eacaf12f3..2f0285a5bc80 100644 --- a/Documentation/networking/device_drivers/index.rst +++ b/Documentation/networking/device_drivers/index.rst @@ -8,7 +8,6 @@ Contents: .. toctree:: :maxdepth: 2 - appletalk/index atm/index cable/index can/index diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 83214e2e70ab..dc50797a2ed0 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -247,12 +247,6 @@ static int __init net_olddevs_init(void) for (num = 0; num < 8; ++num) ethif_probe2(num); -#ifdef CONFIG_COPS - cops_probe(0); - cops_probe(1); - cops_probe(2); -#endif - return 0; } diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig index b38ed52b82bc..b94f731e4576 100644 --- a/drivers/net/appletalk/Kconfig +++ b/drivers/net/appletalk/Kconfig @@ -37,36 +37,6 @@ config DEV_APPLETALK on a network. If your Linux box is connected to such a network, and wish to do IP over it, or you have a LocalTalk card and wish to use it to connect to the AppleTalk network, say Y. - - -config COPS - tristate "COPS LocalTalk PC support" - depends on DEV_APPLETALK && ISA - depends on NETDEVICES - select NETDEV_LEGACY_INIT - help - This allows you to use COPS AppleTalk cards to connect to LocalTalk - networks. You also need version 1.3.3 or later of the netatalk - package. This driver is experimental, which means that it may not - work. This driver will only work if you choose "AppleTalk DDP" - networking support, above. - Please read the file - . - -config COPS_DAYNA - bool "Dayna firmware support" - depends on COPS - help - Support COPS compatible cards with Dayna style firmware (Dayna - DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC - III, Farallon PhoneNET PC II). - -config COPS_TANGENT - bool "Tangent firmware support" - depends on COPS - help - Support COPS compatible cards with Tangent style firmware (Tangent - ATB_II, Novell NL-1000, Daystar Digital LT-200. config IPDDP tristate "Appletalk-IP driver support" diff --git a/drivers/net/appletalk/Makefile b/drivers/net/appletalk/Makefile index 6db2943ce5d6..d8c7b23ec7ff 100644 --- a/drivers/net/appletalk/Makefile +++ b/drivers/net/appletalk/Makefile @@ -4,4 +4,3 @@ # obj-$(CONFIG_IPDDP) += ipddp.o -obj-$(CONFIG_COPS) += cops.o diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c deleted file mode 100644 index 97f254bdbb16..000000000000 --- a/drivers/net/appletalk/cops.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* cops.c: LocalTalk driver for Linux. - * - * Authors: - * - Jay Schulist - * - * With more than a little help from; - * - Alan Cox - * - * Derived from: - * - skeleton.c: A network driver outline for linux. - * Written 1993-94 by Donald Becker. - * - ltpc.c: A driver for the LocalTalk PC card. - * Written by Bradford W. Johnson. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Changes: - * 19970608 Alan Cox Allowed dual card type support - * Can set board type in insmod - * Hooks for cops_setup routine - * (not yet implemented). - * 19971101 Jay Schulist Fixes for multiple lt* devices. - * 19980607 Steven Hirsch Fixed the badly broken support - * for Tangent type cards. Only - * tested on Daystar LT200. Some - * cleanup of formatting and program - * logic. Added emacs 'local-vars' - * setup for Jay's brace style. - * 20000211 Alan Cox Cleaned up for softnet - */ - -static const char *version = -"cops.c:v0.04 6/7/98 Jay Schulist \n"; -/* - * Sources: - * COPS Localtalk SDK. This provides almost all of the information - * needed. - */ - -/* - * insmod/modprobe configurable stuff. - * - IO Port, choose one your card supports or 0 if you dare. - * - IRQ, also choose one your card supports or nothing and let - * the driver figure it out. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For udelay() */ -#include -#include -#include -#include - -#include - -#include -#include - -#include "cops.h" /* Our Stuff */ -#include "cops_ltdrv.h" /* Firmware code for Tangent type cards. */ -#include "cops_ffdrv.h" /* Firmware code for Dayna type cards. */ - -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ - -static const char *cardname = "cops"; - -#ifdef CONFIG_COPS_DAYNA -static int board_type = DAYNA; /* Module exported */ -#else -static int board_type = TANGENT; -#endif - -static int io = 0x240; /* Default IO for Dayna */ -static int irq = 5; /* Default IRQ */ - -/* - * COPS Autoprobe information. - * Right now if port address is right but IRQ is not 5 this will - * return a 5 no matter what since we will still get a status response. - * Need one more additional check to narrow down after we have gotten - * the ioaddr. But since only other possible IRQs is 3 and 4 so no real - * hurry on this. I *STRONGLY* recommend using IRQ 5 for your card with - * this driver. - * - * This driver has 2 modes and they are: Dayna mode and Tangent mode. - * Each mode corresponds with the type of card. It has been found - * that there are 2 main types of cards and all other cards are - * the same and just have different names or only have minor differences - * such as more IO ports. As this driver is tested it will - * become more clear on exactly what cards are supported. The driver - * defaults to using Dayna mode. To change the drivers mode, simply - * select Dayna or Tangent mode when configuring the kernel. - * - * This driver should support: - * TANGENT driver mode: - * Tangent ATB-II, Novell NL-1000, Daystar Digital LT-200, - * COPS LT-1 - * DAYNA driver mode: - * Dayna DL2000/DaynaTalk PC (Half Length), COPS LT-95, - * Farallon PhoneNET PC III, Farallon PhoneNET PC II - * Other cards possibly supported mode unknown though: - * Dayna DL2000 (Full length), COPS LT/M (Micro-Channel) - * - * Cards NOT supported by this driver but supported by the ltpc.c - * driver written by Bradford W. Johnson - * Farallon PhoneNET PC - * Original Apple LocalTalk PC card - * - * N.B. - * - * The Daystar Digital LT200 boards do not support interrupt-driven - * IO. You must specify 'irq=0xff' as a module parameter to invoke - * polled mode. I also believe that the port probing logic is quite - * dangerous at best and certainly hopeless for a polled card. Best to - * specify both. - Steve H. - * - */ - -/* - * Zero terminated list of IO ports to probe. - */ - -static unsigned int ports[] = { - 0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, - 0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360, - 0 -}; - -/* - * Zero terminated list of IRQ ports to probe. - */ - -static int cops_irqlist[] = { - 5, 4, 3, 0 -}; - -static struct timer_list cops_timer; -static struct net_device *cops_timer_dev; - -/* use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */ -#ifndef COPS_DEBUG -#define COPS_DEBUG 1 -#endif -static unsigned int cops_debug = COPS_DEBUG; - -/* The number of low I/O ports used by the card. */ -#define COPS_IO_EXTENT 8 - -/* Information that needs to be kept for each board. */ - -struct cops_local -{ - int board; /* Holds what board type is. */ - int nodeid; /* Set to 1 once have nodeid. */ - unsigned char node_acquire; /* Node ID when acquired. */ - struct atalk_addr node_addr; /* Full node address */ - spinlock_t lock; /* RX/TX lock */ -}; - -/* Index to functions, as function prototypes. */ -static int cops_probe1 (struct net_device *dev, int ioaddr); -static int cops_irq (int ioaddr, int board); - -static int cops_open (struct net_device *dev); -static int cops_jumpstart (struct net_device *dev); -static void cops_reset (struct net_device *dev, int sleep); -static void cops_load (struct net_device *dev); -static int cops_nodeid (struct net_device *dev, int nodeid); - -static irqreturn_t cops_interrupt (int irq, void *dev_id); -static void cops_poll(struct timer_list *t); -static void cops_timeout(struct net_device *dev, unsigned int txqueue); -static void cops_rx (struct net_device *dev); -static netdev_tx_t cops_send_packet (struct sk_buff *skb, - struct net_device *dev); -static void set_multicast_list (struct net_device *dev); -static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); -static int cops_close (struct net_device *dev); - -static void cleanup_card(struct net_device *dev) -{ - if (dev->irq) - free_irq(dev->irq, dev); - release_region(dev->base_addr, COPS_IO_EXTENT); -} - -/* - * Check for a network adaptor of this type, and return '0' iff one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr in [1..0x1ff], always return failure. - * otherwise go with what we pass in. - */ -struct net_device * __init cops_probe(int unit) -{ - struct net_device *dev; - unsigned *port; - int base_addr; - int err = 0; - - dev = alloc_ltalkdev(sizeof(struct cops_local)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "lt%d", unit); - netdev_boot_setup_check(dev); - irq = dev->irq; - base_addr = dev->base_addr; - } else { - base_addr = dev->base_addr = io; - } - - if (base_addr > 0x1ff) { /* Check a single specified location. */ - err = cops_probe1(dev, base_addr); - } else if (base_addr != 0) { /* Don't probe at all. */ - err = -ENXIO; - } else { - /* FIXME Does this really work for cards which generate irq? - * It's definitely N.G. for polled Tangent. sh - * Dayna cards don't autoprobe well at all, but if your card is - * at IRQ 5 & IO 0x240 we find it every time. ;) JS - */ - for (port = ports; *port && cops_probe1(dev, *port) < 0; port++) - ; - if (!*port) - err = -ENODEV; - } - if (err) - goto out; - err = register_netdev(dev); - if (err) - goto out1; - return dev; -out1: - cleanup_card(dev); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -static const struct net_device_ops cops_netdev_ops = { - .ndo_open = cops_open, - .ndo_stop = cops_close, - .ndo_start_xmit = cops_send_packet, - .ndo_tx_timeout = cops_timeout, - .ndo_do_ioctl = cops_ioctl, - .ndo_set_rx_mode = set_multicast_list, -}; - -/* - * This is the real probe routine. Linux has a history of friendly device - * probes on the ISA bus. A good device probes avoids doing writes, and - * verifies that the correct device exists and functions. - */ -static int __init cops_probe1(struct net_device *dev, int ioaddr) -{ - struct cops_local *lp; - static unsigned version_printed; - int board = board_type; - int retval; - - if(cops_debug && version_printed++ == 0) - printk("%s", version); - - /* Grab the region so no one else tries to probe our ioports. */ - if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name)) - return -EBUSY; - - /* - * Since this board has jumpered interrupts, allocate the interrupt - * vector now. There is no point in waiting since no other device - * can use the interrupt, and this marks the irq as busy. Jumpered - * interrupts are typically not reported by the boards, and we must - * used AutoIRQ to find them. - */ - dev->irq = irq; - switch (dev->irq) - { - case 0: - /* COPS AutoIRQ routine */ - dev->irq = cops_irq(ioaddr, board); - if (dev->irq) - break; - fallthrough; /* Once no IRQ found on this port */ - case 1: - retval = -EINVAL; - goto err_out; - - /* Fixup for users that don't know that IRQ 2 is really - * IRQ 9, or don't know which one to set. - */ - case 2: - dev->irq = 9; - break; - - /* Polled operation requested. Although irq of zero passed as - * a parameter tells the init routines to probe, we'll - * overload it to denote polled operation at runtime. - */ - case 0xff: - dev->irq = 0; - break; - - default: - break; - } - - dev->base_addr = ioaddr; - - /* Reserve any actual interrupt. */ - if (dev->irq) { - retval = request_irq(dev->irq, cops_interrupt, 0, dev->name, dev); - if (retval) - goto err_out; - } - - lp = netdev_priv(dev); - spin_lock_init(&lp->lock); - - /* Copy local board variable to lp struct. */ - lp->board = board; - - dev->netdev_ops = &cops_netdev_ops; - dev->watchdog_timeo = HZ * 2; - - - /* Tell the user where the card is and what mode we're in. */ - if(board==DAYNA) - printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", - dev->name, cardname, ioaddr, dev->irq); - if(board==TANGENT) { - if(dev->irq) - printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", - dev->name, cardname, ioaddr, dev->irq); - else - printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", - dev->name, cardname, ioaddr); - - } - return 0; - -err_out: - release_region(ioaddr, COPS_IO_EXTENT); - return retval; -} - -static int __init cops_irq (int ioaddr, int board) -{ /* - * This does not use the IRQ to determine where the IRQ is. We just - * assume that when we get a correct status response that it's the IRQ. - * This really just verifies the IO port but since we only have access - * to such a small number of IRQs (5, 4, 3) this is not bad. - * This will probably not work for more than one card. - */ - int irqaddr=0; - int i, x, status; - - if(board==DAYNA) - { - outb(0, ioaddr+DAYNA_RESET); - inb(ioaddr+DAYNA_RESET); - mdelay(333); - } - if(board==TANGENT) - { - inb(ioaddr); - outb(0, ioaddr); - outb(0, ioaddr+TANG_RESET); - } - - for(i=0; cops_irqlist[i] !=0; i++) - { - irqaddr = cops_irqlist[i]; - for(x = 0xFFFF; x>0; x --) /* wait for response */ - { - if(board==DAYNA) - { - status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); - if(status == 1) - return irqaddr; - } - if(board==TANGENT) - { - if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0) - return irqaddr; - } - } - } - return 0; /* no IRQ found */ -} - -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - */ -static int cops_open(struct net_device *dev) -{ - struct cops_local *lp = netdev_priv(dev); - - if(dev->irq==0) - { - /* - * I don't know if the Dayna-style boards support polled - * operation. For now, only allow it for Tangent. - */ - if(lp->board==TANGENT) /* Poll 20 times per second */ - { - cops_timer_dev = dev; - timer_setup(&cops_timer, cops_poll, 0); - cops_timer.expires = jiffies + HZ/20; - add_timer(&cops_timer); - } - else - { - printk(KERN_WARNING "%s: No irq line set\n", dev->name); - return -EAGAIN; - } - } - - cops_jumpstart(dev); /* Start the card up. */ - - netif_start_queue(dev); - return 0; -} - -/* - * This allows for a dynamic start/restart of the entire card. - */ -static int cops_jumpstart(struct net_device *dev) -{ - struct cops_local *lp = netdev_priv(dev); - - /* - * Once the card has the firmware loaded and has acquired - * the nodeid, if it is reset it will lose it all. - */ - cops_reset(dev,1); /* Need to reset card before load firmware. */ - cops_load(dev); /* Load the firmware. */ - - /* - * If atalkd already gave us a nodeid we will use that - * one again, else we wait for atalkd to give us a nodeid - * in cops_ioctl. This may cause a problem if someone steals - * our nodeid while we are resetting. - */ - if(lp->nodeid == 1) - cops_nodeid(dev,lp->node_acquire); - - return 0; -} - -static void tangent_wait_reset(int ioaddr) -{ - int timeout=0; - - while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) - mdelay(1); /* Wait 1 second */ -} - -/* - * Reset the LocalTalk board. - */ -static void cops_reset(struct net_device *dev, int sleep) -{ - struct cops_local *lp = netdev_priv(dev); - int ioaddr=dev->base_addr; - - if(lp->board==TANGENT) - { - inb(ioaddr); /* Clear request latch. */ - outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */ - outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */ - - tangent_wait_reset(ioaddr); - outb(0, ioaddr+TANG_CLEAR_INT); - } - if(lp->board==DAYNA) - { - outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */ - inb(ioaddr+DAYNA_RESET); /* Clear the reset */ - if (sleep) - msleep(333); - else - mdelay(333); - } - - netif_wake_queue(dev); -} - -static void cops_load (struct net_device *dev) -{ - struct ifreq ifr; - struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru; - struct cops_local *lp = netdev_priv(dev); - int ioaddr=dev->base_addr; - int length, i = 0; - - strcpy(ifr.ifr_name,"lt0"); - - /* Get card's firmware code and do some checks on it. */ -#ifdef CONFIG_COPS_DAYNA - if(lp->board==DAYNA) - { - ltf->length=sizeof(ffdrv_code); - ltf->data=ffdrv_code; - } - else -#endif -#ifdef CONFIG_COPS_TANGENT - if(lp->board==TANGENT) - { - ltf->length=sizeof(ltdrv_code); - ltf->data=ltdrv_code; - } - else -#endif - { - printk(KERN_INFO "%s; unsupported board type.\n", dev->name); - return; - } - - /* Check to make sure firmware is correct length. */ - if(lp->board==DAYNA && ltf->length!=5983) - { - printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name); - return; - } - if(lp->board==TANGENT && ltf->length!=2501) - { - printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name); - return; - } - - if(lp->board==DAYNA) - { - /* - * We must wait for a status response - * with the DAYNA board. - */ - while(++i<65536) - { - if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1) - break; - } - - if(i==65536) - return; - } - - /* - * Upload the firmware and kick. Byte-by-byte works nicely here. - */ - i=0; - length = ltf->length; - while(length--) - { - outb(ltf->data[i], ioaddr); - i++; - } - - if(cops_debug > 1) - printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", - dev->name, i, ltf->length); - - if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */ - outb(1, ioaddr+DAYNA_INT_CARD); - else /* Tell Tang to run the firmware code. */ - inb(ioaddr); - - if(lp->board==TANGENT) - { - tangent_wait_reset(ioaddr); - inb(ioaddr); /* Clear initial ready signal. */ - } -} - -/* - * Get the LocalTalk Nodeid from the card. We can suggest - * any nodeid 1-254. The card will try and get that exact - * address else we can specify 0 as the nodeid and the card - * will autoprobe for a nodeid. - */ -static int cops_nodeid (struct net_device *dev, int nodeid) -{ - struct cops_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - if(lp->board == DAYNA) - { - /* Empty any pending adapter responses. */ - while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) - { - outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */ - if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) - cops_rx(dev); /* Kick any packets waiting. */ - schedule(); - } - - outb(2, ioaddr); /* Output command packet length as 2. */ - outb(0, ioaddr); - outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */ - outb(nodeid, ioaddr); /* Suggest node address. */ - } - - if(lp->board == TANGENT) - { - /* Empty any pending adapter responses. */ - while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) - { - outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */ - cops_rx(dev); /* Kick out packets waiting. */ - schedule(); - } - - /* Not sure what Tangent does if nodeid picked is used. */ - if(nodeid == 0) /* Seed. */ - nodeid = jiffies&0xFF; /* Get a random try */ - outb(2, ioaddr); /* Command length LSB */ - outb(0, ioaddr); /* Command length MSB */ - outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */ - outb(nodeid, ioaddr); /* LAP address hint. */ - outb(0xFF, ioaddr); /* Int. level to use */ - } - - lp->node_acquire=0; /* Set nodeid holder to 0. */ - while(lp->node_acquire==0) /* Get *True* nodeid finally. */ - { - outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */ - - if(lp->board == DAYNA) - { - if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) - cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ - } - if(lp->board == TANGENT) - { - if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) - cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ - } - schedule(); - } - - if(cops_debug > 1) - printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", - dev->name, lp->node_acquire); - - lp->nodeid=1; /* Set got nodeid to 1. */ - - return 0; -} - -/* - * Poll the Tangent type cards to see if we have work. - */ - -static void cops_poll(struct timer_list *unused) -{ - int ioaddr, status; - int boguscount = 0; - struct net_device *dev = cops_timer_dev; - - del_timer(&cops_timer); - - if(dev == NULL) - return; /* We've been downed */ - - ioaddr = dev->base_addr; - do { - status=inb(ioaddr+TANG_CARD_STATUS); - if(status & TANG_RX_READY) - cops_rx(dev); - if(status & TANG_TX_READY) - netif_wake_queue(dev); - status = inb(ioaddr+TANG_CARD_STATUS); - } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); - - /* poll 20 times per second */ - cops_timer.expires = jiffies + HZ/20; - add_timer(&cops_timer); -} - -/* - * The typical workload of the driver: - * Handle the network interface interrupts. - */ -static irqreturn_t cops_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct cops_local *lp; - int ioaddr, status; - int boguscount = 0; - - ioaddr = dev->base_addr; - lp = netdev_priv(dev); - - if(lp->board==DAYNA) - { - do { - outb(0, ioaddr + COPS_CLEAR_INT); - status=inb(ioaddr+DAYNA_CARD_STATUS); - if((status&0x03)==DAYNA_RX_REQUEST) - cops_rx(dev); - netif_wake_queue(dev); - } while(++boguscount < 20); - } - else - { - do { - status=inb(ioaddr+TANG_CARD_STATUS); - if(status & TANG_RX_READY) - cops_rx(dev); - if(status & TANG_TX_READY) - netif_wake_queue(dev); - status=inb(ioaddr+TANG_CARD_STATUS); - } while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY))); - } - - return IRQ_HANDLED; -} - -/* - * We have a good packet(s), get it/them out of the buffers. - */ -static void cops_rx(struct net_device *dev) -{ - int pkt_len = 0; - int rsp_type = 0; - struct sk_buff *skb = NULL; - struct cops_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int boguscount = 0; - unsigned long flags; - - - spin_lock_irqsave(&lp->lock, flags); - - if(lp->board==DAYNA) - { - outb(0, ioaddr); /* Send out Zero length. */ - outb(0, ioaddr); - outb(DATA_READ, ioaddr); /* Send read command out. */ - - /* Wait for DMA to turn around. */ - while(++boguscount<1000000) - { - barrier(); - if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) - break; - } - - if(boguscount==1000000) - { - printk(KERN_WARNING "%s: DMA timed out.\n",dev->name); - spin_unlock_irqrestore(&lp->lock, flags); - return; - } - } - - /* Get response length. */ - pkt_len = inb(ioaddr); - pkt_len |= (inb(ioaddr) << 8); - /* Input IO code. */ - rsp_type=inb(ioaddr); - - /* Malloc up new buffer. */ - skb = dev_alloc_skb(pkt_len); - if(skb == NULL) - { - printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", - dev->name); - dev->stats.rx_dropped++; - while(pkt_len--) /* Discard packet */ - inb(ioaddr); - spin_unlock_irqrestore(&lp->lock, flags); - return; - } - skb->dev = dev; - skb_put(skb, pkt_len); - skb->protocol = htons(ETH_P_LOCALTALK); - - insb(ioaddr, skb->data, pkt_len); /* Eat the Data */ - - if(lp->board==DAYNA) - outb(1, ioaddr+DAYNA_INT_CARD); /* Interrupt the card */ - - spin_unlock_irqrestore(&lp->lock, flags); /* Restore interrupts. */ - - /* Check for bad response length */ - if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE) - { - printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", - dev->name, pkt_len); - dev->stats.tx_errors++; - dev_kfree_skb_any(skb); - return; - } - - /* Set nodeid and then get out. */ - if(rsp_type == LAP_INIT_RSP) - { /* Nodeid taken from received packet. */ - lp->node_acquire = skb->data[0]; - dev_kfree_skb_any(skb); - return; - } - - /* One last check to make sure we have a good packet. */ - if(rsp_type != LAP_RESPONSE) - { - printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); - dev->stats.tx_errors++; - dev_kfree_skb_any(skb); - return; - } - - skb_reset_mac_header(skb); /* Point to entire packet. */ - skb_pull(skb,3); - skb_reset_transport_header(skb); /* Point to data (Skip header). */ - - /* Update the counters. */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - /* Send packet to a higher place. */ - netif_rx(skb); -} - -static void cops_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct cops_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - dev->stats.tx_errors++; - if(lp->board==TANGENT) - { - if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) - printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name); - } - printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name); - cops_jumpstart(dev); /* Restart the card. */ - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); -} - - -/* - * Make the card transmit a LocalTalk packet. - */ - -static netdev_tx_t cops_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct cops_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - unsigned long flags; - - /* - * Block a timer-based transmit from overlapping. - */ - - netif_stop_queue(dev); - - spin_lock_irqsave(&lp->lock, flags); - if(lp->board == DAYNA) /* Wait for adapter transmit buffer. */ - while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) - cpu_relax(); - if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */ - while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) - cpu_relax(); - - /* Output IO length. */ - outb(skb->len, ioaddr); - outb(skb->len >> 8, ioaddr); - - /* Output IO code. */ - outb(LAP_WRITE, ioaddr); - - if(lp->board == DAYNA) /* Check the transmit buffer again. */ - while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0); - - outsb(ioaddr, skb->data, skb->len); /* Send out the data. */ - - if(lp->board==DAYNA) /* Dayna requires you kick the card */ - outb(1, ioaddr+DAYNA_INT_CARD); - - spin_unlock_irqrestore(&lp->lock, flags); /* Restore interrupts. */ - - /* Done sending packet, update counters and cleanup. */ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb (skb); - return NETDEV_TX_OK; -} - -/* - * Dummy function to keep the Appletalk layer happy. - */ - -static void set_multicast_list(struct net_device *dev) -{ - if(cops_debug >= 3) - printk("%s: set_multicast_list executed\n", dev->name); -} - -/* - * System ioctls for the COPS LocalTalk card. - */ - -static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct cops_local *lp = netdev_priv(dev); - struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr; - struct atalk_addr *aa = &lp->node_addr; - - switch(cmd) - { - case SIOCSIFADDR: - /* Get and set the nodeid and network # atalkd wants. */ - cops_nodeid(dev, sa->sat_addr.s_node); - aa->s_net = sa->sat_addr.s_net; - aa->s_node = lp->node_acquire; - - /* Set broardcast address. */ - dev->broadcast[0] = 0xFF; - - /* Set hardware address. */ - dev->addr_len = 1; - dev_addr_set(dev, &aa->s_node); - return 0; - - case SIOCGIFADDR: - sa->sat_addr.s_net = aa->s_net; - sa->sat_addr.s_node = aa->s_node; - return 0; - - default: - return -EOPNOTSUPP; - } -} - -/* - * The inverse routine to cops_open(). - */ - -static int cops_close(struct net_device *dev) -{ - struct cops_local *lp = netdev_priv(dev); - - /* If we were running polled, yank the timer. - */ - if(lp->board==TANGENT && dev->irq==0) - del_timer(&cops_timer); - - netif_stop_queue(dev); - return 0; -} - - -#ifdef MODULE -static struct net_device *cops_dev; - -MODULE_LICENSE("GPL"); -module_param_hw(io, int, ioport, 0); -module_param_hw(irq, int, irq, 0); -module_param_hw(board_type, int, other, 0); - -static int __init cops_module_init(void) -{ - if (io == 0) - printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", - cardname); - cops_dev = cops_probe(-1); - return PTR_ERR_OR_ZERO(cops_dev); -} - -static void __exit cops_module_exit(void) -{ - unregister_netdev(cops_dev); - cleanup_card(cops_dev); - free_netdev(cops_dev); -} -module_init(cops_module_init); -module_exit(cops_module_exit); -#endif /* MODULE */ diff --git a/drivers/net/appletalk/cops.h b/drivers/net/appletalk/cops.h deleted file mode 100644 index 7a0bfb351929..000000000000 --- a/drivers/net/appletalk/cops.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* cops.h: LocalTalk driver for Linux. - * - * Authors: - * - Jay Schulist - */ - -#ifndef __LINUX_COPSLTALK_H -#define __LINUX_COPSLTALK_H - -#ifdef __KERNEL__ - -/* Max LLAP size we will accept. */ -#define MAX_LLAP_SIZE 603 - -/* Tangent */ -#define TANG_CARD_STATUS 1 -#define TANG_CLEAR_INT 1 -#define TANG_RESET 3 - -#define TANG_TX_READY 1 -#define TANG_RX_READY 2 - -/* Dayna */ -#define DAYNA_CMD_DATA 0 -#define DAYNA_CLEAR_INT 1 -#define DAYNA_CARD_STATUS 2 -#define DAYNA_INT_CARD 3 -#define DAYNA_RESET 4 - -#define DAYNA_RX_READY 0 -#define DAYNA_TX_READY 1 -#define DAYNA_RX_REQUEST 3 - -/* Same on both card types */ -#define COPS_CLEAR_INT 1 - -/* LAP response codes received from the cards. */ -#define LAP_INIT 1 /* Init cmd */ -#define LAP_INIT_RSP 2 /* Init response */ -#define LAP_WRITE 3 /* Write cmd */ -#define DATA_READ 4 /* Data read */ -#define LAP_RESPONSE 4 /* Received ALAP frame response */ -#define LAP_GETSTAT 5 /* Get LAP and HW status */ -#define LAP_RSPSTAT 6 /* Status response */ - -#endif - -/* - * Structure to hold the firmware information. - */ -struct ltfirmware -{ - unsigned int length; - const unsigned char *data; -}; - -#define DAYNA 1 -#define TANGENT 2 - -#endif diff --git a/drivers/net/appletalk/cops_ffdrv.h b/drivers/net/appletalk/cops_ffdrv.h deleted file mode 100644 index b02005087c1b..000000000000 --- a/drivers/net/appletalk/cops_ffdrv.h +++ /dev/null @@ -1,532 +0,0 @@ - -/* - * The firmware this driver downloads into the Localtalk card is a - * separate program and is not GPL'd source code, even though the Linux - * side driver and the routine that loads this data into the card are. - * - * It is taken from the COPS SDK and is under the following license - * - * This material is licensed to you strictly for use in conjunction with - * the use of COPS LocalTalk adapters. - * There is no charge for this SDK. And no waranty express or implied - * about its fitness for any purpose. However, we will cheerefully - * refund every penny you paid for this SDK... - * Regards, - * - * Thomas F. Divine - * Chief Scientist - */ - - -/* cops_ffdrv.h: LocalTalk driver firmware dump for Linux. - * - * Authors: - * - Jay Schulist - */ - - -#ifdef CONFIG_COPS_DAYNA - -static const unsigned char ffdrv_code[] = { - 58,3,0,50,228,149,33,255,255,34,226,149, - 249,17,40,152,33,202,154,183,237,82,77,68, - 11,107,98,19,54,0,237,176,175,50,80,0, - 62,128,237,71,62,32,237,57,51,62,12,237, - 57,50,237,57,54,62,6,237,57,52,62,12, - 237,57,49,33,107,137,34,32,128,33,83,130, - 34,40,128,33,86,130,34,42,128,33,112,130, - 34,36,128,33,211,130,34,38,128,62,0,237, - 57,16,33,63,148,34,34,128,237,94,205,15, - 130,251,205,168,145,24,141,67,111,112,121,114, - 105,103,104,116,32,40,67,41,32,49,57,56, - 56,32,45,32,68,97,121,110,97,32,67,111, - 109,109,117,110,105,99,97,116,105,111,110,115, - 32,32,32,65,108,108,32,114,105,103,104,116, - 115,32,114,101,115,101,114,118,101,100,46,32, - 32,40,68,40,68,7,16,8,34,7,22,6, - 16,5,12,4,8,3,6,140,0,16,39,128, - 0,4,96,10,224,6,0,7,126,2,64,11, - 118,12,6,13,0,14,193,15,0,5,96,3, - 192,1,64,9,8,62,9,211,66,62,192,211, - 66,62,100,61,32,253,6,28,33,205,129,14, - 66,237,163,194,253,129,6,28,33,205,129,14, - 64,237,163,194,9,130,201,62,47,50,71,152, - 62,47,211,68,58,203,129,237,57,20,58,204, - 129,237,57,21,33,77,152,54,132,205,233,129, - 58,228,149,254,209,40,6,56,4,62,0,24, - 2,219,96,33,233,149,119,230,62,33,232,149, - 119,213,33,8,152,17,7,0,25,119,19,25, - 119,209,201,251,237,77,245,197,213,229,221,229, - 205,233,129,62,1,50,106,137,205,158,139,221, - 225,225,209,193,241,251,237,77,245,197,213,219, - 72,237,56,16,230,46,237,57,16,237,56,12, - 58,72,152,183,32,26,6,20,17,128,2,237, - 56,46,187,32,35,237,56,47,186,32,29,219, - 72,230,1,32,3,5,32,232,175,50,72,152, - 229,221,229,62,1,50,106,137,205,158,139,221, - 225,225,24,25,62,1,50,72,152,58,201,129, - 237,57,12,58,202,129,237,57,13,237,56,16, - 246,17,237,57,16,209,193,241,251,237,77,245, - 197,229,213,221,229,237,56,16,230,17,237,57, - 16,237,56,20,58,34,152,246,16,246,8,211, - 68,62,6,61,32,253,58,34,152,246,8,211, - 68,58,203,129,237,57,20,58,204,129,237,57, - 21,237,56,16,246,34,237,57,16,221,225,209, - 225,193,241,251,237,77,33,2,0,57,126,230, - 3,237,100,1,40,2,246,128,230,130,245,62, - 5,211,64,241,211,64,201,229,213,243,237,56, - 16,230,46,237,57,16,237,56,12,251,70,35, - 35,126,254,175,202,77,133,254,129,202,15,133, - 230,128,194,191,132,43,58,44,152,119,33,76, - 152,119,35,62,132,119,120,254,255,40,4,58, - 49,152,119,219,72,43,43,112,17,3,0,237, - 56,52,230,248,237,57,52,219,72,230,1,194, - 141,131,209,225,237,56,52,246,6,237,57,52, - 62,1,55,251,201,62,3,211,66,62,192,211, - 66,62,48,211,66,0,0,219,66,230,1,40, - 4,219,67,24,240,205,203,135,58,75,152,254, - 255,202,128,132,58,49,152,254,161,250,207,131, - 58,34,152,211,68,62,10,211,66,62,128,211, - 66,62,11,211,66,62,6,211,66,24,0,62, - 14,211,66,62,33,211,66,62,1,211,66,62, - 64,211,66,62,3,211,66,62,209,211,66,62, - 100,71,219,66,230,1,32,6,5,32,247,195, - 248,132,219,67,71,58,44,152,184,194,248,132, - 62,100,71,219,66,230,1,32,6,5,32,247, - 195,248,132,219,67,62,100,71,219,66,230,1, - 32,6,5,32,247,195,248,132,219,67,254,133, - 32,7,62,0,50,74,152,24,17,254,173,32, - 7,62,1,50,74,152,24,6,254,141,194,248, - 132,71,209,225,58,49,152,254,132,32,10,62, - 50,205,2,134,205,144,135,24,27,254,140,32, - 15,62,110,205,2,134,62,141,184,32,5,205, - 144,135,24,8,62,10,205,2,134,205,8,134, - 62,1,50,106,137,205,158,139,237,56,52,246, - 6,237,57,52,175,183,251,201,62,20,135,237, - 57,20,175,237,57,21,237,56,16,246,2,237, - 57,16,237,56,20,95,237,56,21,123,254,10, - 48,244,237,56,16,230,17,237,57,16,209,225, - 205,144,135,62,1,50,106,137,205,158,139,237, - 56,52,246,6,237,57,52,175,183,251,201,209, - 225,243,219,72,230,1,40,13,62,10,211,66, - 0,0,219,66,230,192,202,226,132,237,56,52, - 246,6,237,57,52,62,1,55,251,201,205,203, - 135,62,1,50,106,137,205,158,139,237,56,52, - 246,6,237,57,52,183,251,201,209,225,62,1, - 50,106,137,205,158,139,237,56,52,246,6,237, - 57,52,62,2,55,251,201,209,225,243,219,72, - 230,1,202,213,132,62,10,211,66,0,0,219, - 66,230,192,194,213,132,229,62,1,50,106,137, - 42,40,152,205,65,143,225,17,3,0,205,111, - 136,62,6,211,66,58,44,152,211,66,237,56, - 52,246,6,237,57,52,183,251,201,209,197,237, - 56,52,230,248,237,57,52,219,72,230,1,32, - 15,193,225,237,56,52,246,6,237,57,52,62, - 1,55,251,201,14,23,58,37,152,254,0,40, - 14,14,2,254,1,32,5,62,140,119,24,3, - 62,132,119,43,43,197,205,203,135,193,62,1, - 211,66,62,64,211,66,62,3,211,66,62,193, - 211,66,62,100,203,39,71,219,66,230,1,32, - 6,5,32,247,195,229,133,33,238,151,219,67, - 71,58,44,152,184,194,229,133,119,62,100,71, - 219,66,230,1,32,6,5,32,247,195,229,133, - 219,67,35,119,13,32,234,193,225,62,1,50, - 106,137,205,158,139,237,56,52,246,6,237,57, - 52,175,183,251,201,33,234,151,35,35,62,255, - 119,193,225,62,1,50,106,137,205,158,139,237, - 56,52,246,6,237,57,52,175,251,201,243,61, - 32,253,251,201,62,3,211,66,62,192,211,66, - 58,49,152,254,140,32,19,197,229,213,17,181, - 129,33,185,129,1,2,0,237,176,209,225,193, - 24,27,229,213,33,187,129,58,49,152,230,15, - 87,30,2,237,92,25,17,181,129,126,18,19, - 35,126,18,209,225,58,34,152,246,8,211,68, - 58,49,152,254,165,40,14,254,164,40,10,62, - 10,211,66,62,224,211,66,24,25,58,74,152, - 254,0,40,10,62,10,211,66,62,160,211,66, - 24,8,62,10,211,66,62,128,211,66,62,11, - 211,66,62,6,211,66,205,147,143,62,5,211, - 66,62,224,211,66,62,5,211,66,62,96,211, - 66,62,5,61,32,253,62,5,211,66,62,224, - 211,66,62,14,61,32,253,62,5,211,66,62, - 233,211,66,62,128,211,66,58,181,129,61,32, - 253,62,1,211,66,62,192,211,66,1,254,19, - 237,56,46,187,32,6,13,32,247,195,226,134, - 62,192,211,66,0,0,219,66,203,119,40,250, - 219,66,203,87,40,250,243,237,56,16,230,17, - 237,57,16,237,56,20,251,62,5,211,66,62, - 224,211,66,58,182,129,61,32,253,229,33,181, - 129,58,183,129,203,63,119,35,58,184,129,119, - 225,62,10,211,66,62,224,211,66,62,11,211, - 66,62,118,211,66,62,47,211,68,62,5,211, - 66,62,233,211,66,58,181,129,61,32,253,62, - 5,211,66,62,224,211,66,58,182,129,61,32, - 253,62,5,211,66,62,96,211,66,201,229,213, - 58,50,152,230,15,87,30,2,237,92,33,187, - 129,25,17,181,129,126,18,35,19,126,18,209, - 225,58,71,152,246,8,211,68,58,50,152,254, - 165,40,14,254,164,40,10,62,10,211,66,62, - 224,211,66,24,8,62,10,211,66,62,128,211, - 66,62,11,211,66,62,6,211,66,195,248,135, - 62,3,211,66,62,192,211,66,197,229,213,17, - 181,129,33,183,129,1,2,0,237,176,209,225, - 193,62,47,211,68,62,10,211,66,62,224,211, - 66,62,11,211,66,62,118,211,66,62,1,211, - 66,62,0,211,66,205,147,143,195,16,136,62, - 3,211,66,62,192,211,66,197,229,213,17,181, - 129,33,183,129,1,2,0,237,176,209,225,193, - 62,47,211,68,62,10,211,66,62,224,211,66, - 62,11,211,66,62,118,211,66,205,147,143,62, - 5,211,66,62,224,211,66,62,5,211,66,62, - 96,211,66,62,5,61,32,253,62,5,211,66, - 62,224,211,66,62,14,61,32,253,62,5,211, - 66,62,233,211,66,62,128,211,66,58,181,129, - 61,32,253,62,1,211,66,62,192,211,66,1, - 254,19,237,56,46,187,32,6,13,32,247,195, - 88,136,62,192,211,66,0,0,219,66,203,119, - 40,250,219,66,203,87,40,250,62,5,211,66, - 62,224,211,66,58,182,129,61,32,253,62,5, - 211,66,62,96,211,66,201,197,14,67,6,0, - 62,3,211,66,62,192,211,66,62,48,211,66, - 0,0,219,66,230,1,40,4,219,67,24,240, - 62,5,211,66,62,233,211,66,62,128,211,66, - 58,181,129,61,32,253,237,163,29,62,192,211, - 66,219,66,230,4,40,250,237,163,29,32,245, - 219,66,230,4,40,250,62,255,71,219,66,230, - 4,40,3,5,32,247,219,66,230,4,40,250, - 62,5,211,66,62,224,211,66,58,182,129,61, - 32,253,62,5,211,66,62,96,211,66,58,71, - 152,254,1,202,18,137,62,16,211,66,62,56, - 211,66,62,14,211,66,62,33,211,66,62,1, - 211,66,62,248,211,66,237,56,48,246,153,230, - 207,237,57,48,62,3,211,66,62,221,211,66, - 193,201,58,71,152,211,68,62,10,211,66,62, - 128,211,66,62,11,211,66,62,6,211,66,62, - 6,211,66,58,44,152,211,66,62,16,211,66, - 62,56,211,66,62,48,211,66,0,0,62,14, - 211,66,62,33,211,66,62,1,211,66,62,248, - 211,66,237,56,48,246,145,246,8,230,207,237, - 57,48,62,3,211,66,62,221,211,66,193,201, - 44,3,1,0,70,69,1,245,197,213,229,175, - 50,72,152,237,56,16,230,46,237,57,16,237, - 56,12,62,1,211,66,0,0,219,66,95,230, - 160,32,3,195,20,139,123,230,96,194,72,139, - 62,48,211,66,62,1,211,66,62,64,211,66, - 237,91,40,152,205,207,143,25,43,55,237,82, - 218,70,139,34,42,152,98,107,58,44,152,190, - 194,210,138,35,35,62,130,190,194,200,137,62, - 1,50,48,152,62,175,190,202,82,139,62,132, - 190,32,44,50,50,152,62,47,50,71,152,229, - 175,50,106,137,42,40,152,205,65,143,225,54, - 133,43,70,58,44,152,119,43,112,17,3,0, - 62,10,205,2,134,205,111,136,195,158,138,62, - 140,190,32,19,50,50,152,58,233,149,230,4, - 202,222,138,62,1,50,71,152,195,219,137,126, - 254,160,250,185,138,254,166,242,185,138,50,50, - 152,43,126,35,229,213,33,234,149,95,22,0, - 25,126,254,132,40,18,254,140,40,14,58,50, - 152,230,15,87,126,31,21,242,65,138,56,2, - 175,119,58,50,152,230,15,87,58,233,149,230, - 62,31,21,242,85,138,218,98,138,209,225,195, - 20,139,58,50,152,33,100,137,230,15,95,22, - 0,25,126,50,71,152,209,225,58,50,152,254, - 164,250,135,138,58,73,152,254,0,40,4,54, - 173,24,2,54,133,43,70,58,44,152,119,43, - 112,17,3,0,205,70,135,175,50,106,137,205, - 208,139,58,199,129,237,57,12,58,200,129,237, - 57,13,237,56,16,246,17,237,57,16,225,209, - 193,241,251,237,77,62,129,190,194,227,138,54, - 130,43,70,58,44,152,119,43,112,17,3,0, - 205,144,135,195,20,139,35,35,126,254,132,194, - 227,138,175,50,106,137,205,158,139,24,42,58, - 201,154,254,1,40,7,62,1,50,106,137,24, - 237,58,106,137,254,1,202,222,138,62,128,166, - 194,222,138,221,229,221,33,67,152,205,127,142, - 205,109,144,221,225,225,209,193,241,251,237,77, - 58,106,137,254,1,202,44,139,58,50,152,254, - 164,250,44,139,58,73,152,238,1,50,73,152, - 221,229,221,33,51,152,205,127,142,221,225,62, - 1,50,106,137,205,158,139,195,13,139,24,208, - 24,206,24,204,230,64,40,3,195,20,139,195, - 20,139,43,126,33,8,152,119,35,58,44,152, - 119,43,237,91,35,152,205,203,135,205,158,139, - 195,13,139,175,50,78,152,62,3,211,66,62, - 192,211,66,201,197,33,4,0,57,126,35,102, - 111,62,1,50,106,137,219,72,205,141,139,193, - 201,62,1,50,78,152,34,40,152,54,0,35, - 35,54,0,195,163,139,58,78,152,183,200,229, - 33,181,129,58,183,129,119,35,58,184,129,119, - 225,62,47,211,68,62,14,211,66,62,193,211, - 66,62,10,211,66,62,224,211,66,62,11,211, - 66,62,118,211,66,195,3,140,58,78,152,183, - 200,58,71,152,211,68,254,69,40,4,254,70, - 32,17,58,73,152,254,0,40,10,62,10,211, - 66,62,160,211,66,24,8,62,10,211,66,62, - 128,211,66,62,11,211,66,62,6,211,66,62, - 6,211,66,58,44,152,211,66,62,16,211,66, - 62,56,211,66,62,48,211,66,0,0,219,66, - 230,1,40,4,219,67,24,240,62,14,211,66, - 62,33,211,66,42,40,152,205,65,143,62,1, - 211,66,62,248,211,66,237,56,48,246,145,246, - 8,230,207,237,57,48,62,3,211,66,62,221, - 211,66,201,62,16,211,66,62,56,211,66,62, - 48,211,66,0,0,219,66,230,1,40,4,219, - 67,24,240,62,14,211,66,62,33,211,66,62, - 1,211,66,62,248,211,66,237,56,48,246,153, - 230,207,237,57,48,62,3,211,66,62,221,211, - 66,201,229,213,33,234,149,95,22,0,25,126, - 254,132,40,4,254,140,32,2,175,119,123,209, - 225,201,6,8,14,0,31,48,1,12,16,250, - 121,201,33,4,0,57,94,35,86,33,2,0, - 57,126,35,102,111,221,229,34,89,152,237,83, - 91,152,221,33,63,152,205,127,142,58,81,152, - 50,82,152,58,80,152,135,50,80,152,205,162, - 140,254,3,56,16,58,81,152,135,60,230,15, - 50,81,152,175,50,80,152,24,23,58,79,152, - 205,162,140,254,3,48,13,58,81,152,203,63, - 50,81,152,62,255,50,79,152,58,81,152,50, - 82,152,58,79,152,135,50,79,152,62,32,50, - 83,152,50,84,152,237,56,16,230,17,237,57, - 16,219,72,62,192,50,93,152,62,93,50,94, - 152,58,93,152,61,50,93,152,32,9,58,94, - 152,61,50,94,152,40,44,62,170,237,57,20, - 175,237,57,21,237,56,16,246,2,237,57,16, - 219,72,230,1,202,29,141,237,56,20,71,237, - 56,21,120,254,10,48,237,237,56,16,230,17, - 237,57,16,243,62,14,211,66,62,65,211,66, - 251,58,39,152,23,23,60,50,39,152,71,58, - 82,152,160,230,15,40,22,71,14,10,219,66, - 230,16,202,186,141,219,72,230,1,202,186,141, - 13,32,239,16,235,42,89,152,237,91,91,152, - 205,47,131,48,7,61,202,186,141,195,227,141, - 221,225,33,0,0,201,221,33,55,152,205,127, - 142,58,84,152,61,50,84,152,40,19,58,82, - 152,246,1,50,82,152,58,79,152,246,1,50, - 79,152,195,29,141,221,225,33,1,0,201,221, - 33,59,152,205,127,142,58,80,152,246,1,50, - 80,152,58,82,152,135,246,1,50,82,152,58, - 83,152,61,50,83,152,194,29,141,221,225,33, - 2,0,201,221,229,33,0,0,57,17,4,0, - 25,126,50,44,152,230,128,50,85,152,58,85, - 152,183,40,6,221,33,88,2,24,4,221,33, - 150,0,58,44,152,183,40,53,60,40,50,60, - 40,47,61,61,33,86,152,119,35,119,35,54, - 129,175,50,48,152,221,43,221,229,225,124,181, - 40,42,33,86,152,17,3,0,205,189,140,17, - 232,3,27,123,178,32,251,58,48,152,183,40, - 224,58,44,152,71,62,7,128,230,127,71,58, - 85,152,176,50,44,152,24,162,221,225,201,183, - 221,52,0,192,221,52,1,192,221,52,2,192, - 221,52,3,192,55,201,245,62,1,211,100,241, - 201,245,62,1,211,96,241,201,33,2,0,57, - 126,35,102,111,237,56,48,230,175,237,57,48, - 62,48,237,57,49,125,237,57,32,124,237,57, - 33,62,0,237,57,34,62,88,237,57,35,62, - 0,237,57,36,237,57,37,33,128,2,125,237, - 57,38,124,237,57,39,237,56,48,246,97,230, - 207,237,57,48,62,0,237,57,0,62,0,211, - 96,211,100,201,33,2,0,57,126,35,102,111, - 237,56,48,230,175,237,57,48,62,12,237,57, - 49,62,76,237,57,32,62,0,237,57,33,237, - 57,34,125,237,57,35,124,237,57,36,62,0, - 237,57,37,33,128,2,125,237,57,38,124,237, - 57,39,237,56,48,246,97,230,207,237,57,48, - 62,1,211,96,201,33,2,0,57,126,35,102, - 111,229,237,56,48,230,87,237,57,48,125,237, - 57,40,124,237,57,41,62,0,237,57,42,62, - 67,237,57,43,62,0,237,57,44,58,106,137, - 254,1,32,5,33,6,0,24,3,33,128,2, - 125,237,57,46,124,237,57,47,237,56,50,230, - 252,246,2,237,57,50,225,201,33,4,0,57, - 94,35,86,33,2,0,57,126,35,102,111,237, - 56,48,230,87,237,57,48,125,237,57,40,124, - 237,57,41,62,0,237,57,42,62,67,237,57, - 43,62,0,237,57,44,123,237,57,46,122,237, - 57,47,237,56,50,230,244,246,0,237,57,50, - 237,56,48,246,145,230,207,237,57,48,201,213, - 237,56,46,95,237,56,47,87,237,56,46,111, - 237,56,47,103,183,237,82,32,235,33,128,2, - 183,237,82,209,201,213,237,56,38,95,237,56, - 39,87,237,56,38,111,237,56,39,103,183,237, - 82,32,235,33,128,2,183,237,82,209,201,245, - 197,1,52,0,237,120,230,253,237,121,193,241, - 201,245,197,1,52,0,237,120,246,2,237,121, - 193,241,201,33,2,0,57,126,35,102,111,126, - 35,110,103,201,33,0,0,34,102,152,34,96, - 152,34,98,152,33,202,154,34,104,152,237,91, - 104,152,42,226,149,183,237,82,17,0,255,25, - 34,100,152,203,124,40,6,33,0,125,34,100, - 152,42,104,152,35,35,35,229,205,120,139,193, - 201,205,186,149,229,42,40,152,35,35,35,229, - 205,39,144,193,124,230,3,103,221,117,254,221, - 116,255,237,91,42,152,35,35,35,183,237,82, - 32,12,17,5,0,42,42,152,205,171,149,242, - 169,144,42,40,152,229,205,120,139,193,195,198, - 149,237,91,42,152,42,98,152,25,34,98,152, - 19,19,19,42,102,152,25,34,102,152,237,91, - 100,152,33,158,253,25,237,91,102,152,205,171, - 149,242,214,144,33,0,0,34,102,152,62,1, - 50,95,152,205,225,144,195,198,149,58,95,152, - 183,200,237,91,96,152,42,102,152,205,171,149, - 242,5,145,237,91,102,152,33,98,2,25,237, - 91,96,152,205,171,149,250,37,145,237,91,96, - 152,42,102,152,183,237,82,32,7,42,98,152, - 125,180,40,13,237,91,102,152,42,96,152,205, - 171,149,242,58,145,237,91,104,152,42,102,152, - 25,35,35,35,229,205,120,139,193,175,50,95, - 152,201,195,107,139,205,206,149,250,255,243,205, - 225,144,251,58,230,149,183,194,198,149,17,1, - 0,42,98,152,205,171,149,250,198,149,62,1, - 50,230,149,237,91,96,152,42,104,152,25,221, - 117,252,221,116,253,237,91,104,152,42,96,152, - 25,35,35,35,221,117,254,221,116,255,35,35, - 35,229,205,39,144,124,230,3,103,35,35,35, - 221,117,250,221,116,251,235,221,110,252,221,102, - 253,115,35,114,35,54,4,62,1,211,100,211, - 84,195,198,149,33,0,0,34,102,152,34,96, - 152,34,98,152,33,202,154,34,104,152,237,91, - 104,152,42,226,149,183,237,82,17,0,255,25, - 34,100,152,33,109,152,54,0,33,107,152,229, - 205,240,142,193,62,47,50,34,152,62,132,50, - 49,152,205,241,145,205,61,145,58,39,152,60, - 50,39,152,24,241,205,206,149,251,255,33,109, - 152,126,183,202,198,149,110,221,117,251,33,109, - 152,54,0,221,126,251,254,1,40,28,254,3, - 40,101,254,4,202,190,147,254,5,202,147,147, - 254,8,40,87,33,107,152,229,205,240,142,195, - 198,149,58,201,154,183,32,21,33,111,152,126, - 50,229,149,205,52,144,33,110,152,110,38,0, - 229,205,11,142,193,237,91,96,152,42,104,152, - 25,221,117,254,221,116,255,35,35,54,2,17, - 2,0,43,43,115,35,114,58,44,152,35,35, - 119,58,228,149,35,119,62,1,211,100,211,84, - 62,1,50,201,154,24,169,205,153,142,58,231, - 149,183,40,250,175,50,231,149,33,110,152,126, - 254,255,40,91,58,233,149,230,63,183,40,83, - 94,22,0,33,234,149,25,126,183,40,13,33, - 110,152,94,33,234,150,25,126,254,3,32,36, - 205,81,148,125,180,33,110,152,94,22,0,40, - 17,33,234,149,25,54,0,33,107,152,229,205, - 240,142,193,195,198,149,33,234,150,25,54,0, - 33,110,152,94,22,0,33,234,149,25,126,50, - 49,152,254,132,32,37,62,47,50,34,152,42, - 107,152,229,33,110,152,229,205,174,140,193,193, - 125,180,33,110,152,94,22,0,33,234,150,202, - 117,147,25,52,195,120,147,58,49,152,254,140, - 32,7,62,1,50,34,152,24,210,62,32,50, - 106,152,24,19,58,49,152,95,58,106,152,163, - 183,58,106,152,32,11,203,63,50,106,152,58, - 106,152,183,32,231,254,2,40,51,254,4,40, - 38,254,8,40,26,254,16,40,13,254,32,32, - 158,62,165,50,49,152,62,69,24,190,62,164, - 50,49,152,62,70,24,181,62,163,50,49,152, - 175,24,173,62,162,50,49,152,62,1,24,164, - 62,161,50,49,152,62,3,24,155,25,54,0, - 221,126,251,254,8,40,7,58,230,149,183,202, - 32,146,33,107,152,229,205,240,142,193,211,84, - 195,198,149,237,91,96,152,42,104,152,25,221, - 117,254,221,116,255,35,35,54,6,17,2,0, - 43,43,115,35,114,58,228,149,35,35,119,58, - 233,149,35,119,205,146,142,195,32,146,237,91, - 96,152,42,104,152,25,229,205,160,142,193,58, - 231,149,183,40,250,175,50,231,149,243,237,91, - 96,152,42,104,152,25,221,117,254,221,116,255, - 78,35,70,221,113,252,221,112,253,89,80,42, - 98,152,183,237,82,34,98,152,203,124,40,19, - 33,0,0,34,98,152,34,102,152,34,96,152, - 62,1,50,95,152,24,40,221,94,252,221,86, - 253,19,19,19,42,96,152,25,34,96,152,237, - 91,100,152,33,158,253,25,237,91,96,152,205, - 171,149,242,55,148,33,0,0,34,96,152,175, - 50,230,149,251,195,32,146,245,62,1,50,231, - 149,62,16,237,57,0,211,80,241,251,237,77, - 201,205,186,149,229,229,33,0,0,34,37,152, - 33,110,152,126,50,234,151,58,44,152,33,235, - 151,119,221,54,253,0,221,54,254,0,195,230, - 148,33,236,151,54,175,33,3,0,229,33,234, - 151,229,205,174,140,193,193,33,236,151,126,254, - 255,40,74,33,245,151,110,221,117,255,33,249, - 151,126,221,166,255,221,119,255,33,253,151,126, - 221,166,255,221,119,255,58,232,149,95,221,126, - 255,163,221,119,255,183,40,15,230,191,33,110, - 152,94,22,0,33,234,149,25,119,24,12,33, - 110,152,94,22,0,33,234,149,25,54,132,33, - 0,0,195,198,149,221,110,253,221,102,254,35, - 221,117,253,221,116,254,17,32,0,221,110,253, - 221,102,254,205,171,149,250,117,148,58,233,149, - 203,87,40,84,33,1,0,34,37,152,221,54, - 253,0,221,54,254,0,24,53,33,236,151,54, - 175,33,3,0,229,33,234,151,229,205,174,140, - 193,193,33,236,151,126,254,255,40,14,33,110, - 152,94,22,0,33,234,149,25,54,140,24,159, - 221,110,253,221,102,254,35,221,117,253,221,116, - 254,17,32,0,221,110,253,221,102,254,205,171, - 149,250,12,149,33,2,0,34,37,152,221,54, - 253,0,221,54,254,0,24,54,33,236,151,54, - 175,33,3,0,229,33,234,151,229,205,174,140, - 193,193,33,236,151,126,254,255,40,15,33,110, - 152,94,22,0,33,234,149,25,54,132,195,211, - 148,221,110,253,221,102,254,35,221,117,253,221, - 116,254,17,32,0,221,110,253,221,102,254,205, - 171,149,250,96,149,33,1,0,195,198,149,124, - 170,250,179,149,237,82,201,124,230,128,237,82, - 60,201,225,253,229,221,229,221,33,0,0,221, - 57,233,221,249,221,225,253,225,201,233,225,253, - 229,221,229,221,33,0,0,221,57,94,35,86, - 35,235,57,249,235,233,0,0,0,0,0,0, - 62,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 175,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,133,1,0,0,0,63, - 255,255,255,255,0,0,0,63,0,0,0,0, - 0,0,0,0,0,0,0,24,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0 - } ; - -#endif diff --git a/drivers/net/appletalk/cops_ltdrv.h b/drivers/net/appletalk/cops_ltdrv.h deleted file mode 100644 index c699b1ad31da..000000000000 --- a/drivers/net/appletalk/cops_ltdrv.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * The firmware this driver downloads into the Localtalk card is a - * separate program and is not GPL'd source code, even though the Linux - * side driver and the routine that loads this data into the card are. - * - * It is taken from the COPS SDK and is under the following license - * - * This material is licensed to you strictly for use in conjunction with - * the use of COPS LocalTalk adapters. - * There is no charge for this SDK. And no waranty express or implied - * about its fitness for any purpose. However, we will cheerefully - * refund every penny you paid for this SDK... - * Regards, - * - * Thomas F. Divine - * Chief Scientist - */ - - -/* cops_ltdrv.h: LocalTalk driver firmware dump for Linux. - * - * Authors: - * - Jay Schulist - */ - - -#ifdef CONFIG_COPS_TANGENT - -static const unsigned char ltdrv_code[] = { - 58,3,0,50,148,10,33,143,15,62,85,119, - 190,32,9,62,170,119,190,32,3,35,24,241, - 34,146,10,249,17,150,10,33,143,15,183,237, - 82,77,68,11,107,98,19,54,0,237,176,62, - 16,237,57,51,62,0,237,57,50,237,57,54, - 62,12,237,57,49,62,195,33,39,2,50,56, - 0,34,57,0,237,86,205,30,2,251,205,60, - 10,24,169,67,111,112,121,114,105,103,104,116, - 32,40,99,41,32,49,57,56,56,45,49,57, - 57,50,44,32,80,114,105,110,116,105,110,103, - 32,67,111,109,109,117,110,105,99,97,116,105, - 111,110,115,32,65,115,115,111,99,105,97,116, - 101,115,44,32,73,110,99,46,65,108,108,32, - 114,105,103,104,116,115,32,114,101,115,101,114, - 118,101,100,46,32,32,4,4,22,40,255,60, - 4,96,10,224,6,0,7,126,2,64,11,246, - 12,6,13,0,14,193,15,0,5,96,3,192, - 1,0,9,8,62,3,211,82,62,192,211,82, - 201,62,3,211,82,62,213,211,82,201,62,5, - 211,82,62,224,211,82,201,62,5,211,82,62, - 224,211,82,201,62,5,211,82,62,96,211,82, - 201,6,28,33,180,1,14,82,237,163,194,4, - 2,33,39,2,34,64,0,58,3,0,230,1, - 192,62,11,237,121,62,118,237,121,201,33,182, - 10,54,132,205,253,1,201,245,197,213,229,42, - 150,10,14,83,17,98,2,67,20,237,162,58, - 179,1,95,219,82,230,1,32,6,29,32,247, - 195,17,3,62,1,211,82,219,82,95,230,160, - 32,10,237,162,32,225,21,32,222,195,15,3, - 237,162,123,230,96,194,21,3,62,48,211,82, - 62,1,211,82,175,211,82,237,91,150,10,43, - 55,237,82,218,19,3,34,152,10,98,107,58, - 154,10,190,32,81,62,1,50,158,10,35,35, - 62,132,190,32,44,54,133,43,70,58,154,10, - 119,43,112,17,3,0,205,137,3,62,16,211, - 82,62,56,211,82,205,217,1,42,150,10,14, - 83,17,98,2,67,20,58,178,1,95,195,59, - 2,62,129,190,194,227,2,54,130,43,70,58, - 154,10,119,43,112,17,3,0,205,137,3,195, - 254,2,35,35,126,254,132,194,227,2,205,61, - 3,24,20,62,128,166,194,222,2,221,229,221, - 33,175,10,205,93,6,205,144,7,221,225,225, - 209,193,241,251,237,77,221,229,221,33,159,10, - 205,93,6,221,225,205,61,3,195,247,2,24, - 237,24,235,24,233,230,64,40,2,24,227,24, - 225,175,50,179,10,205,208,1,201,197,33,4, - 0,57,126,35,102,111,205,51,3,193,201,62, - 1,50,179,10,34,150,10,54,0,58,179,10, - 183,200,62,14,211,82,62,193,211,82,62,10, - 211,82,62,224,211,82,62,6,211,82,58,154, - 10,211,82,62,16,211,82,62,56,211,82,62, - 48,211,82,219,82,230,1,40,4,219,83,24, - 242,62,14,211,82,62,33,211,82,62,1,211, - 82,62,9,211,82,62,32,211,82,205,217,1, - 201,14,83,205,208,1,24,23,14,83,205,208, - 1,205,226,1,58,174,1,61,32,253,205,244, - 1,58,174,1,61,32,253,205,226,1,58,175, - 1,61,32,253,62,5,211,82,62,233,211,82, - 62,128,211,82,58,176,1,61,32,253,237,163, - 27,62,192,211,82,219,82,230,4,40,250,237, - 163,27,122,179,32,243,219,82,230,4,40,250, - 58,178,1,71,219,82,230,4,40,3,5,32, - 247,219,82,230,4,40,250,205,235,1,58,177, - 1,61,32,253,205,244,1,201,229,213,35,35, - 126,230,128,194,145,4,43,58,154,10,119,43, - 70,33,181,10,119,43,112,17,3,0,243,62, - 10,211,82,219,82,230,128,202,41,4,209,225, - 62,1,55,251,201,205,144,3,58,180,10,254, - 255,202,127,4,205,217,1,58,178,1,71,219, - 82,230,1,32,6,5,32,247,195,173,4,219, - 83,71,58,154,10,184,194,173,4,58,178,1, - 71,219,82,230,1,32,6,5,32,247,195,173, - 4,219,83,58,178,1,71,219,82,230,1,32, - 6,5,32,247,195,173,4,219,83,254,133,194, - 173,4,58,179,1,24,4,58,179,1,135,61, - 32,253,209,225,205,137,3,205,61,3,183,251, - 201,209,225,243,62,10,211,82,219,82,230,128, - 202,164,4,62,1,55,251,201,205,144,3,205, - 61,3,183,251,201,209,225,62,2,55,251,201, - 243,62,14,211,82,62,33,211,82,251,201,33, - 4,0,57,94,35,86,33,2,0,57,126,35, - 102,111,221,229,34,193,10,237,83,195,10,221, - 33,171,10,205,93,6,58,185,10,50,186,10, - 58,184,10,135,50,184,10,205,112,6,254,3, - 56,16,58,185,10,135,60,230,15,50,185,10, - 175,50,184,10,24,23,58,183,10,205,112,6, - 254,3,48,13,58,185,10,203,63,50,185,10, - 62,255,50,183,10,58,185,10,50,186,10,58, - 183,10,135,50,183,10,62,32,50,187,10,50, - 188,10,6,255,219,82,230,16,32,3,5,32, - 247,205,180,4,6,40,219,82,230,16,40,3, - 5,32,247,62,10,211,82,219,82,230,128,194, - 46,5,219,82,230,16,40,214,237,95,71,58, - 186,10,160,230,15,40,32,71,14,10,62,10, - 211,82,219,82,230,128,202,119,5,205,180,4, - 195,156,5,219,82,230,16,202,156,5,13,32, - 229,16,225,42,193,10,237,91,195,10,205,252, - 3,48,7,61,202,156,5,195,197,5,221,225, - 33,0,0,201,221,33,163,10,205,93,6,58, - 188,10,61,50,188,10,40,19,58,186,10,246, - 1,50,186,10,58,183,10,246,1,50,183,10, - 195,46,5,221,225,33,1,0,201,221,33,167, - 10,205,93,6,58,184,10,246,1,50,184,10, - 58,186,10,135,246,1,50,186,10,58,187,10, - 61,50,187,10,194,46,5,221,225,33,2,0, - 201,221,229,33,0,0,57,17,4,0,25,126, - 50,154,10,230,128,50,189,10,58,189,10,183, - 40,6,221,33,88,2,24,4,221,33,150,0, - 58,154,10,183,40,49,60,40,46,61,33,190, - 10,119,35,119,35,54,129,175,50,158,10,221, - 43,221,229,225,124,181,40,42,33,190,10,17, - 3,0,205,206,4,17,232,3,27,123,178,32, - 251,58,158,10,183,40,224,58,154,10,71,62, - 7,128,230,127,71,58,189,10,176,50,154,10, - 24,166,221,225,201,183,221,52,0,192,221,52, - 1,192,221,52,2,192,221,52,3,192,55,201, - 6,8,14,0,31,48,1,12,16,250,121,201, - 33,2,0,57,94,35,86,35,78,35,70,35, - 126,35,102,105,79,120,68,103,237,176,201,33, - 2,0,57,126,35,102,111,62,17,237,57,48, - 125,237,57,40,124,237,57,41,62,0,237,57, - 42,62,64,237,57,43,62,0,237,57,44,33, - 128,2,125,237,57,46,124,237,57,47,62,145, - 237,57,48,211,68,58,149,10,211,66,201,33, - 2,0,57,126,35,102,111,62,33,237,57,48, - 62,64,237,57,32,62,0,237,57,33,237,57, - 34,125,237,57,35,124,237,57,36,62,0,237, - 57,37,33,128,2,125,237,57,38,124,237,57, - 39,62,97,237,57,48,211,67,58,149,10,211, - 66,201,237,56,46,95,237,56,47,87,237,56, - 46,111,237,56,47,103,183,237,82,32,235,33, - 128,2,183,237,82,201,237,56,38,95,237,56, - 39,87,237,56,38,111,237,56,39,103,183,237, - 82,32,235,33,128,2,183,237,82,201,205,106, - 10,221,110,6,221,102,7,126,35,110,103,195, - 118,10,205,106,10,33,0,0,34,205,10,34, - 198,10,34,200,10,33,143,15,34,207,10,237, - 91,207,10,42,146,10,183,237,82,17,0,255, - 25,34,203,10,203,124,40,6,33,0,125,34, - 203,10,42,207,10,229,205,37,3,195,118,10, - 205,106,10,229,42,150,10,35,35,35,229,205, - 70,7,193,124,230,3,103,221,117,254,221,116, - 255,237,91,152,10,35,35,35,183,237,82,32, - 12,17,5,0,42,152,10,205,91,10,242,203, - 7,42,150,10,229,205,37,3,195,118,10,237, - 91,152,10,42,200,10,25,34,200,10,42,205, - 10,25,34,205,10,237,91,203,10,33,158,253, - 25,237,91,205,10,205,91,10,242,245,7,33, - 0,0,34,205,10,62,1,50,197,10,205,5, - 8,33,0,0,57,249,195,118,10,205,106,10, - 58,197,10,183,202,118,10,237,91,198,10,42, - 205,10,205,91,10,242,46,8,237,91,205,10, - 33,98,2,25,237,91,198,10,205,91,10,250, - 78,8,237,91,198,10,42,205,10,183,237,82, - 32,7,42,200,10,125,180,40,13,237,91,205, - 10,42,198,10,205,91,10,242,97,8,237,91, - 207,10,42,205,10,25,229,205,37,3,175,50, - 197,10,195,118,10,205,29,3,33,0,0,57, - 249,195,118,10,205,106,10,58,202,10,183,40, - 22,205,14,7,237,91,209,10,19,19,19,205, - 91,10,242,139,8,33,1,0,195,118,10,33, - 0,0,195,118,10,205,126,10,252,255,205,108, - 8,125,180,194,118,10,237,91,200,10,33,0, - 0,205,91,10,242,118,10,237,91,207,10,42, - 198,10,25,221,117,254,221,116,255,35,35,35, - 229,205,70,7,193,124,230,3,103,35,35,35, - 221,117,252,221,116,253,229,221,110,254,221,102, - 255,229,33,212,10,229,205,124,6,193,193,221, - 110,252,221,102,253,34,209,10,33,211,10,54, - 4,33,209,10,227,205,147,6,193,62,1,50, - 202,10,243,221,94,252,221,86,253,42,200,10, - 183,237,82,34,200,10,203,124,40,17,33,0, - 0,34,200,10,34,205,10,34,198,10,50,197, - 10,24,37,221,94,252,221,86,253,42,198,10, - 25,34,198,10,237,91,203,10,33,158,253,25, - 237,91,198,10,205,91,10,242,68,9,33,0, - 0,34,198,10,205,5,8,33,0,0,57,249, - 251,195,118,10,205,106,10,33,49,13,126,183, - 40,16,205,42,7,237,91,47,13,19,19,19, - 205,91,10,242,117,9,58,142,15,198,1,50, - 142,15,195,118,10,33,49,13,126,254,1,40, - 25,254,3,202,7,10,254,5,202,21,10,33, - 49,13,54,0,33,47,13,229,205,207,6,195, - 118,10,58,141,15,183,32,72,33,51,13,126, - 50,149,10,205,86,7,33,50,13,126,230,127, - 183,32,40,58,142,15,230,127,50,142,15,183, - 32,5,198,1,50,142,15,33,50,13,126,111, - 23,159,103,203,125,58,142,15,40,5,198,128, - 50,142,15,33,50,13,119,33,50,13,126,111, - 23,159,103,229,205,237,5,193,33,211,10,54, - 2,33,2,0,34,209,10,58,154,10,33,212, - 10,119,58,148,10,33,213,10,119,33,209,10, - 229,205,147,6,193,24,128,42,47,13,229,33, - 50,13,229,205,191,4,193,24,239,33,211,10, - 54,6,33,3,0,34,209,10,58,154,10,33, - 212,10,119,58,148,10,33,213,10,119,33,214, - 10,54,5,33,209,10,229,205,147,6,24,200, - 205,106,10,33,49,13,54,0,33,47,13,229, - 205,207,6,33,209,10,227,205,147,6,193,205, - 80,9,205,145,8,24,248,124,170,250,99,10, - 237,82,201,124,230,128,237,82,60,201,225,253, - 229,221,229,221,33,0,0,221,57,233,221,249, - 221,225,253,225,201,233,225,253,229,221,229,221, - 33,0,0,221,57,94,35,86,35,235,57,249, - 235,233,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0 - } ; - -#endif diff --git a/include/net/Space.h b/include/net/Space.h index c29f3d51c078..ef42629f4258 100644 --- a/include/net/Space.h +++ b/include/net/Space.h @@ -10,4 +10,3 @@ struct net_device *smc_init(int unit); struct net_device *cs89x0_probe(int unit); struct net_device *tc515_probe(int unit); struct net_device *lance_probe(int unit); -struct net_device *cops_probe(int unit); -- cgit v1.2.3 From 0629f22ec130940c9c8a15fa9a4994996816d474 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 3 Oct 2023 08:34:14 -0700 Subject: ynl: netdev: drop unnecessary enum-as-flags enum-as-flags can be used when enum declares bit positions but we want to carry bitmask in an attribute. If the definition is already provided as flags there's no need to indicate the flag-iness of the attribute. Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231003153416.2479808-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/netdev.yaml | 2 -- 1 file changed, 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index c46fcc78fc04..14511b13f305 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -74,7 +74,6 @@ attribute-sets: doc: Bitmask of enabled xdp-features. type: u64 enum: xdp-act - enum-as-flags: true - name: xdp-zc-max-segs doc: max fragment count supported by ZC driver @@ -87,7 +86,6 @@ attribute-sets: See Documentation/networking/xdp-rx-metadata.rst for more details. type: u64 enum: xdp-rx-metadata - enum-as-flags: true operations: list: -- cgit v1.2.3 From e18f3dc2beaa5055e27334cd2d8b492bc3e9b3a4 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 6 Oct 2023 13:44:35 +0200 Subject: tools: ynl-gen: lift type requirement for attribute subsets In case an attribute is used in a subset, the type has to be currently specified. As the attribute is already defined in the original set, this is a redundant information in yaml file, moreover, may lead to inconsistencies. Example: attribute-sets: ... name: pin enum-name: dpll_a_pin attributes: ... - name: parent-id type: u32 ... - name: pin-parent-device subset-of: pin attributes: - name: parent-id type: u32 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Remove the requirement from schema files to specify the "type" for attribute subsets. Signed-off-by: Jiri Pirko Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20231006114436.1725425-2-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 14 +++++++++++++- Documentation/netlink/genetlink-legacy.yaml | 14 +++++++++++++- Documentation/netlink/genetlink.yaml | 14 +++++++++++++- Documentation/netlink/netlink-raw.yaml | 14 +++++++++++++- 4 files changed, 52 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 9806c44f604c..32736b2d8ae8 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -142,7 +142,7 @@ properties: type: array items: type: object - required: [ name, type ] + required: [ name ] additionalProperties: False properties: name: @@ -215,6 +215,18 @@ properties: not: required: [ name-prefix ] + # type property is only required if not in subset definition + if: + properties: + subset-of: + not: + type: string + then: + properties: + attributes: + items: + required: [ type ] + operations: description: Operations supported by the protocol. type: object diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 12a0a045605d..25fe1379b180 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -180,7 +180,7 @@ properties: type: array items: type: object - required: [ name, type ] + required: [ name ] additionalProperties: False properties: name: @@ -254,6 +254,18 @@ properties: not: required: [ name-prefix ] + # type property is only required if not in subset definition + if: + properties: + subset-of: + not: + type: string + then: + properties: + attributes: + items: + required: [ type ] + operations: description: Operations supported by the protocol. type: object diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 3d338c48bf21..6ea1c947ce51 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -115,7 +115,7 @@ properties: type: array items: type: object - required: [ name, type ] + required: [ name ] additionalProperties: False properties: name: @@ -184,6 +184,18 @@ properties: not: required: [ name-prefix ] + # type property is only required if not in subset definition + if: + properties: + subset-of: + not: + type: string + then: + properties: + attributes: + items: + required: [ type ] + operations: description: Operations supported by the protocol. type: object diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index 896797876414..d976851b80f8 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -187,7 +187,7 @@ properties: type: array items: type: object - required: [ name, type ] + required: [ name ] additionalProperties: False properties: name: @@ -261,6 +261,18 @@ properties: not: required: [ name-prefix ] + # type property is only required if not in subset definition + if: + properties: + subset-of: + not: + type: string + then: + properties: + attributes: + items: + required: [ type ] + operations: description: Operations supported by the protocol. type: object -- cgit v1.2.3 From 7049fd5df78cf0e7463d8e8bb41db60b6762df6c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 6 Oct 2023 13:44:36 +0200 Subject: netlink: specs: remove redundant type keys from attributes in subsets No longer needed to define type for subset attributes. Remove those. Signed-off-by: Jiri Pirko Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20231006114436.1725425-3-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/devlink.yaml | 10 ---------- Documentation/netlink/specs/dpll.yaml | 8 -------- Documentation/netlink/specs/ethtool.yaml | 3 --- 3 files changed, 21 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index d1ebcd927149..86a12c5bcff1 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -199,54 +199,44 @@ attribute-sets: attributes: - name: reload-stats - type: nest - name: remote-reload-stats - type: nest - name: dl-reload-stats subset-of: devlink attributes: - name: reload-action-info - type: nest - name: dl-reload-act-info subset-of: devlink attributes: - name: reload-action - type: u8 - name: reload-action-stats - type: nest - name: dl-reload-act-stats subset-of: devlink attributes: - name: reload-stats-entry - type: nest - name: dl-reload-stats-entry subset-of: devlink attributes: - name: reload-stats-limit - type: u8 - name: reload-stats-value - type: u32 - name: dl-info-version subset-of: devlink attributes: - name: info-version-name - type: string - name: info-version-value - type: string operations: enum-model: directional diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 8b86b28b47a6..1c1b53136c7b 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -278,36 +278,28 @@ attribute-sets: attributes: - name: parent-id - type: u32 - name: direction - type: u32 - name: prio - type: u32 - name: state - type: u32 - name: pin-parent-pin subset-of: pin attributes: - name: parent-id - type: u32 - name: state - type: u32 - name: frequency-range subset-of: pin attributes: - name: frequency-min - type: u64 - name: frequency-max - type: u64 operations: enum-name: dpll_cmd diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 837b565577ca..5c7a65b009b4 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -818,13 +818,10 @@ attribute-sets: attributes: - name: hist-bkt-low - type: u32 - name: hist-bkt-hi - type: u32 - name: hist-val - type: u64 - name: stats attributes: -- cgit v1.2.3 From 1dab47139e6118a420acec8426a860ea4b40c379 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Oct 2023 16:10:28 +0200 Subject: appletalk: remove ipddp driver After the cops driver is removed, ipddp is now the only CONFIG_DEV_APPLETALK but as far as I can tell, this also has no users and can be removed, making appletalk support purely based on ethertalk, using ethernet hardware. Link: https://lore.kernel.org/netdev/e490dd0c-a65d-4acf-89c6-c06cb48ec880@app.fastmail.com/ Link: https://lore.kernel.org/netdev/9cac4fbd-9557-b0b8-54fa-93f0290a6fb8@schmorgal.com/ Cc: Doug Brown Signed-off-by: Arnd Bergmann Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20231009141139.1766345-1-arnd@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/index.rst | 1 - Documentation/networking/ipddp.rst | 78 --------- MAINTAINERS | 1 - drivers/net/Makefile | 1 - drivers/net/appletalk/Kconfig | 72 -------- drivers/net/appletalk/Makefile | 6 - drivers/net/appletalk/ipddp.c | 345 ------------------------------------- drivers/net/appletalk/ipddp.h | 28 --- net/Kconfig | 2 +- net/appletalk/Kconfig | 30 ++++ 10 files changed, 31 insertions(+), 533 deletions(-) delete mode 100644 Documentation/networking/ipddp.rst delete mode 100644 drivers/net/appletalk/Kconfig delete mode 100644 drivers/net/appletalk/Makefile delete mode 100644 drivers/net/appletalk/ipddp.c delete mode 100644 drivers/net/appletalk/ipddp.h create mode 100644 net/appletalk/Kconfig (limited to 'Documentation') diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 5b75c3f7a137..2ffc5ad10295 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -59,7 +59,6 @@ Contents: gtp ila ioam6-sysctl - ipddp ip_dynaddr ipsec ip-sysctl diff --git a/Documentation/networking/ipddp.rst b/Documentation/networking/ipddp.rst deleted file mode 100644 index be7091b77927..000000000000 --- a/Documentation/networking/ipddp.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -========================================================= -AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation -========================================================= - -Documentation ipddp.c - -This file is written by Jay Schulist - -Introduction ------------- - -AppleTalk-IP (IPDDP) is the method computers connected to AppleTalk -networks can use to communicate via IP. AppleTalk-IP is simply IP datagrams -inside AppleTalk packets. - -Through this driver you can either allow your Linux box to communicate -IP over an AppleTalk network or you can provide IP gatewaying functions -for your AppleTalk users. - -You can currently encapsulate or decapsulate AppleTalk-IP on LocalTalk, -EtherTalk and PPPTalk. The only limit on the protocol is that of what -kernel AppleTalk layer and drivers are available. - -Each mode requires its own user space software. - -Compiling AppleTalk-IP Decapsulation/Encapsulation -================================================== - -AppleTalk-IP decapsulation needs to be compiled into your kernel. You -will need to turn on AppleTalk-IP driver support. Then you will need to -select ONE of the two options; IP to AppleTalk-IP encapsulation support or -AppleTalk-IP to IP decapsulation support. If you compile the driver -statically you will only be able to use the driver for the function you have -enabled in the kernel. If you compile the driver as a module you can -select what mode you want it to run in via a module loading param. -ipddp_mode=1 for AppleTalk-IP encapsulation and ipddp_mode=2 for -AppleTalk-IP to IP decapsulation. - -Basic instructions for user space tools -======================================= - -I will briefly describe the operation of the tools, but you will -need to consult the supporting documentation for each set of tools. - -Decapsulation - You will need to download a software package called -MacGate. In this distribution there will be a tool called MacRoute -which enables you to add routes to the kernel for your Macs by hand. -Also the tool MacRegGateWay is included to register the -proper IP Gateway and IP addresses for your machine. Included in this -distribution is a patch to netatalk-1.4b2+asun2.0a17.2 (available from -ftp.u.washington.edu/pub/user-supported/asun/) this patch is optional -but it allows automatic adding and deleting of routes for Macs. (Handy -for locations with large Mac installations) - -Encapsulation - You will need to download a software daemon called ipddpd. -This software expects there to be an AppleTalk-IP gateway on the network. -You will also need to add the proper routes to route your Linux box's IP -traffic out the ipddp interface. - -Common Uses of ipddp.c ----------------------- -Of course AppleTalk-IP decapsulation and encapsulation, but specifically -decapsulation is being used most for connecting LocalTalk networks to -IP networks. Although it has been used on EtherTalk networks to allow -Macs that are only able to tunnel IP over EtherTalk. - -Encapsulation has been used to allow a Linux box stuck on a LocalTalk -network to use IP. It should work equally well if you are stuck on an -EtherTalk only network. - -Further Assistance -------------------- -You can contact me (Jay Schulist ) with any -questions regarding decapsulation or encapsulation. Bradford W. Johnson - originally wrote the ipddp.c driver for IP -encapsulation in AppleTalk. diff --git a/MAINTAINERS b/MAINTAINERS index 1bd96045beb8..698ebbd78075 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1459,7 +1459,6 @@ F: drivers/hwmon/applesmc.c APPLETALK NETWORK LAYER L: netdev@vger.kernel.org S: Odd fixes -F: drivers/net/appletalk/ F: include/linux/atalk.h F: include/uapi/linux/atalk.h F: net/appletalk/ diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e26f98f897c5..8a83db32509d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_MHI_NET) += mhi_net.o # Networking Drivers # obj-$(CONFIG_ARCNET) += arcnet/ -obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_CAIF) += caif/ obj-$(CONFIG_CAN) += can/ obj-$(CONFIG_NET_DSA) += dsa/ diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig deleted file mode 100644 index b94f731e4576..000000000000 --- a/drivers/net/appletalk/Kconfig +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Appletalk driver configuration -# -config ATALK - tristate "Appletalk protocol support" - select LLC - help - AppleTalk is the protocol that Apple computers can use to communicate - on a network. If your Linux box is connected to such a network and you - wish to connect to it, say Y. You will need to use the netatalk package - so that your Linux box can act as a print and file server for Macs as - well as access AppleTalk printers. Check out - on the WWW for details. - EtherTalk is the name used for AppleTalk over Ethernet and the - cheaper and slower LocalTalk is AppleTalk over a proprietary Apple - network using serial links. EtherTalk and LocalTalk are fully - supported by Linux. - - General information about how to connect Linux, Windows machines and - Macs is on the WWW at . The - NET3-4-HOWTO, available from - , contains valuable - information as well. - - To compile this driver as a module, choose M here: the module will be - called appletalk. You almost certainly want to compile it as a - module so you can restart your AppleTalk stack without rebooting - your machine. I hear that the GNU boycott of Apple is over, so - even politically correct people are allowed to say Y here. - -config DEV_APPLETALK - tristate "Appletalk interfaces support" - depends on ATALK - help - AppleTalk is the protocol that Apple computers can use to communicate - on a network. If your Linux box is connected to such a network, and wish - to do IP over it, or you have a LocalTalk card and wish to use it to - connect to the AppleTalk network, say Y. - -config IPDDP - tristate "Appletalk-IP driver support" - depends on DEV_APPLETALK && ATALK - help - This allows IP networking for users who only have AppleTalk - networking available. This feature is experimental. With this - driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux - box is stuck on an AppleTalk only network) or decapsulate (e.g. if - you want your Linux box to act as an Internet gateway for a zoo of - AppleTalk connected Macs). Please see the file - for more information. - - If you say Y here, the AppleTalk-IP support will be compiled into - the kernel. In this case, you can either use encapsulation or - decapsulation, but not both. With the following two questions, you - decide which one you want. - - To compile the AppleTalk-IP support as a module, choose M here: the - module will be called ipddp. - In this case, you will be able to use both encapsulation and - decapsulation simultaneously, by loading two copies of the module - and specifying different values for the module option ipddp_mode. - -config IPDDP_ENCAP - bool "IP to Appletalk-IP Encapsulation support" - depends on IPDDP - help - If you say Y here, the AppleTalk-IP code will be able to encapsulate - IP packets inside AppleTalk frames; this is useful if your Linux box - is stuck on an AppleTalk network (which hopefully contains a - decapsulator somewhere). Please see - for more information. diff --git a/drivers/net/appletalk/Makefile b/drivers/net/appletalk/Makefile deleted file mode 100644 index d8c7b23ec7ff..000000000000 --- a/drivers/net/appletalk/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for drivers/net/appletalk -# - -obj-$(CONFIG_IPDDP) += ipddp.o diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c deleted file mode 100644 index d558535390f9..000000000000 --- a/drivers/net/appletalk/ipddp.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux - * Appletalk-IP to IP Decapsulation driver for Linux - * - * Authors: - * - DDP-IP Encap by: Bradford W. Johnson - * - DDP-IP Decap by: Jay Schulist - * - * Derived from: - * - Almost all code already existed in net/appletalk/ddp.c I just - * moved/reorginized it into a driver file. Original IP-over-DDP code - * was done by Bradford W. Johnson - * - skeleton.c: A network driver outline for linux. - * Written 1993-94 by Donald Becker. - * - dummy.c: A dummy net driver. By Nick Holloway. - * - MacGate: A user space Daemon for Appletalk-IP Decap for - * Linux by Jay Schulist - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ipddp.h" /* Our stuff */ - -static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson \n"; - -static struct ipddp_route *ipddp_route_list; -static DEFINE_SPINLOCK(ipddp_route_lock); - -#ifdef CONFIG_IPDDP_ENCAP -static int ipddp_mode = IPDDP_ENCAP; -#else -static int ipddp_mode = IPDDP_DECAP; -#endif - -/* Index to functions, as function prototypes. */ -static netdev_tx_t ipddp_xmit(struct sk_buff *skb, - struct net_device *dev); -static int ipddp_create(struct ipddp_route *new_rt); -static int ipddp_delete(struct ipddp_route *rt); -static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt); -static int ipddp_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd); - -static const struct net_device_ops ipddp_netdev_ops = { - .ndo_start_xmit = ipddp_xmit, - .ndo_siocdevprivate = ipddp_siocdevprivate, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static struct net_device * __init ipddp_init(void) -{ - static unsigned version_printed; - struct net_device *dev; - int err; - - dev = alloc_etherdev(0); - if (!dev) - return ERR_PTR(-ENOMEM); - - netif_keep_dst(dev); - strcpy(dev->name, "ipddp%d"); - - if (version_printed++ == 0) - printk(version); - - /* Initialize the device structure. */ - dev->netdev_ops = &ipddp_netdev_ops; - - dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ - dev->mtu = 585; - dev->flags |= IFF_NOARP; - - /* - * The worst case header we will need is currently a - * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1) - * We send over SNAP so that takes another 8 bytes. - */ - dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1; - - err = register_netdev(dev); - if (err) { - free_netdev(dev); - return ERR_PTR(err); - } - - /* Let the user now what mode we are in */ - if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", - dev->name); - if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", - dev->name); - - return dev; -} - - -/* - * Transmit LLAP/ELAP frame using aarp_send_ddp. - */ -static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct rtable *rtable = skb_rtable(skb); - __be32 paddr = 0; - struct ddpehdr *ddp; - struct ipddp_route *rt; - struct atalk_addr *our_addr; - - if (rtable->rt_gw_family == AF_INET) - paddr = rtable->rt_gw4; - - spin_lock(&ipddp_route_lock); - - /* - * Find appropriate route to use, based only on IP number. - */ - for(rt = ipddp_route_list; rt != NULL; rt = rt->next) - { - if(rt->ip == paddr) - break; - } - if(rt == NULL) { - spin_unlock(&ipddp_route_lock); - return NETDEV_TX_OK; - } - - our_addr = atalk_find_dev_addr(rt->dev); - - if(ipddp_mode == IPDDP_DECAP) - /* - * Pull off the excess room that should not be there. - * This is due to a hard-header problem. This is the - * quick fix for now though, till it breaks. - */ - skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); - - /* Create the Extended DDP header */ - ddp = (struct ddpehdr *)skb->data; - ddp->deh_len_hops = htons(skb->len + (1<<10)); - ddp->deh_sum = 0; - - /* - * For Localtalk we need aarp_send_ddp to strip the - * long DDP header and place a shot DDP header on it. - */ - if(rt->dev->type == ARPHRD_LOCALTLK) - { - ddp->deh_dnet = 0; /* FIXME more hops?? */ - ddp->deh_snet = 0; - } - else - { - ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */ - ddp->deh_snet = our_addr->s_net; - } - ddp->deh_dnode = rt->at.s_node; - ddp->deh_snode = our_addr->s_node; - ddp->deh_dport = 72; - ddp->deh_sport = 72; - - *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ - - skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - aarp_send_ddp(rt->dev, skb, &rt->at, NULL); - - spin_unlock(&ipddp_route_lock); - - return NETDEV_TX_OK; -} - -/* - * Create a routing entry. We first verify that the - * record does not already exist. If it does we return -EEXIST - */ -static int ipddp_create(struct ipddp_route *new_rt) -{ - struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL); - - if (rt == NULL) - return -ENOMEM; - - rt->ip = new_rt->ip; - rt->at = new_rt->at; - rt->next = NULL; - if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) { - kfree(rt); - return -ENETUNREACH; - } - - spin_lock_bh(&ipddp_route_lock); - if (__ipddp_find_route(rt)) { - spin_unlock_bh(&ipddp_route_lock); - kfree(rt); - return -EEXIST; - } - - rt->next = ipddp_route_list; - ipddp_route_list = rt; - - spin_unlock_bh(&ipddp_route_lock); - - return 0; -} - -/* - * Delete a route, we only delete a FULL match. - * If route does not exist we return -ENOENT. - */ -static int ipddp_delete(struct ipddp_route *rt) -{ - struct ipddp_route **r = &ipddp_route_list; - struct ipddp_route *tmp; - - spin_lock_bh(&ipddp_route_lock); - while((tmp = *r) != NULL) - { - if(tmp->ip == rt->ip && - tmp->at.s_net == rt->at.s_net && - tmp->at.s_node == rt->at.s_node) - { - *r = tmp->next; - spin_unlock_bh(&ipddp_route_lock); - kfree(tmp); - return 0; - } - r = &tmp->next; - } - - spin_unlock_bh(&ipddp_route_lock); - return -ENOENT; -} - -/* - * Find a routing entry, we only return a FULL match - */ -static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) -{ - struct ipddp_route *f; - - for(f = ipddp_route_list; f != NULL; f = f->next) - { - if(f->ip == rt->ip && - f->at.s_net == rt->at.s_net && - f->at.s_node == rt->at.s_node) - return f; - } - - return NULL; -} - -static int ipddp_siocdevprivate(struct net_device *dev, struct ifreq *ifr, - void __user *data, int cmd) -{ - struct ipddp_route rcp, rcp2, *rp; - - if (in_compat_syscall()) - return -EOPNOTSUPP; - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&rcp, data, sizeof(rcp))) - return -EFAULT; - - switch(cmd) - { - case SIOCADDIPDDPRT: - return ipddp_create(&rcp); - - case SIOCFINDIPDDPRT: - spin_lock_bh(&ipddp_route_lock); - rp = __ipddp_find_route(&rcp); - if (rp) { - memset(&rcp2, 0, sizeof(rcp2)); - rcp2.ip = rp->ip; - rcp2.at = rp->at; - rcp2.flags = rp->flags; - } - spin_unlock_bh(&ipddp_route_lock); - - if (rp) { - if (copy_to_user(data, &rcp2, - sizeof(struct ipddp_route))) - return -EFAULT; - return 0; - } else - return -ENOENT; - - case SIOCDELIPDDPRT: - return ipddp_delete(&rcp); - - default: - return -EINVAL; - } -} - -static struct net_device *dev_ipddp; - -MODULE_LICENSE("GPL"); -module_param(ipddp_mode, int, 0); - -static int __init ipddp_init_module(void) -{ - dev_ipddp = ipddp_init(); - return PTR_ERR_OR_ZERO(dev_ipddp); -} - -static void __exit ipddp_cleanup_module(void) -{ - struct ipddp_route *p; - - unregister_netdev(dev_ipddp); - free_netdev(dev_ipddp); - - while (ipddp_route_list) { - p = ipddp_route_list->next; - kfree(ipddp_route_list); - ipddp_route_list = p; - } -} - -module_init(ipddp_init_module); -module_exit(ipddp_cleanup_module); diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h deleted file mode 100644 index 9a8e45a46925..000000000000 --- a/drivers/net/appletalk/ipddp.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * ipddp.h: Header for IP-over-DDP driver for Linux. - */ - -#ifndef __LINUX_IPDDP_H -#define __LINUX_IPDDP_H - -#ifdef __KERNEL__ - -#define SIOCADDIPDDPRT (SIOCDEVPRIVATE) -#define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1) -#define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2) - -struct ipddp_route -{ - struct net_device *dev; /* Carrier device */ - __be32 ip; /* IP address */ - struct atalk_addr at; /* Gateway appletalk address */ - int flags; - struct ipddp_route *next; -}; - -#define IPDDP_ENCAP 1 -#define IPDDP_DECAP 2 - -#endif /* __KERNEL__ */ -#endif /* __LINUX_IPDDP_H */ diff --git a/net/Kconfig b/net/Kconfig index d532ec33f1fe..e248236c29a7 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -246,7 +246,7 @@ source "net/bridge/Kconfig" source "net/dsa/Kconfig" source "net/8021q/Kconfig" source "net/llc/Kconfig" -source "drivers/net/appletalk/Kconfig" +source "net/appletalk/Kconfig" source "net/x25/Kconfig" source "net/lapb/Kconfig" source "net/phonet/Kconfig" diff --git a/net/appletalk/Kconfig b/net/appletalk/Kconfig new file mode 100644 index 000000000000..041141abf925 --- /dev/null +++ b/net/appletalk/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Appletalk configuration +# +config ATALK + tristate "Appletalk protocol support" + select LLC + help + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network and you + wish to connect to it, say Y. You will need to use the netatalk package + so that your Linux box can act as a print and file server for Macs as + well as access AppleTalk printers. Check out + on the WWW for details. + EtherTalk is the name used for AppleTalk over Ethernet and the + cheaper and slower LocalTalk is AppleTalk over a proprietary Apple + network using serial links. EtherTalk and LocalTalk are fully + supported by Linux. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at . The + NET3-4-HOWTO, available from + , contains valuable + information as well. + + To compile this driver as a module, choose M here: the module will be + called appletalk. You almost certainly want to compile it as a + module so you can restart your AppleTalk stack without rebooting + your machine. I hear that the GNU boycott of Apple is over, so + even politically correct people are allowed to say Y here. -- cgit v1.2.3 From 0f07415ebb78e700393237b9148487a2fe27fb04 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 10 Oct 2023 09:48:10 +0200 Subject: netlink: specs: don't allow version to be specified for genetlink There is no good reason to specify the version for new protocols. Forbid it in genetlink schema. If the future proves me wrong, this restriction could be easily lifted. Move the version definition in between legacy properties in genetlink-legacy. Suggested-by: Jakub Kicinski Signed-off-by: Jiri Pirko Link: https://lore.kernel.org/r/20231010074810.191177-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 4 ---- Documentation/netlink/genetlink-legacy.yaml | 8 ++++---- Documentation/netlink/genetlink.yaml | 4 ---- 3 files changed, 4 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 32736b2d8ae8..f9366aaddd21 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -26,10 +26,6 @@ properties: type: string doc: type: string - version: - description: Generic Netlink family version. Default is 1. - type: integer - minimum: 1 protocol: description: Schema compatibility level. Default is "genetlink". enum: [ genetlink, genetlink-c ] diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 25fe1379b180..a6a490333a1a 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -26,10 +26,6 @@ properties: type: string doc: type: string - version: - description: Generic Netlink family version. Default is 1. - type: integer - minimum: 1 protocol: description: Schema compatibility level. Default is "genetlink". enum: [ genetlink, genetlink-c, genetlink-legacy ] # Trim @@ -53,6 +49,10 @@ properties: Defines if the input policy in the kernel is global, per-operation, or split per operation type. Default is split. enum: [ split, per-op, global ] + version: + description: Generic Netlink family version. Default is 1. + type: integer + minimum: 1 # End genetlink-legacy definitions: diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 6ea1c947ce51..2b788e607a14 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -26,10 +26,6 @@ properties: type: string doc: type: string - version: - description: Generic Netlink family version. Default is 1. - type: integer - minimum: 1 protocol: description: Schema compatibility level. Default is "genetlink". enum: [ genetlink ] -- cgit v1.2.3 From 3243fef6a4c0db2dbb01ee3cf30bd787e65b8d56 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 11 Oct 2023 20:51:09 +0200 Subject: documentation/bpf: Document cgroup unix socket address hooks Update the documentation to mention the new cgroup unix sockaddr hooks. Signed-off-by: Daan De Meyer Link: https://lore.kernel.org/r/20231011185113.140426-8-daan.j.demeyer@gmail.com Signed-off-by: Martin KaFai Lau --- Documentation/bpf/libbpf/program_types.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/bpf/libbpf/program_types.rst b/Documentation/bpf/libbpf/program_types.rst index ad4d4d5eecb0..63bb88846e50 100644 --- a/Documentation/bpf/libbpf/program_types.rst +++ b/Documentation/bpf/libbpf/program_types.rst @@ -56,6 +56,16 @@ described in more detail in the footnotes. | | ``BPF_CGROUP_UDP6_RECVMSG`` | ``cgroup/recvmsg6`` | | + +----------------------------------------+----------------------------------+-----------+ | | ``BPF_CGROUP_UDP6_SENDMSG`` | ``cgroup/sendmsg6`` | | +| +----------------------------------------+----------------------------------+-----------+ +| | ``BPF_CGROUP_UNIX_CONNECT`` | ``cgroup/connect_unix`` | | +| +----------------------------------------+----------------------------------+-----------+ +| | ``BPF_CGROUP_UNIX_SENDMSG`` | ``cgroup/sendmsg_unix`` | | +| +----------------------------------------+----------------------------------+-----------+ +| | ``BPF_CGROUP_UNIX_RECVMSG`` | ``cgroup/recvmsg_unix`` | | +| +----------------------------------------+----------------------------------+-----------+ +| | ``BPF_CGROUP_UNIX_GETPEERNAME`` | ``cgroup/getpeername_unix`` | | +| +----------------------------------------+----------------------------------+-----------+ +| | ``BPF_CGROUP_UNIX_GETSOCKNAME`` | ``cgroup/getsockname_unix`` | | +-------------------------------------------+----------------------------------------+----------------------------------+-----------+ | ``BPF_PROG_TYPE_CGROUP_SOCK`` | ``BPF_CGROUP_INET4_POST_BIND`` | ``cgroup/post_bind4`` | | + +----------------------------------------+----------------------------------+-----------+ -- cgit v1.2.3 From 7eeb84d89f2e561ac5b97e0142c029908ddf00d5 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 12 Oct 2023 04:14:01 -0700 Subject: Documentation: netconsole: add support for cmdline targets With the previous patches, there is no more limitation at modifying the targets created at boot time (or module load time). Document the way on how to create the configfs directories to be able to modify these netconsole targets. The design discussion about this topic could be found at: https://lore.kernel.org/all/ZRWRal5bW93px4km@gmail.com/ Signed-off-by: Breno Leitao Link: https://lore.kernel.org/r/20231012111401.333798-5-leitao@debian.org Signed-off-by: Jakub Kicinski --- Documentation/networking/netconsole.rst | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst index 7a9de0568e84..390730a74332 100644 --- a/Documentation/networking/netconsole.rst +++ b/Documentation/networking/netconsole.rst @@ -99,9 +99,6 @@ Dynamic reconfiguration: Dynamic reconfigurability is a useful addition to netconsole that enables remote logging targets to be dynamically added, removed, or have their parameters reconfigured at runtime from a configfs-based userspace interface. -[ Note that the parameters of netconsole targets that were specified/created -from the boot/module option are not exposed via this interface, and hence -cannot be modified dynamically. ] To include this feature, select CONFIG_NETCONSOLE_DYNAMIC when building the netconsole module (or kernel, if netconsole is built-in). @@ -155,6 +152,25 @@ You can also update the local interface dynamically. This is especially useful if you want to use interfaces that have newly come up (and may not have existed when netconsole was loaded / initialized). +Netconsole targets defined at boot time (or module load time) with the +`netconsole=` param are assigned the name `cmdline`. For example, the +first target in the parameter is named `cmdline0`. You can control and modify +these targets by creating configfs directories with the matching name. + +Let's suppose you have two netconsole targets defined at boot time:: + + netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc;4444@10.0.0.1/eth1,9353@10.0.0.3/12:34:56:78:9a:bc + +You can modify these targets in runtime by creating the following targets:: + + mkdir cmdline0 + cat cmdline0/remote_ip + 10.0.0.2 + + mkdir cmdline1 + cat cmdline1/remote_ip + 10.0.0.3 + Extended console: ================= -- cgit v1.2.3 From 58cd34772a30d5cbe9fec7d199772149946a4032 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 12 Oct 2023 12:27:42 -0700 Subject: net/mlx5: fix config name in Kconfig parameter documentation Commit a12ba19269d7 ("net/mlx5: Update Kconfig parameter documentation") adds documentation on Kconfig options for the mlx5 driver. It refers to the config MLX5_EN_MACSEC for MACSec offloading, but the config is actually called MLX5_MACSEC. Fix the reference to the right config name in the documentation. Signed-off-by: Lukas Bulwahn Signed-off-by: Saeed Mahameed --- .../networking/device_drivers/ethernet/mellanox/mlx5/kconfig.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/kconfig.rst b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/kconfig.rst index 0a42c3395ffa..20d3b7e87049 100644 --- a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/kconfig.rst +++ b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/kconfig.rst @@ -67,7 +67,7 @@ Enabling the driver and kconfig options | Enables :ref:`IPSec XFRM cryptography-offload acceleration `. -**CONFIG_MLX5_EN_MACSEC=(y/n)** +**CONFIG_MLX5_MACSEC=(y/n)** | Build support for MACsec cryptography-offload acceleration in the NIC. -- cgit v1.2.3 From bac2cac12c266755fa4b933d88e70bc18580b80f Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Tue, 10 Oct 2023 22:15:21 +0300 Subject: docs: net: description of MSG_ZEROCOPY for AF_VSOCK This adds description of MSG_ZEROCOPY flag support for AF_VSOCK type of socket. Signed-off-by: Arseniy Krasnov Reviewed-by: Stefano Garzarella Signed-off-by: David S. Miller --- Documentation/networking/msg_zerocopy.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/msg_zerocopy.rst b/Documentation/networking/msg_zerocopy.rst index b3ea96af9b49..78fb70e748b7 100644 --- a/Documentation/networking/msg_zerocopy.rst +++ b/Documentation/networking/msg_zerocopy.rst @@ -7,7 +7,8 @@ Intro ===== The MSG_ZEROCOPY flag enables copy avoidance for socket send calls. -The feature is currently implemented for TCP and UDP sockets. +The feature is currently implemented for TCP, UDP and VSOCK (with +virtio transport) sockets. Opportunity and Caveats @@ -174,7 +175,9 @@ read_notification() call in the previous snippet. A notification is encoded in the standard error format, sock_extended_err. The level and type fields in the control data are protocol family -specific, IP_RECVERR or IPV6_RECVERR. +specific, IP_RECVERR or IPV6_RECVERR (for TCP or UDP socket). +For VSOCK socket, cmsg_level will be SOL_VSOCK and cmsg_type will be +VSOCK_RECVERR. Error origin is the new type SO_EE_ORIGIN_ZEROCOPY. ee_errno is zero, as explained before, to avoid blocking read and write system calls on @@ -235,12 +238,15 @@ Implementation Loopback -------- +For TCP and UDP: Data sent to local sockets can be queued indefinitely if the receive process does not read its socket. Unbound notification latency is not acceptable. For this reason all packets generated with MSG_ZEROCOPY that are looped to a local socket will incur a deferred copy. This includes looping onto packet sockets (e.g., tcpdump) and tun devices. +For VSOCK: +Data path sent to local sockets is the same as for non-local sockets. Testing ======= @@ -254,3 +260,6 @@ instance when run with msg_zerocopy.sh between a veth pair across namespaces, the test will not show any improvement. For testing, the loopback restriction can be temporarily relaxed by making skb_orphan_frags_rx identical to skb_orphan_frags. + +For VSOCK type of socket example can be found in +tools/testing/vsock/vsock_test_zerocopy.c. -- cgit v1.2.3 From 6e55b1cbf05dca4651692be6c59acb7b20186653 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 10 Oct 2023 19:42:24 -0700 Subject: docs: try to encourage (netdev?) reviewers Add a section to netdev maintainer doc encouraging reviewers to chime in on the mailing list. The questions about "when is it okay to share feedback" keep coming up (most recently at netconf) and the answer is "pretty much always". Extend the section of 7.AdvancedTopics.rst which deals with reviews a little bit to add stuff we had been recommending locally. Signed-off-by: Jakub Kicinski Reviewed-by: Florian Fainelli Reviewed-by: Martin Habets Signed-off-by: David S. Miller --- Documentation/process/7.AdvancedTopics.rst | 18 ++++++++++++++++++ Documentation/process/maintainer-netdev.rst | 15 +++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'Documentation') diff --git a/Documentation/process/7.AdvancedTopics.rst b/Documentation/process/7.AdvancedTopics.rst index bf7cbfb4caa5..43291704338e 100644 --- a/Documentation/process/7.AdvancedTopics.rst +++ b/Documentation/process/7.AdvancedTopics.rst @@ -146,6 +146,7 @@ pull. The git request-pull command can be helpful in this regard; it will format the request as other developers expect, and will also check to be sure that you have remembered to push those changes to the public server. +.. _development_advancedtopics_reviews: Reviewing patches ----------------- @@ -167,6 +168,12 @@ comments as questions rather than criticisms. Asking "how does the lock get released in this path?" will always work better than stating "the locking here is wrong." +Another technique that is useful in case of a disagreement is to ask for others +to chime in. If a discussion reaches a stalemate after a few exchanges, +then call for opinions of other reviewers or maintainers. Often those in +agreement with a reviewer remain silent unless called upon. +The opinion of multiple people carries exponentially more weight. + Different developers will review code from different points of view. Some are mostly concerned with coding style and whether code lines have trailing white space. Others will focus primarily on whether the change implemented @@ -176,3 +183,14 @@ security issues, duplication of code found elsewhere, adequate documentation, adverse effects on performance, user-space ABI changes, etc. All types of review, if they lead to better code going into the kernel, are welcome and worthwhile. + +There is no strict requirement to use specific tags like ``Reviewed-by``. +In fact reviews in plain English are more informative and encouraged +even when a tag is provided, e.g. "I looked at aspects A, B and C of this +submission and it looks good to me." +Some form of a review message or reply is obviously necessary otherwise +maintainers will not know that the reviewer has looked at the patch at all! + +Last but not least patch review may become a negative process, focused +on pointing out problems. Please throw in a compliment once in a while, +particularly for newbies! diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst index 09dcf6377c27..7feacc20835e 100644 --- a/Documentation/process/maintainer-netdev.rst +++ b/Documentation/process/maintainer-netdev.rst @@ -441,6 +441,21 @@ in a way which would break what would normally be considered uAPI. new ``netdevsim`` features must be accompanied by selftests under ``tools/testing/selftests/``. +Reviewer guidance +----------------- + +Reviewing other people's patches on the list is highly encouraged, +regardless of the level of expertise. For general guidance and +helpful tips please see :ref:`development_advancedtopics_reviews`. + +It's safe to assume that netdev maintainers know the community and the level +of expertise of the reviewers. The reviewers should not be concerned about +their comments impeding or derailing the patch flow. + +Less experienced reviewers are highly encouraged to do more in-depth +review of submissions and not focus exclusively on trivial or subjective +matters like code formatting, tags etc. + Testimonials / feedback ----------------------- -- cgit v1.2.3 From 27ed30d1f861315719bd8c2b2e81576d71750331 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 11 Oct 2023 12:12:32 +0200 Subject: dpll: docs: add support for pin signal phase offset/adjust Add documentation on: - measurement of phase of signal between pin and dpll - adjustment of pin signal phase Signed-off-by: Arkadiusz Kubalewski Signed-off-by: David S. Miller --- Documentation/driver-api/dpll.rst | 53 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/dpll.rst b/Documentation/driver-api/dpll.rst index 69670deb8c4e..e3d593841aa7 100644 --- a/Documentation/driver-api/dpll.rst +++ b/Documentation/driver-api/dpll.rst @@ -173,6 +173,47 @@ in order to configure active input of a MUX-type pin, the user needs to request desired pin state of the child pin on the parent pin, as described in the ``MUX-type pins`` chapter. +Phase offset measurement and adjustment +======================================== + +Device may provide ability to measure a phase difference between signals +on a pin and its parent dpll device. If pin-dpll phase offset measurement +is supported, it shall be provided with ``DPLL_A_PIN_PHASE_OFFSET`` +attribute for each parent dpll device. + +Device may also provide ability to adjust a signal phase on a pin. +If pin phase adjustment is supported, minimal and maximal values that pin +handle shall be provide to the user on ``DPLL_CMD_PIN_GET`` respond +with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and ``DPLL_A_PIN_PHASE_ADJUST_MAX`` +attributes. Configured phase adjust value is provided with +``DPLL_A_PIN_PHASE_ADJUST`` attribute of a pin, and value change can be +requested with the same attribute with ``DPLL_CMD_PIN_SET`` command. + + =============================== ====================================== + ``DPLL_A_PIN_ID`` configured pin id + ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment + ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment + ``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase + adjustment on parent dpll device + ``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting + configuration on given parent dpll + device + ``DPLL_A_PIN_PARENT_ID`` parent dpll device id + ``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference + between a pin and parent dpll device + =============================== ====================================== + +All phase related values are provided in pico seconds, which represents +time difference between signals phase. The negative value means that +phase of signal on pin is earlier in time than dpll's signal. Positive +value means that phase of signal on pin is later in time than signal of +a dpll. + +Phase adjust (also min and max) values are integers, but measured phase +offset values are fractional with 3-digit decimal places and shell be +divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and +modulo divided to get fractional part. + Configuration commands group ============================ @@ -263,6 +304,12 @@ according to attribute purpose. frequencies ``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency ``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency + ``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase + adjustment + ``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase + adjustment + ``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase + adjustment on parent device ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device the pin is connected with ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id @@ -270,8 +317,10 @@ according to attribute purpose. dpll device ``DPLL_A_PIN_STATE`` attr state of pin on the parent dpll device - ``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the + ``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the parent dpll device + ``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference + between a pin and parent dpll ``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin the pin is connected with ``DPLL_A_PIN_PARENT_ID`` attr parent pin id @@ -284,6 +333,8 @@ according to attribute purpose. ``DPLL_CMD_PIN_SET`` command to set pins configuration ``DPLL_A_PIN_ID`` attr unique a pin ID ``DPLL_A_PIN_FREQUENCY`` attr requested frequency of a pin + ``DPLL_A_PIN_PHASE_ADJUST`` attr requested value of phase + adjustment on parent device ``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent dpll device configuration request ``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id -- cgit v1.2.3 From c3c6ab95c397134bf5948f18743b3ba8008e7c47 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kubalewski Date: Wed, 11 Oct 2023 12:12:33 +0200 Subject: dpll: spec: add support for pin-dpll signal phase offset/adjust Add attributes for providing the user with: - measurement of signals phase offset between pin and dpll - ability to adjust the phase of pin signal Signed-off-by: Arkadiusz Kubalewski Signed-off-by: David S. Miller --- Documentation/netlink/specs/dpll.yaml | 30 ++++++++++++++++++++++++++++++ drivers/dpll/dpll_nl.c | 8 +++++--- drivers/dpll/dpll_nl.h | 2 +- include/uapi/linux/dpll.h | 6 ++++++ 4 files changed, 42 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index 1c1b53136c7b..cf8abe1c0550 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -164,6 +164,18 @@ definitions: - name: state-can-change doc: pin state can be changed + - + type: const + name: phase-offset-divider + value: 1000 + doc: | + phase offset divider allows userspace to calculate a value of + measured signal phase difference between a pin and dpll device + as a fractional value with three digit decimal precision. + Value of (DPLL_A_PHASE_OFFSET / DPLL_PHASE_OFFSET_DIVIDER) is an + integer part of a measured phase offset value. + Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a + fractional part of a measured phase offset value. attribute-sets: - @@ -272,6 +284,18 @@ attribute-sets: type: nest multi-attr: true nested-attributes: pin-parent-pin + - + name: phase-adjust-min + type: s32 + - + name: phase-adjust-max + type: s32 + - + name: phase-adjust + type: s32 + - + name: phase-offset + type: s64 - name: pin-parent-device subset-of: pin @@ -284,6 +308,8 @@ attribute-sets: name: prio - name: state + - + name: phase-offset - name: pin-parent-pin subset-of: pin @@ -431,6 +457,9 @@ operations: - capabilities - parent-device - parent-pin + - phase-adjust-min + - phase-adjust-max + - phase-adjust dump: pre: dpll-lock-dumpit @@ -458,6 +487,7 @@ operations: - state - parent-device - parent-pin + - phase-adjust - name: pin-create-ntf doc: Notification about pin appearing diff --git a/drivers/dpll/dpll_nl.c b/drivers/dpll/dpll_nl.c index 14064c8c783b..eaee5be7aa64 100644 --- a/drivers/dpll/dpll_nl.c +++ b/drivers/dpll/dpll_nl.c @@ -11,11 +11,12 @@ #include /* Common nested types */ -const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1] = { +const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1] = { [DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, }, [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), [DPLL_A_PIN_PRIO] = { .type = NLA_U32, }, [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), + [DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, }, }; const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = { @@ -61,7 +62,7 @@ static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] = }; /* DPLL_CMD_PIN_SET - do */ -static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT_PIN + 1] = { +static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1] = { [DPLL_A_PIN_ID] = { .type = NLA_U32, }, [DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, }, [DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2), @@ -69,6 +70,7 @@ static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PARENT_PIN + 1] [DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3), [DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy), [DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy), + [DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, }, }; /* Ops table for dpll */ @@ -140,7 +142,7 @@ static const struct genl_split_ops dpll_nl_ops[] = { .doit = dpll_nl_pin_set_doit, .post_doit = dpll_pin_post_doit, .policy = dpll_pin_set_nl_policy, - .maxattr = DPLL_A_PIN_PARENT_PIN, + .maxattr = DPLL_A_PIN_PHASE_ADJUST, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, }; diff --git a/drivers/dpll/dpll_nl.h b/drivers/dpll/dpll_nl.h index 1f67aaed4742..92d4c9c4f788 100644 --- a/drivers/dpll/dpll_nl.h +++ b/drivers/dpll/dpll_nl.h @@ -12,7 +12,7 @@ #include /* Common nested types */ -extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1]; +extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_OFFSET + 1]; extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1]; int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb, diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 20ef0718f8dc..715a491d2727 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -138,6 +138,8 @@ enum dpll_pin_capabilities { DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE = 4, }; +#define DPLL_PHASE_OFFSET_DIVIDER 1000 + enum dpll_a { DPLL_A_ID = 1, DPLL_A_MODULE_NAME, @@ -173,6 +175,10 @@ enum dpll_a_pin { DPLL_A_PIN_CAPABILITIES, DPLL_A_PIN_PARENT_DEVICE, DPLL_A_PIN_PARENT_PIN, + DPLL_A_PIN_PHASE_ADJUST_MIN, + DPLL_A_PIN_PHASE_ADJUST_MAX, + DPLL_A_PIN_PHASE_ADJUST, + DPLL_A_PIN_PHASE_OFFSET, __DPLL_A_PIN_MAX, DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) -- cgit v1.2.3 From 562b1fdf061bff9394ccd884456ed1173c224fdc Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Wed, 11 Oct 2023 13:30:44 -0700 Subject: tcp: Set pingpong threshold via sysctl TCP pingpong threshold is 1 by default. But some applications, like SQL DB may prefer a higher pingpong threshold to activate delayed acks in quick ack mode for better performance. The pingpong threshold and related code were changed to 3 in the year 2019 in: commit 4a41f453bedf ("tcp: change pingpong threshold to 3") And reverted to 1 in the year 2022 in: commit 4d8f24eeedc5 ("Revert "tcp: change pingpong threshold to 3"") There is no single value that fits all applications. Add net.ipv4.tcp_pingpong_thresh sysctl tunable, so it can be tuned for optimal performance based on the application needs. Signed-off-by: Haiyang Zhang Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Acked-by: Neal Cardwell Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/1697056244-21888-1-git-send-email-haiyangz@microsoft.com Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 13 +++++++++++++ include/net/inet_connection_sock.h | 16 ++++++++++++---- include/net/netns/ipv4.h | 2 ++ net/ipv4/sysctl_net_ipv4.c | 8 ++++++++ net/ipv4/tcp_ipv4.c | 2 ++ net/ipv4/tcp_output.c | 4 ++-- 6 files changed, 39 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index f7dfde3b09a9..e7ec9026e5db 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -1183,6 +1183,19 @@ tcp_plb_cong_thresh - INTEGER Default: 128 +tcp_pingpong_thresh - INTEGER + The number of estimated data replies sent for estimated incoming data + requests that must happen before TCP considers that a connection is a + "ping-pong" (request-response) connection for which delayed + acknowledgments can provide benefits. + + This threshold is 1 by default, but some applications may need a higher + threshold for optimal performance. + + Possible Values: 1 - 255 + + Default: 1 + UDP variables ============= diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index d6d9d1c1985a..086d1193c9ef 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -328,11 +328,10 @@ void inet_csk_update_fastreuse(struct inet_bind_bucket *tb, struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu); -#define TCP_PINGPONG_THRESH 1 - static inline void inet_csk_enter_pingpong_mode(struct sock *sk) { - inet_csk(sk)->icsk_ack.pingpong = TCP_PINGPONG_THRESH; + inet_csk(sk)->icsk_ack.pingpong = + READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_pingpong_thresh); } static inline void inet_csk_exit_pingpong_mode(struct sock *sk) @@ -342,7 +341,16 @@ static inline void inet_csk_exit_pingpong_mode(struct sock *sk) static inline bool inet_csk_in_pingpong_mode(struct sock *sk) { - return inet_csk(sk)->icsk_ack.pingpong >= TCP_PINGPONG_THRESH; + return inet_csk(sk)->icsk_ack.pingpong >= + READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_pingpong_thresh); +} + +static inline void inet_csk_inc_pingpong_cnt(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (icsk->icsk_ack.pingpong < U8_MAX) + icsk->icsk_ack.pingpong++; } static inline bool inet_csk_has_ulp(const struct sock *sk) diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index d96d05b08819..73f43f699199 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -133,6 +133,8 @@ struct netns_ipv4 { u8 sysctl_tcp_migrate_req; u8 sysctl_tcp_comp_sack_nr; u8 sysctl_tcp_backlog_ack_defer; + u8 sysctl_tcp_pingpong_thresh; + int sysctl_tcp_reordering; u8 sysctl_tcp_retries1; u8 sysctl_tcp_retries2; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index e7f024d93572..f63a545a7374 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1498,6 +1498,14 @@ static struct ctl_table ipv4_net_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, + { + .procname = "tcp_pingpong_thresh", + .data = &init_net.ipv4.sysctl_tcp_pingpong_thresh, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ONE, + }, { } }; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a441740616d7..f603ad9307af 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3288,6 +3288,8 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.sysctl_tcp_syn_linear_timeouts = 4; net->ipv4.sysctl_tcp_shrink_window = 0; + net->ipv4.sysctl_tcp_pingpong_thresh = 1; + return 0; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index d5961a82a9e8..8e6ebf35ed58 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -170,10 +170,10 @@ static void tcp_event_data_sent(struct tcp_sock *tp, tp->lsndtime = now; /* If it is a reply for ato after last received - * packet, enter pingpong mode. + * packet, increase pingpong count. */ if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato) - inet_csk_enter_pingpong_mode(sk); + inet_csk_inc_pingpong_cnt(sk); } /* Account for an ACK we sent. */ -- cgit v1.2.3 From ee71d6d5f18b55cbba20c84cce13519f7bb509e6 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 13 Oct 2023 12:06:23 +0800 Subject: dt-bindings: i3c: Add mctp-controller property This property is used to describe a I3C bus with attached MCTP I3C target devices. Signed-off-by: Matt Johnston Reviewed-by: Krzysztof Kozlowski Acked-by: Alexandre Belloni Signed-off-by: Paolo Abeni --- Documentation/devicetree/bindings/i3c/i3c.yaml | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i3c/i3c.yaml b/Documentation/devicetree/bindings/i3c/i3c.yaml index ab69f4115de4..d9483fbd2454 100644 --- a/Documentation/devicetree/bindings/i3c/i3c.yaml +++ b/Documentation/devicetree/bindings/i3c/i3c.yaml @@ -55,6 +55,12 @@ properties: May not be supported by all controllers. + mctp-controller: + type: boolean + description: | + Indicates that the system is accessible via this bus as an endpoint for + MCTP over I3C transport. + required: - "#address-cells" - "#size-cells" -- cgit v1.2.3 From b6f9774719e5601b32f47021b40fee446b356490 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 16 Oct 2023 16:42:53 +0100 Subject: net: phylink: provide mac_get_caps() method Provide a new method, mac_get_caps() to get the MAC capabilities for the specified interface mode. This is for MACs which have special requirements, such as not supporting half-duplex in certain interface modes, and will replace the validate() method. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qsPk5-009wiX-G5@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- Documentation/networking/sfp-phylink.rst | 7 +++++++ drivers/net/phy/phylink.c | 14 +++++++++++--- include/linux/phylink.h | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/sfp-phylink.rst b/Documentation/networking/sfp-phylink.rst index 55b65f607a64..b069d34d7f5c 100644 --- a/Documentation/networking/sfp-phylink.rst +++ b/Documentation/networking/sfp-phylink.rst @@ -200,6 +200,13 @@ this documentation. when the in-band link state changes - otherwise the link will never come up. + The :c:func:`mac_get_caps` method is optional, and if provided should + return the phylink MAC capabilities that are supported for the passed + ``interface`` mode. In general, there is no need to implement this method. + Phylink will use these capabilities in combination with permissible + capabilities for ``interface`` to determine the allowable ethtool link + modes. + The :c:func:`validate` method should mask the supplied supported mask, and ``state->advertising`` with the supported ethtool link modes. These are the new ethtool link modes, so bitmask operations must be diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 0d7354955d62..f5c2ba15d701 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -657,6 +657,7 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, unsigned long *supported, struct phylink_link_state *state) { + unsigned long capabilities; struct phylink_pcs *pcs; int ret; @@ -696,10 +697,17 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, } /* Then validate the link parameters with the MAC */ - if (pl->mac_ops->validate) + if (pl->mac_ops->validate) { pl->mac_ops->validate(pl->config, supported, state); - else - phylink_generic_validate(pl->config, supported, state); + } else { + if (pl->mac_ops->mac_get_caps) + capabilities = pl->mac_ops->mac_get_caps(pl->config, + state->interface); + else + capabilities = pl->config->mac_capabilities; + + phylink_validate_mask_caps(supported, state, capabilities); + } return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; } diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 2b886ea654bb..0798198a09ef 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -228,6 +228,7 @@ void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed); /** * struct phylink_mac_ops - MAC operations structure. * @validate: Validate and update the link configuration. + * @mac_get_caps: Get MAC capabilities for interface mode. * @mac_select_pcs: Select a PCS for the interface mode. * @mac_prepare: prepare for a major reconfiguration of the interface. * @mac_config: configure the MAC for the selected mode and state. @@ -241,6 +242,8 @@ struct phylink_mac_ops { void (*validate)(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); + unsigned long (*mac_get_caps)(struct phylink_config *config, + phy_interface_t interface); struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config, phy_interface_t interface); int (*mac_prepare)(struct phylink_config *config, unsigned int mode, @@ -292,6 +295,18 @@ struct phylink_mac_ops { */ void validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); +/** + * mac_get_caps: Get MAC capabilities for interface mode. + * @config: a pointer to a &struct phylink_config. + * @interface: PHY interface mode. + * + * Optional method. When not provided, config->mac_capabilities will be used. + * When implemented, this returns the MAC capabilities for the specified + * interface mode where there is some special handling required by the MAC + * driver (e.g. not supporting half-duplex in certain interface modes.) + */ +unsigned long mac_get_caps(struct phylink_config *config, + phy_interface_t interface); /** * mac_select_pcs: Select a PCS for the interface mode. * @config: a pointer to a &struct phylink_config. -- cgit v1.2.3 From da5f6b80ad6417f7cf50d273c1c0ecb885e511e8 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 16 Oct 2023 16:43:03 +0100 Subject: net: phylink: remove .validate() method The MAC .validate() method is no longer used, so remove it from the phylink_mac_ops structure, and remove the callsite in phylink_validate_mac_and_pcs(). Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qsPkF-009wij-QM@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- Documentation/networking/sfp-phylink.rst | 5 ----- drivers/net/phy/phylink.c | 16 +++++--------- include/linux/phylink.h | 38 -------------------------------- 3 files changed, 6 insertions(+), 53 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/sfp-phylink.rst b/Documentation/networking/sfp-phylink.rst index b069d34d7f5c..8054d33f449f 100644 --- a/Documentation/networking/sfp-phylink.rst +++ b/Documentation/networking/sfp-phylink.rst @@ -207,11 +207,6 @@ this documentation. capabilities for ``interface`` to determine the allowable ethtool link modes. - The :c:func:`validate` method should mask the supplied supported mask, - and ``state->advertising`` with the supported ethtool link modes. - These are the new ethtool link modes, so bitmask operations must be - used. For an example, see ``drivers/net/ethernet/marvell/mvneta.c``. - The :c:func:`mac_link_state` method is used to read the link state from the MAC, and report back the settings that the MAC is currently using. This is particularly important for in-band negotiation diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index f5c2ba15d701..1c7e73fa58e4 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -697,17 +697,13 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, } /* Then validate the link parameters with the MAC */ - if (pl->mac_ops->validate) { - pl->mac_ops->validate(pl->config, supported, state); - } else { - if (pl->mac_ops->mac_get_caps) - capabilities = pl->mac_ops->mac_get_caps(pl->config, - state->interface); - else - capabilities = pl->config->mac_capabilities; + if (pl->mac_ops->mac_get_caps) + capabilities = pl->mac_ops->mac_get_caps(pl->config, + state->interface); + else + capabilities = pl->config->mac_capabilities; - phylink_validate_mask_caps(supported, state, capabilities); - } + phylink_validate_mask_caps(supported, state, capabilities); return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; } diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 0798198a09ef..0cf559bae1ff 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -227,7 +227,6 @@ void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed); /** * struct phylink_mac_ops - MAC operations structure. - * @validate: Validate and update the link configuration. * @mac_get_caps: Get MAC capabilities for interface mode. * @mac_select_pcs: Select a PCS for the interface mode. * @mac_prepare: prepare for a major reconfiguration of the interface. @@ -239,9 +238,6 @@ void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed); * The individual methods are described more fully below. */ struct phylink_mac_ops { - void (*validate)(struct phylink_config *config, - unsigned long *supported, - struct phylink_link_state *state); unsigned long (*mac_get_caps)(struct phylink_config *config, phy_interface_t interface); struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config, @@ -261,40 +257,6 @@ struct phylink_mac_ops { }; #if 0 /* For kernel-doc purposes only. */ -/** - * validate - Validate and update the link configuration - * @config: a pointer to a &struct phylink_config. - * @supported: ethtool bitmask for supported link modes. - * @state: a pointer to a &struct phylink_link_state. - * - * Clear bits in the @supported and @state->advertising masks that - * are not supportable by the MAC. - * - * Note that the PHY may be able to transform from one connection - * technology to another, so, eg, don't clear 1000BaseX just - * because the MAC is unable to BaseX mode. This is more about - * clearing unsupported speeds and duplex settings. The port modes - * should not be cleared; phylink_set_port_modes() will help with this. - * - * When @config->supported_interfaces has been set, phylink will iterate - * over the supported interfaces to determine the full capability of the - * MAC. The validation function must not print errors if @state->interface - * is set to an unexpected value. - * - * When @config->supported_interfaces is empty, phylink will call this - * function with @state->interface set to %PHY_INTERFACE_MODE_NA, and - * expects the MAC driver to return all supported link modes. - * - * If the @state->interface mode is not supported, then the @supported - * mask must be cleared. - * - * This member is optional; if not set, the generic validator will be - * used making use of @config->mac_capabilities and - * @config->supported_interfaces to determine which link modes are - * supported. - */ -void validate(struct phylink_config *config, unsigned long *supported, - struct phylink_link_state *state); /** * mac_get_caps: Get MAC capabilities for interface mode. * @config: a pointer to a &struct phylink_config. -- cgit v1.2.3 From 5294df643ba6bfee5c70208f0318acd404c2e27d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 16 Oct 2023 14:45:40 -0700 Subject: docs: netlink: clean up after deprecating version Jiri moved version to legacy specs in commit 0f07415ebb78 ("netlink: specs: don't allow version to be specified for genetlink"). Update the documentation. Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20231016214540.1822392-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/userspace-api/netlink/genetlink-legacy.rst | 14 ++++++++++++++ Documentation/userspace-api/netlink/specs.rst | 5 ----- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/netlink/genetlink-legacy.rst b/Documentation/userspace-api/netlink/genetlink-legacy.rst index 40b82ad5d54a..0b3febd57ff5 100644 --- a/Documentation/userspace-api/netlink/genetlink-legacy.rst +++ b/Documentation/userspace-api/netlink/genetlink-legacy.rst @@ -11,6 +11,20 @@ the ``genetlink-legacy`` protocol level. Specification ============= +Globals +------- + +Attributes listed directly at the root level of the spec file. + +version +~~~~~~~ + +Generic Netlink family version, default is 1. + +``version`` has historically been used to introduce family changes +which may break backwards compatibility. Since compatibility breaking changes +are generally not allowed ``version`` is very rarely used. + Attribute type nests -------------------- diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/userspace-api/netlink/specs.rst index cc4e2430997e..40dd7442d2c3 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -86,11 +86,6 @@ name Name of the family. Name identifies the family in a unique way, since the Family IDs are allocated dynamically. -version -~~~~~~~ - -Generic Netlink family version, default is 1. - protocol ~~~~~~~~ -- cgit v1.2.3 From b6f23b319aadae50a03b06c3067bc7e4a659e43b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 13 Oct 2023 14:10:27 +0200 Subject: Documentation: devlink: add nested instance section Add a part talking about nested devlink instances describing the helpers and locking ordering. Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- Documentation/networking/devlink/index.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'Documentation') diff --git a/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst index b49749e2b9a6..52e52a1b603d 100644 --- a/Documentation/networking/devlink/index.rst +++ b/Documentation/networking/devlink/index.rst @@ -18,6 +18,30 @@ netlink commands. Drivers are encouraged to use the devlink instance lock for their own needs. +Nested instances +---------------- + +Some objects, like linecards or port functions, could have another +devlink instances created underneath. In that case, drivers should make +sure to respect following rules: + + - Lock ordering should be maintained. If driver needs to take instance + lock of both nested and parent instances at the same time, devlink + instance lock of the parent instance should be taken first, only then + instance lock of the nested instance could be taken. + - Driver should use object-specific helpers to setup the + nested relationship: + + - ``devl_nested_devlink_set()`` - called to setup devlink -> nested + devlink relationship (could be user for multiple nested instances. + - ``devl_port_fn_devlink_set()`` - called to setup port function -> + nested devlink relationship. + - ``devlink_linecard_nested_dl_set()`` - called to setup linecard -> + nested devlink relationship. + +The nested devlink info is exposed to the userspace over object-specific +attributes of devlink netlink. + Interface documentation ----------------------- -- cgit v1.2.3 From bb11cf9b2c4a21f6d1533ffd28feb0ef1fd659bb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 13 Oct 2023 14:10:28 +0200 Subject: Documentation: devlink: add a note about RTNL lock into locking section Add a note describing the locking order of taking RTNL lock with devlink instance lock. Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- Documentation/networking/devlink/index.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst index 52e52a1b603d..2884ad243b54 100644 --- a/Documentation/networking/devlink/index.rst +++ b/Documentation/networking/devlink/index.rst @@ -18,6 +18,10 @@ netlink commands. Drivers are encouraged to use the devlink instance lock for their own needs. +Drivers need to be cautious when taking devlink instance lock and +taking RTNL lock at the same time. Devlink instance lock needs to be taken +first, only after that RTNL lock could be taken. + Nested instances ---------------- -- cgit v1.2.3 From 0e133a13370389d3894891eafe54fec2c44ad735 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Tue, 17 Oct 2023 20:30:20 +0000 Subject: bpf, docs: Define signed modulo as using truncated division There's different mathematical definitions (truncated, floored, rounded, etc.) and different languages have chosen different definitions [0][1]. E.g., languages/libraries that follow Knuth use a different mathematical definition than C uses. This patch specifies which definition BPF uses, as verified by Eduard [2] and others. [0] https://en.wikipedia.org/wiki/Modulo#Variants_of_the_definition [1] https://torstencurdt.com/tech/posts/modulo-of-negative-numbers/ [2] https://lore.kernel.org/bpf/57e6fefadaf3b2995bb259fa8e711c7220ce5290.camel@gmail.com/ Signed-off-by: Dave Thaler Signed-off-by: Daniel Borkmann Acked-by: David Vernet Acked-by: Eduard Zingerman Link: https://lore.kernel.org/bpf/20231017203020.1500-1-dthaler1968@googlemail.com --- Documentation/bpf/standardization/instruction-set.rst | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/bpf/standardization/instruction-set.rst b/Documentation/bpf/standardization/instruction-set.rst index c5d53a6e8c79..245b6defc298 100644 --- a/Documentation/bpf/standardization/instruction-set.rst +++ b/Documentation/bpf/standardization/instruction-set.rst @@ -283,6 +283,14 @@ For signed operations (``BPF_SDIV`` and ``BPF_SMOD``), for ``BPF_ALU``, is first :term:`sign extended` from 32 to 64 bits, and then interpreted as a 64-bit signed value. +Note that there are varying definitions of the signed modulo operation +when the dividend or divisor are negative, where implementations often +vary by language such that Python, Ruby, etc. differ from C, Go, Java, +etc. This specification requires that signed modulo use truncated division +(where -13 % 3 == -1) as implemented in C, Go, etc.: + + a % n = a - n * trunc(a / n) + The ``BPF_MOVSX`` instruction does a move operation with sign extension. ``BPF_ALU | BPF_MOVSX`` :term:`sign extends` 8-bit and 16-bit operands into 32 bit operands, and zeroes the remaining upper 32 bits. -- cgit v1.2.3 From b91f2e13c972c3f2f33ecc873b0ff0ada3fa1854 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 17 Oct 2023 18:07:58 -0700 Subject: docs: networking: document multi-RSS context There seems to be no docs for the concept of multiple RSS contexts and how to configure it. I had to explain it three times recently, the last one being the charm, document it. Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Reviewed-by: Edward Cree Link: https://lore.kernel.org/r/20231018010758.2382742-1-kuba@kernel.org Signed-off-by: Paolo Abeni --- Documentation/networking/scaling.rst | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'Documentation') diff --git a/Documentation/networking/scaling.rst b/Documentation/networking/scaling.rst index 92c9fb46d6a2..03ae19a689fc 100644 --- a/Documentation/networking/scaling.rst +++ b/Documentation/networking/scaling.rst @@ -105,6 +105,48 @@ a separate CPU. For interrupt handling, HT has shown no benefit in initial tests, so limit the number of queues to the number of CPU cores in the system. +Dedicated RSS contexts +~~~~~~~~~~~~~~~~~~~~~~ + +Modern NICs support creating multiple co-existing RSS configurations +which are selected based on explicit matching rules. This can be very +useful when application wants to constrain the set of queues receiving +traffic for e.g. a particular destination port or IP address. +The example below shows how to direct all traffic to TCP port 22 +to queues 0 and 1. + +To create an additional RSS context use:: + + # ethtool -X eth0 hfunc toeplitz context new + New RSS context is 1 + +Kernel reports back the ID of the allocated context (the default, always +present RSS context has ID of 0). The new context can be queried and +modified using the same APIs as the default context:: + + # ethtool -x eth0 context 1 + RX flow hash indirection table for eth0 with 13 RX ring(s): + 0: 0 1 2 3 4 5 6 7 + 8: 8 9 10 11 12 0 1 2 + [...] + # ethtool -X eth0 equal 2 context 1 + # ethtool -x eth0 context 1 + RX flow hash indirection table for eth0 with 13 RX ring(s): + 0: 0 1 0 1 0 1 0 1 + 8: 0 1 0 1 0 1 0 1 + [...] + +To make use of the new context direct traffic to it using an n-tuple +filter:: + + # ethtool -N eth0 flow-type tcp6 dst-port 22 context 1 + Added rule with ID 1023 + +When done, remove the context and the rule:: + + # ethtool -N eth0 delete 1023 + # ethtool -X eth0 context 1 delete + RPS: Receive Packet Steering ============================ -- cgit v1.2.3 From 659fd097b0988b18323729272ce71ae625e014ba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:20 -0500 Subject: dt-bindings: net: Add missing (unevaluated|additional)Properties on child node schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just as unevaluatedProperties or additionalProperties are required at the top level of schemas, they should (and will) also be required for child node schemas. That ensures only documented properties are present for any node. Add unevaluatedProperties or additionalProperties as appropriate. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Acked-by: Jernej Skrabec Reviewed-by: Gerhard Engleder Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-1-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- .../devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml | 2 ++ Documentation/devicetree/bindings/net/dsa/brcm,sf2.yaml | 1 + Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml | 2 ++ .../devicetree/bindings/net/dsa/microchip,lan937x.yaml | 1 + Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml | 2 ++ Documentation/devicetree/bindings/net/dsa/qca8k.yaml | 1 + Documentation/devicetree/bindings/net/dsa/realtek.yaml | 2 ++ .../devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml | 10 ++-------- Documentation/devicetree/bindings/net/engleder,tsnep.yaml | 1 + Documentation/devicetree/bindings/net/nxp,tja11xx.yaml | 1 + 10 files changed, 15 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml index 4bfac9186886..7fe0352dff0f 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml @@ -158,6 +158,8 @@ allOf: patternProperties: "^ethernet-phy@[0-9a-f]$": type: object + $ref: ethernet-phy.yaml# + unevaluatedProperties: false description: Integrated PHY node diff --git a/Documentation/devicetree/bindings/net/dsa/brcm,sf2.yaml b/Documentation/devicetree/bindings/net/dsa/brcm,sf2.yaml index b06c416893ff..f21bdd0f408d 100644 --- a/Documentation/devicetree/bindings/net/dsa/brcm,sf2.yaml +++ b/Documentation/devicetree/bindings/net/dsa/brcm,sf2.yaml @@ -78,6 +78,7 @@ properties: ports: type: object + additionalProperties: true patternProperties: '^port@[0-9a-f]$': diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml index e532c6b795f4..20f7ba4e2203 100644 --- a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml +++ b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml @@ -154,10 +154,12 @@ properties: patternProperties: "^(ethernet-)?ports$": type: object + additionalProperties: true patternProperties: "^(ethernet-)?port@[0-9]+$": type: object + additionalProperties: true properties: reg: diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml index 8d7e878b84dc..6a4d90d550b6 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml @@ -37,6 +37,7 @@ properties: patternProperties: "^(ethernet-)?ports$": + additionalProperties: true patternProperties: "^(ethernet-)?port@[0-9]+$": allOf: diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml index 4d5f5cc6d031..d179c6971193 100644 --- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml @@ -43,6 +43,7 @@ properties: # PHY 1. mdios: type: object + additionalProperties: false properties: '#address-cells': @@ -74,6 +75,7 @@ properties: patternProperties: "^(ethernet-)?ports$": + additionalProperties: true patternProperties: "^(ethernet-)?port@[0-9]+$": allOf: diff --git a/Documentation/devicetree/bindings/net/dsa/qca8k.yaml b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml index df64eebebe18..167398ab253a 100644 --- a/Documentation/devicetree/bindings/net/dsa/qca8k.yaml +++ b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml @@ -73,6 +73,7 @@ $ref: dsa.yaml# patternProperties: "^(ethernet-)?ports$": type: object + additionalProperties: true patternProperties: "^(ethernet-)?port@[0-6]$": type: object diff --git a/Documentation/devicetree/bindings/net/dsa/realtek.yaml b/Documentation/devicetree/bindings/net/dsa/realtek.yaml index cfd69c2604ea..cce692f57b08 100644 --- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml +++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml @@ -68,6 +68,8 @@ properties: interrupt-controller: type: object + additionalProperties: false + description: | This defines an interrupt controller with an IRQ line (typically a GPIO) that will demultiplex and handle the interrupt from the single diff --git a/Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml b/Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml index 833d2f68daa1..ea285ef3e64f 100644 --- a/Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml +++ b/Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml @@ -61,17 +61,11 @@ properties: ethernet-ports: type: object - properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 - + additionalProperties: true patternProperties: "^(ethernet-)?port@[0-4]$": type: object - description: Ethernet switch ports - + additionalProperties: true properties: pcs-handle: maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/engleder,tsnep.yaml b/Documentation/devicetree/bindings/net/engleder,tsnep.yaml index 82a5d7927ca4..34fd24ff6a71 100644 --- a/Documentation/devicetree/bindings/net/engleder,tsnep.yaml +++ b/Documentation/devicetree/bindings/net/engleder,tsnep.yaml @@ -63,6 +63,7 @@ properties: mdio: type: object $ref: mdio.yaml# + unevaluatedProperties: false description: optional node for embedded MDIO controller required: diff --git a/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml b/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml index ab8867e6939b..85bfa45f5122 100644 --- a/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml +++ b/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml @@ -20,6 +20,7 @@ allOf: patternProperties: "^ethernet-phy@[0-9a-f]+$": type: object + additionalProperties: false description: | Some packages have multiple PHYs. Secondary PHY should be defines as subnode of the first (parent) PHY. -- cgit v1.2.3 From ac8fe40c3628e12123ef32098216476dccea7b6a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:21 -0500 Subject: dt-bindings: net: renesas: Drop ethernet-phy node schema What's connected on the MDIO bus is outside the scope of the binding for ethernet controller's MDIO bus unless it's a fixed internal device, so drop the node name and reference to ethernet-phy.yaml. Signed-off-by: Rob Herring Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-2-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/renesas,ether.yaml | 3 +-- Documentation/devicetree/bindings/net/renesas,etheravb.yaml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/renesas,ether.yaml b/Documentation/devicetree/bindings/net/renesas,ether.yaml index 06b38c9bc6ec..29355ab98569 100644 --- a/Documentation/devicetree/bindings/net/renesas,ether.yaml +++ b/Documentation/devicetree/bindings/net/renesas,ether.yaml @@ -81,9 +81,8 @@ properties: active-high patternProperties: - "^ethernet-phy@[0-9a-f]$": + "@[0-9a-f]$": type: object - $ref: ethernet-phy.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/net/renesas,etheravb.yaml b/Documentation/devicetree/bindings/net/renesas,etheravb.yaml index 3f41294f5997..5d074f27d462 100644 --- a/Documentation/devicetree/bindings/net/renesas,etheravb.yaml +++ b/Documentation/devicetree/bindings/net/renesas,etheravb.yaml @@ -109,9 +109,8 @@ properties: enum: [0, 2000] patternProperties: - "^ethernet-phy@[0-9a-f]$": + "@[0-9a-f]$": type: object - $ref: ethernet-phy.yaml# required: - compatible -- cgit v1.2.3 From 51ff5150258a5af8f45c06518bfd4bba2edeceed Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:22 -0500 Subject: dt-bindings: net: dsa/switch: Make 'ethernet-port' node addresses hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'ethernet-port' node unit-addresses should be in hexadecimal. Some instances have it correct, but fix the ones that don't. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-3-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml | 2 +- Documentation/devicetree/bindings/net/dsa/dsa.yaml | 2 +- Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml | 6 +++--- Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml | 2 +- Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml | 2 +- Documentation/devicetree/bindings/net/ethernet-switch.yaml | 4 ++-- Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml b/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml index aa3162c74833..75d8138298fb 100644 --- a/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml +++ b/Documentation/devicetree/bindings/net/brcm,asp-v2.0.yaml @@ -53,7 +53,7 @@ properties: const: 0 patternProperties: - "^port@[0-9]+$": + "^port@[0-9a-f]+$": type: object $ref: ethernet-controller.yaml# diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.yaml b/Documentation/devicetree/bindings/net/dsa/dsa.yaml index ec74a660beda..e6010821f86f 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.yaml +++ b/Documentation/devicetree/bindings/net/dsa/dsa.yaml @@ -50,7 +50,7 @@ $defs: const: 0 patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-9a-f]+$": description: Ethernet switch ports $ref: dsa-port.yaml# unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml index 20f7ba4e2203..5038818e9f2e 100644 --- a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml +++ b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml @@ -157,7 +157,7 @@ patternProperties: additionalProperties: true patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-6]$": type: object additionalProperties: true @@ -186,7 +186,7 @@ $defs: patternProperties: "^(ethernet-)?ports$": patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-6]$": if: required: [ ethernet ] then: @@ -212,7 +212,7 @@ $defs: patternProperties: "^(ethernet-)?ports$": patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-6]$": if: required: [ ethernet ] then: diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml index 6a4d90d550b6..9973d64f15a7 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml @@ -39,7 +39,7 @@ patternProperties: "^(ethernet-)?ports$": additionalProperties: true patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-7]$": allOf: - if: properties: diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml index d179c6971193..9432565f4f5d 100644 --- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml @@ -77,7 +77,7 @@ patternProperties: "^(ethernet-)?ports$": additionalProperties: true patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-9]$": allOf: - if: properties: diff --git a/Documentation/devicetree/bindings/net/ethernet-switch.yaml b/Documentation/devicetree/bindings/net/ethernet-switch.yaml index f1b9075dc7fb..dcbffe19d71a 100644 --- a/Documentation/devicetree/bindings/net/ethernet-switch.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-switch.yaml @@ -36,7 +36,7 @@ patternProperties: const: 0 patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-9a-f]+$": type: object description: Ethernet switch ports @@ -58,7 +58,7 @@ $defs: $ref: '#' patternProperties: - "^(ethernet-)?port@[0-9]+$": + "^(ethernet-)?port@[0-9a-f]+$": description: Ethernet switch ports $ref: ethernet-switch-port.yaml# unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml b/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml index b04ac4966608..f07ae3173b03 100644 --- a/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml +++ b/Documentation/devicetree/bindings/net/ti,cpsw-switch.yaml @@ -86,7 +86,7 @@ properties: const: 0 patternProperties: - "^port@[0-9]+$": + "^port@[12]$": type: object description: CPSW external ports -- cgit v1.2.3 From f0fdec925fe7adf725de238b9eea59702d0d58e0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:23 -0500 Subject: dt-bindings: net: ethernet-switch: Add missing 'ethernet-ports' level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The '$defs/ethernet-ports' schema is referenced by schemas defining a child node 'ethernet-ports', but this schema misses the 'ethernet-ports' node. It would work if referring schemas made a reference like this: properties: ethernet-ports: $ref: ethernet-switch.yaml#/$defs/ethernet-ports However, that would be different from how dsa.yaml works. For consistency, align the schema definition with dsa.yaml and add the missing level. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-4-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/ethernet-switch.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ethernet-switch.yaml b/Documentation/devicetree/bindings/net/ethernet-switch.yaml index dcbffe19d71a..688938c2e261 100644 --- a/Documentation/devicetree/bindings/net/ethernet-switch.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-switch.yaml @@ -58,9 +58,11 @@ $defs: $ref: '#' patternProperties: - "^(ethernet-)?port@[0-9a-f]+$": - description: Ethernet switch ports - $ref: ethernet-switch-port.yaml# - unevaluatedProperties: false + "^(ethernet-)?ports$": + patternProperties: + "^(ethernet-)?port@[0-9a-f]+$": + description: Ethernet switch ports + $ref: ethernet-switch-port.yaml# + unevaluatedProperties: false ... -- cgit v1.2.3 From b9823df7bbad42bffa1d13e65c11c1e3ae09069c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:24 -0500 Subject: dt-bindings: net: ethernet-switch: Rename $defs "base" to 'ethernet-ports' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name "base" is misleading as the definition is for a complete schema definition without additional properties allowed, not a "base class". Align the same to be the same as dsa.yaml. This schema file without any json pointer path is the base schema which can be extended. There are not yet any references to $defs/base to update. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-5-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/ethernet-switch.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/ethernet-switch.yaml b/Documentation/devicetree/bindings/net/ethernet-switch.yaml index 688938c2e261..72ac67ca3415 100644 --- a/Documentation/devicetree/bindings/net/ethernet-switch.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-switch.yaml @@ -53,7 +53,7 @@ oneOf: additionalProperties: true $defs: - base: + ethernet-ports: description: An ethernet switch without any extra port properties $ref: '#' -- cgit v1.2.3 From 491ec40d67a534a374dbdb77cda294333b29c580 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:25 -0500 Subject: dt-bindings: net: mscc,vsc7514-switch: Clean-up example indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The indentation for the example is completely messed up for 'ethernet-ports'. Fix it. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-6-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- .../bindings/net/mscc,vsc7514-switch.yaml | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml b/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml index 8ee2c7d7ff42..07de52a3a295 100644 --- a/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml +++ b/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml @@ -185,7 +185,7 @@ examples: }; # VSC7512 (DSA) - | - ethernet-switch@1{ + ethernet-switch@1 { compatible = "mscc,vsc7512-switch"; reg = <0x71010000 0x10000>, <0x71030000 0x10000>, @@ -212,22 +212,22 @@ examples: "port7", "port8", "port9", "port10", "qsys", "ana", "s0", "s1", "s2"; - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - ethernet = <&mac_sw>; - phy-handle = <&phy0>; - phy-mode = "internal"; - }; - port@1 { - reg = <1>; - phy-handle = <&phy1>; - phy-mode = "internal"; - }; + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ethernet = <&mac_sw>; + phy-handle = <&phy0>; + phy-mode = "internal"; + }; + port@1 { + reg = <1>; + phy-handle = <&phy1>; + phy-mode = "internal"; }; }; + }; ... -- cgit v1.2.3 From 7c93392d754e53e73efffff34f119f7eaf0deb51 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:26 -0500 Subject: dt-bindings: net: mscc,vsc7514-switch: Simplify DSA and switch references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mscc,vsc7514-switch schema doesn't add any custom port properties, so it can just reference ethernet-switch.yaml#/$defs/base and dsa.yaml#/$defs/ethernet-ports instead of the base file and can skip defining port nodes. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-7-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- .../devicetree/bindings/net/mscc,vsc7514-switch.yaml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml b/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml index 07de52a3a295..86a9c3fc76c8 100644 --- a/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml +++ b/Documentation/devicetree/bindings/net/mscc,vsc7514-switch.yaml @@ -24,7 +24,7 @@ allOf: compatible: const: mscc,vsc7514-switch then: - $ref: ethernet-switch.yaml# + $ref: ethernet-switch.yaml#/$defs/ethernet-ports required: - interrupts - interrupt-names @@ -33,28 +33,18 @@ allOf: minItems: 21 reg-names: minItems: 21 - ethernet-ports: - patternProperties: - "^port@[0-9a-f]+$": - $ref: ethernet-switch-port.yaml# - unevaluatedProperties: false - if: properties: compatible: const: mscc,vsc7512-switch then: - $ref: /schemas/net/dsa/dsa.yaml# + $ref: /schemas/net/dsa/dsa.yaml#/$defs/ethernet-ports properties: reg: maxItems: 20 reg-names: maxItems: 20 - ethernet-ports: - patternProperties: - "^port@[0-9a-f]+$": - $ref: /schemas/net/dsa/dsa-port.yaml# - unevaluatedProperties: false properties: compatible: -- cgit v1.2.3 From 31f47f303c6b15d1d6fde74e9ba108465ed58c51 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Oct 2023 16:44:27 -0500 Subject: dt-bindings: net: dsa: Drop 'ethernet-ports' node properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constraints on 'ethernet-ports' node properties are already defined by the reference to ethernet-switch.yaml, so they can be dropped from the DSA schema. Signed-off-by: Rob Herring Acked-by: Arınç ÜNAL Reviewed-by: Vladimir Oltean Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20231016-dt-net-cleanups-v1-8-a525a090b444@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/dsa/dsa.yaml | 9 --------- 1 file changed, 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.yaml b/Documentation/devicetree/bindings/net/dsa/dsa.yaml index e6010821f86f..6107189d276a 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.yaml +++ b/Documentation/devicetree/bindings/net/dsa/dsa.yaml @@ -40,15 +40,6 @@ $defs: patternProperties: "^(ethernet-)?ports$": - type: object - additionalProperties: false - - properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 - patternProperties: "^(ethernet-)?port@[0-9a-f]+$": description: Ethernet switch ports -- cgit v1.2.3 From f2cab25b0eb7bd735459059e2eb8d21d2569c41d Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Wed, 18 Oct 2023 14:35:55 +0200 Subject: i40e: Align devlink info versions with ice driver and add docs Align devlink info versions with ice driver so change 'fw.mgmt' version to be 2-digit version [major.minor], add 'fw.mgmt.build' that reports mgmt firmware build number and use '"fw.psid.api' for NVM format version instead of incorrect '"fw.psid'. Additionally add missing i40e devlink documentation. Fixes: 5a423552e0d9 ("i40e: Add handler for devlink .info_get") Signed-off-by: Ivan Vecera Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20231018123558.552453-1-ivecera@redhat.com Signed-off-by: Jakub Kicinski --- Documentation/networking/devlink/i40e.rst | 59 ++++++++++++++++++++++++++ Documentation/networking/devlink/index.rst | 1 + drivers/net/ethernet/intel/i40e/i40e_devlink.c | 18 ++++++-- 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 Documentation/networking/devlink/i40e.rst (limited to 'Documentation') diff --git a/Documentation/networking/devlink/i40e.rst b/Documentation/networking/devlink/i40e.rst new file mode 100644 index 000000000000..d3cb5bb5197e --- /dev/null +++ b/Documentation/networking/devlink/i40e.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================== +i40e devlink support +==================== + +This document describes the devlink features implemented by the ``i40e`` +device driver. + +Info versions +============= + +The ``i40e`` driver reports the following versions + +.. list-table:: devlink info versions implemented + :widths: 5 5 5 90 + + * - Name + - Type + - Example + - Description + * - ``board.id`` + - fixed + - K15190-000 + - The Product Board Assembly (PBA) identifier of the board. + * - ``fw.mgmt`` + - running + - 9.130 + - 2-digit version number of the management firmware that controls the + PHY, link, etc. + * - ``fw.mgmt.api`` + - running + - 1.15 + - 2-digit version number of the API exported over the AdminQ by the + management firmware. Used by the driver to identify what commands + are supported. + * - ``fw.mgmt.build`` + - running + - 73618 + - Build number of the source for the management firmware. + * - ``fw.undi`` + - running + - 1.3429.0 + - Version of the Option ROM containing the UEFI driver. The version is + reported in ``major.minor.patch`` format. The major version is + incremented whenever a major breaking change occurs, or when the + minor version would overflow. The minor version is incremented for + non-breaking changes and reset to 1 when the major version is + incremented. The patch version is normally 0 but is incremented when + a fix is delivered as a patch against an older base Option ROM. + * - ``fw.psid.api`` + - running + - 9.30 + - Version defining the format of the flash contents. + * - ``fw.bundle_id`` + - running + - 0x8000e5f3 + - Unique identifier of the firmware image file that was loaded onto + the device. Also referred to as the EETRACK identifier of the NVM. diff --git a/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst index 2884ad243b54..e14d7a701b72 100644 --- a/Documentation/networking/devlink/index.rst +++ b/Documentation/networking/devlink/index.rst @@ -80,6 +80,7 @@ parameters, info versions, and other features it supports. bnxt etas_es58x hns3 + i40e ionic ice mlx4 diff --git a/drivers/net/ethernet/intel/i40e/i40e_devlink.c b/drivers/net/ethernet/intel/i40e/i40e_devlink.c index 9168ade8da47..74bc111b4849 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_devlink.c +++ b/drivers/net/ethernet/intel/i40e/i40e_devlink.c @@ -18,8 +18,14 @@ static void i40e_info_fw_mgmt(struct i40e_hw *hw, char *buf, size_t len) { struct i40e_adminq_info *aq = &hw->aq; - snprintf(buf, len, "%u.%u.%05d", - aq->fw_maj_ver, aq->fw_min_ver, aq->fw_build); + snprintf(buf, len, "%u.%u", aq->fw_maj_ver, aq->fw_min_ver); +} + +static void i40e_info_fw_mgmt_build(struct i40e_hw *hw, char *buf, size_t len) +{ + struct i40e_adminq_info *aq = &hw->aq; + + snprintf(buf, len, "%05d", aq->fw_build); } static void i40e_info_fw_api(struct i40e_hw *hw, char *buf, size_t len) @@ -77,6 +83,12 @@ static int i40e_devlink_info_get(struct devlink *dl, if (err) return err; + i40e_info_fw_mgmt_build(hw, buf, sizeof(buf)); + err = i40e_devlink_info_put(req, I40E_DL_VERSION_RUNNING, + "fw.mgmt.build", buf); + if (err) + return err; + i40e_info_fw_api(hw, buf, sizeof(buf)); err = i40e_devlink_info_put(req, I40E_DL_VERSION_RUNNING, DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API, @@ -86,7 +98,7 @@ static int i40e_devlink_info_get(struct devlink *dl, i40e_info_nvm_ver(hw, buf, sizeof(buf)); err = i40e_devlink_info_put(req, I40E_DL_VERSION_RUNNING, - DEVLINK_INFO_VERSION_GENERIC_FW_PSID, buf); + "fw.psid.api", buf); if (err) return err; -- cgit v1.2.3 From 668c1ac828fb546b81da6b36dae09d754bd0f59e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 18 Oct 2023 09:39:16 -0700 Subject: tools: ynl-gen: support full range of min/max checks for integer values Extend the support to full range of min/max checks. None of the existing YNL families required complex integer validation. The support is less than trivial, because we try to keep struct nla_policy tiny the min/max members it holds in place are s16. Meaning we can only express checks in range of s16. For larger ranges we need to define a structure and link it in the policy. Link: https://lore.kernel.org/r/20231018163917.2514503-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 3 ++ Documentation/netlink/genetlink-legacy.yaml | 3 ++ Documentation/netlink/genetlink.yaml | 3 ++ tools/net/ynl/ynl-gen-c.py | 66 ++++++++++++++++++++++++++--- 4 files changed, 68 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index f9366aaddd21..75af0b51f3d7 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -184,6 +184,9 @@ properties: min: description: Min value for an integer attribute. type: integer + max: + description: Max value for an integer attribute. + type: integer min-len: description: Min length for a binary attribute. $ref: '#/$defs/len-or-define' diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index a6a490333a1a..c0f17a8bfe0d 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -227,6 +227,9 @@ properties: min: description: Min value for an integer attribute. type: integer + max: + description: Max value for an integer attribute. + type: integer min-len: description: Min length for a binary attribute. $ref: '#/$defs/len-or-define' diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 2b788e607a14..4fd56e3b1553 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -157,6 +157,9 @@ properties: min: description: Min value for an integer attribute. type: integer + max: + description: Max value for an integer attribute. + type: integer min-len: description: Min length for a binary attribute. $ref: '#/$defs/len-or-define' diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 7f4ad4014d17..9d008346dd50 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -47,6 +47,7 @@ class Type(SpecAttr): if 'len' in attr: self.len = attr['len'] + if 'nested-attributes' in attr: self.nested_attrs = attr['nested-attributes'] if self.nested_attrs == family.name: @@ -262,6 +263,27 @@ class TypeScalar(Type): if 'byte-order' in attr: self.byte_order_comment = f" /* {attr['byte-order']} */" + if 'enum' in self.attr: + enum = self.family.consts[self.attr['enum']] + low, high = enum.value_range() + if 'min' not in self.checks: + if low != 0 or self.type[0] == 's': + self.checks['min'] = low + if 'max' not in self.checks: + self.checks['max'] = high + + if 'min' in self.checks and 'max' in self.checks: + if self.checks['min'] > self.checks['max']: + raise Exception(f'Invalid limit for "{self.name}" min: {self.checks["min"]} max: {self.checks["max"]}') + self.checks['range'] = True + + low = min(self.checks.get('min', 0), self.checks.get('max', 0)) + high = max(self.checks.get('min', 0), self.checks.get('max', 0)) + if low < 0 and self.type[0] == 'u': + raise Exception(f'Invalid limit for "{self.name}" negative limit for unsigned type') + if low < -32768 or high > 32767: + self.checks['full-range'] = True + # Added by resolve(): self.is_bitfield = None delattr(self, "is_bitfield") @@ -301,14 +323,14 @@ class TypeScalar(Type): flag_cnt = len(flags['entries']) mask = (1 << flag_cnt) - 1 return f"NLA_POLICY_MASK({policy}, 0x{mask:x})" + elif 'full-range' in self.checks: + return f"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)" + elif 'range' in self.checks: + return f"NLA_POLICY_RANGE({policy}, {self.checks['min']}, {self.checks['max']})" elif 'min' in self.checks: return f"NLA_POLICY_MIN({policy}, {self.checks['min']})" - elif 'enum' in self.attr: - enum = self.family.consts[self.attr['enum']] - low, high = enum.value_range() - if low == 0: - return f"NLA_POLICY_MAX({policy}, {high})" - return f"NLA_POLICY_RANGE({policy}, {low}, {high})" + elif 'max' in self.checks: + return f"NLA_POLICY_MAX({policy}, {self.checks['max']})" return super()._attr_policy(policy) def _attr_typol(self): @@ -1241,7 +1263,7 @@ class CodeWriter: for one in members: line = '.' + one[0] line += '\t' * ((longest - len(one[0]) - 1 + 7) // 8) - line += '= ' + one[1] + ',' + line += '= ' + str(one[1]) + ',' self.p(line) @@ -1940,6 +1962,34 @@ def policy_should_be_static(family): return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family) +def print_kernel_policy_ranges(family, cw): + first = True + for _, attr_set in family.attr_sets.items(): + if attr_set.subset_of: + continue + + for _, attr in attr_set.items(): + if not attr.request: + continue + if 'full-range' not in attr.checks: + continue + + if first: + cw.p('/* Integer value ranges */') + first = False + + sign = '' if attr.type[0] == 'u' else '_signed' + cw.block_start(line=f'struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =') + members = [] + if 'min' in attr.checks: + members.append(('min', attr.checks['min'])) + if 'max' in attr.checks: + members.append(('max', attr.checks['max'])) + cw.write_struct_init(members) + cw.block_end(line=';') + cw.nl() + + def print_kernel_op_table_fwd(family, cw, terminate): exported = not kernel_can_gen_family_struct(family) @@ -2479,6 +2529,8 @@ def main(): print_kernel_mcgrp_hdr(parsed, cw) print_kernel_family_struct_hdr(parsed, cw) else: + print_kernel_policy_ranges(parsed, cw) + for _, struct in sorted(parsed.pure_nested_structs.items()): if struct.request: cw.p('/* Common nested types */') -- cgit v1.2.3 From f9bc3cbc20d08c5c7b89a91e07ba46ab8042561e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 18 Oct 2023 09:39:17 -0700 Subject: tools: ynl-gen: support limit names Support the use of symbolic names like s8-min or u32-max in checks to make writing specs less painful. Link: https://lore.kernel.org/r/20231018163917.2514503-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 9 ++++-- Documentation/netlink/genetlink-legacy.yaml | 9 ++++-- Documentation/netlink/genetlink.yaml | 9 ++++-- tools/net/ynl/ynl-gen-c.py | 45 ++++++++++++++++++++++------- 4 files changed, 55 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 75af0b51f3d7..dee11c514896 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -13,6 +13,11 @@ $defs: type: [ string, integer ] pattern: ^[0-9A-Za-z_]+( - 1)?$ minimum: 0 + len-or-limit: + # literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc. + type: [ string, integer ] + pattern: ^[su](8|16|32|64)-(min|max)$ + minimum: 0 # Schema for specs title: Protocol @@ -183,10 +188,10 @@ properties: type: string min: description: Min value for an integer attribute. - type: integer + $ref: '#/$defs/len-or-limit' max: description: Max value for an integer attribute. - type: integer + $ref: '#/$defs/len-or-limit' min-len: description: Min length for a binary attribute. $ref: '#/$defs/len-or-define' diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index c0f17a8bfe0d..9194f3e223ef 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -13,6 +13,11 @@ $defs: type: [ string, integer ] pattern: ^[0-9A-Za-z_]+( - 1)?$ minimum: 0 + len-or-limit: + # literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc. + type: [ string, integer ] + pattern: ^[su](8|16|32|64)-(min|max)$ + minimum: 0 # Schema for specs title: Protocol @@ -226,10 +231,10 @@ properties: type: string min: description: Min value for an integer attribute. - type: integer + $ref: '#/$defs/len-or-limit' max: description: Max value for an integer attribute. - type: integer + $ref: '#/$defs/len-or-limit' min-len: description: Min length for a binary attribute. $ref: '#/$defs/len-or-define' diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 4fd56e3b1553..0a4ae861d011 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -13,6 +13,11 @@ $defs: type: [ string, integer ] pattern: ^[0-9A-Za-z_]+( - 1)?$ minimum: 0 + len-or-limit: + # literal int or limit based on fixed-width type e.g. u8-min, u16-max, etc. + type: [ string, integer ] + pattern: ^[su](8|16|32|64)-(min|max)$ + minimum: 0 # Schema for specs title: Protocol @@ -156,10 +161,10 @@ properties: type: string min: description: Min value for an integer attribute. - type: integer + $ref: '#/$defs/len-or-limit' max: description: Max value for an integer attribute. - type: integer + $ref: '#/$defs/len-or-limit' min-len: description: Min length for a binary attribute. $ref: '#/$defs/len-or-define' diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 9d008346dd50..552ba49a444c 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -20,6 +20,21 @@ def c_lower(name): return name.lower().replace('-', '_') +def limit_to_number(name): + """ + Turn a string limit like u32-max or s64-min into its numerical value + """ + if name[0] == 'u' and name.endswith('-min'): + return 0 + width = int(name[1:-4]) + if name[0] == 's': + width -= 1 + value = (1 << width) - 1 + if name[0] == 's' and name.endswith('-min'): + value = -value - 1 + return value + + class BaseNlLib: def get_family_id(self): return 'ys->family_id' @@ -68,6 +83,14 @@ class Type(SpecAttr): self.enum_name = None delattr(self, "enum_name") + def get_limit(self, limit, default=None): + value = self.checks.get(limit, default) + if value is None: + return value + if not isinstance(value, int): + value = limit_to_number(value) + return value + def resolve(self): if 'name-prefix' in self.attr: enum_name = f"{self.attr['name-prefix']}{self.name}" @@ -273,12 +296,12 @@ class TypeScalar(Type): self.checks['max'] = high if 'min' in self.checks and 'max' in self.checks: - if self.checks['min'] > self.checks['max']: - raise Exception(f'Invalid limit for "{self.name}" min: {self.checks["min"]} max: {self.checks["max"]}') + if self.get_limit('min') > self.get_limit('max'): + raise Exception(f'Invalid limit for "{self.name}" min: {self.get_limit("min")} max: {self.get_limit("max")}') self.checks['range'] = True - low = min(self.checks.get('min', 0), self.checks.get('max', 0)) - high = max(self.checks.get('min', 0), self.checks.get('max', 0)) + low = min(self.get_limit('min', 0), self.get_limit('max', 0)) + high = max(self.get_limit('min', 0), self.get_limit('max', 0)) if low < 0 and self.type[0] == 'u': raise Exception(f'Invalid limit for "{self.name}" negative limit for unsigned type') if low < -32768 or high > 32767: @@ -326,11 +349,11 @@ class TypeScalar(Type): elif 'full-range' in self.checks: return f"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)" elif 'range' in self.checks: - return f"NLA_POLICY_RANGE({policy}, {self.checks['min']}, {self.checks['max']})" + return f"NLA_POLICY_RANGE({policy}, {self.get_limit('min')}, {self.get_limit('max')})" elif 'min' in self.checks: - return f"NLA_POLICY_MIN({policy}, {self.checks['min']})" + return f"NLA_POLICY_MIN({policy}, {self.get_limit('min')})" elif 'max' in self.checks: - return f"NLA_POLICY_MAX({policy}, {self.checks['max']})" + return f"NLA_POLICY_MAX({policy}, {self.get_limit('max')})" return super()._attr_policy(policy) def _attr_typol(self): @@ -382,7 +405,7 @@ class TypeString(Type): def _attr_policy(self, policy): mem = '{ .type = ' + policy if 'max-len' in self.checks: - mem += ', .len = ' + str(self.checks['max-len']) + mem += ', .len = ' + str(self.get_limit('max-len')) mem += ', }' return mem @@ -431,7 +454,7 @@ class TypeBinary(Type): def _attr_policy(self, policy): mem = '{ ' if len(self.checks) == 1 and 'min-len' in self.checks: - mem += '.len = ' + str(self.checks['min-len']) + mem += '.len = ' + str(self.get_limit('min-len')) elif len(self.checks) == 0: mem += '.type = NLA_BINARY' else: @@ -1982,9 +2005,9 @@ def print_kernel_policy_ranges(family, cw): cw.block_start(line=f'struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =') members = [] if 'min' in attr.checks: - members.append(('min', attr.checks['min'])) + members.append(('min', attr.get_limit('min'))) if 'max' in attr.checks: - members.append(('max', attr.checks['max'])) + members.append(('max', attr.get_limit('max'))) cw.write_struct_init(members) cw.block_end(line=';') cw.nl() -- cgit v1.2.3 From 374d345d9b5e13380c66d7042f9533a6ac6d1195 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 18 Oct 2023 14:39:20 -0700 Subject: netlink: add variable-length / auto integers We currently push everyone to use padding to align 64b values in netlink. Un-padded nla_put_u64() doesn't even exist any more. The story behind this possibly start with this thread: https://lore.kernel.org/netdev/20121204.130914.1457976839967676240.davem@davemloft.net/ where DaveM was concerned about the alignment of a structure containing 64b stats. If user space tries to access such struct directly: struct some_stats *stats = nla_data(attr); printf("A: %llu", stats->a); lack of alignment may become problematic for some architectures. These days we most often put every single member in a separate attribute, meaning that the code above would use a helper like nla_get_u64(), which can deal with alignment internally. Even for arches which don't have good unaligned access - access aligned to 4B should be pretty efficient. Kernel and well known libraries deal with unaligned input already. Padded 64b is quite space-inefficient (64b + pad means at worst 16B per attr vs 32b which takes 8B). It is also more typing: if (nla_put_u64_pad(rsp, NETDEV_A_SOMETHING_SOMETHING, value, NETDEV_A_SOMETHING_PAD)) Create a new attribute type which will use 32 bits at netlink level if value is small enough (probably most of the time?), and (4B-aligned) 64 bits otherwise. Kernel API is just: if (nla_put_uint(rsp, NETDEV_A_SOMETHING_SOMETHING, value)) Calling this new type "just" sint / uint with no specific size will hopefully also make people more comfortable with using it. Currently telling people "don't use u8, you may need the bits, and netlink will round up to 4B, anyway" is the #1 comment we give to newcomers. In terms of netlink layout it looks like this: 0 4 8 12 16 32b: [nlattr][ u32 ] 64b: [ pad ][nlattr][ u64 ] uint(32) [nlattr][ u32 ] uint(64) [nlattr][ u64 ] Signed-off-by: Jakub Kicinski Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- Documentation/userspace-api/netlink/specs.rst | 18 ++++++- include/net/netlink.h | 69 ++++++++++++++++++++++++++- include/uapi/linux/netlink.h | 5 ++ lib/nlattr.c | 22 +++++++++ net/netlink/policy.c | 14 ++++-- 5 files changed, 121 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/userspace-api/netlink/specs.rst index 40dd7442d2c3..c1b951649113 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -403,10 +403,21 @@ This section describes the attribute types supported by the ``genetlink`` compatibility level. Refer to documentation of different levels for additional attribute types. -Scalar integer types +Common integer types -------------------- -Fixed-width integer types: +``sint`` and ``uint`` represent signed and unsigned 64 bit integers. +If the value can fit on 32 bits only 32 bits are carried in netlink +messages, otherwise full 64 bits are carried. Note that the payload +is only aligned to 4B, so the full 64 bit value may be unaligned! + +Common integer types should be preferred over fix-width types in majority +of cases. + +Fix-width integer types +----------------------- + +Fixed-width integer types include: ``u8``, ``u16``, ``u32``, ``u64``, ``s8``, ``s16``, ``s32``, ``s64``. Note that types smaller than 32 bit should be avoided as using them @@ -416,6 +427,9 @@ See :ref:`pad_type` for padding of 64 bit attributes. The payload of the attribute is the integer in host order unless ``byte-order`` specifies otherwise. +64 bit values are usually aligned by the kernel but it is recommended +that the user space is able to deal with unaligned values. + .. _pad_type: pad diff --git a/include/net/netlink.h b/include/net/netlink.h index 8a7cd1170e1f..aba2b162a226 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -128,6 +128,8 @@ * nla_len(nla) length of attribute payload * * Attribute Payload Access for Basic Types: + * nla_get_uint(nla) get payload for a uint attribute + * nla_get_sint(nla) get payload for a sint attribute * nla_get_u8(nla) get payload for a u8 attribute * nla_get_u16(nla) get payload for a u16 attribute * nla_get_u32(nla) get payload for a u32 attribute @@ -183,6 +185,8 @@ enum { NLA_REJECT, NLA_BE16, NLA_BE32, + NLA_SINT, + NLA_UINT, __NLA_TYPE_MAX, }; @@ -229,6 +233,7 @@ enum nla_policy_validation { * nested header (or empty); len field is used if * nested_policy is also used, for the max attr * number in the nested policy. + * NLA_SINT, NLA_UINT, * NLA_U8, NLA_U16, * NLA_U32, NLA_U64, * NLA_S8, NLA_S16, @@ -260,12 +265,14 @@ enum nla_policy_validation { * while an array has the nested attributes at another * level down and the attribute types directly in the * nesting don't matter. + * NLA_UINT, * NLA_U8, * NLA_U16, * NLA_U32, * NLA_U64, * NLA_BE16, * NLA_BE32, + * NLA_SINT, * NLA_S8, * NLA_S16, * NLA_S32, @@ -280,6 +287,7 @@ enum nla_policy_validation { * or NLA_POLICY_FULL_RANGE_SIGNED() macros instead. * Use the NLA_POLICY_MIN(), NLA_POLICY_MAX() and * NLA_POLICY_RANGE() macros. + * NLA_UINT, * NLA_U8, * NLA_U16, * NLA_U32, @@ -288,6 +296,7 @@ enum nla_policy_validation { * to a struct netlink_range_validation that indicates * the min/max values. * Use NLA_POLICY_FULL_RANGE(). + * NLA_SINT, * NLA_S8, * NLA_S16, * NLA_S32, @@ -377,9 +386,11 @@ struct nla_policy { #define __NLA_IS_UINT_TYPE(tp) \ (tp == NLA_U8 || tp == NLA_U16 || tp == NLA_U32 || \ - tp == NLA_U64 || tp == NLA_BE16 || tp == NLA_BE32) + tp == NLA_U64 || tp == NLA_UINT || \ + tp == NLA_BE16 || tp == NLA_BE32) #define __NLA_IS_SINT_TYPE(tp) \ - (tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64) + (tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64 || \ + tp == NLA_SINT) #define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition)) #define NLA_ENSURE_UINT_TYPE(tp) \ @@ -1357,6 +1368,22 @@ static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value) return nla_put(skb, attrtype, sizeof(u32), &tmp); } +/** + * nla_put_uint - Add a variable-size unsigned int to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @value: numeric value + */ +static inline int nla_put_uint(struct sk_buff *skb, int attrtype, u64 value) +{ + u64 tmp64 = value; + u32 tmp32 = value; + + if (tmp64 == tmp32) + return nla_put_u32(skb, attrtype, tmp32); + return nla_put(skb, attrtype, sizeof(u64), &tmp64); +} + /** * nla_put_be32 - Add a __be32 netlink attribute to a socket buffer * @skb: socket buffer to add attribute to @@ -1511,6 +1538,22 @@ static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value, return nla_put_64bit(skb, attrtype, sizeof(s64), &tmp, padattr); } +/** + * nla_put_sint - Add a variable-size signed int to a socket buffer + * @skb: socket buffer to add attribute to + * @attrtype: attribute type + * @value: numeric value + */ +static inline int nla_put_sint(struct sk_buff *skb, int attrtype, s64 value) +{ + s64 tmp64 = value; + s32 tmp32 = value; + + if (tmp64 == tmp32) + return nla_put_s32(skb, attrtype, tmp32); + return nla_put(skb, attrtype, sizeof(s64), &tmp64); +} + /** * nla_put_string - Add a string netlink attribute to a socket buffer * @skb: socket buffer to add attribute to @@ -1667,6 +1710,17 @@ static inline u64 nla_get_u64(const struct nlattr *nla) return tmp; } +/** + * nla_get_uint - return payload of uint attribute + * @nla: uint netlink attribute + */ +static inline u64 nla_get_uint(const struct nlattr *nla) +{ + if (nla_len(nla) == sizeof(u32)) + return nla_get_u32(nla); + return nla_get_u64(nla); +} + /** * nla_get_be64 - return payload of __be64 attribute * @nla: __be64 netlink attribute @@ -1729,6 +1783,17 @@ static inline s64 nla_get_s64(const struct nlattr *nla) return tmp; } +/** + * nla_get_sint - return payload of uint attribute + * @nla: uint netlink attribute + */ +static inline s64 nla_get_sint(const struct nlattr *nla) +{ + if (nla_len(nla) == sizeof(s32)) + return nla_get_s32(nla); + return nla_get_s64(nla); +} + /** * nla_get_flag - return payload of flag attribute * @nla: flag netlink attribute diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index e2ae82e3f9f7..f87aaf28a649 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -298,6 +298,8 @@ struct nla_bitfield32 { * entry has attributes again, the policy for those inner ones * and the corresponding maxtype may be specified. * @NL_ATTR_TYPE_BITFIELD32: &struct nla_bitfield32 attribute + * @NL_ATTR_TYPE_SINT: 32-bit or 64-bit signed attribute, aligned to 4B + * @NL_ATTR_TYPE_UINT: 32-bit or 64-bit unsigned attribute, aligned to 4B */ enum netlink_attribute_type { NL_ATTR_TYPE_INVALID, @@ -322,6 +324,9 @@ enum netlink_attribute_type { NL_ATTR_TYPE_NESTED_ARRAY, NL_ATTR_TYPE_BITFIELD32, + + NL_ATTR_TYPE_SINT, + NL_ATTR_TYPE_UINT, }; /** diff --git a/lib/nlattr.c b/lib/nlattr.c index 7a2b6c38fd59..dc15e7888fc1 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -134,6 +134,7 @@ void nla_get_range_unsigned(const struct nla_policy *pt, range->max = U32_MAX; break; case NLA_U64: + case NLA_UINT: case NLA_MSECS: range->max = U64_MAX; break; @@ -183,6 +184,9 @@ static int nla_validate_range_unsigned(const struct nla_policy *pt, case NLA_U64: value = nla_get_u64(nla); break; + case NLA_UINT: + value = nla_get_uint(nla); + break; case NLA_MSECS: value = nla_get_u64(nla); break; @@ -248,6 +252,7 @@ void nla_get_range_signed(const struct nla_policy *pt, range->max = S32_MAX; break; case NLA_S64: + case NLA_SINT: range->min = S64_MIN; range->max = S64_MAX; break; @@ -295,6 +300,9 @@ static int nla_validate_int_range_signed(const struct nla_policy *pt, case NLA_S64: value = nla_get_s64(nla); break; + case NLA_SINT: + value = nla_get_sint(nla); + break; default: return -EINVAL; } @@ -320,6 +328,7 @@ static int nla_validate_int_range(const struct nla_policy *pt, case NLA_U16: case NLA_U32: case NLA_U64: + case NLA_UINT: case NLA_MSECS: case NLA_BINARY: case NLA_BE16: @@ -329,6 +338,7 @@ static int nla_validate_int_range(const struct nla_policy *pt, case NLA_S16: case NLA_S32: case NLA_S64: + case NLA_SINT: return nla_validate_int_range_signed(pt, nla, extack); default: WARN_ON(1); @@ -355,6 +365,9 @@ static int nla_validate_mask(const struct nla_policy *pt, case NLA_U64: value = nla_get_u64(nla); break; + case NLA_UINT: + value = nla_get_uint(nla); + break; case NLA_BE16: value = ntohs(nla_get_be16(nla)); break; @@ -433,6 +446,15 @@ static int validate_nla(const struct nlattr *nla, int maxtype, goto out_err; break; + case NLA_SINT: + case NLA_UINT: + if (attrlen != sizeof(u32) && attrlen != sizeof(u64)) { + NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt, + "invalid attribute length"); + return -EINVAL; + } + break; + case NLA_BITFIELD32: if (attrlen != sizeof(struct nla_bitfield32)) goto out_err; diff --git a/net/netlink/policy.c b/net/netlink/policy.c index e2f111edf66c..1f8909c16f14 100644 --- a/net/netlink/policy.c +++ b/net/netlink/policy.c @@ -230,6 +230,8 @@ int netlink_policy_dump_attr_size_estimate(const struct nla_policy *pt) case NLA_S16: case NLA_S32: case NLA_S64: + case NLA_SINT: + case NLA_UINT: /* maximum is common, u64 min/max with padding */ return common + 2 * (nla_attr_size(0) + nla_attr_size(sizeof(u64))); @@ -288,6 +290,7 @@ __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state, case NLA_U16: case NLA_U32: case NLA_U64: + case NLA_UINT: case NLA_MSECS: { struct netlink_range_validation range; @@ -297,8 +300,10 @@ __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state, type = NL_ATTR_TYPE_U16; else if (pt->type == NLA_U32) type = NL_ATTR_TYPE_U32; - else + else if (pt->type == NLA_U64) type = NL_ATTR_TYPE_U64; + else + type = NL_ATTR_TYPE_UINT; if (pt->validation_type == NLA_VALIDATE_MASK) { if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK, @@ -320,7 +325,8 @@ __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state, case NLA_S8: case NLA_S16: case NLA_S32: - case NLA_S64: { + case NLA_S64: + case NLA_SINT: { struct netlink_range_validation_signed range; if (pt->type == NLA_S8) @@ -329,8 +335,10 @@ __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state, type = NL_ATTR_TYPE_S16; else if (pt->type == NLA_S32) type = NL_ATTR_TYPE_S32; - else + else if (pt->type == NLA_S64) type = NL_ATTR_TYPE_S64; + else + type = NL_ATTR_TYPE_SINT; nla_get_range_signed(pt, &range); -- cgit v1.2.3 From 7d4caf54d2e8df2ed52240fe339adb13372c6251 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 18 Oct 2023 14:39:21 -0700 Subject: netlink: specs: add support for auto-sized scalars Support uint / sint types in specs and YNL. Signed-off-by: Jakub Kicinski Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- Documentation/netlink/genetlink-c.yaml | 3 ++- Documentation/netlink/genetlink-legacy.yaml | 3 ++- Documentation/netlink/genetlink.yaml | 3 ++- tools/net/ynl/lib/nlspec.py | 6 ++++++ tools/net/ynl/lib/ynl.c | 6 ++++++ tools/net/ynl/lib/ynl.h | 17 +++++++++++++++++ tools/net/ynl/lib/ynl.py | 14 ++++++++++++++ tools/net/ynl/ynl-gen-c.py | 6 ++++-- 8 files changed, 53 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index dee11c514896..c72c8a428911 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -149,7 +149,8 @@ properties: name: type: string type: &attr-type - enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64, + enum: [ unused, pad, flag, binary, + uint, sint, u8, u16, u32, u64, s32, s64, string, nest, array-nest, nest-type-value ] doc: description: Documentation of the attribute. diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 9194f3e223ef..923de0ff1a9e 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -192,7 +192,8 @@ properties: type: string type: &attr-type description: The netlink attribute type - enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64, + enum: [ unused, pad, flag, binary, + uint, sint, u8, u16, u32, u64, s32, s64, string, nest, array-nest, nest-type-value ] doc: description: Documentation of the attribute. diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 0a4ae861d011..9ceb096b2df2 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -122,7 +122,8 @@ properties: name: type: string type: &attr-type - enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64, + enum: [ unused, pad, flag, binary, + uint, sint, u8, u16, u32, u64, s32, s64, string, nest, array-nest, nest-type-value ] doc: description: Documentation of the attribute. diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 37bcb4d8b37b..92889298b197 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -149,6 +149,7 @@ class SpecAttr(SpecElement): Represents a single attribute type within an attr space. Attributes: + type string, attribute type value numerical ID when serialized attr_set Attribute Set containing this attr is_multi bool, attr may repeat multiple times @@ -157,10 +158,13 @@ class SpecAttr(SpecElement): len integer, optional byte length of binary types display_hint string, hint to help choose format specifier when displaying the value + + is_auto_scalar bool, attr is a variable-size scalar """ def __init__(self, family, attr_set, yaml, value): super().__init__(family, yaml) + self.type = yaml['type'] self.value = value self.attr_set = attr_set self.is_multi = yaml.get('multi-attr', False) @@ -170,6 +174,8 @@ class SpecAttr(SpecElement): self.len = yaml.get('len') self.display_hint = yaml.get('display-hint') + self.is_auto_scalar = self.type == "sint" or self.type == "uint" + class SpecAttrSet(SpecElement): """ Netlink Attribute Set class. diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 514e0d69e731..350ddc247450 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -352,6 +352,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, "Invalid attribute (u64 %s)", policy->name); return -1; + case YNL_PT_UINT: + if (len == sizeof(__u32) || len == sizeof(__u64)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (uint %s)", policy->name); + return -1; case YNL_PT_FLAG: /* Let flags grow into real attrs, why not.. */ break; diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 9eafa3552c16..87b4dad832f0 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -133,6 +133,7 @@ enum ynl_policy_type { YNL_PT_U16, YNL_PT_U32, YNL_PT_U64, + YNL_PT_UINT, YNL_PT_NUL_STR, }; @@ -234,4 +235,20 @@ int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); +#ifndef MNL_HAS_AUTO_SCALARS +static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr) +{ + if (mnl_attr_get_len(attr) == 4) + return mnl_attr_get_u32(attr); + return mnl_attr_get_u64(attr); +} + +static inline void +mnl_attr_put_uint(struct nlmsghdr *nlh, uint16_t type, uint64_t data) +{ + if ((uint32_t)data == (uint64_t)data) + return mnl_attr_put_u32(nlh, type, data); + return mnl_attr_put_u64(nlh, type, data); +} +#endif #endif diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 28ac35008e65..3b36553a66cc 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -130,6 +130,13 @@ class NlAttr: format = self.get_format(attr_type, byte_order) return format.unpack(self.raw)[0] + def as_auto_scalar(self, attr_type, byte_order=None): + if len(self.raw) != 4 and len(self.raw) != 8: + raise Exception(f"Auto-scalar len payload be 4 or 8 bytes, got {len(self.raw)}") + real_type = attr_type[0] + str(len(self.raw) * 8) + format = self.get_format(real_type, byte_order) + return format.unpack(self.raw)[0] + def as_strz(self): return self.raw.decode('ascii')[:-1] @@ -463,6 +470,11 @@ class YnlFamily(SpecFamily): attr_payload = bytes.fromhex(value) else: raise Exception(f'Unknown type for binary attribute, value: {value}') + elif attr.is_auto_scalar: + scalar = int(value) + real_type = attr["type"][0] + ('32' if scalar.bit_length() <= 32 else '64') + format = NlAttr.get_format(real_type, attr.byte_order) + attr_payload = format.pack(int(value)) elif attr['type'] in NlAttr.type_formats: format = NlAttr.get_format(attr['type'], attr.byte_order) attr_payload = format.pack(int(value)) @@ -529,6 +541,8 @@ class YnlFamily(SpecFamily): decoded = self._decode_binary(attr, attr_spec) elif attr_spec["type"] == 'flag': decoded = True + elif attr_spec.is_auto_scalar: + decoded = attr.as_auto_scalar(attr_spec['type'], attr_spec.byte_order) elif attr_spec["type"] in NlAttr.type_formats: decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order) elif attr_spec["type"] == 'array-nest': diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 6f4c538bda9a..a9e8898c9386 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -335,6 +335,8 @@ class TypeScalar(Type): maybe_enum = not self.is_bitfield and 'enum' in self.attr if maybe_enum and self.family.consts[self.attr['enum']].enum_name: self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" + elif self.is_auto_scalar: + self.type_name = '__' + self.type[0] + '64' else: self.type_name = '__' + self.type @@ -362,7 +364,7 @@ class TypeScalar(Type): return super()._attr_policy(policy) def _attr_typol(self): - return f'.type = YNL_PT_U{self.type[1:]}, ' + return f'.type = YNL_PT_U{c_upper(self.type[1:])}, ' def arg_member(self, ri): return [f'{self.type_name} {self.c_name}{self.byte_order_comment}'] @@ -1291,7 +1293,7 @@ class CodeWriter: self.p(line) -scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64'} +scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'} direction_to_suffix = { 'reply': '_rsp', -- cgit v1.2.3 From 2703bc8513996e848b5aefa2deb1ff3baae5d79b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 12 Oct 2023 14:42:28 +0300 Subject: wifi: mac80211: rename ieee80211_tx_status() to ieee80211_tx_status_skb() make htmldocs warns: Documentation/driver-api/80211/mac80211:109: ./include/net/mac80211.h:5170: WARNING: Duplicate C declaration, also defined at mac80211:1117. Declaration is '.. c:function:: void ieee80211_tx_status (struct ieee80211_hw *hw, struct sk_buff *skb)'. This is because there's a function named ieee80211_tx_status() and a struct named ieee80211_tx_status. This has been discussed previously but no solution found: https://lore.kernel.org/all/20220521114629.6ee9fc06@coco.lan/ There's also a bug open for three years with no solution in sight: https://github.com/sphinx-doc/sphinx/pull/8313 So I guess we have no other solution than to a workaround this in the code, for example to rename the function to ieee80211_tx_status_skb() to avoid the name conflict. I got the idea for the name from ieee80211_tx_status_noskb() in which the skb is not provided as an argument, instead with ieee80211_tx_status_skb() the skb is provided. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20231012114229.2931808-2-kvalo@kernel.org Signed-off-by: Johannes Berg --- Documentation/driver-api/80211/mac80211.rst | 2 +- drivers/net/wireless/ath/ath12k/dp_tx.c | 4 ++-- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- drivers/net/wireless/broadcom/b43/dma.c | 4 ++-- drivers/net/wireless/broadcom/b43/pio.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/tx.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++-- drivers/net/wireless/mediatek/mt7601u/tx.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/st/cw1200/txrx.c | 2 +- drivers/net/wireless/ti/wl1251/tx.c | 6 +++--- include/net/mac80211.h | 30 +++++++++++++------------- net/mac80211/main.c | 2 +- net/mac80211/status.c | 4 ++-- 16 files changed, 37 insertions(+), 37 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-api/80211/mac80211.rst b/Documentation/driver-api/80211/mac80211.rst index 67d2e58b45e4..e38a220401f5 100644 --- a/Documentation/driver-api/80211/mac80211.rst +++ b/Documentation/driver-api/80211/mac80211.rst @@ -120,7 +120,7 @@ functions/definitions ieee80211_rx ieee80211_rx_ni ieee80211_rx_irqsafe - ieee80211_tx_status + ieee80211_tx_status_skb ieee80211_tx_status_ni ieee80211_tx_status_irqsafe ieee80211_rts_get diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index f5e0f5426226..492ca6ce6714 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -401,7 +401,7 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, } } - ieee80211_tx_status(ar->hw, msdu); + ieee80211_tx_status_skb(ar->hw, msdu); } static void @@ -498,7 +498,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, * Might end up reporting it out-of-band from HTT stats. */ - ieee80211_tx_status(ar->hw, msdu); + ieee80211_tx_status_skb(ar->hw, msdu); exit: rcu_read_unlock(); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 597d1f916dfd..9f534ed2fbb3 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1770,7 +1770,7 @@ ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb, ah->stats.antenna_tx[0]++; /* invalid */ trace_ath5k_tx_complete(ah, skb, txq, ts); - ieee80211_tx_status(ah->hw, skb); + ieee80211_tx_status_skb(ah->hw, skb); } static void diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 672789e3c55d..800177021baf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -523,7 +523,7 @@ send_mac80211: } /* Send status to mac80211 */ - ieee80211_tx_status(priv->hw, skb); + ieee80211_tx_status_skb(priv->hw, skb); } static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 4e939dcac1c9..f15684379b03 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -94,7 +94,7 @@ static void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | IEEE80211_TX_STATUS_EOSP)) { - ieee80211_tx_status(hw, skb); + ieee80211_tx_status_skb(hw, skb); return; } diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 9a7c62bd5e43..760d1a28edc6 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1531,9 +1531,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ - ieee80211_tx_status(dev->wl->hw, meta->skb); + ieee80211_tx_status_skb(dev->wl->hw, meta->skb); - /* skb will be freed by ieee80211_tx_status(). + /* skb will be freed by ieee80211_tx_status_skb(). * Poison our pointer. */ meta->skb = B43_DMA_PTR_POISON; } else { diff --git a/drivers/net/wireless/broadcom/b43/pio.c b/drivers/net/wireless/broadcom/b43/pio.c index 8c28a9250cd1..0cf70fdb60a6 100644 --- a/drivers/net/wireless/broadcom/b43/pio.c +++ b/drivers/net/wireless/broadcom/b43/pio.c @@ -582,7 +582,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, q->buffer_used -= total_len; q->free_packet_slots += 1; - ieee80211_tx_status(dev->wl->hw, pack->skb); + ieee80211_tx_status_skb(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index 60a7b61d59aa..b0322af8e081 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -1247,7 +1247,7 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) while (!skb_queue_empty(&skbs)) { skb = __skb_dequeue(&skbs); - ieee80211_tx_status(priv->hw, skb); + ieee80211_tx_status_skb(priv->hw, skb); } } @@ -1384,6 +1384,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, while (!skb_queue_empty(&reclaimed_skbs)) { skb = __skb_dequeue(&reclaimed_skbs); - ieee80211_tx_status(priv->hw, skb); + ieee80211_tx_status_skb(priv->hw, skb); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index b0f3d51a7613..73c5f1094a75 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1724,7 +1724,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, RS_DRV_DATA_PACK(lq_color, tx_resp->reduced_tpc); if (likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr1))) - ieee80211_tx_status(mvm->hw, skb); + ieee80211_tx_status_skb(mvm->hw, skb); } /* This is an aggregation queue or might become one, so we use @@ -2080,7 +2080,7 @@ out: while (!skb_queue_empty(&reclaimed_skbs)) { skb = __skb_dequeue(&reclaimed_skbs); - ieee80211_tx_status(mvm->hw, skb); + ieee80211_tx_status_skb(mvm->hw, skb); } } diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index 51d977ffc52f..5aeeac0dd9fe 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -110,7 +110,7 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) info->flags |= IEEE80211_TX_STAT_ACK; spin_lock_bh(&dev->mac_lock); - ieee80211_tx_status(dev->hw, skb); + ieee80211_tx_status_skb(dev->hw, skb); spin_unlock_bh(&dev->mac_lock); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index 9a9cfd0ce402..c88ce446e117 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -533,7 +533,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, */ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TASKLET_CONTEXT)) - ieee80211_tx_status(rt2x00dev->hw, entry->skb); + ieee80211_tx_status_skb(rt2x00dev->hw, entry->skb); else ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); } else { diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index e16e9ae90d20..084d52b11f5b 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -994,7 +994,7 @@ void cw1200_skb_dtor(struct cw1200_common *priv, txpriv->raw_link_id, txpriv->tid); tx_policy_put(priv, txpriv->rate_id); } - ieee80211_tx_status(priv->hw, skb); + ieee80211_tx_status_skb(priv->hw, skb); } void cw1200_rx_cb(struct cw1200_common *priv, diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c index e9dc3c72bb11..474b603c121c 100644 --- a/drivers/net/wireless/ti/wl1251/tx.c +++ b/drivers/net/wireless/ti/wl1251/tx.c @@ -434,7 +434,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, result->status, wl1251_tx_parse_status(result->status)); - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status_skb(wl->hw, skb); wl->tx_frames[result->id] = NULL; } @@ -566,7 +566,7 @@ void wl1251_tx_flush(struct wl1251 *wl) if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) continue; - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status_skb(wl->hw, skb); } for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) @@ -577,7 +577,7 @@ void wl1251_tx_flush(struct wl1251 *wl) if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) continue; - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status_skb(wl->hw, skb); wl->tx_frames[i] = NULL; } } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 511d5d1c042f..580781ff9dcf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4911,7 +4911,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw); * for a single hardware must be synchronized against each other. Calls to * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be * mixed for a single hardware. Must not run concurrently with - * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * ieee80211_tx_status_skb() or ieee80211_tx_status_ni(). * * This function must be called with BHs disabled and RCU read lock * @@ -4936,7 +4936,7 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *sta, * for a single hardware must be synchronized against each other. Calls to * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be * mixed for a single hardware. Must not run concurrently with - * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * ieee80211_tx_status_skb() or ieee80211_tx_status_ni(). * * This function must be called with BHs disabled. * @@ -4961,7 +4961,7 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *sta, * for a single hardware must be synchronized against each other. Calls to * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be * mixed for a single hardware. Must not run concurrently with - * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * ieee80211_tx_status_skb() or ieee80211_tx_status_ni(). * * In process context use instead ieee80211_rx_ni(). * @@ -4981,7 +4981,7 @@ static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) * * Calls to this function, ieee80211_rx() or ieee80211_rx_ni() may not * be mixed for a single hardware.Must not run concurrently with - * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * ieee80211_tx_status_skb() or ieee80211_tx_status_ni(). * * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call @@ -4996,7 +4996,7 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); * * Calls to this function, ieee80211_rx() and ieee80211_rx_irqsafe() may * not be mixed for a single hardware. Must not run concurrently with - * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * ieee80211_tx_status_skb() or ieee80211_tx_status_ni(). * * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call @@ -5172,7 +5172,7 @@ void ieee80211_tx_rate_update(struct ieee80211_hw *hw, struct ieee80211_tx_info *info); /** - * ieee80211_tx_status - transmit status callback + * ieee80211_tx_status_skb - transmit status callback * * Call this function for all transmitted frames after they have been * transmitted. It is permissible to not call this function for @@ -5187,13 +5187,13 @@ void ieee80211_tx_rate_update(struct ieee80211_hw *hw, * @hw: the hardware the frame was transmitted by * @skb: the frame that was transmitted, owned by mac80211 after this call */ -void ieee80211_tx_status(struct ieee80211_hw *hw, - struct sk_buff *skb); +void ieee80211_tx_status_skb(struct ieee80211_hw *hw, + struct sk_buff *skb); /** * ieee80211_tx_status_ext - extended transmit status callback * - * This function can be used as a replacement for ieee80211_tx_status + * This function can be used as a replacement for ieee80211_tx_status_skb() * in drivers that may want to provide extra information that does not * fit into &struct ieee80211_tx_info. * @@ -5210,7 +5210,7 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, /** * ieee80211_tx_status_noskb - transmit status callback without skb * - * This function can be used as a replacement for ieee80211_tx_status + * This function can be used as a replacement for ieee80211_tx_status_skb() * in drivers that cannot reliably map tx status information back to * specific skbs. * @@ -5238,9 +5238,9 @@ static inline void ieee80211_tx_status_noskb(struct ieee80211_hw *hw, /** * ieee80211_tx_status_ni - transmit status callback (in process context) * - * Like ieee80211_tx_status() but can be called in process context. + * Like ieee80211_tx_status_skb() but can be called in process context. * - * Calls to this function, ieee80211_tx_status() and + * Calls to this function, ieee80211_tx_status_skb() and * ieee80211_tx_status_irqsafe() may not be mixed * for a single hardware. * @@ -5251,17 +5251,17 @@ static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw, struct sk_buff *skb) { local_bh_disable(); - ieee80211_tx_status(hw, skb); + ieee80211_tx_status_skb(hw, skb); local_bh_enable(); } /** * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback * - * Like ieee80211_tx_status() but can be called in IRQ context + * Like ieee80211_tx_status_skb() but can be called in IRQ context * (internally defers to a tasklet.) * - * Calls to this function, ieee80211_tx_status() and + * Calls to this function, ieee80211_tx_status_skb() and * ieee80211_tx_status_ni() may not be mixed for a single hardware. * * @hw: the hardware the frame was transmitted by diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b46f4d733c5d..033a5261ac3a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -319,7 +319,7 @@ static void ieee80211_tasklet_handler(struct tasklet_struct *t) break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; - ieee80211_tx_status(&local->hw, skb); + ieee80211_tx_status_skb(&local->hw, skb); break; default: WARN(1, "mac80211: Packet is of unknown type %d\n", diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 807cdab38d5e..1708b33cdc5e 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -1092,7 +1092,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, send_to_cooked, status); } -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_tx_status_skb(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); @@ -1111,7 +1111,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) ieee80211_tx_status_ext(hw, &status); rcu_read_unlock(); } -EXPORT_SYMBOL(ieee80211_tx_status); +EXPORT_SYMBOL(ieee80211_tx_status_skb); void ieee80211_tx_status_ext(struct ieee80211_hw *hw, struct ieee80211_tx_status *status) -- cgit v1.2.3 From 4e2846fd6684227c8f8129ec184fbf090279216d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 21 Oct 2023 13:27:03 +0200 Subject: tools: ynl-gen: introduce support for bitfield32 attribute type Introduce support for attribute type bitfield32. Note that since the generated code works with struct nla_bitfield32, the generator adds netlink.h to the list of includes for userspace headers in case any bitfield32 is present. Note that this is added only to genetlink-legacy scheme as requested by Jakub Kicinski. Signed-off-by: Jiri Pirko Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20231021112711.660606-3-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-legacy.yaml | 2 +- .../userspace-api/netlink/genetlink-legacy.rst | 2 +- tools/net/ynl/lib/ynl.c | 6 ++++ tools/net/ynl/lib/ynl.h | 1 + tools/net/ynl/lib/ynl.py | 13 ++++++-- tools/net/ynl/ynl-gen-c.py | 39 ++++++++++++++++++++++ 6 files changed, 58 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 923de0ff1a9e..565bf615b501 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -192,7 +192,7 @@ properties: type: string type: &attr-type description: The netlink attribute type - enum: [ unused, pad, flag, binary, + enum: [ unused, pad, flag, binary, bitfield32, uint, sint, u8, u16, u32, u64, s32, s64, string, nest, array-nest, nest-type-value ] doc: diff --git a/Documentation/userspace-api/netlink/genetlink-legacy.rst b/Documentation/userspace-api/netlink/genetlink-legacy.rst index 0b3febd57ff5..70a77387f6c4 100644 --- a/Documentation/userspace-api/netlink/genetlink-legacy.rst +++ b/Documentation/userspace-api/netlink/genetlink-legacy.rst @@ -182,7 +182,7 @@ members - ``name`` - The attribute name of the struct member - ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``, - ``s16``, ``s32``, ``s64``, ``string`` or ``binary``. + ``s16``, ``s32``, ``s64``, ``string``, ``binary`` or ``bitfield32``. - ``byte-order`` - ``big-endian`` or ``little-endian`` - ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for :ref:`attribute definitions ` diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index 350ddc247450..830d25097009 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -379,6 +379,12 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, "Invalid attribute (string %s)", policy->name); return -1; + case YNL_PT_BITFIELD32: + if (len == sizeof(struct nla_bitfield32)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (bitfield32 %s)", policy->name); + return -1; default: yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, "Invalid attribute (unknown %s)", policy->name); diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 87b4dad832f0..c883e4747cfa 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -135,6 +135,7 @@ enum ynl_policy_type { YNL_PT_U64, YNL_PT_UINT, YNL_PT_NUL_STR, + YNL_PT_BITFIELD32, }; struct ynl_policy_attr { diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 3b36553a66cc..b1da4aea9336 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -478,6 +478,8 @@ class YnlFamily(SpecFamily): elif attr['type'] in NlAttr.type_formats: format = NlAttr.get_format(attr['type'], attr.byte_order) attr_payload = format.pack(int(value)) + elif attr['type'] in "bitfield32": + attr_payload = struct.pack("II", int(value["value"]), int(value["selector"])) else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') @@ -545,14 +547,19 @@ class YnlFamily(SpecFamily): decoded = attr.as_auto_scalar(attr_spec['type'], attr_spec.byte_order) elif attr_spec["type"] in NlAttr.type_formats: decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order) + if 'enum' in attr_spec: + decoded = self._decode_enum(decoded, attr_spec) elif attr_spec["type"] == 'array-nest': decoded = self._decode_array_nest(attr, attr_spec) + elif attr_spec["type"] == 'bitfield32': + value, selector = struct.unpack("II", attr.raw) + if 'enum' in attr_spec: + value = self._decode_enum(value, attr_spec) + selector = self._decode_enum(selector, attr_spec) + decoded = {"value": value, "selector": selector} else: raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') - if 'enum' in attr_spec: - decoded = self._decode_enum(decoded, attr_spec) - if not attr_spec.is_multi: rsp[attr_spec['name']] = decoded elif attr_spec.name in rsp: diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index a9e8898c9386..7d6c318397be 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -488,6 +488,31 @@ class TypeBinary(Type): f'memcpy({member}, {self.c_name}, {presence}_len);'] +class TypeBitfield32(Type): + def _complex_member_type(self, ri): + return "struct nla_bitfield32" + + def _attr_typol(self): + return f'.type = YNL_PT_BITFIELD32, ' + + def _attr_policy(self, policy): + if not 'enum' in self.attr: + raise Exception('Enum required for bitfield32 attr') + enum = self.family.consts[self.attr['enum']] + mask = enum.get_mask(as_flags=True) + return f"NLA_POLICY_BITFIELD32({mask})" + + def attr_put(self, ri, var): + line = f"mnl_attr_put(nlh, {self.enum_name}, sizeof(struct nla_bitfield32), &{var}->{self.c_name})" + self._attr_put_line(ri, var, line) + + def _attr_get(self, ri, var): + return f"memcpy(&{var}->{self.c_name}, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32));", None, None + + def _setter_lines(self, ri, member, presence): + return [f"memcpy(&{member}, {self.c_name}, sizeof(struct nla_bitfield32));"] + + class TypeNest(Type): def _complex_member_type(self, ri): return self.nested_struct_type @@ -786,6 +811,8 @@ class AttrSet(SpecAttrSet): t = TypeString(self.family, self, elem, value) elif elem['type'] == 'binary': t = TypeBinary(self.family, self, elem, value) + elif elem['type'] == 'bitfield32': + t = TypeBitfield32(self.family, self, elem, value) elif elem['type'] == 'nest': t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'array-nest': @@ -2414,6 +2441,16 @@ def render_user_family(family, cw, prototype): cw.block_end(line=';') +def family_contains_bitfield32(family): + for _, attr_set in family.attr_sets.items(): + if attr_set.subset_of: + continue + for _, attr in attr_set.items(): + if attr.type == "bitfield32": + return True + return False + + def find_kernel_root(full_path): sub_path = '' while True: @@ -2499,6 +2536,8 @@ def main(): cw.p('#include ') if args.header: cw.p('#include ') + if family_contains_bitfield32(parsed): + cw.p('#include ') else: cw.p(f'#include "{parsed.name}-user.h"') cw.p('#include "ynl.h"') -- cgit v1.2.3 From c48066b0cc2c02d2193a710c823e7d6f41d2ea85 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 21 Oct 2023 13:27:05 +0200 Subject: netlink: specs: devlink: remove reload-action from devlink-get cmd reply devlink-get command does not contain reload-action attr in reply. Remove it. Signed-off-by: Jiri Pirko Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20231021112711.660606-5-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/devlink.yaml | 1 - tools/net/ynl/generated/devlink-user.c | 5 ----- tools/net/ynl/generated/devlink-user.h | 2 -- 3 files changed, 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index dec130d2507c..94a1ca10f5fc 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -263,7 +263,6 @@ operations: - bus-name - dev-name - reload-failed - - reload-action - dev-stats dump: reply: *get-reply diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c index 2cb2518500cb..a002f71d6068 100644 --- a/tools/net/ynl/generated/devlink-user.c +++ b/tools/net/ynl/generated/devlink-user.c @@ -475,11 +475,6 @@ int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) return MNL_CB_ERROR; dst->_present.reload_failed = 1; dst->reload_failed = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_ACTION) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_action = 1; - dst->reload_action = mnl_attr_get_u8(attr); } else if (type == DEVLINK_ATTR_DEV_STATS) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h index 4b686d147613..d00bcf79fa0d 100644 --- a/tools/net/ynl/generated/devlink-user.h +++ b/tools/net/ynl/generated/devlink-user.h @@ -112,14 +112,12 @@ struct devlink_get_rsp { __u32 bus_name_len; __u32 dev_name_len; __u32 reload_failed:1; - __u32 reload_action:1; __u32 dev_stats:1; } _present; char *bus_name; char *dev_name; __u8 reload_failed; - __u8 reload_action; struct devlink_dl_dev_stats dev_stats; }; -- cgit v1.2.3 From 6cc8ad97c101912e02733d807bc5273ce6d938bd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 21 Oct 2023 13:27:06 +0200 Subject: netlink: specs: devlink: make dont-validate single line Make dont-validate field more compact and push it into a single line. Reviewed-by: Jakub Kicinski Signed-off-by: Jiri Pirko Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20231021112711.660606-6-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/devlink.yaml | 67 ++++++++------------------------ 1 file changed, 16 insertions(+), 51 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index 94a1ca10f5fc..dd035a8f5eb4 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -245,10 +245,7 @@ operations: name: get doc: Get devlink instances. attribute-set: devlink - dont-validate: - - strict - - dump - + dont-validate: [ strict, dump ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -271,9 +268,7 @@ operations: name: port-get doc: Get devlink port instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit-port post: devlink-nl-post-doit @@ -299,9 +294,7 @@ operations: name: sb-get doc: Get shared buffer instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -325,9 +318,7 @@ operations: name: sb-pool-get doc: Get shared buffer pool instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -352,9 +343,7 @@ operations: name: sb-port-pool-get doc: Get shared buffer port-pool combinations and threshold. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit-port post: devlink-nl-post-doit @@ -380,9 +369,7 @@ operations: name: sb-tc-pool-bind-get doc: Get shared buffer port-TC to pool bindings and threshold. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit-port post: devlink-nl-post-doit @@ -409,9 +396,7 @@ operations: name: param-get doc: Get param instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -435,9 +420,7 @@ operations: name: region-get doc: Get region instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit-port-optional post: devlink-nl-post-doit @@ -462,10 +445,7 @@ operations: name: info-get doc: Get device information, like driver name, hardware and firmware versions etc. attribute-set: devlink - dont-validate: - - strict - - dump - + dont-validate: [ strict, dump ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -489,9 +469,7 @@ operations: name: health-reporter-get doc: Get health reporter instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit-port-optional post: devlink-nl-post-doit @@ -514,9 +492,7 @@ operations: name: trap-get doc: Get trap instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -540,9 +516,7 @@ operations: name: trap-group-get doc: Get trap group instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -566,9 +540,7 @@ operations: name: trap-policer-get doc: Get trap policer instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -592,9 +564,7 @@ operations: name: rate-get doc: Get rate instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -619,9 +589,7 @@ operations: name: linecard-get doc: Get line card instances. attribute-set: devlink - dont-validate: - - strict - + dont-validate: [ strict ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit @@ -645,10 +613,7 @@ operations: name: selftests-get doc: Get device selftest instances. attribute-set: devlink - dont-validate: - - strict - - dump - + dont-validate: [ strict, dump ] do: pre: devlink-nl-pre-doit post: devlink-nl-post-doit -- cgit v1.2.3 From f2f9dd164db079161a834c8698c68a94a50b4168 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 21 Oct 2023 13:27:09 +0200 Subject: netlink: specs: devlink: add the remaining command to generate complete split_ops Currently, some of the commands are not described in devlink yaml file and are manually filled in net/devlink/netlink.c in small_ops. To make all part of split_ops, add definitions of the rest of the commands alongside with needed attributes and enums. Note that this focuses on the kernel side. The requests are fully described in order to generate split_op alongside with policies. Follow-up will describe the replies in order to make the userspace helpers complete. Signed-off-by: Jiri Pirko Reviewed-by: Jacob Keller Link: https://lore.kernel.org/r/20231021112711.660606-9-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/devlink.yaml | 1530 ++++++++- net/devlink/netlink_gen.c | 757 ++++- net/devlink/netlink_gen.h | 64 +- tools/net/ynl/generated/devlink-user.c | 5062 ++++++++++++++++++++++++++---- tools/net/ynl/generated/devlink-user.h | 4213 ++++++++++++++++++++++--- 5 files changed, 10495 insertions(+), 1131 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index dd035a8f5eb4..c6ba4889575a 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -15,6 +15,161 @@ definitions: name: ingress - name: egress + - + type: enum + name: port-type + entries: + - + name: notset + - + name: auto + - + name: eth + - + name: ib + - + type: enum + name: port-flavour + entries: + - + name: physical + - + name: cpu + - + name: dsa + - + name: pci_pf + - + name: pci_vf + - + name: virtual + - + name: unused + - + name: pci_sf + - + type: enum + name: port-fn-state + entries: + - + name: inactive + - + name: active + - + type: enum + name: port-fn-opstate + entries: + - + name: detached + - + name: attached + - + type: enum + name: port-fn-attr-cap + entries: + - + name: roce-bit + - + name: migratable-bit + - + type: enum + name: sb-threshold-type + entries: + - + name: static + - + name: dynamic + - + type: enum + name: eswitch-mode + entries: + - + name: legacy + - + name: switchdev + - + type: enum + name: eswitch-inline-mode + entries: + - + name: none + - + name: link + - + name: network + - + name: transport + - + type: enum + name: eswitch-encap-mode + entries: + - + name: none + - + name: basic + - + type: enum + name: dpipe-match-type + entries: + - + name: field-exact + - + type: enum + name: dpipe-action-type + entries: + - + name: field-modify + - + type: enum + name: dpipe-field-mapping-type + entries: + - + name: none + - + name: ifindex + - + type: enum + name: resource-unit + entries: + - + name: entry + - + type: enum + name: reload-action + entries: + - + name: driver-reinit + value: 1 + - + name: fw-activate + - + type: enum + name: param-cmode + entries: + - + name: runtime + - + name: driverinit + - + name: permanent + - + type: enum + name: flash-overwrite + entries: + - + name: settings-bit + - + name: identifiers-bit + - + type: enum + name: trap-action + entries: + - + name: drop + - + name: trap + - + name: mirror attribute-sets: - @@ -31,6 +186,17 @@ attribute-sets: - name: port-index type: u32 + - + name: port-type + type: u16 + enum: port-type + + # TODO: fill in the attributes in between + + - + name: port-split-count + type: u32 + value: 9 # TODO: fill in the attributes in between @@ -45,18 +211,224 @@ attribute-sets: name: sb-pool-index type: u16 value: 17 - - name: sb-pool-type type: u8 enum: sb-pool-type + - + name: sb-pool-size + type: u32 + - + name: sb-pool-threshold-type + type: u8 + enum: sb-threshold-type + - + name: sb-threshold + type: u32 + - + name: sb-tc-index + type: u16 + value: 22 # TODO: fill in the attributes in between - - name: sb-tc-index + name: eswitch-mode type: u16 - value: 22 + value: 25 + enum: eswitch-mode + + - + name: eswitch-inline-mode + type: u16 + enum: eswitch-inline-mode + - + name: dpipe-tables + type: nest + nested-attributes: dl-dpipe-tables + - + name: dpipe-table + type: nest + multi-attr: true + nested-attributes: dl-dpipe-table + - + name: dpipe-table-name + type: string + - + name: dpipe-table-size + type: u64 + - + name: dpipe-table-matches + type: nest + nested-attributes: dl-dpipe-table-matches + - + name: dpipe-table-actions + type: nest + nested-attributes: dl-dpipe-table-actions + - + name: dpipe-table-counters-enabled + type: u8 + - + name: dpipe-entries + type: nest + nested-attributes: dl-dpipe-entries + - + name: dpipe-entry + type: nest + multi-attr: true + nested-attributes: dl-dpipe-entry + - + name: dpipe-entry-index + type: u64 + - + name: dpipe-entry-match-values + type: nest + nested-attributes: dl-dpipe-entry-match-values + - + name: dpipe-entry-action-values + type: nest + nested-attributes: dl-dpipe-entry-action-values + - + name: dpipe-entry-counter + type: u64 + - + name: dpipe-match + type: nest + multi-attr: true + nested-attributes: dl-dpipe-match + - + name: dpipe-match-value + type: nest + multi-attr: true + nested-attributes: dl-dpipe-match-value + - + name: dpipe-match-type + type: u32 + enum: dpipe-match-type + - + name: dpipe-action + type: nest + multi-attr: true + nested-attributes: dl-dpipe-action + - + name: dpipe-action-value + type: nest + multi-attr: true + nested-attributes: dl-dpipe-action-value + - + name: dpipe-action-type + type: u32 + enum: dpipe-action-type + - + name: dpipe-value + type: binary + - + name: dpipe-value-mask + type: binary + - + name: dpipe-value-mapping + type: u32 + - + name: dpipe-headers + type: nest + nested-attributes: dl-dpipe-headers + - + name: dpipe-header + type: nest + multi-attr: true + nested-attributes: dl-dpipe-header + - + name: dpipe-header-name + type: string + - + name: dpipe-header-id + type: u32 + - + name: dpipe-header-fields + type: nest + nested-attributes: dl-dpipe-header-fields + - + name: dpipe-header-global + type: u8 + - + name: dpipe-header-index + type: u32 + - + name: dpipe-field + type: nest + multi-attr: true + nested-attributes: dl-dpipe-field + - + name: dpipe-field-name + type: string + - + name: dpipe-field-id + type: u32 + - + name: dpipe-field-bitwidth + type: u32 + - + name: dpipe-field-mapping-type + type: u32 + enum: dpipe-field-mapping-type + - + name: pad + type: pad + - + name: eswitch-encap-mode + type: u8 + value: 62 + enum: eswitch-encap-mode + - + name: resource-list + type: nest + nested-attributes: dl-resource-list + - + name: resource + type: nest + multi-attr: true + nested-attributes: dl-resource + - + name: resource-name + type: string + - + name: resource-id + type: u64 + - + name: resource-size + type: u64 + - + name: resource-size-new + type: u64 + - + name: resource-size-valid + type: u8 + - + name: resource-size-min + type: u64 + - + name: resource-size-max + type: u64 + - + name: resource-size-gran + type: u64 + - + name: resource-unit + type: u8 + enum: resource-unit + - + name: resource-occ + type: u64 + - + name: dpipe-table-resource-id + type: u64 + - + name: dpipe-table-resource-units + type: u64 + - + name: port-flavour + type: u16 + enum: port-flavour # TODO: fill in the attributes in between @@ -67,17 +439,41 @@ attribute-sets: # TODO: fill in the attributes in between + - + name: param-type + type: u8 + value: 83 + + # TODO: fill in the attributes in between + + - + name: param-value-cmode + type: u8 + enum: param-cmode + value: 87 - name: region-name type: string - value: 88 # TODO: fill in the attributes in between + - + name: region-snapshot-id + type: u32 + value: 92 + + # TODO: fill in the attributes in between + + - + name: region-chunk-addr + type: u64 + value: 96 + - + name: region-chunk-len + type: u64 - name: info-driver-name type: string - value: 98 - name: info-serial-number type: string @@ -105,6 +501,29 @@ attribute-sets: # TODO: fill in the attributes in between + - + name: fmsg + type: nest + nested-attributes: dl-fmsg + value: 106 + - + name: fmsg-obj-nest-start + type: flag + - + name: fmsg-pair-nest-start + type: flag + - + name: fmsg-arr-nest-start + type: flag + - + name: fmsg-nest-end + type: flag + - + name: fmsg-obj-name + type: string + + # TODO: fill in the attributes in between + - name: health-reporter-name type: string @@ -112,10 +531,37 @@ attribute-sets: # TODO: fill in the attributes in between + - + name: health-reporter-graceful-period + type: u64 + value: 120 + - + name: health-reporter-auto-recover + type: u8 + - + name: flash-update-file-name + type: string + - + name: flash-update-component + type: string + + # TODO: fill in the attributes in between + + - + name: port-pci-pf-number + type: u16 + value: 127 + + # TODO: fill in the attributes in between + - name: trap-name type: string value: 130 + - + name: trap-action + type: u8 + enum: trap-action # TODO: fill in the attributes in between @@ -131,23 +577,68 @@ attribute-sets: # TODO: fill in the attributes in between - - name: trap-policer-id + name: netns-fd + type: u32 + value: 138 + - + name: netns-pid + type: u32 + - + name: netns-id type: u32 - value: 142 # TODO: fill in the attributes in between - - name: reload-action + name: health-reporter-auto-dump type: u8 - value: 153 + value: 141 + - + name: trap-policer-id + type: u32 + - + name: trap-policer-rate + type: u64 + - + name: trap-policer-burst + type: u64 + - + name: port-function + type: nest + nested-attributes: dl-port-function + + # TODO: fill in the attributes in between + + - + name: port-controller-number + type: u32 + value: 150 # TODO: fill in the attributes in between + - + name: flash-update-overwrite-mask + type: bitfield32 + enum: flash-overwrite + enum-as-flags: True + value: 152 + - + name: reload-action + type: u8 + enum: reload-action + - + name: reload-actions-performed + type: bitfield32 + enum: reload-action + enum-as-flags: True + - + name: reload-limits + type: bitfield32 + enum: reload-action + enum-as-flags: True - name: dev-stats type: nest - value: 156 nested-attributes: dl-dev-stats - name: reload-stats @@ -181,10 +672,26 @@ attribute-sets: # TODO: fill in the attributes in between + - + name: port-pci-sf-number + type: u32 + value: 164 + + # TODO: fill in the attributes in between + + - + name: rate-tx-share + type: u64 + value: 166 + - + name: rate-tx-max + type: u64 - name: rate-node-name type: string - value: 168 + - + name: rate-parent-node-name + type: string # TODO: fill in the attributes in between @@ -193,6 +700,30 @@ attribute-sets: type: u32 value: 171 + # TODO: fill in the attributes in between + + - + name: linecard-type + type: string + value: 173 + + # TODO: fill in the attributes in between + + - + name: selftests + type: nest + value: 176 + nested-attributes: dl-selftest-id + - + name: rate-tx-priority + type: u32 + - + name: rate-tx-weight + type: u32 + - + name: region-direct + type: flag + - name: dl-dev-stats subset-of: devlink @@ -222,21 +753,276 @@ attribute-sets: - name: reload-stats-entry - - name: dl-reload-stats-entry + name: dl-reload-stats-entry + subset-of: devlink + attributes: + - + name: reload-stats-limit + - + name: reload-stats-value + - + name: dl-info-version + subset-of: devlink + attributes: + - + name: info-version-name + - + name: info-version-value + - + name: dl-port-function + name-prefix: devlink-port-fn-attr- + attr-max-name: devlink-port-function-attr-max + attributes: + - + name-prefix: devlink-port-function-attr- + name: hw-addr + type: binary + value: 1 + - + name: state + type: u8 + enum: port-fn-state + - + name: opstate + type: u8 + enum: port-fn-opstate + - + name: caps + type: bitfield32 + enum: port-fn-attr-cap + enum-as-flags: True + + - + name: dl-dpipe-tables + subset-of: devlink + attributes: + - + name: dpipe-table + + - + name: dl-dpipe-table + subset-of: devlink + attributes: + - + name: dpipe-table-name + - + name: dpipe-table-size + - + name: dpipe-table-name + - + name: dpipe-table-size + - + name: dpipe-table-matches + - + name: dpipe-table-actions + - + name: dpipe-table-counters-enabled + - + name: dpipe-table-resource-id + - + name: dpipe-table-resource-units + + - + name: dl-dpipe-table-matches + subset-of: devlink + attributes: + - + name: dpipe-match + + - + name: dl-dpipe-table-actions + subset-of: devlink + attributes: + - + name: dpipe-action + + - + name: dl-dpipe-entries + subset-of: devlink + attributes: + - + name: dpipe-entry + + - + name: dl-dpipe-entry + subset-of: devlink + attributes: + - + name: dpipe-entry-index + - + name: dpipe-entry-match-values + - + name: dpipe-entry-action-values + - + name: dpipe-entry-counter + + - + name: dl-dpipe-entry-match-values + subset-of: devlink + attributes: + - + name: dpipe-match-value + + - + name: dl-dpipe-entry-action-values + subset-of: devlink + attributes: + - + name: dpipe-action-value + + - + name: dl-dpipe-match + subset-of: devlink + attributes: + - + name: dpipe-match-type + - + name: dpipe-header-id + - + name: dpipe-header-global + - + name: dpipe-header-index + - + name: dpipe-field-id + + - + name: dl-dpipe-match-value + subset-of: devlink + attributes: + - + name: dpipe-match + - + name: dpipe-value + - + name: dpipe-value-mask + - + name: dpipe-value-mapping + + - + name: dl-dpipe-action + subset-of: devlink + attributes: + - + name: dpipe-action-type + - + name: dpipe-header-id + - + name: dpipe-header-global + - + name: dpipe-header-index + - + name: dpipe-field-id + + - + name: dl-dpipe-action-value + subset-of: devlink + attributes: + - + name: dpipe-action + - + name: dpipe-value + - + name: dpipe-value-mask + - + name: dpipe-value-mapping + + - + name: dl-dpipe-headers + subset-of: devlink + attributes: + - + name: dpipe-header + + - + name: dl-dpipe-header + subset-of: devlink + attributes: + - + name: dpipe-header-name + - + name: dpipe-header-id + - + name: dpipe-header-global + - + name: dpipe-header-fields + + - + name: dl-dpipe-header-fields + subset-of: devlink + attributes: + - + name: dpipe-field + + - + name: dl-dpipe-field + subset-of: devlink + attributes: + - + name: dpipe-field-name + - + name: dpipe-field-id + - + name: dpipe-field-bitwidth + - + name: dpipe-field-mapping-type + + - + name: dl-resource + subset-of: devlink + attributes: + # - + # name: resource-list + # This is currently unsupported due to circular dependency + - + name: resource-name + - + name: resource-id + - + name: resource-size + - + name: resource-size-new + - + name: resource-size-valid + - + name: resource-size-min + - + name: resource-size-max + - + name: resource-size-gran + - + name: resource-unit + - + name: resource-occ + + - + name: dl-resource-list + subset-of: devlink + attributes: + - + name: resource + + - + name: dl-fmsg subset-of: devlink attributes: - - name: reload-stats-limit + name: fmsg-obj-nest-start - - name: reload-stats-value + name: fmsg-pair-nest-start + - + name: fmsg-arr-nest-start + - + name: fmsg-nest-end + - + name: fmsg-obj-name + - - name: dl-info-version - subset-of: devlink + name: dl-selftest-id + name-prefix: devlink-attr-selftest-id- attributes: - - name: info-version-name - - - name: info-version-value + name: flash + type: flag operations: enum-model: directional @@ -287,8 +1073,84 @@ operations: reply: value: 3 # due to a bug, port dump returns DEVLINK_CMD_NEW attributes: *port-id-attrs + - + name: port-set + doc: Set devlink port instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - port-index + - port-type + - port-function + + - + name: port-new + doc: Create devlink port instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - port-index + - port-flavour + - port-pci-pf-number + - port-pci-sf-number + - port-controller-number + reply: + value: 7 + attributes: *port-id-attrs + + - + name: port-del + doc: Delete devlink port instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: *port-id-attrs - # TODO: fill in the operations in between + - + name: port-split + doc: Split devlink port instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - port-index + - port-split-count + + - + name: port-unsplit + doc: Unplit devlink port instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: *port-id-attrs - name: sb-get @@ -312,8 +1174,6 @@ operations: attributes: *dev-id-attrs reply: *sb-get-reply - # TODO: fill in the operations in between - - name: sb-pool-get doc: Get shared buffer pool instances. @@ -337,7 +1197,23 @@ operations: attributes: *dev-id-attrs reply: *sb-pool-get-reply - # TODO: fill in the operations in between + - + name: sb-pool-set + doc: Set shared buffer pool instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - sb-index + - sb-pool-index + - sb-pool-threshold-type + - sb-pool-size - name: sb-port-pool-get @@ -363,34 +1239,263 @@ operations: attributes: *dev-id-attrs reply: *sb-port-pool-get-reply - # TODO: fill in the operations in between + - + name: sb-port-pool-set + doc: Set shared buffer port-pool combinations and threshold. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - port-index + - sb-index + - sb-pool-index + - sb-threshold + + - + name: sb-tc-pool-bind-get + doc: Get shared buffer port-TC to pool bindings and threshold. + attribute-set: devlink + dont-validate: [ strict ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + value: 23 + attributes: &sb-tc-pool-bind-id-attrs + - bus-name + - dev-name + - port-index + - sb-index + - sb-pool-type + - sb-tc-index + reply: &sb-tc-pool-bind-get-reply + value: 25 + attributes: *sb-tc-pool-bind-id-attrs + dump: + request: + attributes: *dev-id-attrs + reply: *sb-tc-pool-bind-get-reply + + - + name: sb-tc-pool-bind-set + doc: Set shared buffer port-TC to pool bindings and threshold. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - port-index + - sb-index + - sb-pool-index + - sb-pool-type + - sb-tc-index + - sb-threshold + + - + name: sb-occ-snapshot + doc: Take occupancy snapshot of shared buffer. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + value: 27 + attributes: + - bus-name + - dev-name + - sb-index + + - + name: sb-occ-max-clear + doc: Clear occupancy watermarks of shared buffer. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - sb-index + + - + name: eswitch-get + doc: Get eswitch attributes. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: *dev-id-attrs + reply: + value: 29 + attributes: &eswitch-attrs + - bus-name + - dev-name + - eswitch-mode + - eswitch-inline-mode + - eswitch-encap-mode + + - + name: eswitch-set + doc: Set eswitch attributes. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: *eswitch-attrs + + - + name: dpipe-table-get + doc: Get dpipe table attributes. + attribute-set: devlink + dont-validate: [ strict ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - dpipe-table-name + reply: + value: 31 + attributes: + - bus-name + - dev-name + - dpipe-tables + + - + name: dpipe-entries-get + doc: Get dpipe entries attributes. + attribute-set: devlink + dont-validate: [ strict ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - dpipe-table-name + reply: + attributes: + - bus-name + - dev-name + - dpipe-entries + + - + name: dpipe-headers-get + doc: Get dpipe headers attributes. + attribute-set: devlink + dont-validate: [ strict ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + reply: + attributes: + - bus-name + - dev-name + - dpipe-headers + + - + name: dpipe-table-counters-set + doc: Set dpipe counter attributes. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - dpipe-table-name + - dpipe-table-counters-enabled + + - + name: resource-set + doc: Set resource attributes. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - resource-id + - resource-size + + - + name: resource-dump + doc: Get resource attributes. + attribute-set: devlink + dont-validate: [ strict ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + reply: + value: 36 + attributes: + - bus-name + - dev-name + - resource-list - - name: sb-tc-pool-bind-get - doc: Get shared buffer port-TC to pool bindings and threshold. + name: reload + doc: Reload devlink. attribute-set: devlink dont-validate: [ strict ] + flags: [ admin-perm ] do: - pre: devlink-nl-pre-doit-port + pre: devlink-nl-pre-doit post: devlink-nl-post-doit request: - value: 23 - attributes: &sb-tc-pool-bind-id-attrs + attributes: - bus-name - dev-name - - port-index - - sb-index - - sb-pool-type - - sb-tc-index - reply: &sb-tc-pool-bind-get-reply - value: 25 - attributes: *sb-tc-pool-bind-id-attrs - dump: - request: - attributes: *dev-id-attrs - reply: *sb-tc-pool-bind-get-reply - - # TODO: fill in the operations in between + - reload-action + - reload-limits + - netns-pid + - netns-fd + - netns-id + reply: + attributes: + - bus-name + - dev-name + - reload-actions-performed - name: param-get @@ -401,20 +1506,34 @@ operations: pre: devlink-nl-pre-doit post: devlink-nl-post-doit request: - value: 38 attributes: ¶m-id-attrs - bus-name - dev-name - param-name reply: ¶m-get-reply - value: 38 attributes: *param-id-attrs dump: request: attributes: *dev-id-attrs reply: *param-get-reply - # TODO: fill in the operations in between + - + name: param-set + doc: Set param instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - param-name + - param-type + # param-value-data is missing here as the type is variable + - param-value-cmode - name: region-get @@ -439,7 +1558,91 @@ operations: attributes: *dev-id-attrs reply: *region-get-reply - # TODO: fill in the operations in between + - + name: region-new + doc: Create region snapshot. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + value: 44 + attributes: ®ion-snapshot-id-attrs + - bus-name + - dev-name + - port-index + - region-name + - region-snapshot-id + reply: + value: 44 + attributes: *region-snapshot-id-attrs + + - + name: region-del + doc: Delete region snapshot. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + attributes: *region-snapshot-id-attrs + + - + name: region-read + doc: Read region data. + attribute-set: devlink + dont-validate: [ dump-strict ] + flags: [ admin-perm ] + dump: + request: + attributes: + - bus-name + - dev-name + - port-index + - region-name + - region-snapshot-id + - region-direct + - region-chunk-addr + - region-chunk-len + reply: + value: 46 + attributes: + - bus-name + - dev-name + - port-index + - region-name + + - + name: port-param-get + doc: Get port param instances. + attribute-set: devlink + dont-validate: [ strict, dump-strict ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: *port-id-attrs + reply: + attributes: *port-id-attrs + dump: + reply: + attributes: *port-id-attrs + + - + name: port-param-set + doc: Set port param instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + attributes: *port-id-attrs - name: info-get @@ -486,7 +1689,91 @@ operations: attributes: *port-id-attrs reply: *health-reporter-get-reply - # TODO: fill in the operations in between + - + name: health-reporter-set + doc: Set health reporter instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - port-index + - health-reporter-name + - health-reporter-graceful-period + - health-reporter-auto-recover + - health-reporter-auto-dump + + - + name: health-reporter-recover + doc: Recover health reporter instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + attributes: *health-reporter-id-attrs + + - + name: health-reporter-diagnose + doc: Diagnose health reporter instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + attributes: *health-reporter-id-attrs + + - + name: health-reporter-dump-get + doc: Dump health reporter instances. + attribute-set: devlink + dont-validate: [ dump-strict ] + flags: [ admin-perm ] + dump: + request: + attributes: *health-reporter-id-attrs + reply: + value: 56 + attributes: + - fmsg + + - + name: health-reporter-dump-clear + doc: Clear dump of health reporter instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + attributes: *health-reporter-id-attrs + + - + name: flash-update + doc: Flash update devlink instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - flash-update-file-name + - flash-update-component + - flash-update-overwrite-mask - name: trap-get @@ -510,7 +1797,21 @@ operations: attributes: *dev-id-attrs reply: *trap-get-reply - # TODO: fill in the operations in between + - + name: trap-set + doc: Set trap instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - trap-name + - trap-action - name: trap-group-get @@ -534,7 +1835,22 @@ operations: attributes: *dev-id-attrs reply: *trap-group-get-reply - # TODO: fill in the operations in between + - + name: trap-group-set + doc: Set trap group instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - trap-group-name + - trap-action + - trap-policer-id - name: trap-policer-get @@ -558,7 +1874,35 @@ operations: attributes: *dev-id-attrs reply: *trap-policer-get-reply - # TODO: fill in the operations in between + - + name: trap-policer-set + doc: Get trap policer instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - trap-policer-id + - trap-policer-rate + - trap-policer-burst + + - + name: health-reporter-test + doc: Test health reporter instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit-port-optional + post: devlink-nl-post-doit + request: + value: 73 + attributes: *health-reporter-id-attrs - name: rate-get @@ -583,7 +1927,60 @@ operations: attributes: *dev-id-attrs reply: *rate-get-reply - # TODO: fill in the operations in between + - + name: rate-set + doc: Set rate instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - rate-node-name + - rate-tx-share + - rate-tx-max + - rate-tx-priority + - rate-tx-weight + - rate-parent-node-name + + - + name: rate-new + doc: Create rate instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - rate-node-name + - rate-tx-share + - rate-tx-max + - rate-tx-priority + - rate-tx-weight + - rate-parent-node-name + + - + name: rate-del + doc: Delete rate instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - rate-node-name - name: linecard-get @@ -607,7 +2004,21 @@ operations: attributes: *dev-id-attrs reply: *linecard-get-reply - # TODO: fill in the operations in between + - + name: linecard-set + doc: Set line card instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - linecard-index + - linecard-type - name: selftests-get @@ -625,3 +2036,18 @@ operations: attributes: *dev-id-attrs dump: reply: *selftests-get-reply + + - + name: selftests-run + doc: Run device selftest instances. + attribute-set: devlink + dont-validate: [ strict ] + flags: [ admin-perm ] + do: + pre: devlink-nl-pre-doit + post: devlink-nl-post-doit + request: + attributes: + - bus-name + - dev-name + - selftests diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c index 467b7a431de1..9cbae0169249 100644 --- a/net/devlink/netlink_gen.c +++ b/net/devlink/netlink_gen.c @@ -10,6 +10,18 @@ #include +/* Common nested types */ +const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_FN_ATTR_CAPS + 1] = { + [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY, }, + [DEVLINK_PORT_FN_ATTR_STATE] = NLA_POLICY_MAX(NLA_U8, 1), + [DEVLINK_PORT_FN_ATTR_OPSTATE] = NLA_POLICY_MAX(NLA_U8, 1), + [DEVLINK_PORT_FN_ATTR_CAPS] = NLA_POLICY_BITFIELD32(3), +}; + +const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1] = { + [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .type = NLA_FLAG, }, +}; + /* DEVLINK_CMD_GET - do */ static const struct nla_policy devlink_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -29,6 +41,48 @@ static const struct nla_policy devlink_port_get_dump_nl_policy[DEVLINK_ATTR_DEV_ [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_PORT_SET - do */ +static const struct nla_policy devlink_port_set_nl_policy[DEVLINK_ATTR_PORT_FUNCTION + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_MAX(NLA_U16, 3), + [DEVLINK_ATTR_PORT_FUNCTION] = NLA_POLICY_NESTED(devlink_dl_port_function_nl_policy), +}; + +/* DEVLINK_CMD_PORT_NEW - do */ +static const struct nla_policy devlink_port_new_nl_policy[DEVLINK_ATTR_PORT_PCI_SF_NUMBER + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_PORT_FLAVOUR] = NLA_POLICY_MAX(NLA_U16, 7), + [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16, }, + [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32, }, + [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_PORT_DEL - do */ +static const struct nla_policy devlink_port_del_nl_policy[DEVLINK_ATTR_PORT_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_PORT_SPLIT - do */ +static const struct nla_policy devlink_port_split_nl_policy[DEVLINK_ATTR_PORT_SPLIT_COUNT + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_PORT_UNSPLIT - do */ +static const struct nla_policy devlink_port_unsplit_nl_policy[DEVLINK_ATTR_PORT_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, +}; + /* DEVLINK_CMD_SB_GET - do */ static const struct nla_policy devlink_sb_get_do_nl_policy[DEVLINK_ATTR_SB_INDEX + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -56,6 +110,16 @@ static const struct nla_policy devlink_sb_pool_get_dump_nl_policy[DEVLINK_ATTR_D [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_SB_POOL_SET - do */ +static const struct nla_policy devlink_sb_pool_set_nl_policy[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16, }, + [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = NLA_POLICY_MAX(NLA_U8, 1), + [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32, }, +}; + /* DEVLINK_CMD_SB_PORT_POOL_GET - do */ static const struct nla_policy devlink_sb_port_pool_get_do_nl_policy[DEVLINK_ATTR_SB_POOL_INDEX + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -71,6 +135,16 @@ static const struct nla_policy devlink_sb_port_pool_get_dump_nl_policy[DEVLINK_A [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ +static const struct nla_policy devlink_sb_port_pool_set_nl_policy[DEVLINK_ATTR_SB_THRESHOLD + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16, }, + [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32, }, +}; + /* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ static const struct nla_policy devlink_sb_tc_pool_bind_get_do_nl_policy[DEVLINK_ATTR_SB_TC_INDEX + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -87,6 +161,100 @@ static const struct nla_policy devlink_sb_tc_pool_bind_get_dump_nl_policy[DEVLIN [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ +static const struct nla_policy devlink_sb_tc_pool_bind_set_nl_policy[DEVLINK_ATTR_SB_TC_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16, }, + [DEVLINK_ATTR_SB_POOL_TYPE] = NLA_POLICY_MAX(NLA_U8, 1), + [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16, }, + [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ +static const struct nla_policy devlink_sb_occ_snapshot_nl_policy[DEVLINK_ATTR_SB_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ +static const struct nla_policy devlink_sb_occ_max_clear_nl_policy[DEVLINK_ATTR_SB_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_ESWITCH_GET - do */ +static const struct nla_policy devlink_eswitch_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_ESWITCH_SET - do */ +static const struct nla_policy devlink_eswitch_set_nl_policy[DEVLINK_ATTR_ESWITCH_ENCAP_MODE + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_MAX(NLA_U16, 1), + [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = NLA_POLICY_MAX(NLA_U16, 3), + [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = NLA_POLICY_MAX(NLA_U8, 1), +}; + +/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ +static const struct nla_policy devlink_dpipe_table_get_nl_policy[DEVLINK_ATTR_DPIPE_TABLE_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ +static const struct nla_policy devlink_dpipe_entries_get_nl_policy[DEVLINK_ATTR_DPIPE_TABLE_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ +static const struct nla_policy devlink_dpipe_headers_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ +static const struct nla_policy devlink_dpipe_table_counters_set_nl_policy[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8, }, +}; + +/* DEVLINK_CMD_RESOURCE_SET - do */ +static const struct nla_policy devlink_resource_set_nl_policy[DEVLINK_ATTR_RESOURCE_SIZE + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64, }, +}; + +/* DEVLINK_CMD_RESOURCE_DUMP - do */ +static const struct nla_policy devlink_resource_dump_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_RELOAD - do */ +static const struct nla_policy devlink_reload_nl_policy[DEVLINK_ATTR_RELOAD_LIMITS + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, 1, 2), + [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(6), + [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32, }, + [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32, }, + [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32, }, +}; + /* DEVLINK_CMD_PARAM_GET - do */ static const struct nla_policy devlink_param_get_do_nl_policy[DEVLINK_ATTR_PARAM_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -100,6 +268,15 @@ static const struct nla_policy devlink_param_get_dump_nl_policy[DEVLINK_ATTR_DEV [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_PARAM_SET - do */ +static const struct nla_policy devlink_param_set_nl_policy[DEVLINK_ATTR_PARAM_VALUE_CMODE + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8, }, + [DEVLINK_ATTR_PARAM_VALUE_CMODE] = NLA_POLICY_MAX(NLA_U8, 2), +}; + /* DEVLINK_CMD_REGION_GET - do */ static const struct nla_policy devlink_region_get_do_nl_policy[DEVLINK_ATTR_REGION_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -114,6 +291,50 @@ static const struct nla_policy devlink_region_get_dump_nl_policy[DEVLINK_ATTR_DE [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_REGION_NEW - do */ +static const struct nla_policy devlink_region_new_nl_policy[DEVLINK_ATTR_REGION_SNAPSHOT_ID + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_REGION_DEL - do */ +static const struct nla_policy devlink_region_del_nl_policy[DEVLINK_ATTR_REGION_SNAPSHOT_ID + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_REGION_READ - dump */ +static const struct nla_policy devlink_region_read_nl_policy[DEVLINK_ATTR_REGION_DIRECT + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32, }, + [DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG, }, + [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64, }, + [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64, }, +}; + +/* DEVLINK_CMD_PORT_PARAM_GET - do */ +static const struct nla_policy devlink_port_param_get_nl_policy[DEVLINK_ATTR_PORT_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_PORT_PARAM_SET - do */ +static const struct nla_policy devlink_port_param_set_nl_policy[DEVLINK_ATTR_PORT_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, +}; + /* DEVLINK_CMD_INFO_GET - do */ static const struct nla_policy devlink_info_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -135,6 +356,58 @@ static const struct nla_policy devlink_health_reporter_get_dump_nl_policy[DEVLIN [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, }; +/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ +static const struct nla_policy devlink_health_reporter_set_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64, }, + [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8, }, + [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8, }, +}; + +/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ +static const struct nla_policy devlink_health_reporter_recover_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ +static const struct nla_policy devlink_health_reporter_diagnose_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ +static const struct nla_policy devlink_health_reporter_dump_get_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ +static const struct nla_policy devlink_health_reporter_dump_clear_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_FLASH_UPDATE - do */ +static const struct nla_policy devlink_flash_update_nl_policy[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] = NLA_POLICY_BITFIELD32(3), +}; + /* DEVLINK_CMD_TRAP_GET - do */ static const struct nla_policy devlink_trap_get_do_nl_policy[DEVLINK_ATTR_TRAP_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -148,6 +421,14 @@ static const struct nla_policy devlink_trap_get_dump_nl_policy[DEVLINK_ATTR_DEV_ [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_TRAP_SET - do */ +static const struct nla_policy devlink_trap_set_nl_policy[DEVLINK_ATTR_TRAP_ACTION + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_TRAP_ACTION] = NLA_POLICY_MAX(NLA_U8, 2), +}; + /* DEVLINK_CMD_TRAP_GROUP_GET - do */ static const struct nla_policy devlink_trap_group_get_do_nl_policy[DEVLINK_ATTR_TRAP_GROUP_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -161,6 +442,15 @@ static const struct nla_policy devlink_trap_group_get_dump_nl_policy[DEVLINK_ATT [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_TRAP_GROUP_SET - do */ +static const struct nla_policy devlink_trap_group_set_nl_policy[DEVLINK_ATTR_TRAP_POLICER_ID + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_TRAP_ACTION] = NLA_POLICY_MAX(NLA_U8, 2), + [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32, }, +}; + /* DEVLINK_CMD_TRAP_POLICER_GET - do */ static const struct nla_policy devlink_trap_policer_get_do_nl_policy[DEVLINK_ATTR_TRAP_POLICER_ID + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -174,6 +464,23 @@ static const struct nla_policy devlink_trap_policer_get_dump_nl_policy[DEVLINK_A [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_TRAP_POLICER_SET - do */ +static const struct nla_policy devlink_trap_policer_set_nl_policy[DEVLINK_ATTR_TRAP_POLICER_BURST + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32, }, + [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64, }, + [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64, }, +}; + +/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ +static const struct nla_policy devlink_health_reporter_test_nl_policy[DEVLINK_ATTR_HEALTH_REPORTER_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING, }, +}; + /* DEVLINK_CMD_RATE_GET - do */ static const struct nla_policy devlink_rate_get_do_nl_policy[DEVLINK_ATTR_RATE_NODE_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -188,6 +495,37 @@ static const struct nla_policy devlink_rate_get_dump_nl_policy[DEVLINK_ATTR_DEV_ [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_RATE_SET - do */ +static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_RATE_TX_WEIGHT + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64, }, + [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64, }, + [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .type = NLA_U32, }, + [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32, }, + [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_RATE_NEW - do */ +static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_RATE_TX_WEIGHT + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64, }, + [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64, }, + [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .type = NLA_U32, }, + [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32, }, + [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING, }, +}; + +/* DEVLINK_CMD_RATE_DEL - do */ +static const struct nla_policy devlink_rate_del_nl_policy[DEVLINK_ATTR_RATE_NODE_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING, }, +}; + /* DEVLINK_CMD_LINECARD_GET - do */ static const struct nla_policy devlink_linecard_get_do_nl_policy[DEVLINK_ATTR_LINECARD_INDEX + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, @@ -201,14 +539,29 @@ static const struct nla_policy devlink_linecard_get_dump_nl_policy[DEVLINK_ATTR_ [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_LINECARD_SET - do */ +static const struct nla_policy devlink_linecard_set_nl_policy[DEVLINK_ATTR_LINECARD_TYPE + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32, }, + [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING, }, +}; + /* DEVLINK_CMD_SELFTESTS_GET - do */ static const struct nla_policy devlink_selftests_get_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, }; +/* DEVLINK_CMD_SELFTESTS_RUN - do */ +static const struct nla_policy devlink_selftests_run_nl_policy[DEVLINK_ATTR_SELFTESTS + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_SELFTESTS] = NLA_POLICY_NESTED(devlink_dl_selftest_id_nl_policy), +}; + /* Ops table for devlink */ -const struct genl_split_ops devlink_nl_ops[32] = { +const struct genl_split_ops devlink_nl_ops[73] = { { .cmd = DEVLINK_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -242,6 +595,56 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_PORT_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_set_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_FUNCTION, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_PORT_NEW, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_port_new_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_new_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_PCI_SF_NUMBER, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_PORT_DEL, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_del_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_del_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_INDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_PORT_SPLIT, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_split_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_split_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_SPLIT_COUNT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_PORT_UNSPLIT, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_unsplit_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_unsplit_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_INDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_SB_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -276,6 +679,16 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_SB_POOL_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_sb_pool_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_sb_pool_set_nl_policy, + .maxattr = DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_SB_PORT_POOL_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -293,6 +706,16 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_SB_PORT_POOL_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_sb_port_pool_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_sb_port_pool_set_nl_policy, + .maxattr = DEVLINK_ATTR_SB_THRESHOLD, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -310,6 +733,126 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_sb_tc_pool_bind_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_sb_tc_pool_bind_set_nl_policy, + .maxattr = DEVLINK_ATTR_SB_TC_INDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_sb_occ_snapshot_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_sb_occ_snapshot_nl_policy, + .maxattr = DEVLINK_ATTR_SB_INDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_sb_occ_max_clear_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_sb_occ_max_clear_nl_policy, + .maxattr = DEVLINK_ATTR_SB_INDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_ESWITCH_GET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_eswitch_get_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_eswitch_get_nl_policy, + .maxattr = DEVLINK_ATTR_DEV_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_ESWITCH_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_eswitch_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_eswitch_set_nl_policy, + .maxattr = DEVLINK_ATTR_ESWITCH_ENCAP_MODE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_DPIPE_TABLE_GET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_dpipe_table_get_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_dpipe_table_get_nl_policy, + .maxattr = DEVLINK_ATTR_DPIPE_TABLE_NAME, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_dpipe_entries_get_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_dpipe_entries_get_nl_policy, + .maxattr = DEVLINK_ATTR_DPIPE_TABLE_NAME, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_dpipe_headers_get_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_dpipe_headers_get_nl_policy, + .maxattr = DEVLINK_ATTR_DEV_NAME, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_dpipe_table_counters_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_dpipe_table_counters_set_nl_policy, + .maxattr = DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_RESOURCE_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_resource_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_resource_set_nl_policy, + .maxattr = DEVLINK_ATTR_RESOURCE_SIZE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_RESOURCE_DUMP, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_resource_dump_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_resource_dump_nl_policy, + .maxattr = DEVLINK_ATTR_DEV_NAME, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_RELOAD, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_reload_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_reload_nl_policy, + .maxattr = DEVLINK_ATTR_RELOAD_LIMITS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_PARAM_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -327,6 +870,16 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_PARAM_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_param_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_param_set_nl_policy, + .maxattr = DEVLINK_ATTR_PARAM_VALUE_CMODE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_REGION_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -344,6 +897,60 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_REGION_NEW, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_region_new_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_region_new_nl_policy, + .maxattr = DEVLINK_ATTR_REGION_SNAPSHOT_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_REGION_DEL, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_region_del_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_region_del_nl_policy, + .maxattr = DEVLINK_ATTR_REGION_SNAPSHOT_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_REGION_READ, + .validate = GENL_DONT_VALIDATE_DUMP_STRICT, + .dumpit = devlink_nl_region_read_dumpit, + .policy = devlink_region_read_nl_policy, + .maxattr = DEVLINK_ATTR_REGION_DIRECT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = DEVLINK_CMD_PORT_PARAM_GET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_param_get_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_param_get_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_INDEX, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_PORT_PARAM_GET, + .validate = GENL_DONT_VALIDATE_DUMP_STRICT, + .dumpit = devlink_nl_port_param_get_dumpit, + .flags = GENL_CMD_CAP_DUMP, + }, + { + .cmd = DEVLINK_CMD_PORT_PARAM_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_param_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_param_set_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_INDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_INFO_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -377,6 +984,64 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_PORT_INDEX, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_health_reporter_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_health_reporter_set_nl_policy, + .maxattr = DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_health_reporter_recover_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_health_reporter_recover_nl_policy, + .maxattr = DEVLINK_ATTR_HEALTH_REPORTER_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_health_reporter_diagnose_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_health_reporter_diagnose_nl_policy, + .maxattr = DEVLINK_ATTR_HEALTH_REPORTER_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, + .validate = GENL_DONT_VALIDATE_DUMP_STRICT, + .dumpit = devlink_nl_health_reporter_dump_get_dumpit, + .policy = devlink_health_reporter_dump_get_nl_policy, + .maxattr = DEVLINK_ATTR_HEALTH_REPORTER_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_health_reporter_dump_clear_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_health_reporter_dump_clear_nl_policy, + .maxattr = DEVLINK_ATTR_HEALTH_REPORTER_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_FLASH_UPDATE, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_flash_update_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_flash_update_nl_policy, + .maxattr = DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_TRAP_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -394,6 +1059,16 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_TRAP_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_trap_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_trap_set_nl_policy, + .maxattr = DEVLINK_ATTR_TRAP_ACTION, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_TRAP_GROUP_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -411,6 +1086,16 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_TRAP_GROUP_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_trap_group_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_trap_group_set_nl_policy, + .maxattr = DEVLINK_ATTR_TRAP_POLICER_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_TRAP_POLICER_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -428,6 +1113,26 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_TRAP_POLICER_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_trap_policer_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_trap_policer_set_nl_policy, + .maxattr = DEVLINK_ATTR_TRAP_POLICER_BURST, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port_optional, + .doit = devlink_nl_health_reporter_test_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_health_reporter_test_nl_policy, + .maxattr = DEVLINK_ATTR_HEALTH_REPORTER_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_RATE_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -445,6 +1150,36 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_RATE_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_rate_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_rate_set_nl_policy, + .maxattr = DEVLINK_ATTR_RATE_TX_WEIGHT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_RATE_NEW, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_rate_new_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_rate_new_nl_policy, + .maxattr = DEVLINK_ATTR_RATE_TX_WEIGHT, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_RATE_DEL, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_rate_del_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_rate_del_nl_policy, + .maxattr = DEVLINK_ATTR_RATE_NODE_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_LINECARD_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -462,6 +1197,16 @@ const struct genl_split_ops devlink_nl_ops[32] = { .maxattr = DEVLINK_ATTR_DEV_NAME, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_LINECARD_SET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_linecard_set_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_linecard_set_nl_policy, + .maxattr = DEVLINK_ATTR_LINECARD_TYPE, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, { .cmd = DEVLINK_CMD_SELFTESTS_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -478,4 +1223,14 @@ const struct genl_split_ops devlink_nl_ops[32] = { .dumpit = devlink_nl_selftests_get_dumpit, .flags = GENL_CMD_CAP_DUMP, }, + { + .cmd = DEVLINK_CMD_SELFTESTS_RUN, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_selftests_run_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_selftests_run_nl_policy, + .maxattr = DEVLINK_ATTR_SELFTESTS, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, }; diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h index f8bbc93e39be..0e9e89c31c31 100644 --- a/net/devlink/netlink_gen.h +++ b/net/devlink/netlink_gen.h @@ -11,8 +11,12 @@ #include +/* Common nested types */ +extern const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_FN_ATTR_CAPS + 1]; +extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1]; + /* Ops table for devlink */ -extern const struct genl_split_ops devlink_nl_ops[32]; +extern const struct genl_split_ops devlink_nl_ops[73]; int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); @@ -30,25 +34,61 @@ int devlink_nl_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int devlink_nl_port_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_port_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_port_set_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_port_new_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_port_del_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_port_split_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_port_unsplit_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_sb_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_sb_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int devlink_nl_sb_pool_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_sb_pool_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_sb_port_pool_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_sb_port_pool_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_sb_port_pool_set_doit(struct sk_buff *skb, + struct genl_info *info); int devlink_nl_sb_tc_pool_bind_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_sb_tc_pool_bind_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_sb_occ_max_clear_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_param_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_param_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_param_set_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_region_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_region_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_region_new_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_region_read_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int devlink_nl_port_param_get_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_port_param_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int devlink_nl_port_param_set_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_info_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_info_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); @@ -56,24 +96,46 @@ int devlink_nl_health_reporter_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_health_reporter_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_health_reporter_set_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_health_reporter_recover_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_health_reporter_diagnose_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_health_reporter_dump_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); +int devlink_nl_health_reporter_dump_clear_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_flash_update_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_trap_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_trap_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_trap_set_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_trap_group_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_trap_group_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_trap_group_set_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_trap_policer_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_trap_policer_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_trap_policer_set_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_health_reporter_test_doit(struct sk_buff *skb, + struct genl_info *info); int devlink_nl_rate_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_rate_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_rate_set_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_linecard_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_linecard_set_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_selftests_get_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_selftests_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info); #endif /* _LINUX_DEVLINK_GEN_H */ diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c index a002f71d6068..75b744b47986 100644 --- a/tools/net/ynl/generated/devlink-user.c +++ b/tools/net/ynl/generated/devlink-user.c @@ -16,14 +16,25 @@ static const char * const devlink_op_strmap[] = { [3] = "get", [7] = "port-get", + [DEVLINK_CMD_PORT_NEW] = "port-new", [13] = "sb-get", [17] = "sb-pool-get", [21] = "sb-port-pool-get", [25] = "sb-tc-pool-bind-get", + [DEVLINK_CMD_ESWITCH_GET] = "eswitch-get", + [DEVLINK_CMD_DPIPE_TABLE_GET] = "dpipe-table-get", + [DEVLINK_CMD_DPIPE_ENTRIES_GET] = "dpipe-entries-get", + [DEVLINK_CMD_DPIPE_HEADERS_GET] = "dpipe-headers-get", + [DEVLINK_CMD_RESOURCE_DUMP] = "resource-dump", + [DEVLINK_CMD_RELOAD] = "reload", [DEVLINK_CMD_PARAM_GET] = "param-get", [DEVLINK_CMD_REGION_GET] = "region-get", + [DEVLINK_CMD_REGION_NEW] = "region-new", + [DEVLINK_CMD_REGION_READ] = "region-read", + [DEVLINK_CMD_PORT_PARAM_GET] = "port-param-get", [DEVLINK_CMD_INFO_GET] = "info-get", [DEVLINK_CMD_HEALTH_REPORTER_GET] = "health-reporter-get", + [DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET] = "health-reporter-dump-get", [63] = "trap-get", [67] = "trap-group-get", [71] = "trap-policer-get", @@ -51,7 +62,303 @@ const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value) return devlink_sb_pool_type_strmap[value]; } +static const char * const devlink_port_type_strmap[] = { + [0] = "notset", + [1] = "auto", + [2] = "eth", + [3] = "ib", +}; + +const char *devlink_port_type_str(enum devlink_port_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_type_strmap)) + return NULL; + return devlink_port_type_strmap[value]; +} + +static const char * const devlink_port_flavour_strmap[] = { + [0] = "physical", + [1] = "cpu", + [2] = "dsa", + [3] = "pci_pf", + [4] = "pci_vf", + [5] = "virtual", + [6] = "unused", + [7] = "pci_sf", +}; + +const char *devlink_port_flavour_str(enum devlink_port_flavour value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_flavour_strmap)) + return NULL; + return devlink_port_flavour_strmap[value]; +} + +static const char * const devlink_port_fn_state_strmap[] = { + [0] = "inactive", + [1] = "active", +}; + +const char *devlink_port_fn_state_str(enum devlink_port_fn_state value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_state_strmap)) + return NULL; + return devlink_port_fn_state_strmap[value]; +} + +static const char * const devlink_port_fn_opstate_strmap[] = { + [0] = "detached", + [1] = "attached", +}; + +const char *devlink_port_fn_opstate_str(enum devlink_port_fn_opstate value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_opstate_strmap)) + return NULL; + return devlink_port_fn_opstate_strmap[value]; +} + +static const char * const devlink_port_fn_attr_cap_strmap[] = { + [0] = "roce-bit", + [1] = "migratable-bit", +}; + +const char *devlink_port_fn_attr_cap_str(enum devlink_port_fn_attr_cap value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_port_fn_attr_cap_strmap)) + return NULL; + return devlink_port_fn_attr_cap_strmap[value]; +} + +static const char * const devlink_sb_threshold_type_strmap[] = { + [0] = "static", + [1] = "dynamic", +}; + +const char *devlink_sb_threshold_type_str(enum devlink_sb_threshold_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_sb_threshold_type_strmap)) + return NULL; + return devlink_sb_threshold_type_strmap[value]; +} + +static const char * const devlink_eswitch_mode_strmap[] = { + [0] = "legacy", + [1] = "switchdev", +}; + +const char *devlink_eswitch_mode_str(enum devlink_eswitch_mode value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_mode_strmap)) + return NULL; + return devlink_eswitch_mode_strmap[value]; +} + +static const char * const devlink_eswitch_inline_mode_strmap[] = { + [0] = "none", + [1] = "link", + [2] = "network", + [3] = "transport", +}; + +const char * +devlink_eswitch_inline_mode_str(enum devlink_eswitch_inline_mode value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_inline_mode_strmap)) + return NULL; + return devlink_eswitch_inline_mode_strmap[value]; +} + +static const char * const devlink_eswitch_encap_mode_strmap[] = { + [0] = "none", + [1] = "basic", +}; + +const char * +devlink_eswitch_encap_mode_str(enum devlink_eswitch_encap_mode value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_eswitch_encap_mode_strmap)) + return NULL; + return devlink_eswitch_encap_mode_strmap[value]; +} + +static const char * const devlink_dpipe_match_type_strmap[] = { + [0] = "field-exact", +}; + +const char *devlink_dpipe_match_type_str(enum devlink_dpipe_match_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_match_type_strmap)) + return NULL; + return devlink_dpipe_match_type_strmap[value]; +} + +static const char * const devlink_dpipe_action_type_strmap[] = { + [0] = "field-modify", +}; + +const char *devlink_dpipe_action_type_str(enum devlink_dpipe_action_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_action_type_strmap)) + return NULL; + return devlink_dpipe_action_type_strmap[value]; +} + +static const char * const devlink_dpipe_field_mapping_type_strmap[] = { + [0] = "none", + [1] = "ifindex", +}; + +const char * +devlink_dpipe_field_mapping_type_str(enum devlink_dpipe_field_mapping_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_dpipe_field_mapping_type_strmap)) + return NULL; + return devlink_dpipe_field_mapping_type_strmap[value]; +} + +static const char * const devlink_resource_unit_strmap[] = { + [0] = "entry", +}; + +const char *devlink_resource_unit_str(enum devlink_resource_unit value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_resource_unit_strmap)) + return NULL; + return devlink_resource_unit_strmap[value]; +} + +static const char * const devlink_reload_action_strmap[] = { + [1] = "driver-reinit", + [2] = "fw-activate", +}; + +const char *devlink_reload_action_str(enum devlink_reload_action value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_reload_action_strmap)) + return NULL; + return devlink_reload_action_strmap[value]; +} + +static const char * const devlink_param_cmode_strmap[] = { + [0] = "runtime", + [1] = "driverinit", + [2] = "permanent", +}; + +const char *devlink_param_cmode_str(enum devlink_param_cmode value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_param_cmode_strmap)) + return NULL; + return devlink_param_cmode_strmap[value]; +} + +static const char * const devlink_flash_overwrite_strmap[] = { + [0] = "settings-bit", + [1] = "identifiers-bit", +}; + +const char *devlink_flash_overwrite_str(enum devlink_flash_overwrite value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_flash_overwrite_strmap)) + return NULL; + return devlink_flash_overwrite_strmap[value]; +} + +static const char * const devlink_trap_action_strmap[] = { + [0] = "drop", + [1] = "trap", + [2] = "mirror", +}; + +const char *devlink_trap_action_str(enum devlink_trap_action value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(devlink_trap_action_strmap)) + return NULL; + return devlink_trap_action_strmap[value]; +} + /* Policies */ +struct ynl_policy_attr devlink_dl_dpipe_match_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = { .name = "dpipe-match-type", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_match_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_match_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_match_value_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, + [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, + [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, + [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_match_value_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_match_value_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_action_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = { .name = "dpipe-action-type", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_action_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_action_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_action_value_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, + [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, + [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, + [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_action_value_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_action_value_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_field_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_FIELD_NAME] = { .name = "dpipe-field-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = { .name = "dpipe-field-bitwidth", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = { .name = "dpipe-field-mapping-type", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_field_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_field_policy, +}; + +struct ynl_policy_attr devlink_dl_resource_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RESOURCE_NAME] = { .name = "resource-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_RESOURCE_ID] = { .name = "resource-id", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE] = { .name = "resource-size", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_NEW] = { .name = "resource-size-new", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_VALID] = { .name = "resource-size-valid", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RESOURCE_SIZE_MIN] = { .name = "resource-size-min", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_MAX] = { .name = "resource-size-max", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_GRAN] = { .name = "resource-size-gran", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_UNIT] = { .name = "resource-unit", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RESOURCE_OCC] = { .name = "resource-occ", .type = YNL_PT_U64, }, +}; + +struct ynl_policy_nest devlink_dl_resource_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_resource_policy, +}; + struct ynl_policy_attr devlink_dl_info_version_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, @@ -62,6 +369,31 @@ struct ynl_policy_nest devlink_dl_info_version_nest = { .table = devlink_dl_info_version_policy, }; +struct ynl_policy_attr devlink_dl_fmsg_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_FMSG_OBJ_NEST_START] = { .name = "fmsg-obj-nest-start", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_PAIR_NEST_START] = { .name = "fmsg-pair-nest-start", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_ARR_NEST_START] = { .name = "fmsg-arr-nest-start", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_NEST_END] = { .name = "fmsg-nest-end", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_OBJ_NAME] = { .name = "fmsg-obj-name", .type = YNL_PT_NUL_STR, }, +}; + +struct ynl_policy_nest devlink_dl_fmsg_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_fmsg_policy, +}; + +struct ynl_policy_attr devlink_dl_port_function_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = { + [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .name = "hw-addr", .type = YNL_PT_BINARY,}, + [DEVLINK_PORT_FN_ATTR_STATE] = { .name = "state", .type = YNL_PT_U8, }, + [DEVLINK_PORT_FN_ATTR_OPSTATE] = { .name = "opstate", .type = YNL_PT_U8, }, + [DEVLINK_PORT_FN_ATTR_CAPS] = { .name = "caps", .type = YNL_PT_BITFIELD32, }, +}; + +struct ynl_policy_nest devlink_dl_port_function_nest = { + .max_attr = DEVLINK_PORT_FUNCTION_ATTR_MAX, + .table = devlink_dl_port_function_policy, +}; + struct ynl_policy_attr devlink_dl_reload_stats_entry_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, @@ -81,6 +413,69 @@ struct ynl_policy_nest devlink_dl_reload_act_stats_nest = { .table = devlink_dl_reload_act_stats_policy, }; +struct ynl_policy_attr devlink_dl_selftest_id_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = { + [DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .name = "flash", .type = YNL_PT_FLAG, }, +}; + +struct ynl_policy_nest devlink_dl_selftest_id_nest = { + .max_attr = DEVLINK_ATTR_SELFTEST_ID_MAX, + .table = devlink_dl_selftest_id_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_table_matches_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_table_matches_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_table_matches_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_table_actions_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_table_actions_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_table_actions_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_entry_match_values_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = { .name = "dpipe-match-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_value_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_entry_match_values_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_entry_match_values_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_entry_action_values_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = { .name = "dpipe-action-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_value_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_entry_action_values_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_entry_action_values_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_header_fields_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_FIELD] = { .name = "dpipe-field", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_field_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_header_fields_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_header_fields_policy, +}; + +struct ynl_policy_attr devlink_dl_resource_list_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RESOURCE] = { .name = "resource", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_nest, }, +}; + +struct ynl_policy_nest devlink_dl_resource_list_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_resource_list_policy, +}; + struct ynl_policy_attr devlink_dl_reload_act_info_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, @@ -91,6 +486,45 @@ struct ynl_policy_nest devlink_dl_reload_act_info_nest = { .table = devlink_dl_reload_act_info_policy, }; +struct ynl_policy_attr devlink_dl_dpipe_table_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .name = "dpipe-table-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = { .name = "dpipe-table-size", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = { .name = "dpipe-table-matches", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_matches_nest, }, + [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = { .name = "dpipe-table-actions", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_actions_nest, }, + [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .name = "dpipe-table-counters-enabled", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] = { .name = "dpipe-table-resource-id", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS] = { .name = "dpipe-table-resource-units", .type = YNL_PT_U64, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_table_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_table_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_entry_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = { .name = "dpipe-entry-index", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = { .name = "dpipe-entry-match-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_match_values_nest, }, + [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = { .name = "dpipe-entry-action-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_action_values_nest, }, + [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = { .name = "dpipe-entry-counter", .type = YNL_PT_U64, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_entry_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_entry_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_header_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_HEADER_NAME] = { .name = "dpipe-header-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = { .name = "dpipe-header-fields", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_fields_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_header_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_header_policy, +}; + struct ynl_policy_attr devlink_dl_reload_stats_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, }; @@ -100,6 +534,33 @@ struct ynl_policy_nest devlink_dl_reload_stats_nest = { .table = devlink_dl_reload_stats_policy, }; +struct ynl_policy_attr devlink_dl_dpipe_tables_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_TABLE] = { .name = "dpipe-table", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_tables_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_tables_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_entries_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_ENTRY] = { .name = "dpipe-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_entries_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_entries_policy, +}; + +struct ynl_policy_attr devlink_dl_dpipe_headers_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_DPIPE_HEADER] = { .name = "dpipe-header", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dpipe_headers_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dpipe_headers_policy, +}; + struct ynl_policy_attr devlink_dl_dev_stats_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, @@ -114,12 +575,75 @@ struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_BUS_NAME] = { .name = "bus-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_PORT_INDEX] = { .name = "port-index", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_PORT_TYPE] = { .name = "port-type", .type = YNL_PT_U16, }, + [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .name = "port-split-count", .type = YNL_PT_U32, }, [DEVLINK_ATTR_SB_INDEX] = { .name = "sb-index", .type = YNL_PT_U32, }, [DEVLINK_ATTR_SB_POOL_INDEX] = { .name = "sb-pool-index", .type = YNL_PT_U16, }, [DEVLINK_ATTR_SB_POOL_TYPE] = { .name = "sb-pool-type", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_SB_POOL_SIZE] = { .name = "sb-pool-size", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .name = "sb-pool-threshold-type", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_SB_THRESHOLD] = { .name = "sb-threshold", .type = YNL_PT_U32, }, [DEVLINK_ATTR_SB_TC_INDEX] = { .name = "sb-tc-index", .type = YNL_PT_U16, }, + [DEVLINK_ATTR_ESWITCH_MODE] = { .name = "eswitch-mode", .type = YNL_PT_U16, }, + [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .name = "eswitch-inline-mode", .type = YNL_PT_U16, }, + [DEVLINK_ATTR_DPIPE_TABLES] = { .name = "dpipe-tables", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_tables_nest, }, + [DEVLINK_ATTR_DPIPE_TABLE] = { .name = "dpipe-table", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_nest, }, + [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .name = "dpipe-table-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = { .name = "dpipe-table-size", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = { .name = "dpipe-table-matches", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_matches_nest, }, + [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = { .name = "dpipe-table-actions", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_table_actions_nest, }, + [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .name = "dpipe-table-counters-enabled", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DPIPE_ENTRIES] = { .name = "dpipe-entries", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entries_nest, }, + [DEVLINK_ATTR_DPIPE_ENTRY] = { .name = "dpipe-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_nest, }, + [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = { .name = "dpipe-entry-index", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = { .name = "dpipe-entry-match-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_match_values_nest, }, + [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = { .name = "dpipe-entry-action-values", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_entry_action_values_nest, }, + [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = { .name = "dpipe-entry-counter", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_MATCH] = { .name = "dpipe-match", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_nest, }, + [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = { .name = "dpipe-match-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_match_value_nest, }, + [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = { .name = "dpipe-match-type", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_ACTION] = { .name = "dpipe-action", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_nest, }, + [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = { .name = "dpipe-action-value", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_action_value_nest, }, + [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = { .name = "dpipe-action-type", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_VALUE] = { .name = "dpipe-value", .type = YNL_PT_BINARY,}, + [DEVLINK_ATTR_DPIPE_VALUE_MASK] = { .name = "dpipe-value-mask", .type = YNL_PT_BINARY,}, + [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = { .name = "dpipe-value-mapping", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADERS] = { .name = "dpipe-headers", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_headers_nest, }, + [DEVLINK_ATTR_DPIPE_HEADER] = { .name = "dpipe-header", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_nest, }, + [DEVLINK_ATTR_DPIPE_HEADER_NAME] = { .name = "dpipe-header-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DPIPE_HEADER_ID] = { .name = "dpipe-header-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = { .name = "dpipe-header-fields", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_header_fields_nest, }, + [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = { .name = "dpipe-header-global", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = { .name = "dpipe-header-index", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD] = { .name = "dpipe-field", .type = YNL_PT_NEST, .nest = &devlink_dl_dpipe_field_nest, }, + [DEVLINK_ATTR_DPIPE_FIELD_NAME] = { .name = "dpipe-field-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DPIPE_FIELD_ID] = { .name = "dpipe-field-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = { .name = "dpipe-field-bitwidth", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = { .name = "dpipe-field-mapping-type", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, + [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .name = "eswitch-encap-mode", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RESOURCE_LIST] = { .name = "resource-list", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_list_nest, }, + [DEVLINK_ATTR_RESOURCE] = { .name = "resource", .type = YNL_PT_NEST, .nest = &devlink_dl_resource_nest, }, + [DEVLINK_ATTR_RESOURCE_NAME] = { .name = "resource-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_RESOURCE_ID] = { .name = "resource-id", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE] = { .name = "resource-size", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_NEW] = { .name = "resource-size-new", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_VALID] = { .name = "resource-size-valid", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RESOURCE_SIZE_MIN] = { .name = "resource-size-min", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_MAX] = { .name = "resource-size-max", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_SIZE_GRAN] = { .name = "resource-size-gran", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RESOURCE_UNIT] = { .name = "resource-unit", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RESOURCE_OCC] = { .name = "resource-occ", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] = { .name = "dpipe-table-resource-id", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS] = { .name = "dpipe-table-resource-units", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_PORT_FLAVOUR] = { .name = "port-flavour", .type = YNL_PT_U16, }, [DEVLINK_ATTR_PARAM_NAME] = { .name = "param-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_PARAM_TYPE] = { .name = "param-type", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .name = "param-value-cmode", .type = YNL_PT_U8, }, [DEVLINK_ATTR_REGION_NAME] = { .name = "region-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .name = "region-snapshot-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .name = "region-chunk-addr", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .name = "region-chunk-len", .type = YNL_PT_U64, }, [DEVLINK_ATTR_INFO_DRIVER_NAME] = { .name = "info-driver-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = { .name = "info-serial-number", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_INFO_VERSION_FIXED] = { .name = "info-version-fixed", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, @@ -127,12 +651,35 @@ struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_INFO_VERSION_STORED] = { .name = "info-version-stored", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_FMSG] = { .name = "fmsg", .type = YNL_PT_NEST, .nest = &devlink_dl_fmsg_nest, }, + [DEVLINK_ATTR_FMSG_OBJ_NEST_START] = { .name = "fmsg-obj-nest-start", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_PAIR_NEST_START] = { .name = "fmsg-pair-nest-start", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_ARR_NEST_START] = { .name = "fmsg-arr-nest-start", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_NEST_END] = { .name = "fmsg-nest-end", .type = YNL_PT_FLAG, }, + [DEVLINK_ATTR_FMSG_OBJ_NAME] = { .name = "fmsg-obj-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .name = "health-reporter-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .name = "health-reporter-graceful-period", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .name = "health-reporter-auto-recover", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .name = "flash-update-file-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .name = "flash-update-component", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .name = "port-pci-pf-number", .type = YNL_PT_U16, }, [DEVLINK_ATTR_TRAP_NAME] = { .name = "trap-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_TRAP_ACTION] = { .name = "trap-action", .type = YNL_PT_U8, }, [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .name = "trap-group-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_NETNS_FD] = { .name = "netns-fd", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_NETNS_PID] = { .name = "netns-pid", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_NETNS_ID] = { .name = "netns-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .name = "health-reporter-auto-dump", .type = YNL_PT_U8, }, [DEVLINK_ATTR_TRAP_POLICER_ID] = { .name = "trap-policer-id", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .name = "trap-policer-rate", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .name = "trap-policer-burst", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_PORT_FUNCTION] = { .name = "port-function", .type = YNL_PT_NEST, .nest = &devlink_dl_port_function_nest, }, + [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .name = "port-controller-number", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] = { .name = "flash-update-overwrite-mask", .type = YNL_PT_BITFIELD32, }, [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED] = { .name = "reload-actions-performed", .type = YNL_PT_BITFIELD32, }, + [DEVLINK_ATTR_RELOAD_LIMITS] = { .name = "reload-limits", .type = YNL_PT_BITFIELD32, }, [DEVLINK_ATTR_DEV_STATS] = { .name = "dev-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_dev_stats_nest, }, [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, @@ -141,8 +688,17 @@ struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, + [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .name = "port-pci-sf-number", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_RATE_TX_SHARE] = { .name = "rate-tx-share", .type = YNL_PT_U64, }, + [DEVLINK_ATTR_RATE_TX_MAX] = { .name = "rate-tx-max", .type = YNL_PT_U64, }, [DEVLINK_ATTR_RATE_NODE_NAME] = { .name = "rate-node-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .name = "rate-parent-node-name", .type = YNL_PT_NUL_STR, }, [DEVLINK_ATTR_LINECARD_INDEX] = { .name = "linecard-index", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_LINECARD_TYPE] = { .name = "linecard-type", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_SELFTESTS] = { .name = "selftests", .type = YNL_PT_NEST, .nest = &devlink_dl_selftest_id_nest, }, + [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .name = "rate-tx-priority", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .name = "rate-tx-weight", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_REGION_DIRECT] = { .name = "region-direct", .type = YNL_PT_FLAG, }, }; struct ynl_policy_nest devlink_nest = { @@ -151,43 +707,44 @@ struct ynl_policy_nest devlink_nest = { }; /* Common nested types */ -void devlink_dl_info_version_free(struct devlink_dl_info_version *obj) +void devlink_dl_dpipe_match_free(struct devlink_dl_dpipe_match *obj) { - free(obj->info_version_name); - free(obj->info_version_value); } -int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) +int devlink_dl_dpipe_match_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) { - struct devlink_dl_info_version *dst = yarg->data; + struct devlink_dl_dpipe_match *dst = yarg->data; const struct nlattr *attr; mnl_attr_for_each_nested(attr, nested) { unsigned int type = mnl_attr_get_type(attr); - if (type == DEVLINK_ATTR_INFO_VERSION_NAME) { - unsigned int len; - + if (type == DEVLINK_ATTR_DPIPE_MATCH_TYPE) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_name_len = len; - dst->info_version_name = malloc(len + 1); - memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); - dst->info_version_name[len] = 0; - } else if (type == DEVLINK_ATTR_INFO_VERSION_VALUE) { - unsigned int len; - + dst->_present.dpipe_match_type = 1; + dst->dpipe_match_type = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.info_version_value_len = len; - dst->info_version_value = malloc(len + 1); - memcpy(dst->info_version_value, mnl_attr_get_str(attr), len); - dst->info_version_value[len] = 0; + dst->_present.dpipe_header_id = 1; + dst->dpipe_header_id = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_global = 1; + dst->dpipe_header_global = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_index = 1; + dst->dpipe_header_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_field_id = 1; + dst->dpipe_field_id = mnl_attr_get_u32(attr); } } @@ -195,75 +752,194 @@ int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, } void -devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj) +devlink_dl_dpipe_match_value_free(struct devlink_dl_dpipe_match_value *obj) { + unsigned int i; + + for (i = 0; i < obj->n_dpipe_match; i++) + devlink_dl_dpipe_match_free(&obj->dpipe_match[i]); + free(obj->dpipe_match); + free(obj->dpipe_value); + free(obj->dpipe_value_mask); } -int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) +int devlink_dl_dpipe_match_value_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) { - struct devlink_dl_reload_stats_entry *dst = yarg->data; + struct devlink_dl_dpipe_match_value *dst = yarg->data; + unsigned int n_dpipe_match = 0; const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_match) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-match-value.dpipe-match)"); mnl_attr_for_each_nested(attr, nested) { unsigned int type = mnl_attr_get_type(attr); - if (type == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { + if (type == DEVLINK_ATTR_DPIPE_MATCH) { + n_dpipe_match++; + } else if (type == DEVLINK_ATTR_DPIPE_VALUE) { + unsigned int len; + if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.reload_stats_limit = 1; - dst->reload_stats_limit = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_STATS_VALUE) { + + len = mnl_attr_get_payload_len(attr); + dst->_present.dpipe_value_len = len; + dst->dpipe_value = malloc(len); + memcpy(dst->dpipe_value, mnl_attr_get_payload(attr), len); + } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MASK) { + unsigned int len; + if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.reload_stats_value = 1; - dst->reload_stats_value = mnl_attr_get_u32(attr); + + len = mnl_attr_get_payload_len(attr); + dst->_present.dpipe_value_mask_len = len; + dst->dpipe_value_mask = malloc(len); + memcpy(dst->dpipe_value_mask, mnl_attr_get_payload(attr), len); + } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MAPPING) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_value_mapping = 1; + dst->dpipe_value_mapping = mnl_attr_get_u32(attr); + } + } + + if (n_dpipe_match) { + dst->dpipe_match = calloc(n_dpipe_match, sizeof(*dst->dpipe_match)); + dst->n_dpipe_match = n_dpipe_match; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_match_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH) { + parg.data = &dst->dpipe_match[i]; + if (devlink_dl_dpipe_match_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } } } return 0; } -void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj) +void devlink_dl_dpipe_action_free(struct devlink_dl_dpipe_action *obj) +{ +} + +int devlink_dl_dpipe_action_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_action *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_ACTION_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_action_type = 1; + dst->dpipe_action_type = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_id = 1; + dst->dpipe_header_id = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_global = 1; + dst->dpipe_header_global = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_index = 1; + dst->dpipe_header_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_field_id = 1; + dst->dpipe_field_id = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +void +devlink_dl_dpipe_action_value_free(struct devlink_dl_dpipe_action_value *obj) { unsigned int i; - for (i = 0; i < obj->n_reload_stats_entry; i++) - devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]); - free(obj->reload_stats_entry); + for (i = 0; i < obj->n_dpipe_action; i++) + devlink_dl_dpipe_action_free(&obj->dpipe_action[i]); + free(obj->dpipe_action); + free(obj->dpipe_value); + free(obj->dpipe_value_mask); } -int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) +int devlink_dl_dpipe_action_value_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) { - struct devlink_dl_reload_act_stats *dst = yarg->data; - unsigned int n_reload_stats_entry = 0; + struct devlink_dl_dpipe_action_value *dst = yarg->data; + unsigned int n_dpipe_action = 0; const struct nlattr *attr; struct ynl_parse_arg parg; int i; parg.ys = yarg->ys; - if (dst->reload_stats_entry) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); + if (dst->dpipe_action) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-action-value.dpipe-action)"); mnl_attr_for_each_nested(attr, nested) { unsigned int type = mnl_attr_get_type(attr); - if (type == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - n_reload_stats_entry++; + if (type == DEVLINK_ATTR_DPIPE_ACTION) { + n_dpipe_action++; + } else if (type == DEVLINK_ATTR_DPIPE_VALUE) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.dpipe_value_len = len; + dst->dpipe_value = malloc(len); + memcpy(dst->dpipe_value, mnl_attr_get_payload(attr), len); + } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MASK) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.dpipe_value_mask_len = len; + dst->dpipe_value_mask = malloc(len); + memcpy(dst->dpipe_value_mask, mnl_attr_get_payload(attr), len); + } else if (type == DEVLINK_ATTR_DPIPE_VALUE_MAPPING) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_value_mapping = 1; + dst->dpipe_value_mapping = mnl_attr_get_u32(attr); } } - if (n_reload_stats_entry) { - dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry)); - dst->n_reload_stats_entry = n_reload_stats_entry; + if (n_dpipe_action) { + dst->dpipe_action = calloc(n_dpipe_action, sizeof(*dst->dpipe_action)); + dst->n_dpipe_action = n_dpipe_action; i = 0; - parg.rsp_policy = &devlink_dl_reload_stats_entry_nest; + parg.rsp_policy = &devlink_dl_dpipe_action_nest; mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { - parg.data = &dst->reload_stats_entry[i]; - if (devlink_dl_reload_stats_entry_parse(&parg, attr)) + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION) { + parg.data = &dst->dpipe_action[i]; + if (devlink_dl_dpipe_action_parse(&parg, attr)) return MNL_CB_ERROR; i++; } @@ -273,172 +949,2645 @@ int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, return 0; } -void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj) +void devlink_dl_dpipe_field_free(struct devlink_dl_dpipe_field *obj) { - unsigned int i; - - for (i = 0; i < obj->n_reload_action_stats; i++) - devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]); - free(obj->reload_action_stats); + free(obj->dpipe_field_name); } -int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) +int devlink_dl_dpipe_field_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) { - struct devlink_dl_reload_act_info *dst = yarg->data; - unsigned int n_reload_action_stats = 0; + struct devlink_dl_dpipe_field *dst = yarg->data; const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - - parg.ys = yarg->ys; - - if (dst->reload_action_stats) - return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); mnl_attr_for_each_nested(attr, nested) { unsigned int type = mnl_attr_get_type(attr); - if (type == DEVLINK_ATTR_RELOAD_ACTION) { + if (type == DEVLINK_ATTR_DPIPE_FIELD_NAME) { + unsigned int len; + if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.reload_action = 1; - dst->reload_action = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - n_reload_action_stats++; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dpipe_field_name_len = len; + dst->dpipe_field_name = malloc(len + 1); + memcpy(dst->dpipe_field_name, mnl_attr_get_str(attr), len); + dst->dpipe_field_name[len] = 0; + } else if (type == DEVLINK_ATTR_DPIPE_FIELD_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_field_id = 1; + dst->dpipe_field_id = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_field_bitwidth = 1; + dst->dpipe_field_bitwidth = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_field_mapping_type = 1; + dst->dpipe_field_mapping_type = mnl_attr_get_u32(attr); } } - if (n_reload_action_stats) { - dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats)); - dst->n_reload_action_stats = n_reload_action_stats; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_stats_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { - parg.data = &dst->reload_action_stats[i]; - if (devlink_dl_reload_act_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } + return 0; +} + +void devlink_dl_resource_free(struct devlink_dl_resource *obj) +{ + free(obj->resource_name); +} + +int devlink_dl_resource_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_resource *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RESOURCE_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.resource_name_len = len; + dst->resource_name = malloc(len + 1); + memcpy(dst->resource_name, mnl_attr_get_str(attr), len); + dst->resource_name[len] = 0; + } else if (type == DEVLINK_ATTR_RESOURCE_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_id = 1; + dst->resource_id = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_size = 1; + dst->resource_size = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_NEW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_size_new = 1; + dst->resource_size_new = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_VALID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_size_valid = 1; + dst->resource_size_valid = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_MIN) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_size_min = 1; + dst->resource_size_min = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_size_max = 1; + dst->resource_size_max = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_SIZE_GRAN) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_size_gran = 1; + dst->resource_size_gran = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_UNIT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_unit = 1; + dst->resource_unit = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_RESOURCE_OCC) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.resource_occ = 1; + dst->resource_occ = mnl_attr_get_u64(attr); } } return 0; } -void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj) +void devlink_dl_info_version_free(struct devlink_dl_info_version *obj) { - unsigned int i; - - for (i = 0; i < obj->n_reload_action_info; i++) - devlink_dl_reload_act_info_free(&obj->reload_action_info[i]); - free(obj->reload_action_info); + free(obj->info_version_name); + free(obj->info_version_value); } -int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, +int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, const struct nlattr *nested) { - struct devlink_dl_reload_stats *dst = yarg->data; - unsigned int n_reload_action_info = 0; + struct devlink_dl_info_version *dst = yarg->data; const struct nlattr *attr; - struct ynl_parse_arg parg; - int i; - parg.ys = yarg->ys; + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); - if (dst->reload_action_info) - return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); + if (type == DEVLINK_ATTR_INFO_VERSION_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.info_version_name_len = len; + dst->info_version_name = malloc(len + 1); + memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); + dst->info_version_name[len] = 0; + } else if (type == DEVLINK_ATTR_INFO_VERSION_VALUE) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.info_version_value_len = len; + dst->info_version_value = malloc(len + 1); + memcpy(dst->info_version_value, mnl_attr_get_str(attr), len); + dst->info_version_value[len] = 0; + } + } + + return 0; +} + +void devlink_dl_fmsg_free(struct devlink_dl_fmsg *obj) +{ + free(obj->fmsg_obj_name); +} + +int devlink_dl_fmsg_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_fmsg *dst = yarg->data; + const struct nlattr *attr; mnl_attr_for_each_nested(attr, nested) { unsigned int type = mnl_attr_get_type(attr); - if (type == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - n_reload_action_info++; + if (type == DEVLINK_ATTR_FMSG_OBJ_NEST_START) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.fmsg_obj_nest_start = 1; + } else if (type == DEVLINK_ATTR_FMSG_PAIR_NEST_START) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.fmsg_pair_nest_start = 1; + } else if (type == DEVLINK_ATTR_FMSG_ARR_NEST_START) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.fmsg_arr_nest_start = 1; + } else if (type == DEVLINK_ATTR_FMSG_NEST_END) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.fmsg_nest_end = 1; + } else if (type == DEVLINK_ATTR_FMSG_OBJ_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.fmsg_obj_name_len = len; + dst->fmsg_obj_name = malloc(len + 1); + memcpy(dst->fmsg_obj_name, mnl_attr_get_str(attr), len); + dst->fmsg_obj_name[len] = 0; } } - if (n_reload_action_info) { - dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info)); - dst->n_reload_action_info = n_reload_action_info; - i = 0; - parg.rsp_policy = &devlink_dl_reload_act_info_nest; - mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { - parg.data = &dst->reload_action_info[i]; - if (devlink_dl_reload_act_info_parse(&parg, attr)) - return MNL_CB_ERROR; - i++; - } + return 0; +} + +void devlink_dl_port_function_free(struct devlink_dl_port_function *obj) +{ + free(obj->hw_addr); +} + +int devlink_dl_port_function_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct devlink_dl_port_function *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.hw_addr_len) + mnl_attr_put(nlh, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, obj->_present.hw_addr_len, obj->hw_addr); + if (obj->_present.state) + mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_STATE, obj->state); + if (obj->_present.opstate) + mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_OPSTATE, obj->opstate); + if (obj->_present.caps) + mnl_attr_put(nlh, DEVLINK_PORT_FN_ATTR_CAPS, sizeof(struct nla_bitfield32), &obj->caps); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +void +devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj) +{ +} + +int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_stats_entry *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_stats_limit = 1; + dst->reload_stats_limit = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_RELOAD_STATS_VALUE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_stats_value = 1; + dst->reload_stats_value = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_reload_stats_entry; i++) + devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]); + free(obj->reload_stats_entry); +} + +int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_act_stats *dst = yarg->data; + unsigned int n_reload_stats_entry = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->reload_stats_entry) + return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { + n_reload_stats_entry++; + } + } + + if (n_reload_stats_entry) { + dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry)); + dst->n_reload_stats_entry = n_reload_stats_entry; + i = 0; + parg.rsp_policy = &devlink_dl_reload_stats_entry_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { + parg.data = &dst->reload_stats_entry[i]; + if (devlink_dl_reload_stats_entry_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_selftest_id_free(struct devlink_dl_selftest_id *obj) +{ +} + +int devlink_dl_selftest_id_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct devlink_dl_selftest_id *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.flash) + mnl_attr_put(nlh, DEVLINK_ATTR_SELFTEST_ID_FLASH, 0, NULL); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +void +devlink_dl_dpipe_table_matches_free(struct devlink_dl_dpipe_table_matches *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_match; i++) + devlink_dl_dpipe_match_free(&obj->dpipe_match[i]); + free(obj->dpipe_match); +} + +int devlink_dl_dpipe_table_matches_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_table_matches *dst = yarg->data; + unsigned int n_dpipe_match = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_match) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-table-matches.dpipe-match)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_MATCH) { + n_dpipe_match++; + } + } + + if (n_dpipe_match) { + dst->dpipe_match = calloc(n_dpipe_match, sizeof(*dst->dpipe_match)); + dst->n_dpipe_match = n_dpipe_match; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_match_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH) { + parg.data = &dst->dpipe_match[i]; + if (devlink_dl_dpipe_match_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void +devlink_dl_dpipe_table_actions_free(struct devlink_dl_dpipe_table_actions *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_action; i++) + devlink_dl_dpipe_action_free(&obj->dpipe_action[i]); + free(obj->dpipe_action); +} + +int devlink_dl_dpipe_table_actions_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_table_actions *dst = yarg->data; + unsigned int n_dpipe_action = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_action) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-table-actions.dpipe-action)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_ACTION) { + n_dpipe_action++; + } + } + + if (n_dpipe_action) { + dst->dpipe_action = calloc(n_dpipe_action, sizeof(*dst->dpipe_action)); + dst->n_dpipe_action = n_dpipe_action; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_action_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION) { + parg.data = &dst->dpipe_action[i]; + if (devlink_dl_dpipe_action_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void +devlink_dl_dpipe_entry_match_values_free(struct devlink_dl_dpipe_entry_match_values *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_match_value; i++) + devlink_dl_dpipe_match_value_free(&obj->dpipe_match_value[i]); + free(obj->dpipe_match_value); +} + +int devlink_dl_dpipe_entry_match_values_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_entry_match_values *dst = yarg->data; + unsigned int n_dpipe_match_value = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_match_value) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entry-match-values.dpipe-match-value)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_MATCH_VALUE) { + n_dpipe_match_value++; + } + } + + if (n_dpipe_match_value) { + dst->dpipe_match_value = calloc(n_dpipe_match_value, sizeof(*dst->dpipe_match_value)); + dst->n_dpipe_match_value = n_dpipe_match_value; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_match_value_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_MATCH_VALUE) { + parg.data = &dst->dpipe_match_value[i]; + if (devlink_dl_dpipe_match_value_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void +devlink_dl_dpipe_entry_action_values_free(struct devlink_dl_dpipe_entry_action_values *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_action_value; i++) + devlink_dl_dpipe_action_value_free(&obj->dpipe_action_value[i]); + free(obj->dpipe_action_value); +} + +int devlink_dl_dpipe_entry_action_values_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_entry_action_values *dst = yarg->data; + unsigned int n_dpipe_action_value = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_action_value) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entry-action-values.dpipe-action-value)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_ACTION_VALUE) { + n_dpipe_action_value++; + } + } + + if (n_dpipe_action_value) { + dst->dpipe_action_value = calloc(n_dpipe_action_value, sizeof(*dst->dpipe_action_value)); + dst->n_dpipe_action_value = n_dpipe_action_value; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_action_value_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ACTION_VALUE) { + parg.data = &dst->dpipe_action_value[i]; + if (devlink_dl_dpipe_action_value_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void +devlink_dl_dpipe_header_fields_free(struct devlink_dl_dpipe_header_fields *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_field; i++) + devlink_dl_dpipe_field_free(&obj->dpipe_field[i]); + free(obj->dpipe_field); +} + +int devlink_dl_dpipe_header_fields_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_header_fields *dst = yarg->data; + unsigned int n_dpipe_field = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_field) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-header-fields.dpipe-field)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_FIELD) { + n_dpipe_field++; + } + } + + if (n_dpipe_field) { + dst->dpipe_field = calloc(n_dpipe_field, sizeof(*dst->dpipe_field)); + dst->n_dpipe_field = n_dpipe_field; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_field_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_FIELD) { + parg.data = &dst->dpipe_field[i]; + if (devlink_dl_dpipe_field_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_resource_list_free(struct devlink_dl_resource_list *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_resource; i++) + devlink_dl_resource_free(&obj->resource[i]); + free(obj->resource); +} + +int devlink_dl_resource_list_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_resource_list *dst = yarg->data; + unsigned int n_resource = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->resource) + return ynl_error_parse(yarg, "attribute already present (dl-resource-list.resource)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RESOURCE) { + n_resource++; + } + } + + if (n_resource) { + dst->resource = calloc(n_resource, sizeof(*dst->resource)); + dst->n_resource = n_resource; + i = 0; + parg.rsp_policy = &devlink_dl_resource_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RESOURCE) { + parg.data = &dst->resource[i]; + if (devlink_dl_resource_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_reload_action_stats; i++) + devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]); + free(obj->reload_action_stats); +} + +int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_act_info *dst = yarg->data; + unsigned int n_reload_action_stats = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->reload_action_stats) + return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_ACTION) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_action = 1; + dst->reload_action = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_RELOAD_ACTION_STATS) { + n_reload_action_stats++; + } + } + + if (n_reload_action_stats) { + dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats)); + dst->n_reload_action_stats = n_reload_action_stats; + i = 0; + parg.rsp_policy = &devlink_dl_reload_act_stats_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { + parg.data = &dst->reload_action_stats[i]; + if (devlink_dl_reload_act_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_dpipe_table_free(struct devlink_dl_dpipe_table *obj) +{ + free(obj->dpipe_table_name); + devlink_dl_dpipe_table_matches_free(&obj->dpipe_table_matches); + devlink_dl_dpipe_table_actions_free(&obj->dpipe_table_actions); +} + +int devlink_dl_dpipe_table_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_table *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_TABLE_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dpipe_table_name_len = len; + dst->dpipe_table_name = malloc(len + 1); + memcpy(dst->dpipe_table_name, mnl_attr_get_str(attr), len); + dst->dpipe_table_name[len] = 0; + } else if (type == DEVLINK_ATTR_DPIPE_TABLE_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_table_size = 1; + dst->dpipe_table_size = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_DPIPE_TABLE_MATCHES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_table_matches = 1; + + parg.rsp_policy = &devlink_dl_dpipe_table_matches_nest; + parg.data = &dst->dpipe_table_matches; + if (devlink_dl_dpipe_table_matches_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == DEVLINK_ATTR_DPIPE_TABLE_ACTIONS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_table_actions = 1; + + parg.rsp_policy = &devlink_dl_dpipe_table_actions_nest; + parg.data = &dst->dpipe_table_actions; + if (devlink_dl_dpipe_table_actions_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_table_counters_enabled = 1; + dst->dpipe_table_counters_enabled = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_table_resource_id = 1; + dst->dpipe_table_resource_id = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_table_resource_units = 1; + dst->dpipe_table_resource_units = mnl_attr_get_u64(attr); + } + } + + return 0; +} + +void devlink_dl_dpipe_entry_free(struct devlink_dl_dpipe_entry *obj) +{ + devlink_dl_dpipe_entry_match_values_free(&obj->dpipe_entry_match_values); + devlink_dl_dpipe_entry_action_values_free(&obj->dpipe_entry_action_values); +} + +int devlink_dl_dpipe_entry_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_entry *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_ENTRY_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_entry_index = 1; + dst->dpipe_entry_index = mnl_attr_get_u64(attr); + } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_entry_match_values = 1; + + parg.rsp_policy = &devlink_dl_dpipe_entry_match_values_nest; + parg.data = &dst->dpipe_entry_match_values; + if (devlink_dl_dpipe_entry_match_values_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_entry_action_values = 1; + + parg.rsp_policy = &devlink_dl_dpipe_entry_action_values_nest; + parg.data = &dst->dpipe_entry_action_values; + if (devlink_dl_dpipe_entry_action_values_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == DEVLINK_ATTR_DPIPE_ENTRY_COUNTER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_entry_counter = 1; + dst->dpipe_entry_counter = mnl_attr_get_u64(attr); + } + } + + return 0; +} + +void devlink_dl_dpipe_header_free(struct devlink_dl_dpipe_header *obj) +{ + free(obj->dpipe_header_name); + devlink_dl_dpipe_header_fields_free(&obj->dpipe_header_fields); +} + +int devlink_dl_dpipe_header_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_header *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_HEADER_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dpipe_header_name_len = len; + dst->dpipe_header_name = malloc(len + 1); + memcpy(dst->dpipe_header_name, mnl_attr_get_str(attr), len); + dst->dpipe_header_name[len] = 0; + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_id = 1; + dst->dpipe_header_id = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_GLOBAL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_global = 1; + dst->dpipe_header_global = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_DPIPE_HEADER_FIELDS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_header_fields = 1; + + parg.rsp_policy = &devlink_dl_dpipe_header_fields_nest; + parg.data = &dst->dpipe_header_fields; + if (devlink_dl_dpipe_header_fields_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return 0; +} + +void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_reload_action_info; i++) + devlink_dl_reload_act_info_free(&obj->reload_action_info[i]); + free(obj->reload_action_info); +} + +int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_stats *dst = yarg->data; + unsigned int n_reload_action_info = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->reload_action_info) + return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_ACTION_INFO) { + n_reload_action_info++; + } + } + + if (n_reload_action_info) { + dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info)); + dst->n_reload_action_info = n_reload_action_info; + i = 0; + parg.rsp_policy = &devlink_dl_reload_act_info_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { + parg.data = &dst->reload_action_info[i]; + if (devlink_dl_reload_act_info_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_dpipe_tables_free(struct devlink_dl_dpipe_tables *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_table; i++) + devlink_dl_dpipe_table_free(&obj->dpipe_table[i]); + free(obj->dpipe_table); +} + +int devlink_dl_dpipe_tables_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_tables *dst = yarg->data; + unsigned int n_dpipe_table = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_table) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-tables.dpipe-table)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_TABLE) { + n_dpipe_table++; + } + } + + if (n_dpipe_table) { + dst->dpipe_table = calloc(n_dpipe_table, sizeof(*dst->dpipe_table)); + dst->n_dpipe_table = n_dpipe_table; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_table_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_TABLE) { + parg.data = &dst->dpipe_table[i]; + if (devlink_dl_dpipe_table_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_dpipe_entries_free(struct devlink_dl_dpipe_entries *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_entry; i++) + devlink_dl_dpipe_entry_free(&obj->dpipe_entry[i]); + free(obj->dpipe_entry); +} + +int devlink_dl_dpipe_entries_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_entries *dst = yarg->data; + unsigned int n_dpipe_entry = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_entry) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-entries.dpipe-entry)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_ENTRY) { + n_dpipe_entry++; + } + } + + if (n_dpipe_entry) { + dst->dpipe_entry = calloc(n_dpipe_entry, sizeof(*dst->dpipe_entry)); + dst->n_dpipe_entry = n_dpipe_entry; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_entry_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_ENTRY) { + parg.data = &dst->dpipe_entry[i]; + if (devlink_dl_dpipe_entry_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_dpipe_headers_free(struct devlink_dl_dpipe_headers *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_dpipe_header; i++) + devlink_dl_dpipe_header_free(&obj->dpipe_header[i]); + free(obj->dpipe_header); +} + +int devlink_dl_dpipe_headers_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dpipe_headers *dst = yarg->data; + unsigned int n_dpipe_header = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->dpipe_header) + return ynl_error_parse(yarg, "attribute already present (dl-dpipe-headers.dpipe-header)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_DPIPE_HEADER) { + n_dpipe_header++; + } + } + + if (n_dpipe_header) { + dst->dpipe_header = calloc(n_dpipe_header, sizeof(*dst->dpipe_header)); + dst->n_dpipe_header = n_dpipe_header; + i = 0; + parg.rsp_policy = &devlink_dl_dpipe_header_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DPIPE_HEADER) { + parg.data = &dst->dpipe_header[i]; + if (devlink_dl_dpipe_header_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj) +{ + devlink_dl_reload_stats_free(&obj->reload_stats); + devlink_dl_reload_stats_free(&obj->remote_reload_stats); +} + +int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dev_stats *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_stats = 1; + + parg.rsp_policy = &devlink_dl_reload_stats_nest; + parg.data = &dst->reload_stats; + if (devlink_dl_reload_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.remote_reload_stats = 1; + + parg.rsp_policy = &devlink_dl_reload_stats_nest; + parg.data = &dst->remote_reload_stats; + if (devlink_dl_reload_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return 0; +} + +/* ============== DEVLINK_CMD_GET ============== */ +/* DEVLINK_CMD_GET - do */ +void devlink_get_req_free(struct devlink_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_get_rsp_free(struct devlink_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + devlink_dl_dev_stats_free(&rsp->dev_stats); + free(rsp); +} + +int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct devlink_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_RELOAD_FAILED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_failed = 1; + dst->reload_failed = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_DEV_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dev_stats = 1; + + parg.rsp_policy = &devlink_dl_dev_stats_nest; + parg.data = &dst->dev_stats; + if (devlink_dl_dev_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct devlink_get_rsp * +devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_get_rsp_parse; + yrs.rsp_cmd = 3; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_GET - dump */ +void devlink_get_list_free(struct devlink_get_list *rsp) +{ + struct devlink_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + devlink_dl_dev_stats_free(&rsp->obj.dev_stats); + free(rsp); + } +} + +struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_get_list); + yds.cb = devlink_get_rsp_parse; + yds.rsp_cmd = 3; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_PORT_GET ============== */ +/* DEVLINK_CMD_PORT_GET - do */ +void devlink_port_get_req_free(struct devlink_port_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_port_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct devlink_port_get_rsp *dst; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_PORT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port_index = 1; + dst->port_index = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct devlink_port_get_rsp * +devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_port_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_port_get_rsp_parse; + yrs.rsp_cmd = 7; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_port_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_PORT_GET - dump */ +int devlink_port_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) +{ + struct devlink_port_get_rsp_dump *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_PORT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port_index = 1; + dst->port_index = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp) +{ + struct devlink_port_get_rsp_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + free(rsp); + } +} + +struct devlink_port_get_rsp_list * +devlink_port_get_dump(struct ynl_sock *ys, + struct devlink_port_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_port_get_rsp_list); + yds.cb = devlink_port_get_rsp_dump_parse; + yds.rsp_cmd = 7; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_port_get_rsp_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_PORT_SET ============== */ +/* DEVLINK_CMD_PORT_SET - do */ +void devlink_port_set_req_free(struct devlink_port_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + devlink_dl_port_function_free(&req->port_function); + free(req); +} + +int devlink_port_set(struct ynl_sock *ys, struct devlink_port_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.port_type) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, req->port_type); + if (req->_present.port_function) + devlink_dl_port_function_put(nlh, DEVLINK_ATTR_PORT_FUNCTION, &req->port_function); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_PORT_NEW ============== */ +/* DEVLINK_CMD_PORT_NEW - do */ +void devlink_port_new_req_free(struct devlink_port_new_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_port_new_rsp_free(struct devlink_port_new_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_port_new_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct devlink_port_new_rsp *dst; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_PORT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port_index = 1; + dst->port_index = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct devlink_port_new_rsp * +devlink_port_new(struct ynl_sock *ys, struct devlink_port_new_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_port_new_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_NEW, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.port_flavour) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_FLAVOUR, req->port_flavour); + if (req->_present.port_pci_pf_number) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, req->port_pci_pf_number); + if (req->_present.port_pci_sf_number) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, req->port_pci_sf_number); + if (req->_present.port_controller_number) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, req->port_controller_number); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_port_new_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_PORT_NEW; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_port_new_rsp_free(rsp); + return NULL; +} + +/* ============== DEVLINK_CMD_PORT_DEL ============== */ +/* DEVLINK_CMD_PORT_DEL - do */ +void devlink_port_del_req_free(struct devlink_port_del_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_port_del(struct ynl_sock *ys, struct devlink_port_del_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_DEL, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_PORT_SPLIT ============== */ +/* DEVLINK_CMD_PORT_SPLIT - do */ +void devlink_port_split_req_free(struct devlink_port_split_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_port_split(struct ynl_sock *ys, struct devlink_port_split_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_SPLIT, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.port_split_count) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, req->port_split_count); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_PORT_UNSPLIT ============== */ +/* DEVLINK_CMD_PORT_UNSPLIT - do */ +void devlink_port_unsplit_req_free(struct devlink_port_unsplit_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_port_unsplit(struct ynl_sock *ys, + struct devlink_port_unsplit_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_UNSPLIT, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_SB_GET ============== */ +/* DEVLINK_CMD_SB_GET - do */ +void devlink_sb_get_req_free(struct devlink_sb_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_sb_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct devlink_sb_get_rsp *dst; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_SB_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_index = 1; + dst->sb_index = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct devlink_sb_get_rsp * +devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_sb_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_sb_get_rsp_parse; + yrs.rsp_cmd = 13; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_sb_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_SB_GET - dump */ +void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp) +{ + struct devlink_sb_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + free(rsp); + } +} + +struct devlink_sb_get_list * +devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_sb_get_list); + yds.cb = devlink_sb_get_rsp_parse; + yds.rsp_cmd = 13; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_sb_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ +/* DEVLINK_CMD_SB_POOL_GET - do */ +void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_sb_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct devlink_sb_pool_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_SB_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_index = 1; + dst->sb_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_pool_index = 1; + dst->sb_pool_index = mnl_attr_get_u16(attr); + } + } + + return MNL_CB_OK; +} + +struct devlink_sb_pool_get_rsp * +devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_sb_pool_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.sb_pool_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_sb_pool_get_rsp_parse; + yrs.rsp_cmd = 17; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_sb_pool_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_SB_POOL_GET - dump */ +void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp) +{ + struct devlink_sb_pool_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + free(rsp); + } +} + +struct devlink_sb_pool_get_list * +devlink_sb_pool_get_dump(struct ynl_sock *ys, + struct devlink_sb_pool_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_sb_pool_get_list); + yds.cb = devlink_sb_pool_get_rsp_parse; + yds.rsp_cmd = 17; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_sb_pool_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_SB_POOL_SET ============== */ +/* DEVLINK_CMD_SB_POOL_SET - do */ +void devlink_sb_pool_set_req_free(struct devlink_sb_pool_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_sb_pool_set(struct ynl_sock *ys, + struct devlink_sb_pool_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.sb_pool_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + if (req->_present.sb_pool_threshold_type) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, req->sb_pool_threshold_type); + if (req->_present.sb_pool_size) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, req->sb_pool_size); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ +/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ +void +devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void +devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_sb_port_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct devlink_sb_port_pool_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_PORT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port_index = 1; + dst->port_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_SB_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_index = 1; + dst->sb_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_pool_index = 1; + dst->sb_pool_index = mnl_attr_get_u16(attr); + } + } + + return MNL_CB_OK; +} + +struct devlink_sb_port_pool_get_rsp * +devlink_sb_port_pool_get(struct ynl_sock *ys, + struct devlink_sb_port_pool_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_sb_port_pool_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.sb_pool_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_sb_port_pool_get_rsp_parse; + yrs.rsp_cmd = 21; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_sb_port_pool_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ +void +devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp) +{ + struct devlink_sb_port_pool_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + free(rsp); + } +} + +struct devlink_sb_port_pool_get_list * +devlink_sb_port_pool_get_dump(struct ynl_sock *ys, + struct devlink_sb_port_pool_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_sb_port_pool_get_list); + yds.cb = devlink_sb_port_pool_get_rsp_parse; + yds.rsp_cmd = 21; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_sb_port_pool_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_SB_PORT_POOL_SET ============== */ +/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ +void +devlink_sb_port_pool_set_req_free(struct devlink_sb_port_pool_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_sb_port_pool_set(struct ynl_sock *ys, + struct devlink_sb_port_pool_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.sb_pool_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + if (req->_present.sb_threshold) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, req->sb_threshold); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ +/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ +void +devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void +devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_sb_tc_pool_bind_get_rsp_parse(const struct nlmsghdr *nlh, + void *data) +{ + struct devlink_sb_tc_pool_bind_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_PORT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port_index = 1; + dst->port_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_SB_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_index = 1; + dst->sb_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_SB_POOL_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_pool_type = 1; + dst->sb_pool_type = mnl_attr_get_u8(attr); + } else if (type == DEVLINK_ATTR_SB_TC_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sb_tc_index = 1; + dst->sb_tc_index = mnl_attr_get_u16(attr); + } + } + + return MNL_CB_OK; +} + +struct devlink_sb_tc_pool_bind_get_rsp * +devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, + struct devlink_sb_tc_pool_bind_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_sb_tc_pool_bind_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.sb_pool_type) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); + if (req->_present.sb_tc_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_sb_tc_pool_bind_get_rsp_parse; + yrs.rsp_cmd = 25; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_sb_tc_pool_bind_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ +void +devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp) +{ + struct devlink_sb_tc_pool_bind_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + free(rsp); + } +} + +struct devlink_sb_tc_pool_bind_get_list * +devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, + struct devlink_sb_tc_pool_bind_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_sb_tc_pool_bind_get_list); + yds.cb = devlink_sb_tc_pool_bind_get_rsp_parse; + yds.rsp_cmd = 25; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_sb_tc_pool_bind_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_SET ============== */ +/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ +void +devlink_sb_tc_pool_bind_set_req_free(struct devlink_sb_tc_pool_bind_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_sb_tc_pool_bind_set(struct ynl_sock *ys, + struct devlink_sb_tc_pool_bind_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.sb_pool_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + if (req->_present.sb_pool_type) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); + if (req->_present.sb_tc_index) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); + if (req->_present.sb_threshold) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, req->sb_threshold); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_SB_OCC_SNAPSHOT ============== */ +/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ +void devlink_sb_occ_snapshot_req_free(struct devlink_sb_occ_snapshot_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_sb_occ_snapshot(struct ynl_sock *ys, + struct devlink_sb_occ_snapshot_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_OCC_SNAPSHOT, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_SB_OCC_MAX_CLEAR ============== */ +/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ +void +devlink_sb_occ_max_clear_req_free(struct devlink_sb_occ_max_clear_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_sb_occ_max_clear(struct ynl_sock *ys, + struct devlink_sb_occ_max_clear_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_OCC_MAX_CLEAR, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.sb_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_ESWITCH_GET ============== */ +/* DEVLINK_CMD_ESWITCH_GET - do */ +void devlink_eswitch_get_req_free(struct devlink_eswitch_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_eswitch_get_rsp_free(struct devlink_eswitch_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp); +} + +int devlink_eswitch_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct devlink_eswitch_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_ESWITCH_MODE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.eswitch_mode = 1; + dst->eswitch_mode = mnl_attr_get_u16(attr); + } else if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.eswitch_inline_mode = 1; + dst->eswitch_inline_mode = mnl_attr_get_u16(attr); + } else if (type == DEVLINK_ATTR_ESWITCH_ENCAP_MODE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.eswitch_encap_mode = 1; + dst->eswitch_encap_mode = mnl_attr_get_u8(attr); } } - return 0; + return MNL_CB_OK; } -void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj) +struct devlink_eswitch_get_rsp * +devlink_eswitch_get(struct ynl_sock *ys, struct devlink_eswitch_get_req *req) { - devlink_dl_reload_stats_free(&obj->reload_stats); - devlink_dl_reload_stats_free(&obj->remote_reload_stats); -} + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_eswitch_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; -int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, - const struct nlattr *nested) -{ - struct devlink_dl_dev_stats *dst = yarg->data; - const struct nlattr *attr; - struct ynl_parse_arg parg; + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_ESWITCH_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; - parg.ys = yarg->ys; + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - mnl_attr_for_each_nested(attr, nested) { - unsigned int type = mnl_attr_get_type(attr); + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_eswitch_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_ESWITCH_GET; - if (type == DEVLINK_ATTR_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.reload_stats = 1; + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } else if (type == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.remote_reload_stats = 1; + return rsp; - parg.rsp_policy = &devlink_dl_reload_stats_nest; - parg.data = &dst->remote_reload_stats; - if (devlink_dl_reload_stats_parse(&parg, attr)) - return MNL_CB_ERROR; - } - } +err_free: + devlink_eswitch_get_rsp_free(rsp); + return NULL; +} + +/* ============== DEVLINK_CMD_ESWITCH_SET ============== */ +/* DEVLINK_CMD_ESWITCH_SET - do */ +void devlink_eswitch_set_req_free(struct devlink_eswitch_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_eswitch_set(struct ynl_sock *ys, + struct devlink_eswitch_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_ESWITCH_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.eswitch_mode) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, req->eswitch_mode); + if (req->_present.eswitch_inline_mode) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE, req->eswitch_inline_mode); + if (req->_present.eswitch_encap_mode) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, req->eswitch_encap_mode); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; return 0; } -/* ============== DEVLINK_CMD_GET ============== */ -/* DEVLINK_CMD_GET - do */ -void devlink_get_req_free(struct devlink_get_req *req) +/* ============== DEVLINK_CMD_DPIPE_TABLE_GET ============== */ +/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ +void devlink_dpipe_table_get_req_free(struct devlink_dpipe_table_get_req *req) { free(req->bus_name); free(req->dev_name); + free(req->dpipe_table_name); free(req); } -void devlink_get_rsp_free(struct devlink_get_rsp *rsp) +void devlink_dpipe_table_get_rsp_free(struct devlink_dpipe_table_get_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); - devlink_dl_dev_stats_free(&rsp->dev_stats); + devlink_dl_dpipe_tables_free(&rsp->dpipe_tables); free(rsp); } -int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +int devlink_dpipe_table_get_rsp_parse(const struct nlmsghdr *nlh, void *data) { + struct devlink_dpipe_table_get_rsp *dst; struct ynl_parse_arg *yarg = data; - struct devlink_get_rsp *dst; const struct nlattr *attr; struct ynl_parse_arg parg; @@ -470,19 +3619,14 @@ int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_RELOAD_FAILED) { + } else if (type == DEVLINK_ATTR_DPIPE_TABLES) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.reload_failed = 1; - dst->reload_failed = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_DEV_STATS) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.dev_stats = 1; + dst->_present.dpipe_tables = 1; - parg.rsp_policy = &devlink_dl_dev_stats_nest; - parg.data = &dst->dev_stats; - if (devlink_dl_dev_stats_parse(&parg, attr)) + parg.rsp_policy = &devlink_dl_dpipe_tables_nest; + parg.data = &dst->dpipe_tables; + if (devlink_dl_dpipe_tables_parse(&parg, attr)) return MNL_CB_ERROR; } } @@ -490,15 +3634,16 @@ int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } -struct devlink_get_rsp * -devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) +struct devlink_dpipe_table_get_rsp * +devlink_dpipe_table_get(struct ynl_sock *ys, + struct devlink_dpipe_table_get_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_get_rsp *rsp; + struct devlink_dpipe_table_get_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_TABLE_GET, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -506,11 +3651,13 @@ devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.dpipe_table_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_get_rsp_parse; - yrs.rsp_cmd = 3; + yrs.cb = devlink_dpipe_table_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_DPIPE_TABLE_GET; err = ynl_exec(ys, nlh, &yrs); if (err < 0) @@ -519,74 +3666,144 @@ devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) return rsp; err_free: - devlink_get_rsp_free(rsp); + devlink_dpipe_table_get_rsp_free(rsp); return NULL; } -/* DEVLINK_CMD_GET - dump */ -void devlink_get_list_free(struct devlink_get_list *rsp) +/* ============== DEVLINK_CMD_DPIPE_ENTRIES_GET ============== */ +/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ +void +devlink_dpipe_entries_get_req_free(struct devlink_dpipe_entries_get_req *req) { - struct devlink_get_list *next = rsp; + free(req->bus_name); + free(req->dev_name); + free(req->dpipe_table_name); + free(req); +} - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; +void +devlink_dpipe_entries_get_rsp_free(struct devlink_dpipe_entries_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + devlink_dl_dpipe_entries_free(&rsp->dpipe_entries); + free(rsp); +} - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - devlink_dl_dev_stats_free(&rsp->obj.dev_stats); - free(rsp); +int devlink_dpipe_entries_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct devlink_dpipe_entries_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } else if (type == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == DEVLINK_ATTR_DPIPE_ENTRIES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dpipe_entries = 1; + + parg.rsp_policy = &devlink_dl_dpipe_entries_nest; + parg.data = &dst->dpipe_entries; + if (devlink_dl_dpipe_entries_parse(&parg, attr)) + return MNL_CB_ERROR; + } } + + return MNL_CB_OK; } -struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys) +struct devlink_dpipe_entries_get_rsp * +devlink_dpipe_entries_get(struct ynl_sock *ys, + struct devlink_dpipe_entries_get_req *req) { - struct ynl_dump_state yds = {}; + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_dpipe_entries_get_rsp *rsp; struct nlmsghdr *nlh; int err; - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_get_list); - yds.cb = devlink_get_rsp_parse; - yds.rsp_cmd = 3; - yds.rsp_policy = &devlink_nest; + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_ENTRIES_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1); + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.dpipe_table_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); - err = ynl_exec_dump(ys, nlh, &yds); + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_dpipe_entries_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET; + + err = ynl_exec(ys, nlh, &yrs); if (err < 0) - goto free_list; + goto err_free; - return yds.first; + return rsp; -free_list: - devlink_get_list_free(yds.first); +err_free: + devlink_dpipe_entries_get_rsp_free(rsp); return NULL; } -/* ============== DEVLINK_CMD_PORT_GET ============== */ -/* DEVLINK_CMD_PORT_GET - do */ -void devlink_port_get_req_free(struct devlink_port_get_req *req) +/* ============== DEVLINK_CMD_DPIPE_HEADERS_GET ============== */ +/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ +void +devlink_dpipe_headers_get_req_free(struct devlink_dpipe_headers_get_req *req) { free(req->bus_name); free(req->dev_name); free(req); } -void devlink_port_get_rsp_free(struct devlink_port_get_rsp *rsp) +void +devlink_dpipe_headers_get_rsp_free(struct devlink_dpipe_headers_get_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); + devlink_dl_dpipe_headers_free(&rsp->dpipe_headers); free(rsp); } -int devlink_port_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +int devlink_dpipe_headers_get_rsp_parse(const struct nlmsghdr *nlh, void *data) { + struct devlink_dpipe_headers_get_rsp *dst; struct ynl_parse_arg *yarg = data; - struct devlink_port_get_rsp *dst; const struct nlattr *attr; + struct ynl_parse_arg parg; dst = yarg->data; + parg.ys = yarg->ys; mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { unsigned int type = mnl_attr_get_type(attr); @@ -613,26 +3830,31 @@ int devlink_port_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { + } else if (type == DEVLINK_ATTR_DPIPE_HEADERS) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); + dst->_present.dpipe_headers = 1; + + parg.rsp_policy = &devlink_dl_dpipe_headers_nest; + parg.data = &dst->dpipe_headers; + if (devlink_dl_dpipe_headers_parse(&parg, attr)) + return MNL_CB_ERROR; } } return MNL_CB_OK; } -struct devlink_port_get_rsp * -devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req) +struct devlink_dpipe_headers_get_rsp * +devlink_dpipe_headers_get(struct ynl_sock *ys, + struct devlink_dpipe_headers_get_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_port_get_rsp *rsp; + struct devlink_dpipe_headers_get_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_HEADERS_GET, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -640,33 +3862,119 @@ devlink_port_get(struct ynl_sock *ys, struct devlink_port_get_req *req) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_port_get_rsp_parse; - yrs.rsp_cmd = 7; + yrs.cb = devlink_dpipe_headers_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_DPIPE_HEADERS_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_dpipe_headers_get_rsp_free(rsp); + return NULL; +} + +/* ============== DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ============== */ +/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ +void +devlink_dpipe_table_counters_set_req_free(struct devlink_dpipe_table_counters_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->dpipe_table_name); + free(req); +} + +int devlink_dpipe_table_counters_set(struct ynl_sock *ys, + struct devlink_dpipe_table_counters_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.dpipe_table_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME, req->dpipe_table_name); + if (req->_present.dpipe_table_counters_enabled) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, req->dpipe_table_counters_enabled); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_RESOURCE_SET ============== */ +/* DEVLINK_CMD_RESOURCE_SET - do */ +void devlink_resource_set_req_free(struct devlink_resource_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_resource_set(struct ynl_sock *ys, + struct devlink_resource_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RESOURCE_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.resource_id) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID, req->resource_id); + if (req->_present.resource_size) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE, req->resource_size); - err = ynl_exec(ys, nlh, &yrs); + err = ynl_exec(ys, nlh, NULL); if (err < 0) - goto err_free; + return -1; - return rsp; + return 0; +} -err_free: - devlink_port_get_rsp_free(rsp); - return NULL; +/* ============== DEVLINK_CMD_RESOURCE_DUMP ============== */ +/* DEVLINK_CMD_RESOURCE_DUMP - do */ +void devlink_resource_dump_req_free(struct devlink_resource_dump_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); } -/* DEVLINK_CMD_PORT_GET - dump */ -int devlink_port_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) +void devlink_resource_dump_rsp_free(struct devlink_resource_dump_rsp *rsp) { - struct devlink_port_get_rsp_dump *dst; + free(rsp->bus_name); + free(rsp->dev_name); + devlink_dl_resource_list_free(&rsp->resource_list); + free(rsp); +} + +int devlink_resource_dump_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct devlink_resource_dump_rsp *dst; struct ynl_parse_arg *yarg = data; const struct nlattr *attr; + struct ynl_parse_arg parg; dst = yarg->data; + parg.ys = yarg->ys; mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { unsigned int type = mnl_attr_get_type(attr); @@ -693,84 +4001,75 @@ int devlink_port_get_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PORT_INDEX) { + } else if (type == DEVLINK_ATTR_RESOURCE_LIST) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.port_index = 1; - dst->port_index = mnl_attr_get_u32(attr); + dst->_present.resource_list = 1; + + parg.rsp_policy = &devlink_dl_resource_list_nest; + parg.data = &dst->resource_list; + if (devlink_dl_resource_list_parse(&parg, attr)) + return MNL_CB_ERROR; } } return MNL_CB_OK; } -void devlink_port_get_rsp_list_free(struct devlink_port_get_rsp_list *rsp) -{ - struct devlink_port_get_rsp_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_port_get_rsp_list * -devlink_port_get_dump(struct ynl_sock *ys, - struct devlink_port_get_req_dump *req) +struct devlink_resource_dump_rsp * +devlink_resource_dump(struct ynl_sock *ys, + struct devlink_resource_dump_req *req) { - struct ynl_dump_state yds = {}; + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_resource_dump_rsp *rsp; struct nlmsghdr *nlh; int err; - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_port_get_rsp_list); - yds.cb = devlink_port_get_rsp_dump_parse; - yds.rsp_cmd = 7; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RESOURCE_DUMP, 1); ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; if (req->_present.bus_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - err = ynl_exec_dump(ys, nlh, &yds); + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_resource_dump_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_RESOURCE_DUMP; + + err = ynl_exec(ys, nlh, &yrs); if (err < 0) - goto free_list; + goto err_free; - return yds.first; + return rsp; -free_list: - devlink_port_get_rsp_list_free(yds.first); +err_free: + devlink_resource_dump_rsp_free(rsp); return NULL; } -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -void devlink_sb_get_req_free(struct devlink_sb_get_req *req) +/* ============== DEVLINK_CMD_RELOAD ============== */ +/* DEVLINK_CMD_RELOAD - do */ +void devlink_reload_req_free(struct devlink_reload_req *req) { free(req->bus_name); free(req->dev_name); free(req); } -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp) +void devlink_reload_rsp_free(struct devlink_reload_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); free(rsp); } -int devlink_sb_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +int devlink_reload_rsp_parse(const struct nlmsghdr *nlh, void *data) { struct ynl_parse_arg *yarg = data; - struct devlink_sb_get_rsp *dst; + struct devlink_reload_rsp *dst; const struct nlattr *attr; dst = yarg->data; @@ -800,26 +4099,26 @@ int devlink_sb_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { + } else if (type == DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); + dst->_present.reload_actions_performed = 1; + memcpy(&dst->reload_actions_performed, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32)); } } return MNL_CB_OK; } -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) +struct devlink_reload_rsp * +devlink_reload(struct ynl_sock *ys, struct devlink_reload_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_get_rsp *rsp; + struct devlink_reload_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RELOAD, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -827,13 +4126,21 @@ devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); + if (req->_present.reload_action) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION, req->reload_action); + if (req->_present.reload_limits) + mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(struct nla_bitfield32), &req->reload_limits); + if (req->_present.netns_pid) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_PID, req->netns_pid); + if (req->_present.netns_fd) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_FD, req->netns_fd); + if (req->_present.netns_id) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_NETNS_ID, req->netns_id); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_sb_get_rsp_parse; - yrs.rsp_cmd = 13; + yrs.cb = devlink_reload_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_RELOAD; err = ynl_exec(ys, nlh, &yrs); if (err < 0) @@ -842,76 +4149,31 @@ devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req) return rsp; err_free: - devlink_sb_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_SB_GET - dump */ -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp) -{ - struct devlink_sb_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } -} - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req) -{ - struct ynl_dump_state yds = {}; - struct nlmsghdr *nlh; - int err; - - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_get_list); - yds.cb = devlink_sb_get_rsp_parse; - yds.rsp_cmd = 13; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - - err = ynl_exec_dump(ys, nlh, &yds); - if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_get_list_free(yds.first); + devlink_reload_rsp_free(rsp); return NULL; } -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req) +/* ============== DEVLINK_CMD_PARAM_GET ============== */ +/* DEVLINK_CMD_PARAM_GET - do */ +void devlink_param_get_req_free(struct devlink_param_get_req *req) { free(req->bus_name); free(req->dev_name); + free(req->param_name); free(req); } -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp) +void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); + free(rsp->param_name); free(rsp); } -int devlink_sb_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +int devlink_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) { - struct devlink_sb_pool_get_rsp *dst; + struct devlink_param_get_rsp *dst; struct ynl_parse_arg *yarg = data; const struct nlattr *attr; @@ -942,31 +4204,32 @@ int devlink_sb_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { + } else if (type == DEVLINK_ATTR_PARAM_NAME) { + unsigned int len; + if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.param_name_len = len; + dst->param_name = malloc(len + 1); + memcpy(dst->param_name, mnl_attr_get_str(attr), len); + dst->param_name[len] = 0; } } return MNL_CB_OK; } -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) +struct devlink_param_get_rsp * +devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_pool_get_rsp *rsp; + struct devlink_param_get_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -974,15 +4237,13 @@ devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + if (req->_present.param_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_sb_pool_get_rsp_parse; - yrs.rsp_cmd = 17; + yrs.cb = devlink_param_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_PARAM_GET; err = ynl_exec(ys, nlh, &yrs); if (err < 0) @@ -991,14 +4252,14 @@ devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req) return rsp; err_free: - devlink_sb_pool_get_rsp_free(rsp); + devlink_param_get_rsp_free(rsp); return NULL; } -/* DEVLINK_CMD_SB_POOL_GET - dump */ -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp) +/* DEVLINK_CMD_PARAM_GET - dump */ +void devlink_param_get_list_free(struct devlink_param_get_list *rsp) { - struct devlink_sb_pool_get_list *next = rsp; + struct devlink_param_get_list *next = rsp; while ((void *)next != YNL_LIST_END) { rsp = next; @@ -1006,25 +4267,26 @@ void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp) free(rsp->obj.bus_name); free(rsp->obj.dev_name); + free(rsp->obj.param_name); free(rsp); } } -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req) +struct devlink_param_get_list * +devlink_param_get_dump(struct ynl_sock *ys, + struct devlink_param_get_req_dump *req) { struct ynl_dump_state yds = {}; struct nlmsghdr *nlh; int err; yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_pool_get_list); - yds.cb = devlink_sb_pool_get_rsp_parse; - yds.rsp_cmd = 17; + yds.alloc_sz = sizeof(struct devlink_param_get_list); + yds.cb = devlink_param_get_rsp_parse; + yds.rsp_cmd = DEVLINK_CMD_PARAM_GET; yds.rsp_policy = &devlink_nest; - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_POOL_GET, 1); + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); ys->req_policy = &devlink_nest; if (req->_present.bus_name_len) @@ -1039,31 +4301,67 @@ devlink_sb_pool_get_dump(struct ynl_sock *ys, return yds.first; free_list: - devlink_sb_pool_get_list_free(yds.first); + devlink_param_get_list_free(yds.first); return NULL; } -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req) +/* ============== DEVLINK_CMD_PARAM_SET ============== */ +/* DEVLINK_CMD_PARAM_SET - do */ +void devlink_param_set_req_free(struct devlink_param_set_req *req) { free(req->bus_name); free(req->dev_name); + free(req->param_name); free(req); } -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp) +int devlink_param_set(struct ynl_sock *ys, struct devlink_param_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.param_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); + if (req->_present.param_type) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, req->param_type); + if (req->_present.param_value_cmode) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, req->param_value_cmode); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_REGION_GET ============== */ +/* DEVLINK_CMD_REGION_GET - do */ +void devlink_region_get_req_free(struct devlink_region_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->region_name); + free(req); +} + +void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); + free(rsp->region_name); free(rsp); } -int devlink_sb_port_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +int devlink_region_get_rsp_parse(const struct nlmsghdr *nlh, void *data) { - struct devlink_sb_port_pool_get_rsp *dst; + struct devlink_region_get_rsp *dst; struct ynl_parse_arg *yarg = data; const struct nlattr *attr; @@ -1099,32 +4397,32 @@ int devlink_sb_port_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data) return MNL_CB_ERROR; dst->_present.port_index = 1; dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_INDEX) { + } else if (type == DEVLINK_ATTR_REGION_NAME) { + unsigned int len; + if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.sb_pool_index = 1; - dst->sb_pool_index = mnl_attr_get_u16(attr); + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.region_name_len = len; + dst->region_name = malloc(len + 1); + memcpy(dst->region_name, mnl_attr_get_str(attr), len); + dst->region_name[len] = 0; } } return MNL_CB_OK; } -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req) +struct devlink_region_get_rsp * +devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_port_pool_get_rsp *rsp; + struct devlink_region_get_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -1134,15 +4432,13 @@ devlink_sb_port_pool_get(struct ynl_sock *ys, mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); if (req->_present.port_index) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, req->sb_pool_index); + if (req->_present.region_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_sb_port_pool_get_rsp_parse; - yrs.rsp_cmd = 21; + yrs.cb = devlink_region_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_REGION_GET; err = ynl_exec(ys, nlh, &yrs); if (err < 0) @@ -1151,15 +4447,14 @@ devlink_sb_port_pool_get(struct ynl_sock *ys, return rsp; err_free: - devlink_sb_port_pool_get_rsp_free(rsp); + devlink_region_get_rsp_free(rsp); return NULL; } -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp) +/* DEVLINK_CMD_REGION_GET - dump */ +void devlink_region_get_list_free(struct devlink_region_get_list *rsp) { - struct devlink_sb_port_pool_get_list *next = rsp; + struct devlink_region_get_list *next = rsp; while ((void *)next != YNL_LIST_END) { rsp = next; @@ -1167,25 +4462,26 @@ devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp) free(rsp->obj.bus_name); free(rsp->obj.dev_name); + free(rsp->obj.region_name); free(rsp); } } -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req) +struct devlink_region_get_list * +devlink_region_get_dump(struct ynl_sock *ys, + struct devlink_region_get_req_dump *req) { struct ynl_dump_state yds = {}; struct nlmsghdr *nlh; int err; yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_port_pool_get_list); - yds.cb = devlink_sb_port_pool_get_rsp_parse; - yds.rsp_cmd = 21; + yds.alloc_sz = sizeof(struct devlink_region_get_list); + yds.cb = devlink_region_get_rsp_parse; + yds.rsp_cmd = DEVLINK_CMD_REGION_GET; yds.rsp_policy = &devlink_nest; - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_PORT_POOL_GET, 1); + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); ys->req_policy = &devlink_nest; if (req->_present.bus_name_len) @@ -1200,32 +4496,31 @@ devlink_sb_port_pool_get_dump(struct ynl_sock *ys, return yds.first; free_list: - devlink_sb_port_pool_get_list_free(yds.first); + devlink_region_get_list_free(yds.first); return NULL; } -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req) +/* ============== DEVLINK_CMD_REGION_NEW ============== */ +/* DEVLINK_CMD_REGION_NEW - do */ +void devlink_region_new_req_free(struct devlink_region_new_req *req) { free(req->bus_name); free(req->dev_name); + free(req->region_name); free(req); } -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp) +void devlink_region_new_rsp_free(struct devlink_region_new_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); + free(rsp->region_name); free(rsp); } -int devlink_sb_tc_pool_bind_get_rsp_parse(const struct nlmsghdr *nlh, - void *data) +int devlink_region_new_rsp_parse(const struct nlmsghdr *nlh, void *data) { - struct devlink_sb_tc_pool_bind_get_rsp *dst; + struct devlink_region_new_rsp *dst; struct ynl_parse_arg *yarg = data; const struct nlattr *attr; @@ -1261,37 +4556,37 @@ int devlink_sb_tc_pool_bind_get_rsp_parse(const struct nlmsghdr *nlh, return MNL_CB_ERROR; dst->_present.port_index = 1; dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_INDEX) { - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - dst->_present.sb_index = 1; - dst->sb_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_SB_POOL_TYPE) { + } else if (type == DEVLINK_ATTR_REGION_NAME) { + unsigned int len; + if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.sb_pool_type = 1; - dst->sb_pool_type = mnl_attr_get_u8(attr); - } else if (type == DEVLINK_ATTR_SB_TC_INDEX) { + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.region_name_len = len; + dst->region_name = malloc(len + 1); + memcpy(dst->region_name, mnl_attr_get_str(attr), len); + dst->region_name[len] = 0; + } else if (type == DEVLINK_ATTR_REGION_SNAPSHOT_ID) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; - dst->_present.sb_tc_index = 1; - dst->sb_tc_index = mnl_attr_get_u16(attr); + dst->_present.region_snapshot_id = 1; + dst->region_snapshot_id = mnl_attr_get_u32(attr); } } return MNL_CB_OK; } -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req) +struct devlink_region_new_rsp * +devlink_region_new(struct ynl_sock *ys, struct devlink_region_new_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_sb_tc_pool_bind_get_rsp *rsp; + struct devlink_region_new_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_NEW, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -1301,17 +4596,15 @@ devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); if (req->_present.port_index) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.sb_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, req->sb_index); - if (req->_present.sb_pool_type) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, req->sb_pool_type); - if (req->_present.sb_tc_index) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, req->sb_tc_index); + if (req->_present.region_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); + if (req->_present.region_snapshot_id) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yrs.rsp_cmd = 25; + yrs.cb = devlink_region_new_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_REGION_NEW; err = ynl_exec(ys, nlh, &yrs); if (err < 0) @@ -1320,80 +4613,51 @@ devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, return rsp; err_free: - devlink_sb_tc_pool_bind_get_rsp_free(rsp); + devlink_region_new_rsp_free(rsp); return NULL; } -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp) +/* ============== DEVLINK_CMD_REGION_DEL ============== */ +/* DEVLINK_CMD_REGION_DEL - do */ +void devlink_region_del_req_free(struct devlink_region_del_req *req) { - struct devlink_sb_tc_pool_bind_get_list *next = rsp; - - while ((void *)next != YNL_LIST_END) { - rsp = next; - next = rsp->next; - - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp); - } + free(req->bus_name); + free(req->dev_name); + free(req->region_name); + free(req); } -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req) +int devlink_region_del(struct ynl_sock *ys, struct devlink_region_del_req *req) { - struct ynl_dump_state yds = {}; struct nlmsghdr *nlh; int err; - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_sb_tc_pool_bind_get_list); - yds.cb = devlink_sb_tc_pool_bind_get_rsp_parse; - yds.rsp_cmd = 25; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_SB_TC_POOL_BIND_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_DEL, 1); ys->req_policy = &devlink_nest; if (req->_present.bus_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.region_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); + if (req->_present.region_snapshot_id) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); - err = ynl_exec_dump(ys, nlh, &yds); + err = ynl_exec(ys, nlh, NULL); if (err < 0) - goto free_list; - - return yds.first; - -free_list: - devlink_sb_tc_pool_bind_get_list_free(yds.first); - return NULL; -} - -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -void devlink_param_get_req_free(struct devlink_param_get_req *req) -{ - free(req->bus_name); - free(req->dev_name); - free(req->param_name); - free(req); -} + return -1; -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp) -{ - free(rsp->bus_name); - free(rsp->dev_name); - free(rsp->param_name); - free(rsp); + return 0; } -int devlink_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +/* ============== DEVLINK_CMD_REGION_READ ============== */ +/* DEVLINK_CMD_REGION_READ - dump */ +int devlink_region_read_rsp_dump_parse(const struct nlmsghdr *nlh, void *data) { - struct devlink_param_get_rsp *dst; + struct devlink_region_read_rsp_dump *dst; struct ynl_parse_arg *yarg = data; const struct nlattr *attr; @@ -1424,62 +4688,32 @@ int devlink_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } else if (type == DEVLINK_ATTR_PARAM_NAME) { + } else if (type == DEVLINK_ATTR_PORT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port_index = 1; + dst->port_index = mnl_attr_get_u32(attr); + } else if (type == DEVLINK_ATTR_REGION_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.param_name_len = len; - dst->param_name = malloc(len + 1); - memcpy(dst->param_name, mnl_attr_get_str(attr), len); - dst->param_name[len] = 0; + dst->_present.region_name_len = len; + dst->region_name = malloc(len + 1); + memcpy(dst->region_name, mnl_attr_get_str(attr), len); + dst->region_name[len] = 0; } } return MNL_CB_OK; } -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req) -{ - struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_param_get_rsp *rsp; - struct nlmsghdr *nlh; - int err; - - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); - ys->req_policy = &devlink_nest; - yrs.yarg.rsp_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.param_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME, req->param_name); - - rsp = calloc(1, sizeof(*rsp)); - yrs.yarg.data = rsp; - yrs.cb = devlink_param_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_PARAM_GET; - - err = ynl_exec(ys, nlh, &yrs); - if (err < 0) - goto err_free; - - return rsp; - -err_free: - devlink_param_get_rsp_free(rsp); - return NULL; -} - -/* DEVLINK_CMD_PARAM_GET - dump */ -void devlink_param_get_list_free(struct devlink_param_get_list *rsp) +void +devlink_region_read_rsp_list_free(struct devlink_region_read_rsp_list *rsp) { - struct devlink_param_get_list *next = rsp; + struct devlink_region_read_rsp_list *next = rsp; while ((void *)next != YNL_LIST_END) { rsp = next; @@ -1487,32 +4721,44 @@ void devlink_param_get_list_free(struct devlink_param_get_list *rsp) free(rsp->obj.bus_name); free(rsp->obj.dev_name); - free(rsp->obj.param_name); + free(rsp->obj.region_name); free(rsp); } } -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req) +struct devlink_region_read_rsp_list * +devlink_region_read_dump(struct ynl_sock *ys, + struct devlink_region_read_req_dump *req) { struct ynl_dump_state yds = {}; struct nlmsghdr *nlh; int err; yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_param_get_list); - yds.cb = devlink_param_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_PARAM_GET; + yds.alloc_sz = sizeof(struct devlink_region_read_rsp_list); + yds.cb = devlink_region_read_rsp_dump_parse; + yds.rsp_cmd = DEVLINK_CMD_REGION_READ; yds.rsp_policy = &devlink_nest; - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PARAM_GET, 1); + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_READ, 1); ys->req_policy = &devlink_nest; if (req->_present.bus_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.region_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); + if (req->_present.region_snapshot_id) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID, req->region_snapshot_id); + if (req->_present.region_direct) + mnl_attr_put(nlh, DEVLINK_ATTR_REGION_DIRECT, 0, NULL); + if (req->_present.region_chunk_addr) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR, req->region_chunk_addr); + if (req->_present.region_chunk_len) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN, req->region_chunk_len); err = ynl_exec_dump(ys, nlh, &yds); if (err < 0) @@ -1521,31 +4767,29 @@ devlink_param_get_dump(struct ynl_sock *ys, return yds.first; free_list: - devlink_param_get_list_free(yds.first); + devlink_region_read_rsp_list_free(yds.first); return NULL; } -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -void devlink_region_get_req_free(struct devlink_region_get_req *req) +/* ============== DEVLINK_CMD_PORT_PARAM_GET ============== */ +/* DEVLINK_CMD_PORT_PARAM_GET - do */ +void devlink_port_param_get_req_free(struct devlink_port_param_get_req *req) { free(req->bus_name); free(req->dev_name); - free(req->region_name); free(req); } -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp) +void devlink_port_param_get_rsp_free(struct devlink_port_param_get_rsp *rsp) { free(rsp->bus_name); free(rsp->dev_name); - free(rsp->region_name); free(rsp); } -int devlink_region_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +int devlink_port_param_get_rsp_parse(const struct nlmsghdr *nlh, void *data) { - struct devlink_region_get_rsp *dst; + struct devlink_port_param_get_rsp *dst; struct ynl_parse_arg *yarg = data; const struct nlattr *attr; @@ -1581,32 +4825,22 @@ int devlink_region_get_rsp_parse(const struct nlmsghdr *nlh, void *data) return MNL_CB_ERROR; dst->_present.port_index = 1; dst->port_index = mnl_attr_get_u32(attr); - } else if (type == DEVLINK_ATTR_REGION_NAME) { - unsigned int len; - - if (ynl_attr_validate(yarg, attr)) - return MNL_CB_ERROR; - - len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); - dst->_present.region_name_len = len; - dst->region_name = malloc(len + 1); - memcpy(dst->region_name, mnl_attr_get_str(attr), len); - dst->region_name[len] = 0; } } return MNL_CB_OK; } -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) +struct devlink_port_param_get_rsp * +devlink_port_param_get(struct ynl_sock *ys, + struct devlink_port_param_get_req *req) { struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; - struct devlink_region_get_rsp *rsp; + struct devlink_port_param_get_rsp *rsp; struct nlmsghdr *nlh; int err; - nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_GET, 1); ys->req_policy = &devlink_nest; yrs.yarg.rsp_policy = &devlink_nest; @@ -1616,13 +4850,11 @@ devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); if (req->_present.port_index) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - if (req->_present.region_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME, req->region_name); rsp = calloc(1, sizeof(*rsp)); yrs.yarg.data = rsp; - yrs.cb = devlink_region_get_rsp_parse; - yrs.rsp_cmd = DEVLINK_CMD_REGION_GET; + yrs.cb = devlink_port_param_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_PORT_PARAM_GET; err = ynl_exec(ys, nlh, &yrs); if (err < 0) @@ -1631,14 +4863,14 @@ devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req) return rsp; err_free: - devlink_region_get_rsp_free(rsp); + devlink_port_param_get_rsp_free(rsp); return NULL; } -/* DEVLINK_CMD_REGION_GET - dump */ -void devlink_region_get_list_free(struct devlink_region_get_list *rsp) +/* DEVLINK_CMD_PORT_PARAM_GET - dump */ +void devlink_port_param_get_list_free(struct devlink_port_param_get_list *rsp) { - struct devlink_region_get_list *next = rsp; + struct devlink_port_param_get_list *next = rsp; while ((void *)next != YNL_LIST_END) { rsp = next; @@ -1646,32 +4878,24 @@ void devlink_region_get_list_free(struct devlink_region_get_list *rsp) free(rsp->obj.bus_name); free(rsp->obj.dev_name); - free(rsp->obj.region_name); free(rsp); } } -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req) +struct devlink_port_param_get_list * +devlink_port_param_get_dump(struct ynl_sock *ys) { struct ynl_dump_state yds = {}; struct nlmsghdr *nlh; int err; yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_region_get_list); - yds.cb = devlink_region_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_REGION_GET; + yds.alloc_sz = sizeof(struct devlink_port_param_get_list); + yds.cb = devlink_port_param_get_rsp_parse; + yds.rsp_cmd = DEVLINK_CMD_PORT_PARAM_GET; yds.rsp_policy = &devlink_nest; - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_REGION_GET, 1); - ys->req_policy = &devlink_nest; - - if (req->_present.bus_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); - if (req->_present.dev_name_len) - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_GET, 1); err = ynl_exec_dump(ys, nlh, &yds); if (err < 0) @@ -1680,10 +4904,42 @@ devlink_region_get_dump(struct ynl_sock *ys, return yds.first; free_list: - devlink_region_get_list_free(yds.first); + devlink_port_param_get_list_free(yds.first); return NULL; } +/* ============== DEVLINK_CMD_PORT_PARAM_SET ============== */ +/* DEVLINK_CMD_PORT_PARAM_SET - do */ +void devlink_port_param_set_req_free(struct devlink_port_param_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_port_param_set(struct ynl_sock *ys, + struct devlink_port_param_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_PORT_PARAM_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + /* ============== DEVLINK_CMD_INFO_GET ============== */ /* DEVLINK_CMD_INFO_GET - do */ void devlink_info_get_req_free(struct devlink_info_get_req *req) @@ -2046,46 +5302,316 @@ devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *r rsp = next; next = rsp->next; - free(rsp->obj.bus_name); - free(rsp->obj.dev_name); - free(rsp->obj.health_reporter_name); - free(rsp); - } + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + free(rsp->obj.health_reporter_name); + free(rsp); + } +} + +struct devlink_health_reporter_get_list * +devlink_health_reporter_get_dump(struct ynl_sock *ys, + struct devlink_health_reporter_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_health_reporter_get_list); + yds.cb = devlink_health_reporter_get_rsp_parse; + yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_health_reporter_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_SET ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ +void +devlink_health_reporter_set_req_free(struct devlink_health_reporter_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->health_reporter_name); + free(req); +} + +int devlink_health_reporter_set(struct ynl_sock *ys, + struct devlink_health_reporter_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.health_reporter_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); + if (req->_present.health_reporter_graceful_period) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, req->health_reporter_graceful_period); + if (req->_present.health_reporter_auto_recover) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, req->health_reporter_auto_recover); + if (req->_present.health_reporter_auto_dump) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP, req->health_reporter_auto_dump); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_RECOVER ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ +void +devlink_health_reporter_recover_req_free(struct devlink_health_reporter_recover_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->health_reporter_name); + free(req); +} + +int devlink_health_reporter_recover(struct ynl_sock *ys, + struct devlink_health_reporter_recover_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_RECOVER, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.health_reporter_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ +void +devlink_health_reporter_diagnose_req_free(struct devlink_health_reporter_diagnose_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->health_reporter_name); + free(req); +} + +int devlink_health_reporter_diagnose(struct ynl_sock *ys, + struct devlink_health_reporter_diagnose_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.health_reporter_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ +int devlink_health_reporter_dump_get_rsp_dump_parse(const struct nlmsghdr *nlh, + void *data) +{ + struct devlink_health_reporter_dump_get_rsp_dump *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_FMSG) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.fmsg = 1; + + parg.rsp_policy = &devlink_dl_fmsg_nest; + parg.data = &dst->fmsg; + if (devlink_dl_fmsg_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +void +devlink_health_reporter_dump_get_rsp_list_free(struct devlink_health_reporter_dump_get_rsp_list *rsp) +{ + struct devlink_health_reporter_dump_get_rsp_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + devlink_dl_fmsg_free(&rsp->obj.fmsg); + free(rsp); + } +} + +struct devlink_health_reporter_dump_get_rsp_list * +devlink_health_reporter_dump_get_dump(struct ynl_sock *ys, + struct devlink_health_reporter_dump_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_health_reporter_dump_get_rsp_list); + yds.cb = devlink_health_reporter_dump_get_rsp_dump_parse; + yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.health_reporter_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_health_reporter_dump_get_rsp_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ +void +devlink_health_reporter_dump_clear_req_free(struct devlink_health_reporter_dump_clear_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->health_reporter_name); + free(req); +} + +int devlink_health_reporter_dump_clear(struct ynl_sock *ys, + struct devlink_health_reporter_dump_clear_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.health_reporter_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_FLASH_UPDATE ============== */ +/* DEVLINK_CMD_FLASH_UPDATE - do */ +void devlink_flash_update_req_free(struct devlink_flash_update_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->flash_update_file_name); + free(req->flash_update_component); + free(req); } -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req) +int devlink_flash_update(struct ynl_sock *ys, + struct devlink_flash_update_req *req) { - struct ynl_dump_state yds = {}; struct nlmsghdr *nlh; int err; - yds.ys = ys; - yds.alloc_sz = sizeof(struct devlink_health_reporter_get_list); - yds.cb = devlink_health_reporter_get_rsp_parse; - yds.rsp_cmd = DEVLINK_CMD_HEALTH_REPORTER_GET; - yds.rsp_policy = &devlink_nest; - - nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_GET, 1); + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_FLASH_UPDATE, 1); ys->req_policy = &devlink_nest; if (req->_present.bus_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); if (req->_present.dev_name_len) mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); - if (req->_present.port_index) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); - - err = ynl_exec_dump(ys, nlh, &yds); + if (req->_present.flash_update_file_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME, req->flash_update_file_name); + if (req->_present.flash_update_component_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, req->flash_update_component); + if (req->_present.flash_update_overwrite_mask) + mnl_attr_put(nlh, DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK, sizeof(struct nla_bitfield32), &req->flash_update_overwrite_mask); + + err = ynl_exec(ys, nlh, NULL); if (err < 0) - goto free_list; - - return yds.first; + return -1; -free_list: - devlink_health_reporter_get_list_free(yds.first); - return NULL; + return 0; } /* ============== DEVLINK_CMD_TRAP_GET ============== */ @@ -2240,6 +5766,40 @@ free_list: return NULL; } +/* ============== DEVLINK_CMD_TRAP_SET ============== */ +/* DEVLINK_CMD_TRAP_SET - do */ +void devlink_trap_set_req_free(struct devlink_trap_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->trap_name); + free(req); +} + +int devlink_trap_set(struct ynl_sock *ys, struct devlink_trap_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.trap_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME, req->trap_name); + if (req->_present.trap_action) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION, req->trap_action); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + /* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ /* DEVLINK_CMD_TRAP_GROUP_GET - do */ void devlink_trap_group_get_req_free(struct devlink_trap_group_get_req *req) @@ -2393,6 +5953,43 @@ free_list: return NULL; } +/* ============== DEVLINK_CMD_TRAP_GROUP_SET ============== */ +/* DEVLINK_CMD_TRAP_GROUP_SET - do */ +void devlink_trap_group_set_req_free(struct devlink_trap_group_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->trap_group_name); + free(req); +} + +int devlink_trap_group_set(struct ynl_sock *ys, + struct devlink_trap_group_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_GROUP_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.trap_group_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME, req->trap_group_name); + if (req->_present.trap_action) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION, req->trap_action); + if (req->_present.trap_policer_id) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + /* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ /* DEVLINK_CMD_TRAP_POLICER_GET - do */ void @@ -2540,6 +6137,79 @@ free_list: return NULL; } +/* ============== DEVLINK_CMD_TRAP_POLICER_SET ============== */ +/* DEVLINK_CMD_TRAP_POLICER_SET - do */ +void +devlink_trap_policer_set_req_free(struct devlink_trap_policer_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +int devlink_trap_policer_set(struct ynl_sock *ys, + struct devlink_trap_policer_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_TRAP_POLICER_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.trap_policer_id) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID, req->trap_policer_id); + if (req->_present.trap_policer_rate) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_RATE, req->trap_policer_rate); + if (req->_present.trap_policer_burst) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_BURST, req->trap_policer_burst); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_TEST ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ +void +devlink_health_reporter_test_req_free(struct devlink_health_reporter_test_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->health_reporter_name); + free(req); +} + +int devlink_health_reporter_test(struct ynl_sock *ys, + struct devlink_health_reporter_test_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_HEALTH_REPORTER_TEST, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.port_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, req->port_index); + if (req->_present.health_reporter_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, req->health_reporter_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + /* ============== DEVLINK_CMD_RATE_GET ============== */ /* DEVLINK_CMD_RATE_GET - do */ void devlink_rate_get_req_free(struct devlink_rate_get_req *req) @@ -2699,6 +6369,124 @@ free_list: return NULL; } +/* ============== DEVLINK_CMD_RATE_SET ============== */ +/* DEVLINK_CMD_RATE_SET - do */ +void devlink_rate_set_req_free(struct devlink_rate_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->rate_node_name); + free(req->rate_parent_node_name); + free(req); +} + +int devlink_rate_set(struct ynl_sock *ys, struct devlink_rate_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.rate_node_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); + if (req->_present.rate_tx_share) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE, req->rate_tx_share); + if (req->_present.rate_tx_max) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX, req->rate_tx_max); + if (req->_present.rate_tx_priority) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_PRIORITY, req->rate_tx_priority); + if (req->_present.rate_tx_weight) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_WEIGHT, req->rate_tx_weight); + if (req->_present.rate_parent_node_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, req->rate_parent_node_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_RATE_NEW ============== */ +/* DEVLINK_CMD_RATE_NEW - do */ +void devlink_rate_new_req_free(struct devlink_rate_new_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->rate_node_name); + free(req->rate_parent_node_name); + free(req); +} + +int devlink_rate_new(struct ynl_sock *ys, struct devlink_rate_new_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_NEW, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.rate_node_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); + if (req->_present.rate_tx_share) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE, req->rate_tx_share); + if (req->_present.rate_tx_max) + mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX, req->rate_tx_max); + if (req->_present.rate_tx_priority) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_PRIORITY, req->rate_tx_priority); + if (req->_present.rate_tx_weight) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_RATE_TX_WEIGHT, req->rate_tx_weight); + if (req->_present.rate_parent_node_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, req->rate_parent_node_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== DEVLINK_CMD_RATE_DEL ============== */ +/* DEVLINK_CMD_RATE_DEL - do */ +void devlink_rate_del_req_free(struct devlink_rate_del_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->rate_node_name); + free(req); +} + +int devlink_rate_del(struct ynl_sock *ys, struct devlink_rate_del_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_RATE_DEL, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.rate_node_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME, req->rate_node_name); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + /* ============== DEVLINK_CMD_LINECARD_GET ============== */ /* DEVLINK_CMD_LINECARD_GET - do */ void devlink_linecard_get_req_free(struct devlink_linecard_get_req *req) @@ -2842,6 +6630,41 @@ free_list: return NULL; } +/* ============== DEVLINK_CMD_LINECARD_SET ============== */ +/* DEVLINK_CMD_LINECARD_SET - do */ +void devlink_linecard_set_req_free(struct devlink_linecard_set_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req->linecard_type); + free(req); +} + +int devlink_linecard_set(struct ynl_sock *ys, + struct devlink_linecard_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_LINECARD_SET, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.linecard_index) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_LINECARD_INDEX, req->linecard_index); + if (req->_present.linecard_type_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_LINECARD_TYPE, req->linecard_type); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + /* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ /* DEVLINK_CMD_SELFTESTS_GET - do */ void devlink_selftests_get_req_free(struct devlink_selftests_get_req *req) @@ -2972,6 +6795,39 @@ free_list: return NULL; } +/* ============== DEVLINK_CMD_SELFTESTS_RUN ============== */ +/* DEVLINK_CMD_SELFTESTS_RUN - do */ +void devlink_selftests_run_req_free(struct devlink_selftests_run_req *req) +{ + free(req->bus_name); + free(req->dev_name); + devlink_dl_selftest_id_free(&req->selftests); + free(req); +} + +int devlink_selftests_run(struct ynl_sock *ys, + struct devlink_selftests_run_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_SELFTESTS_RUN, 1); + ys->req_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + if (req->_present.selftests) + devlink_dl_selftest_id_put(nlh, DEVLINK_ATTR_SELFTESTS, &req->selftests); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + const struct ynl_family ynl_devlink_family = { .name = "devlink", }; diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h index d00bcf79fa0d..9f45cc0d854c 100644 --- a/tools/net/ynl/generated/devlink-user.h +++ b/tools/net/ynl/generated/devlink-user.h @@ -9,6 +9,7 @@ #include #include #include +#include #include struct ynl_sock; @@ -18,8 +19,130 @@ extern const struct ynl_family ynl_devlink_family; /* Enums */ const char *devlink_op_str(int op); const char *devlink_sb_pool_type_str(enum devlink_sb_pool_type value); +const char *devlink_port_type_str(enum devlink_port_type value); +const char *devlink_port_flavour_str(enum devlink_port_flavour value); +const char *devlink_port_fn_state_str(enum devlink_port_fn_state value); +const char *devlink_port_fn_opstate_str(enum devlink_port_fn_opstate value); +const char *devlink_port_fn_attr_cap_str(enum devlink_port_fn_attr_cap value); +const char * +devlink_sb_threshold_type_str(enum devlink_sb_threshold_type value); +const char *devlink_eswitch_mode_str(enum devlink_eswitch_mode value); +const char * +devlink_eswitch_inline_mode_str(enum devlink_eswitch_inline_mode value); +const char * +devlink_eswitch_encap_mode_str(enum devlink_eswitch_encap_mode value); +const char *devlink_dpipe_match_type_str(enum devlink_dpipe_match_type value); +const char * +devlink_dpipe_action_type_str(enum devlink_dpipe_action_type value); +const char * +devlink_dpipe_field_mapping_type_str(enum devlink_dpipe_field_mapping_type value); +const char *devlink_resource_unit_str(enum devlink_resource_unit value); +const char *devlink_reload_action_str(enum devlink_reload_action value); +const char *devlink_param_cmode_str(enum devlink_param_cmode value); +const char *devlink_flash_overwrite_str(enum devlink_flash_overwrite value); +const char *devlink_trap_action_str(enum devlink_trap_action value); /* Common nested types */ +struct devlink_dl_dpipe_match { + struct { + __u32 dpipe_match_type:1; + __u32 dpipe_header_id:1; + __u32 dpipe_header_global:1; + __u32 dpipe_header_index:1; + __u32 dpipe_field_id:1; + } _present; + + enum devlink_dpipe_match_type dpipe_match_type; + __u32 dpipe_header_id; + __u8 dpipe_header_global; + __u32 dpipe_header_index; + __u32 dpipe_field_id; +}; + +struct devlink_dl_dpipe_match_value { + struct { + __u32 dpipe_value_len; + __u32 dpipe_value_mask_len; + __u32 dpipe_value_mapping:1; + } _present; + + unsigned int n_dpipe_match; + struct devlink_dl_dpipe_match *dpipe_match; + void *dpipe_value; + void *dpipe_value_mask; + __u32 dpipe_value_mapping; +}; + +struct devlink_dl_dpipe_action { + struct { + __u32 dpipe_action_type:1; + __u32 dpipe_header_id:1; + __u32 dpipe_header_global:1; + __u32 dpipe_header_index:1; + __u32 dpipe_field_id:1; + } _present; + + enum devlink_dpipe_action_type dpipe_action_type; + __u32 dpipe_header_id; + __u8 dpipe_header_global; + __u32 dpipe_header_index; + __u32 dpipe_field_id; +}; + +struct devlink_dl_dpipe_action_value { + struct { + __u32 dpipe_value_len; + __u32 dpipe_value_mask_len; + __u32 dpipe_value_mapping:1; + } _present; + + unsigned int n_dpipe_action; + struct devlink_dl_dpipe_action *dpipe_action; + void *dpipe_value; + void *dpipe_value_mask; + __u32 dpipe_value_mapping; +}; + +struct devlink_dl_dpipe_field { + struct { + __u32 dpipe_field_name_len; + __u32 dpipe_field_id:1; + __u32 dpipe_field_bitwidth:1; + __u32 dpipe_field_mapping_type:1; + } _present; + + char *dpipe_field_name; + __u32 dpipe_field_id; + __u32 dpipe_field_bitwidth; + enum devlink_dpipe_field_mapping_type dpipe_field_mapping_type; +}; + +struct devlink_dl_resource { + struct { + __u32 resource_name_len; + __u32 resource_id:1; + __u32 resource_size:1; + __u32 resource_size_new:1; + __u32 resource_size_valid:1; + __u32 resource_size_min:1; + __u32 resource_size_max:1; + __u32 resource_size_gran:1; + __u32 resource_unit:1; + __u32 resource_occ:1; + } _present; + + char *resource_name; + __u64 resource_id; + __u64 resource_size; + __u64 resource_size_new; + __u8 resource_size_valid; + __u64 resource_size_min; + __u64 resource_size_max; + __u64 resource_size_gran; + enum devlink_resource_unit resource_unit; + __u64 resource_occ; +}; + struct devlink_dl_info_version { struct { __u32 info_version_name_len; @@ -30,6 +153,32 @@ struct devlink_dl_info_version { char *info_version_value; }; +struct devlink_dl_fmsg { + struct { + __u32 fmsg_obj_nest_start:1; + __u32 fmsg_pair_nest_start:1; + __u32 fmsg_arr_nest_start:1; + __u32 fmsg_nest_end:1; + __u32 fmsg_obj_name_len; + } _present; + + char *fmsg_obj_name; +}; + +struct devlink_dl_port_function { + struct { + __u32 hw_addr_len; + __u32 state:1; + __u32 opstate:1; + __u32 caps:1; + } _present; + + void *hw_addr; + enum devlink_port_fn_state state; + enum devlink_port_fn_opstate opstate; + struct nla_bitfield32 caps; +}; + struct devlink_dl_reload_stats_entry { struct { __u32 reload_stats_limit:1; @@ -45,21 +194,120 @@ struct devlink_dl_reload_act_stats { struct devlink_dl_reload_stats_entry *reload_stats_entry; }; +struct devlink_dl_selftest_id { + struct { + __u32 flash:1; + } _present; +}; + +struct devlink_dl_dpipe_table_matches { + unsigned int n_dpipe_match; + struct devlink_dl_dpipe_match *dpipe_match; +}; + +struct devlink_dl_dpipe_table_actions { + unsigned int n_dpipe_action; + struct devlink_dl_dpipe_action *dpipe_action; +}; + +struct devlink_dl_dpipe_entry_match_values { + unsigned int n_dpipe_match_value; + struct devlink_dl_dpipe_match_value *dpipe_match_value; +}; + +struct devlink_dl_dpipe_entry_action_values { + unsigned int n_dpipe_action_value; + struct devlink_dl_dpipe_action_value *dpipe_action_value; +}; + +struct devlink_dl_dpipe_header_fields { + unsigned int n_dpipe_field; + struct devlink_dl_dpipe_field *dpipe_field; +}; + +struct devlink_dl_resource_list { + unsigned int n_resource; + struct devlink_dl_resource *resource; +}; + struct devlink_dl_reload_act_info { struct { __u32 reload_action:1; } _present; - __u8 reload_action; + enum devlink_reload_action reload_action; unsigned int n_reload_action_stats; struct devlink_dl_reload_act_stats *reload_action_stats; }; +struct devlink_dl_dpipe_table { + struct { + __u32 dpipe_table_name_len; + __u32 dpipe_table_size:1; + __u32 dpipe_table_matches:1; + __u32 dpipe_table_actions:1; + __u32 dpipe_table_counters_enabled:1; + __u32 dpipe_table_resource_id:1; + __u32 dpipe_table_resource_units:1; + } _present; + + char *dpipe_table_name; + __u64 dpipe_table_size; + struct devlink_dl_dpipe_table_matches dpipe_table_matches; + struct devlink_dl_dpipe_table_actions dpipe_table_actions; + __u8 dpipe_table_counters_enabled; + __u64 dpipe_table_resource_id; + __u64 dpipe_table_resource_units; +}; + +struct devlink_dl_dpipe_entry { + struct { + __u32 dpipe_entry_index:1; + __u32 dpipe_entry_match_values:1; + __u32 dpipe_entry_action_values:1; + __u32 dpipe_entry_counter:1; + } _present; + + __u64 dpipe_entry_index; + struct devlink_dl_dpipe_entry_match_values dpipe_entry_match_values; + struct devlink_dl_dpipe_entry_action_values dpipe_entry_action_values; + __u64 dpipe_entry_counter; +}; + +struct devlink_dl_dpipe_header { + struct { + __u32 dpipe_header_name_len; + __u32 dpipe_header_id:1; + __u32 dpipe_header_global:1; + __u32 dpipe_header_fields:1; + } _present; + + char *dpipe_header_name; + __u32 dpipe_header_id; + __u8 dpipe_header_global; + struct devlink_dl_dpipe_header_fields dpipe_header_fields; +}; + struct devlink_dl_reload_stats { unsigned int n_reload_action_info; struct devlink_dl_reload_act_info *reload_action_info; }; +struct devlink_dl_dpipe_tables { + unsigned int n_dpipe_table; + struct devlink_dl_dpipe_table *dpipe_table; +}; + +struct devlink_dl_dpipe_entries { + unsigned int n_dpipe_entry; + struct devlink_dl_dpipe_entry *dpipe_entry; +}; + +struct devlink_dl_dpipe_headers { + unsigned int n_dpipe_header; + struct devlink_dl_dpipe_header *dpipe_header; +}; + struct devlink_dl_dev_stats { struct { __u32 reload_stats:1; @@ -269,29 +517,33 @@ struct devlink_port_get_rsp_list * devlink_port_get_dump(struct ynl_sock *ys, struct devlink_port_get_req_dump *req); -/* ============== DEVLINK_CMD_SB_GET ============== */ -/* DEVLINK_CMD_SB_GET - do */ -struct devlink_sb_get_req { +/* ============== DEVLINK_CMD_PORT_SET ============== */ +/* DEVLINK_CMD_PORT_SET - do */ +struct devlink_port_set_req { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 sb_index:1; + __u32 port_index:1; + __u32 port_type:1; + __u32 port_function:1; } _present; char *bus_name; char *dev_name; - __u32 sb_index; + __u32 port_index; + enum devlink_port_type port_type; + struct devlink_dl_port_function port_function; }; -static inline struct devlink_sb_get_req *devlink_sb_get_req_alloc(void) +static inline struct devlink_port_set_req *devlink_port_set_req_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_get_req)); + return calloc(1, sizeof(struct devlink_port_set_req)); } -void devlink_sb_get_req_free(struct devlink_sb_get_req *req); +void devlink_port_set_req_free(struct devlink_port_set_req *req); static inline void -devlink_sb_get_req_set_bus_name(struct devlink_sb_get_req *req, - const char *bus_name) +devlink_port_set_req_set_bus_name(struct devlink_port_set_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -300,8 +552,8 @@ devlink_sb_get_req_set_bus_name(struct devlink_sb_get_req *req, req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_get_req_set_dev_name(struct devlink_sb_get_req *req, - const char *dev_name) +devlink_port_set_req_set_dev_name(struct devlink_port_set_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -310,53 +562,89 @@ devlink_sb_get_req_set_dev_name(struct devlink_sb_get_req *req, req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_sb_get_req_set_sb_index(struct devlink_sb_get_req *req, __u32 sb_index) +devlink_port_set_req_set_port_index(struct devlink_port_set_req *req, + __u32 port_index) { - req->_present.sb_index = 1; - req->sb_index = sb_index; + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_port_set_req_set_port_type(struct devlink_port_set_req *req, + enum devlink_port_type port_type) +{ + req->_present.port_type = 1; + req->port_type = port_type; +} +static inline void +devlink_port_set_req_set_port_function_hw_addr(struct devlink_port_set_req *req, + const void *hw_addr, size_t len) +{ + free(req->port_function.hw_addr); + req->port_function._present.hw_addr_len = len; + req->port_function.hw_addr = malloc(req->port_function._present.hw_addr_len); + memcpy(req->port_function.hw_addr, hw_addr, req->port_function._present.hw_addr_len); +} +static inline void +devlink_port_set_req_set_port_function_state(struct devlink_port_set_req *req, + enum devlink_port_fn_state state) +{ + req->_present.port_function = 1; + req->port_function._present.state = 1; + req->port_function.state = state; +} +static inline void +devlink_port_set_req_set_port_function_opstate(struct devlink_port_set_req *req, + enum devlink_port_fn_opstate opstate) +{ + req->_present.port_function = 1; + req->port_function._present.opstate = 1; + req->port_function.opstate = opstate; +} +static inline void +devlink_port_set_req_set_port_function_caps(struct devlink_port_set_req *req, + struct nla_bitfield32 *caps) +{ + req->_present.port_function = 1; + req->port_function._present.caps = 1; + memcpy(&req->port_function.caps, caps, sizeof(struct nla_bitfield32)); } - -struct devlink_sb_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; -}; - -void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp); /* - * Get shared buffer instances. + * Set devlink port instances. */ -struct devlink_sb_get_rsp * -devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req); +int devlink_port_set(struct ynl_sock *ys, struct devlink_port_set_req *req); -/* DEVLINK_CMD_SB_GET - dump */ -struct devlink_sb_get_req_dump { +/* ============== DEVLINK_CMD_PORT_NEW ============== */ +/* DEVLINK_CMD_PORT_NEW - do */ +struct devlink_port_new_req { struct { __u32 bus_name_len; __u32 dev_name_len; + __u32 port_index:1; + __u32 port_flavour:1; + __u32 port_pci_pf_number:1; + __u32 port_pci_sf_number:1; + __u32 port_controller_number:1; } _present; char *bus_name; char *dev_name; + __u32 port_index; + enum devlink_port_flavour port_flavour; + __u16 port_pci_pf_number; + __u32 port_pci_sf_number; + __u32 port_controller_number; }; -static inline struct devlink_sb_get_req_dump * -devlink_sb_get_req_dump_alloc(void) +static inline struct devlink_port_new_req *devlink_port_new_req_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_get_req_dump)); + return calloc(1, sizeof(struct devlink_port_new_req)); } -void devlink_sb_get_req_dump_free(struct devlink_sb_get_req_dump *req); +void devlink_port_new_req_free(struct devlink_port_new_req *req); static inline void -devlink_sb_get_req_dump_set_bus_name(struct devlink_sb_get_req_dump *req, - const char *bus_name) +devlink_port_new_req_set_bus_name(struct devlink_port_new_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -365,8 +653,8 @@ devlink_sb_get_req_dump_set_bus_name(struct devlink_sb_get_req_dump *req, req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_get_req_dump_set_dev_name(struct devlink_sb_get_req_dump *req, - const char *dev_name) +devlink_port_new_req_set_dev_name(struct devlink_port_new_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -374,119 +662,85 @@ devlink_sb_get_req_dump_set_dev_name(struct devlink_sb_get_req_dump *req, memcpy(req->dev_name, dev_name, req->_present.dev_name_len); req->dev_name[req->_present.dev_name_len] = 0; } - -struct devlink_sb_get_list { - struct devlink_sb_get_list *next; - struct devlink_sb_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp); - -struct devlink_sb_get_list * -devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req); - -/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ -/* DEVLINK_CMD_SB_POOL_GET - do */ -struct devlink_sb_pool_get_req { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; -}; - -static inline struct devlink_sb_pool_get_req * -devlink_sb_pool_get_req_alloc(void) +static inline void +devlink_port_new_req_set_port_index(struct devlink_port_new_req *req, + __u32 port_index) { - return calloc(1, sizeof(struct devlink_sb_pool_get_req)); + req->_present.port_index = 1; + req->port_index = port_index; } -void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req); - static inline void -devlink_sb_pool_get_req_set_bus_name(struct devlink_sb_pool_get_req *req, - const char *bus_name) +devlink_port_new_req_set_port_flavour(struct devlink_port_new_req *req, + enum devlink_port_flavour port_flavour) { - free(req->bus_name); - req->_present.bus_name_len = strlen(bus_name); - req->bus_name = malloc(req->_present.bus_name_len + 1); - memcpy(req->bus_name, bus_name, req->_present.bus_name_len); - req->bus_name[req->_present.bus_name_len] = 0; + req->_present.port_flavour = 1; + req->port_flavour = port_flavour; } static inline void -devlink_sb_pool_get_req_set_dev_name(struct devlink_sb_pool_get_req *req, - const char *dev_name) +devlink_port_new_req_set_port_pci_pf_number(struct devlink_port_new_req *req, + __u16 port_pci_pf_number) { - free(req->dev_name); - req->_present.dev_name_len = strlen(dev_name); - req->dev_name = malloc(req->_present.dev_name_len + 1); - memcpy(req->dev_name, dev_name, req->_present.dev_name_len); - req->dev_name[req->_present.dev_name_len] = 0; + req->_present.port_pci_pf_number = 1; + req->port_pci_pf_number = port_pci_pf_number; } static inline void -devlink_sb_pool_get_req_set_sb_index(struct devlink_sb_pool_get_req *req, - __u32 sb_index) +devlink_port_new_req_set_port_pci_sf_number(struct devlink_port_new_req *req, + __u32 port_pci_sf_number) { - req->_present.sb_index = 1; - req->sb_index = sb_index; + req->_present.port_pci_sf_number = 1; + req->port_pci_sf_number = port_pci_sf_number; } static inline void -devlink_sb_pool_get_req_set_sb_pool_index(struct devlink_sb_pool_get_req *req, - __u16 sb_pool_index) +devlink_port_new_req_set_port_controller_number(struct devlink_port_new_req *req, + __u32 port_controller_number) { - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; + req->_present.port_controller_number = 1; + req->port_controller_number = port_controller_number; } -struct devlink_sb_pool_get_rsp { +struct devlink_port_new_rsp { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 sb_index:1; - __u32 sb_pool_index:1; + __u32 port_index:1; } _present; char *bus_name; char *dev_name; - __u32 sb_index; - __u16 sb_pool_index; + __u32 port_index; }; -void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp); +void devlink_port_new_rsp_free(struct devlink_port_new_rsp *rsp); /* - * Get shared buffer pool instances. + * Create devlink port instances. */ -struct devlink_sb_pool_get_rsp * -devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req); +struct devlink_port_new_rsp * +devlink_port_new(struct ynl_sock *ys, struct devlink_port_new_req *req); -/* DEVLINK_CMD_SB_POOL_GET - dump */ -struct devlink_sb_pool_get_req_dump { +/* ============== DEVLINK_CMD_PORT_DEL ============== */ +/* DEVLINK_CMD_PORT_DEL - do */ +struct devlink_port_del_req { struct { __u32 bus_name_len; __u32 dev_name_len; + __u32 port_index:1; } _present; char *bus_name; char *dev_name; + __u32 port_index; }; -static inline struct devlink_sb_pool_get_req_dump * -devlink_sb_pool_get_req_dump_alloc(void) +static inline struct devlink_port_del_req *devlink_port_del_req_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_pool_get_req_dump)); + return calloc(1, sizeof(struct devlink_port_del_req)); } -void -devlink_sb_pool_get_req_dump_free(struct devlink_sb_pool_get_req_dump *req); +void devlink_port_del_req_free(struct devlink_port_del_req *req); static inline void -devlink_sb_pool_get_req_dump_set_bus_name(struct devlink_sb_pool_get_req_dump *req, - const char *bus_name) +devlink_port_del_req_set_bus_name(struct devlink_port_del_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -495,8 +749,8 @@ devlink_sb_pool_get_req_dump_set_bus_name(struct devlink_sb_pool_get_req_dump *r req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_pool_get_req_dump_set_dev_name(struct devlink_sb_pool_get_req_dump *req, - const char *dev_name) +devlink_port_del_req_set_dev_name(struct devlink_port_del_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -504,47 +758,44 @@ devlink_sb_pool_get_req_dump_set_dev_name(struct devlink_sb_pool_get_req_dump *r memcpy(req->dev_name, dev_name, req->_present.dev_name_len); req->dev_name[req->_present.dev_name_len] = 0; } +static inline void +devlink_port_del_req_set_port_index(struct devlink_port_del_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} -struct devlink_sb_pool_get_list { - struct devlink_sb_pool_get_list *next; - struct devlink_sb_pool_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp); - -struct devlink_sb_pool_get_list * -devlink_sb_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_pool_get_req_dump *req); +/* + * Delete devlink port instances. + */ +int devlink_port_del(struct ynl_sock *ys, struct devlink_port_del_req *req); -/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ -/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ -struct devlink_sb_port_pool_get_req { +/* ============== DEVLINK_CMD_PORT_SPLIT ============== */ +/* DEVLINK_CMD_PORT_SPLIT - do */ +struct devlink_port_split_req { struct { __u32 bus_name_len; __u32 dev_name_len; __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; + __u32 port_split_count:1; } _present; char *bus_name; char *dev_name; __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; + __u32 port_split_count; }; -static inline struct devlink_sb_port_pool_get_req * -devlink_sb_port_pool_get_req_alloc(void) +static inline struct devlink_port_split_req *devlink_port_split_req_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req)); + return calloc(1, sizeof(struct devlink_port_split_req)); } -void -devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req); +void devlink_port_split_req_free(struct devlink_port_split_req *req); static inline void -devlink_sb_port_pool_get_req_set_bus_name(struct devlink_sb_port_pool_get_req *req, - const char *bus_name) +devlink_port_split_req_set_bus_name(struct devlink_port_split_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -553,8 +804,8 @@ devlink_sb_port_pool_get_req_set_bus_name(struct devlink_sb_port_pool_get_req *r req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_port_pool_get_req_set_dev_name(struct devlink_sb_port_pool_get_req *req, - const char *dev_name) +devlink_port_split_req_set_dev_name(struct devlink_port_split_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -563,75 +814,49 @@ devlink_sb_port_pool_get_req_set_dev_name(struct devlink_sb_port_pool_get_req *r req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_sb_port_pool_get_req_set_port_index(struct devlink_sb_port_pool_get_req *req, - __u32 port_index) +devlink_port_split_req_set_port_index(struct devlink_port_split_req *req, + __u32 port_index) { req->_present.port_index = 1; req->port_index = port_index; } static inline void -devlink_sb_port_pool_get_req_set_sb_index(struct devlink_sb_port_pool_get_req *req, - __u32 sb_index) -{ - req->_present.sb_index = 1; - req->sb_index = sb_index; -} -static inline void -devlink_sb_port_pool_get_req_set_sb_pool_index(struct devlink_sb_port_pool_get_req *req, - __u16 sb_pool_index) +devlink_port_split_req_set_port_split_count(struct devlink_port_split_req *req, + __u32 port_split_count) { - req->_present.sb_pool_index = 1; - req->sb_pool_index = sb_pool_index; + req->_present.port_split_count = 1; + req->port_split_count = port_split_count; } -struct devlink_sb_port_pool_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 sb_index:1; - __u32 sb_pool_index:1; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - __u32 sb_index; - __u16 sb_pool_index; -}; - -void -devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp); - /* - * Get shared buffer port-pool combinations and threshold. + * Split devlink port instances. */ -struct devlink_sb_port_pool_get_rsp * -devlink_sb_port_pool_get(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req *req); +int devlink_port_split(struct ynl_sock *ys, struct devlink_port_split_req *req); -/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ -struct devlink_sb_port_pool_get_req_dump { +/* ============== DEVLINK_CMD_PORT_UNSPLIT ============== */ +/* DEVLINK_CMD_PORT_UNSPLIT - do */ +struct devlink_port_unsplit_req { struct { __u32 bus_name_len; __u32 dev_name_len; + __u32 port_index:1; } _present; char *bus_name; char *dev_name; + __u32 port_index; }; -static inline struct devlink_sb_port_pool_get_req_dump * -devlink_sb_port_pool_get_req_dump_alloc(void) +static inline struct devlink_port_unsplit_req * +devlink_port_unsplit_req_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_port_pool_get_req_dump)); + return calloc(1, sizeof(struct devlink_port_unsplit_req)); } -void -devlink_sb_port_pool_get_req_dump_free(struct devlink_sb_port_pool_get_req_dump *req); +void devlink_port_unsplit_req_free(struct devlink_port_unsplit_req *req); static inline void -devlink_sb_port_pool_get_req_dump_set_bus_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *bus_name) +devlink_port_unsplit_req_set_bus_name(struct devlink_port_unsplit_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -640,8 +865,8 @@ devlink_sb_port_pool_get_req_dump_set_bus_name(struct devlink_sb_port_pool_get_r req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_port_pool_get_req_dump_set_dev_name(struct devlink_sb_port_pool_get_req_dump *req, - const char *dev_name) +devlink_port_unsplit_req_set_dev_name(struct devlink_port_unsplit_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -649,50 +874,43 @@ devlink_sb_port_pool_get_req_dump_set_dev_name(struct devlink_sb_port_pool_get_r memcpy(req->dev_name, dev_name, req->_present.dev_name_len); req->dev_name[req->_present.dev_name_len] = 0; } +static inline void +devlink_port_unsplit_req_set_port_index(struct devlink_port_unsplit_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} -struct devlink_sb_port_pool_get_list { - struct devlink_sb_port_pool_get_list *next; - struct devlink_sb_port_pool_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp); - -struct devlink_sb_port_pool_get_list * -devlink_sb_port_pool_get_dump(struct ynl_sock *ys, - struct devlink_sb_port_pool_get_req_dump *req); +/* + * Unplit devlink port instances. + */ +int devlink_port_unsplit(struct ynl_sock *ys, + struct devlink_port_unsplit_req *req); -/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ -struct devlink_sb_tc_pool_bind_get_req { +/* ============== DEVLINK_CMD_SB_GET ============== */ +/* DEVLINK_CMD_SB_GET - do */ +struct devlink_sb_get_req { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 port_index:1; __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; } _present; char *bus_name; char *dev_name; - __u32 port_index; __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; }; -static inline struct devlink_sb_tc_pool_bind_get_req * -devlink_sb_tc_pool_bind_get_req_alloc(void) +static inline struct devlink_sb_get_req *devlink_sb_get_req_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req)); + return calloc(1, sizeof(struct devlink_sb_get_req)); } -void -devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req); +void devlink_sb_get_req_free(struct devlink_sb_get_req *req); static inline void -devlink_sb_tc_pool_bind_get_req_set_bus_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *bus_name) +devlink_sb_get_req_set_bus_name(struct devlink_sb_get_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -701,8 +919,8 @@ devlink_sb_tc_pool_bind_get_req_set_bus_name(struct devlink_sb_tc_pool_bind_get_ req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_tc_pool_bind_get_req_set_dev_name(struct devlink_sb_tc_pool_bind_get_req *req, - const char *dev_name) +devlink_sb_get_req_set_dev_name(struct devlink_sb_get_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -711,64 +929,34 @@ devlink_sb_tc_pool_bind_get_req_set_dev_name(struct devlink_sb_tc_pool_bind_get_ req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_sb_tc_pool_bind_get_req_set_port_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 port_index) -{ - req->_present.port_index = 1; - req->port_index = port_index; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u32 sb_index) +devlink_sb_get_req_set_sb_index(struct devlink_sb_get_req *req, __u32 sb_index) { req->_present.sb_index = 1; req->sb_index = sb_index; } -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_get_req *req, - enum devlink_sb_pool_type sb_pool_type) -{ - req->_present.sb_pool_type = 1; - req->sb_pool_type = sb_pool_type; -} -static inline void -devlink_sb_tc_pool_bind_get_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_get_req *req, - __u16 sb_tc_index) -{ - req->_present.sb_tc_index = 1; - req->sb_tc_index = sb_tc_index; -} -struct devlink_sb_tc_pool_bind_get_rsp { +struct devlink_sb_get_rsp { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 port_index:1; __u32 sb_index:1; - __u32 sb_pool_type:1; - __u32 sb_tc_index:1; } _present; char *bus_name; char *dev_name; - __u32 port_index; __u32 sb_index; - enum devlink_sb_pool_type sb_pool_type; - __u16 sb_tc_index; }; -void -devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp); +void devlink_sb_get_rsp_free(struct devlink_sb_get_rsp *rsp); /* - * Get shared buffer port-TC to pool bindings and threshold. + * Get shared buffer instances. */ -struct devlink_sb_tc_pool_bind_get_rsp * -devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req *req); +struct devlink_sb_get_rsp * +devlink_sb_get(struct ynl_sock *ys, struct devlink_sb_get_req *req); -/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ -struct devlink_sb_tc_pool_bind_get_req_dump { +/* DEVLINK_CMD_SB_GET - dump */ +struct devlink_sb_get_req_dump { struct { __u32 bus_name_len; __u32 dev_name_len; @@ -778,17 +966,16 @@ struct devlink_sb_tc_pool_bind_get_req_dump { char *dev_name; }; -static inline struct devlink_sb_tc_pool_bind_get_req_dump * -devlink_sb_tc_pool_bind_get_req_dump_alloc(void) +static inline struct devlink_sb_get_req_dump * +devlink_sb_get_req_dump_alloc(void) { - return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req_dump)); + return calloc(1, sizeof(struct devlink_sb_get_req_dump)); } -void -devlink_sb_tc_pool_bind_get_req_dump_free(struct devlink_sb_tc_pool_bind_get_req_dump *req); +void devlink_sb_get_req_dump_free(struct devlink_sb_get_req_dump *req); static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_bus_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *bus_name) +devlink_sb_get_req_dump_set_bus_name(struct devlink_sb_get_req_dump *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -797,8 +984,8 @@ devlink_sb_tc_pool_bind_get_req_dump_set_bus_name(struct devlink_sb_tc_pool_bind req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_sb_tc_pool_bind_get_req_dump_set_dev_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, - const char *dev_name) +devlink_sb_get_req_dump_set_dev_name(struct devlink_sb_get_req_dump *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -807,41 +994,42 @@ devlink_sb_tc_pool_bind_get_req_dump_set_dev_name(struct devlink_sb_tc_pool_bind req->dev_name[req->_present.dev_name_len] = 0; } -struct devlink_sb_tc_pool_bind_get_list { - struct devlink_sb_tc_pool_bind_get_list *next; - struct devlink_sb_tc_pool_bind_get_rsp obj __attribute__ ((aligned (8))); +struct devlink_sb_get_list { + struct devlink_sb_get_list *next; + struct devlink_sb_get_rsp obj __attribute__ ((aligned (8))); }; -void -devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp); +void devlink_sb_get_list_free(struct devlink_sb_get_list *rsp); -struct devlink_sb_tc_pool_bind_get_list * -devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, - struct devlink_sb_tc_pool_bind_get_req_dump *req); +struct devlink_sb_get_list * +devlink_sb_get_dump(struct ynl_sock *ys, struct devlink_sb_get_req_dump *req); -/* ============== DEVLINK_CMD_PARAM_GET ============== */ -/* DEVLINK_CMD_PARAM_GET - do */ -struct devlink_param_get_req { +/* ============== DEVLINK_CMD_SB_POOL_GET ============== */ +/* DEVLINK_CMD_SB_POOL_GET - do */ +struct devlink_sb_pool_get_req { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 param_name_len; + __u32 sb_index:1; + __u32 sb_pool_index:1; } _present; char *bus_name; char *dev_name; - char *param_name; + __u32 sb_index; + __u16 sb_pool_index; }; -static inline struct devlink_param_get_req *devlink_param_get_req_alloc(void) +static inline struct devlink_sb_pool_get_req * +devlink_sb_pool_get_req_alloc(void) { - return calloc(1, sizeof(struct devlink_param_get_req)); + return calloc(1, sizeof(struct devlink_sb_pool_get_req)); } -void devlink_param_get_req_free(struct devlink_param_get_req *req); +void devlink_sb_pool_get_req_free(struct devlink_sb_pool_get_req *req); static inline void -devlink_param_get_req_set_bus_name(struct devlink_param_get_req *req, - const char *bus_name) +devlink_sb_pool_get_req_set_bus_name(struct devlink_sb_pool_get_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -850,8 +1038,8 @@ devlink_param_get_req_set_bus_name(struct devlink_param_get_req *req, req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_param_get_req_set_dev_name(struct devlink_param_get_req *req, - const char *dev_name) +devlink_sb_pool_get_req_set_dev_name(struct devlink_sb_pool_get_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -860,38 +1048,44 @@ devlink_param_get_req_set_dev_name(struct devlink_param_get_req *req, req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_param_get_req_set_param_name(struct devlink_param_get_req *req, - const char *param_name) +devlink_sb_pool_get_req_set_sb_index(struct devlink_sb_pool_get_req *req, + __u32 sb_index) { - free(req->param_name); - req->_present.param_name_len = strlen(param_name); - req->param_name = malloc(req->_present.param_name_len + 1); - memcpy(req->param_name, param_name, req->_present.param_name_len); - req->param_name[req->_present.param_name_len] = 0; + req->_present.sb_index = 1; + req->sb_index = sb_index; +} +static inline void +devlink_sb_pool_get_req_set_sb_pool_index(struct devlink_sb_pool_get_req *req, + __u16 sb_pool_index) +{ + req->_present.sb_pool_index = 1; + req->sb_pool_index = sb_pool_index; } -struct devlink_param_get_rsp { +struct devlink_sb_pool_get_rsp { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 param_name_len; + __u32 sb_index:1; + __u32 sb_pool_index:1; } _present; char *bus_name; char *dev_name; - char *param_name; + __u32 sb_index; + __u16 sb_pool_index; }; -void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp); +void devlink_sb_pool_get_rsp_free(struct devlink_sb_pool_get_rsp *rsp); /* - * Get param instances. + * Get shared buffer pool instances. */ -struct devlink_param_get_rsp * -devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req); +struct devlink_sb_pool_get_rsp * +devlink_sb_pool_get(struct ynl_sock *ys, struct devlink_sb_pool_get_req *req); -/* DEVLINK_CMD_PARAM_GET - dump */ -struct devlink_param_get_req_dump { +/* DEVLINK_CMD_SB_POOL_GET - dump */ +struct devlink_sb_pool_get_req_dump { struct { __u32 bus_name_len; __u32 dev_name_len; @@ -901,16 +1095,2307 @@ struct devlink_param_get_req_dump { char *dev_name; }; -static inline struct devlink_param_get_req_dump * -devlink_param_get_req_dump_alloc(void) +static inline struct devlink_sb_pool_get_req_dump * +devlink_sb_pool_get_req_dump_alloc(void) { - return calloc(1, sizeof(struct devlink_param_get_req_dump)); + return calloc(1, sizeof(struct devlink_sb_pool_get_req_dump)); } -void devlink_param_get_req_dump_free(struct devlink_param_get_req_dump *req); +void +devlink_sb_pool_get_req_dump_free(struct devlink_sb_pool_get_req_dump *req); + +static inline void +devlink_sb_pool_get_req_dump_set_bus_name(struct devlink_sb_pool_get_req_dump *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_pool_get_req_dump_set_dev_name(struct devlink_sb_pool_get_req_dump *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_sb_pool_get_list { + struct devlink_sb_pool_get_list *next; + struct devlink_sb_pool_get_rsp obj __attribute__ ((aligned (8))); +}; + +void devlink_sb_pool_get_list_free(struct devlink_sb_pool_get_list *rsp); + +struct devlink_sb_pool_get_list * +devlink_sb_pool_get_dump(struct ynl_sock *ys, + struct devlink_sb_pool_get_req_dump *req); + +/* ============== DEVLINK_CMD_SB_POOL_SET ============== */ +/* DEVLINK_CMD_SB_POOL_SET - do */ +struct devlink_sb_pool_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 sb_index:1; + __u32 sb_pool_index:1; + __u32 sb_pool_threshold_type:1; + __u32 sb_pool_size:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 sb_index; + __u16 sb_pool_index; + enum devlink_sb_threshold_type sb_pool_threshold_type; + __u32 sb_pool_size; +}; + +static inline struct devlink_sb_pool_set_req * +devlink_sb_pool_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_pool_set_req)); +} +void devlink_sb_pool_set_req_free(struct devlink_sb_pool_set_req *req); + +static inline void +devlink_sb_pool_set_req_set_bus_name(struct devlink_sb_pool_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_pool_set_req_set_dev_name(struct devlink_sb_pool_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_pool_set_req_set_sb_index(struct devlink_sb_pool_set_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} +static inline void +devlink_sb_pool_set_req_set_sb_pool_index(struct devlink_sb_pool_set_req *req, + __u16 sb_pool_index) +{ + req->_present.sb_pool_index = 1; + req->sb_pool_index = sb_pool_index; +} +static inline void +devlink_sb_pool_set_req_set_sb_pool_threshold_type(struct devlink_sb_pool_set_req *req, + enum devlink_sb_threshold_type sb_pool_threshold_type) +{ + req->_present.sb_pool_threshold_type = 1; + req->sb_pool_threshold_type = sb_pool_threshold_type; +} +static inline void +devlink_sb_pool_set_req_set_sb_pool_size(struct devlink_sb_pool_set_req *req, + __u32 sb_pool_size) +{ + req->_present.sb_pool_size = 1; + req->sb_pool_size = sb_pool_size; +} + +/* + * Set shared buffer pool instances. + */ +int devlink_sb_pool_set(struct ynl_sock *ys, + struct devlink_sb_pool_set_req *req); + +/* ============== DEVLINK_CMD_SB_PORT_POOL_GET ============== */ +/* DEVLINK_CMD_SB_PORT_POOL_GET - do */ +struct devlink_sb_port_pool_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 sb_index:1; + __u32 sb_pool_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + __u32 sb_index; + __u16 sb_pool_index; +}; + +static inline struct devlink_sb_port_pool_get_req * +devlink_sb_port_pool_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_port_pool_get_req)); +} +void +devlink_sb_port_pool_get_req_free(struct devlink_sb_port_pool_get_req *req); + +static inline void +devlink_sb_port_pool_get_req_set_bus_name(struct devlink_sb_port_pool_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_port_pool_get_req_set_dev_name(struct devlink_sb_port_pool_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_port_pool_get_req_set_port_index(struct devlink_sb_port_pool_get_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_sb_port_pool_get_req_set_sb_index(struct devlink_sb_port_pool_get_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} +static inline void +devlink_sb_port_pool_get_req_set_sb_pool_index(struct devlink_sb_port_pool_get_req *req, + __u16 sb_pool_index) +{ + req->_present.sb_pool_index = 1; + req->sb_pool_index = sb_pool_index; +} + +struct devlink_sb_port_pool_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 sb_index:1; + __u32 sb_pool_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + __u32 sb_index; + __u16 sb_pool_index; +}; + +void +devlink_sb_port_pool_get_rsp_free(struct devlink_sb_port_pool_get_rsp *rsp); + +/* + * Get shared buffer port-pool combinations and threshold. + */ +struct devlink_sb_port_pool_get_rsp * +devlink_sb_port_pool_get(struct ynl_sock *ys, + struct devlink_sb_port_pool_get_req *req); + +/* DEVLINK_CMD_SB_PORT_POOL_GET - dump */ +struct devlink_sb_port_pool_get_req_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_sb_port_pool_get_req_dump * +devlink_sb_port_pool_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_port_pool_get_req_dump)); +} +void +devlink_sb_port_pool_get_req_dump_free(struct devlink_sb_port_pool_get_req_dump *req); + +static inline void +devlink_sb_port_pool_get_req_dump_set_bus_name(struct devlink_sb_port_pool_get_req_dump *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_port_pool_get_req_dump_set_dev_name(struct devlink_sb_port_pool_get_req_dump *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_sb_port_pool_get_list { + struct devlink_sb_port_pool_get_list *next; + struct devlink_sb_port_pool_get_rsp obj __attribute__ ((aligned (8))); +}; + +void +devlink_sb_port_pool_get_list_free(struct devlink_sb_port_pool_get_list *rsp); + +struct devlink_sb_port_pool_get_list * +devlink_sb_port_pool_get_dump(struct ynl_sock *ys, + struct devlink_sb_port_pool_get_req_dump *req); + +/* ============== DEVLINK_CMD_SB_PORT_POOL_SET ============== */ +/* DEVLINK_CMD_SB_PORT_POOL_SET - do */ +struct devlink_sb_port_pool_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 sb_index:1; + __u32 sb_pool_index:1; + __u32 sb_threshold:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + __u32 sb_index; + __u16 sb_pool_index; + __u32 sb_threshold; +}; + +static inline struct devlink_sb_port_pool_set_req * +devlink_sb_port_pool_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_port_pool_set_req)); +} +void +devlink_sb_port_pool_set_req_free(struct devlink_sb_port_pool_set_req *req); + +static inline void +devlink_sb_port_pool_set_req_set_bus_name(struct devlink_sb_port_pool_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_port_pool_set_req_set_dev_name(struct devlink_sb_port_pool_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_port_pool_set_req_set_port_index(struct devlink_sb_port_pool_set_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_sb_port_pool_set_req_set_sb_index(struct devlink_sb_port_pool_set_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} +static inline void +devlink_sb_port_pool_set_req_set_sb_pool_index(struct devlink_sb_port_pool_set_req *req, + __u16 sb_pool_index) +{ + req->_present.sb_pool_index = 1; + req->sb_pool_index = sb_pool_index; +} +static inline void +devlink_sb_port_pool_set_req_set_sb_threshold(struct devlink_sb_port_pool_set_req *req, + __u32 sb_threshold) +{ + req->_present.sb_threshold = 1; + req->sb_threshold = sb_threshold; +} + +/* + * Set shared buffer port-pool combinations and threshold. + */ +int devlink_sb_port_pool_set(struct ynl_sock *ys, + struct devlink_sb_port_pool_set_req *req); + +/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_GET ============== */ +/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - do */ +struct devlink_sb_tc_pool_bind_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 sb_index:1; + __u32 sb_pool_type:1; + __u32 sb_tc_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + __u32 sb_index; + enum devlink_sb_pool_type sb_pool_type; + __u16 sb_tc_index; +}; + +static inline struct devlink_sb_tc_pool_bind_get_req * +devlink_sb_tc_pool_bind_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req)); +} +void +devlink_sb_tc_pool_bind_get_req_free(struct devlink_sb_tc_pool_bind_get_req *req); + +static inline void +devlink_sb_tc_pool_bind_get_req_set_bus_name(struct devlink_sb_tc_pool_bind_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_tc_pool_bind_get_req_set_dev_name(struct devlink_sb_tc_pool_bind_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_tc_pool_bind_get_req_set_port_index(struct devlink_sb_tc_pool_bind_get_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_sb_tc_pool_bind_get_req_set_sb_index(struct devlink_sb_tc_pool_bind_get_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} +static inline void +devlink_sb_tc_pool_bind_get_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_get_req *req, + enum devlink_sb_pool_type sb_pool_type) +{ + req->_present.sb_pool_type = 1; + req->sb_pool_type = sb_pool_type; +} +static inline void +devlink_sb_tc_pool_bind_get_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_get_req *req, + __u16 sb_tc_index) +{ + req->_present.sb_tc_index = 1; + req->sb_tc_index = sb_tc_index; +} + +struct devlink_sb_tc_pool_bind_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 sb_index:1; + __u32 sb_pool_type:1; + __u32 sb_tc_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + __u32 sb_index; + enum devlink_sb_pool_type sb_pool_type; + __u16 sb_tc_index; +}; + +void +devlink_sb_tc_pool_bind_get_rsp_free(struct devlink_sb_tc_pool_bind_get_rsp *rsp); + +/* + * Get shared buffer port-TC to pool bindings and threshold. + */ +struct devlink_sb_tc_pool_bind_get_rsp * +devlink_sb_tc_pool_bind_get(struct ynl_sock *ys, + struct devlink_sb_tc_pool_bind_get_req *req); + +/* DEVLINK_CMD_SB_TC_POOL_BIND_GET - dump */ +struct devlink_sb_tc_pool_bind_get_req_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_sb_tc_pool_bind_get_req_dump * +devlink_sb_tc_pool_bind_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_get_req_dump)); +} +void +devlink_sb_tc_pool_bind_get_req_dump_free(struct devlink_sb_tc_pool_bind_get_req_dump *req); + +static inline void +devlink_sb_tc_pool_bind_get_req_dump_set_bus_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_tc_pool_bind_get_req_dump_set_dev_name(struct devlink_sb_tc_pool_bind_get_req_dump *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_sb_tc_pool_bind_get_list { + struct devlink_sb_tc_pool_bind_get_list *next; + struct devlink_sb_tc_pool_bind_get_rsp obj __attribute__ ((aligned (8))); +}; + +void +devlink_sb_tc_pool_bind_get_list_free(struct devlink_sb_tc_pool_bind_get_list *rsp); + +struct devlink_sb_tc_pool_bind_get_list * +devlink_sb_tc_pool_bind_get_dump(struct ynl_sock *ys, + struct devlink_sb_tc_pool_bind_get_req_dump *req); + +/* ============== DEVLINK_CMD_SB_TC_POOL_BIND_SET ============== */ +/* DEVLINK_CMD_SB_TC_POOL_BIND_SET - do */ +struct devlink_sb_tc_pool_bind_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 sb_index:1; + __u32 sb_pool_index:1; + __u32 sb_pool_type:1; + __u32 sb_tc_index:1; + __u32 sb_threshold:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + __u32 sb_index; + __u16 sb_pool_index; + enum devlink_sb_pool_type sb_pool_type; + __u16 sb_tc_index; + __u32 sb_threshold; +}; + +static inline struct devlink_sb_tc_pool_bind_set_req * +devlink_sb_tc_pool_bind_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_tc_pool_bind_set_req)); +} +void +devlink_sb_tc_pool_bind_set_req_free(struct devlink_sb_tc_pool_bind_set_req *req); + +static inline void +devlink_sb_tc_pool_bind_set_req_set_bus_name(struct devlink_sb_tc_pool_bind_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_dev_name(struct devlink_sb_tc_pool_bind_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_port_index(struct devlink_sb_tc_pool_bind_set_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_sb_index(struct devlink_sb_tc_pool_bind_set_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_sb_pool_index(struct devlink_sb_tc_pool_bind_set_req *req, + __u16 sb_pool_index) +{ + req->_present.sb_pool_index = 1; + req->sb_pool_index = sb_pool_index; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_sb_pool_type(struct devlink_sb_tc_pool_bind_set_req *req, + enum devlink_sb_pool_type sb_pool_type) +{ + req->_present.sb_pool_type = 1; + req->sb_pool_type = sb_pool_type; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_sb_tc_index(struct devlink_sb_tc_pool_bind_set_req *req, + __u16 sb_tc_index) +{ + req->_present.sb_tc_index = 1; + req->sb_tc_index = sb_tc_index; +} +static inline void +devlink_sb_tc_pool_bind_set_req_set_sb_threshold(struct devlink_sb_tc_pool_bind_set_req *req, + __u32 sb_threshold) +{ + req->_present.sb_threshold = 1; + req->sb_threshold = sb_threshold; +} + +/* + * Set shared buffer port-TC to pool bindings and threshold. + */ +int devlink_sb_tc_pool_bind_set(struct ynl_sock *ys, + struct devlink_sb_tc_pool_bind_set_req *req); + +/* ============== DEVLINK_CMD_SB_OCC_SNAPSHOT ============== */ +/* DEVLINK_CMD_SB_OCC_SNAPSHOT - do */ +struct devlink_sb_occ_snapshot_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 sb_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 sb_index; +}; + +static inline struct devlink_sb_occ_snapshot_req * +devlink_sb_occ_snapshot_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_occ_snapshot_req)); +} +void devlink_sb_occ_snapshot_req_free(struct devlink_sb_occ_snapshot_req *req); + +static inline void +devlink_sb_occ_snapshot_req_set_bus_name(struct devlink_sb_occ_snapshot_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_occ_snapshot_req_set_dev_name(struct devlink_sb_occ_snapshot_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_occ_snapshot_req_set_sb_index(struct devlink_sb_occ_snapshot_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} + +/* + * Take occupancy snapshot of shared buffer. + */ +int devlink_sb_occ_snapshot(struct ynl_sock *ys, + struct devlink_sb_occ_snapshot_req *req); + +/* ============== DEVLINK_CMD_SB_OCC_MAX_CLEAR ============== */ +/* DEVLINK_CMD_SB_OCC_MAX_CLEAR - do */ +struct devlink_sb_occ_max_clear_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 sb_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 sb_index; +}; + +static inline struct devlink_sb_occ_max_clear_req * +devlink_sb_occ_max_clear_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_sb_occ_max_clear_req)); +} +void +devlink_sb_occ_max_clear_req_free(struct devlink_sb_occ_max_clear_req *req); + +static inline void +devlink_sb_occ_max_clear_req_set_bus_name(struct devlink_sb_occ_max_clear_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_sb_occ_max_clear_req_set_dev_name(struct devlink_sb_occ_max_clear_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_sb_occ_max_clear_req_set_sb_index(struct devlink_sb_occ_max_clear_req *req, + __u32 sb_index) +{ + req->_present.sb_index = 1; + req->sb_index = sb_index; +} + +/* + * Clear occupancy watermarks of shared buffer. + */ +int devlink_sb_occ_max_clear(struct ynl_sock *ys, + struct devlink_sb_occ_max_clear_req *req); + +/* ============== DEVLINK_CMD_ESWITCH_GET ============== */ +/* DEVLINK_CMD_ESWITCH_GET - do */ +struct devlink_eswitch_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_eswitch_get_req * +devlink_eswitch_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_eswitch_get_req)); +} +void devlink_eswitch_get_req_free(struct devlink_eswitch_get_req *req); + +static inline void +devlink_eswitch_get_req_set_bus_name(struct devlink_eswitch_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_eswitch_get_req_set_dev_name(struct devlink_eswitch_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_eswitch_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 eswitch_mode:1; + __u32 eswitch_inline_mode:1; + __u32 eswitch_encap_mode:1; + } _present; + + char *bus_name; + char *dev_name; + enum devlink_eswitch_mode eswitch_mode; + enum devlink_eswitch_inline_mode eswitch_inline_mode; + enum devlink_eswitch_encap_mode eswitch_encap_mode; +}; + +void devlink_eswitch_get_rsp_free(struct devlink_eswitch_get_rsp *rsp); + +/* + * Get eswitch attributes. + */ +struct devlink_eswitch_get_rsp * +devlink_eswitch_get(struct ynl_sock *ys, struct devlink_eswitch_get_req *req); + +/* ============== DEVLINK_CMD_ESWITCH_SET ============== */ +/* DEVLINK_CMD_ESWITCH_SET - do */ +struct devlink_eswitch_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 eswitch_mode:1; + __u32 eswitch_inline_mode:1; + __u32 eswitch_encap_mode:1; + } _present; + + char *bus_name; + char *dev_name; + enum devlink_eswitch_mode eswitch_mode; + enum devlink_eswitch_inline_mode eswitch_inline_mode; + enum devlink_eswitch_encap_mode eswitch_encap_mode; +}; + +static inline struct devlink_eswitch_set_req * +devlink_eswitch_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_eswitch_set_req)); +} +void devlink_eswitch_set_req_free(struct devlink_eswitch_set_req *req); + +static inline void +devlink_eswitch_set_req_set_bus_name(struct devlink_eswitch_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_eswitch_set_req_set_dev_name(struct devlink_eswitch_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_eswitch_set_req_set_eswitch_mode(struct devlink_eswitch_set_req *req, + enum devlink_eswitch_mode eswitch_mode) +{ + req->_present.eswitch_mode = 1; + req->eswitch_mode = eswitch_mode; +} +static inline void +devlink_eswitch_set_req_set_eswitch_inline_mode(struct devlink_eswitch_set_req *req, + enum devlink_eswitch_inline_mode eswitch_inline_mode) +{ + req->_present.eswitch_inline_mode = 1; + req->eswitch_inline_mode = eswitch_inline_mode; +} +static inline void +devlink_eswitch_set_req_set_eswitch_encap_mode(struct devlink_eswitch_set_req *req, + enum devlink_eswitch_encap_mode eswitch_encap_mode) +{ + req->_present.eswitch_encap_mode = 1; + req->eswitch_encap_mode = eswitch_encap_mode; +} + +/* + * Set eswitch attributes. + */ +int devlink_eswitch_set(struct ynl_sock *ys, + struct devlink_eswitch_set_req *req); + +/* ============== DEVLINK_CMD_DPIPE_TABLE_GET ============== */ +/* DEVLINK_CMD_DPIPE_TABLE_GET - do */ +struct devlink_dpipe_table_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 dpipe_table_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *dpipe_table_name; +}; + +static inline struct devlink_dpipe_table_get_req * +devlink_dpipe_table_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_dpipe_table_get_req)); +} +void devlink_dpipe_table_get_req_free(struct devlink_dpipe_table_get_req *req); + +static inline void +devlink_dpipe_table_get_req_set_bus_name(struct devlink_dpipe_table_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_dpipe_table_get_req_set_dev_name(struct devlink_dpipe_table_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_dpipe_table_get_req_set_dpipe_table_name(struct devlink_dpipe_table_get_req *req, + const char *dpipe_table_name) +{ + free(req->dpipe_table_name); + req->_present.dpipe_table_name_len = strlen(dpipe_table_name); + req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); + memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); + req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; +} + +struct devlink_dpipe_table_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 dpipe_tables:1; + } _present; + + char *bus_name; + char *dev_name; + struct devlink_dl_dpipe_tables dpipe_tables; +}; + +void devlink_dpipe_table_get_rsp_free(struct devlink_dpipe_table_get_rsp *rsp); + +/* + * Get dpipe table attributes. + */ +struct devlink_dpipe_table_get_rsp * +devlink_dpipe_table_get(struct ynl_sock *ys, + struct devlink_dpipe_table_get_req *req); + +/* ============== DEVLINK_CMD_DPIPE_ENTRIES_GET ============== */ +/* DEVLINK_CMD_DPIPE_ENTRIES_GET - do */ +struct devlink_dpipe_entries_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 dpipe_table_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *dpipe_table_name; +}; + +static inline struct devlink_dpipe_entries_get_req * +devlink_dpipe_entries_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_dpipe_entries_get_req)); +} +void +devlink_dpipe_entries_get_req_free(struct devlink_dpipe_entries_get_req *req); + +static inline void +devlink_dpipe_entries_get_req_set_bus_name(struct devlink_dpipe_entries_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_dpipe_entries_get_req_set_dev_name(struct devlink_dpipe_entries_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_dpipe_entries_get_req_set_dpipe_table_name(struct devlink_dpipe_entries_get_req *req, + const char *dpipe_table_name) +{ + free(req->dpipe_table_name); + req->_present.dpipe_table_name_len = strlen(dpipe_table_name); + req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); + memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); + req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; +} + +struct devlink_dpipe_entries_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 dpipe_entries:1; + } _present; + + char *bus_name; + char *dev_name; + struct devlink_dl_dpipe_entries dpipe_entries; +}; + +void +devlink_dpipe_entries_get_rsp_free(struct devlink_dpipe_entries_get_rsp *rsp); + +/* + * Get dpipe entries attributes. + */ +struct devlink_dpipe_entries_get_rsp * +devlink_dpipe_entries_get(struct ynl_sock *ys, + struct devlink_dpipe_entries_get_req *req); + +/* ============== DEVLINK_CMD_DPIPE_HEADERS_GET ============== */ +/* DEVLINK_CMD_DPIPE_HEADERS_GET - do */ +struct devlink_dpipe_headers_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_dpipe_headers_get_req * +devlink_dpipe_headers_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_dpipe_headers_get_req)); +} +void +devlink_dpipe_headers_get_req_free(struct devlink_dpipe_headers_get_req *req); + +static inline void +devlink_dpipe_headers_get_req_set_bus_name(struct devlink_dpipe_headers_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_dpipe_headers_get_req_set_dev_name(struct devlink_dpipe_headers_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_dpipe_headers_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 dpipe_headers:1; + } _present; + + char *bus_name; + char *dev_name; + struct devlink_dl_dpipe_headers dpipe_headers; +}; + +void +devlink_dpipe_headers_get_rsp_free(struct devlink_dpipe_headers_get_rsp *rsp); + +/* + * Get dpipe headers attributes. + */ +struct devlink_dpipe_headers_get_rsp * +devlink_dpipe_headers_get(struct ynl_sock *ys, + struct devlink_dpipe_headers_get_req *req); + +/* ============== DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET ============== */ +/* DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET - do */ +struct devlink_dpipe_table_counters_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 dpipe_table_name_len; + __u32 dpipe_table_counters_enabled:1; + } _present; + + char *bus_name; + char *dev_name; + char *dpipe_table_name; + __u8 dpipe_table_counters_enabled; +}; + +static inline struct devlink_dpipe_table_counters_set_req * +devlink_dpipe_table_counters_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_dpipe_table_counters_set_req)); +} +void +devlink_dpipe_table_counters_set_req_free(struct devlink_dpipe_table_counters_set_req *req); + +static inline void +devlink_dpipe_table_counters_set_req_set_bus_name(struct devlink_dpipe_table_counters_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_dpipe_table_counters_set_req_set_dev_name(struct devlink_dpipe_table_counters_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_dpipe_table_counters_set_req_set_dpipe_table_name(struct devlink_dpipe_table_counters_set_req *req, + const char *dpipe_table_name) +{ + free(req->dpipe_table_name); + req->_present.dpipe_table_name_len = strlen(dpipe_table_name); + req->dpipe_table_name = malloc(req->_present.dpipe_table_name_len + 1); + memcpy(req->dpipe_table_name, dpipe_table_name, req->_present.dpipe_table_name_len); + req->dpipe_table_name[req->_present.dpipe_table_name_len] = 0; +} +static inline void +devlink_dpipe_table_counters_set_req_set_dpipe_table_counters_enabled(struct devlink_dpipe_table_counters_set_req *req, + __u8 dpipe_table_counters_enabled) +{ + req->_present.dpipe_table_counters_enabled = 1; + req->dpipe_table_counters_enabled = dpipe_table_counters_enabled; +} + +/* + * Set dpipe counter attributes. + */ +int devlink_dpipe_table_counters_set(struct ynl_sock *ys, + struct devlink_dpipe_table_counters_set_req *req); + +/* ============== DEVLINK_CMD_RESOURCE_SET ============== */ +/* DEVLINK_CMD_RESOURCE_SET - do */ +struct devlink_resource_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 resource_id:1; + __u32 resource_size:1; + } _present; + + char *bus_name; + char *dev_name; + __u64 resource_id; + __u64 resource_size; +}; + +static inline struct devlink_resource_set_req * +devlink_resource_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_resource_set_req)); +} +void devlink_resource_set_req_free(struct devlink_resource_set_req *req); + +static inline void +devlink_resource_set_req_set_bus_name(struct devlink_resource_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_resource_set_req_set_dev_name(struct devlink_resource_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_resource_set_req_set_resource_id(struct devlink_resource_set_req *req, + __u64 resource_id) +{ + req->_present.resource_id = 1; + req->resource_id = resource_id; +} +static inline void +devlink_resource_set_req_set_resource_size(struct devlink_resource_set_req *req, + __u64 resource_size) +{ + req->_present.resource_size = 1; + req->resource_size = resource_size; +} + +/* + * Set resource attributes. + */ +int devlink_resource_set(struct ynl_sock *ys, + struct devlink_resource_set_req *req); + +/* ============== DEVLINK_CMD_RESOURCE_DUMP ============== */ +/* DEVLINK_CMD_RESOURCE_DUMP - do */ +struct devlink_resource_dump_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_resource_dump_req * +devlink_resource_dump_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_resource_dump_req)); +} +void devlink_resource_dump_req_free(struct devlink_resource_dump_req *req); + +static inline void +devlink_resource_dump_req_set_bus_name(struct devlink_resource_dump_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_resource_dump_req_set_dev_name(struct devlink_resource_dump_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_resource_dump_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 resource_list:1; + } _present; + + char *bus_name; + char *dev_name; + struct devlink_dl_resource_list resource_list; +}; + +void devlink_resource_dump_rsp_free(struct devlink_resource_dump_rsp *rsp); + +/* + * Get resource attributes. + */ +struct devlink_resource_dump_rsp * +devlink_resource_dump(struct ynl_sock *ys, + struct devlink_resource_dump_req *req); + +/* ============== DEVLINK_CMD_RELOAD ============== */ +/* DEVLINK_CMD_RELOAD - do */ +struct devlink_reload_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 reload_action:1; + __u32 reload_limits:1; + __u32 netns_pid:1; + __u32 netns_fd:1; + __u32 netns_id:1; + } _present; + + char *bus_name; + char *dev_name; + enum devlink_reload_action reload_action; + struct nla_bitfield32 reload_limits; + __u32 netns_pid; + __u32 netns_fd; + __u32 netns_id; +}; + +static inline struct devlink_reload_req *devlink_reload_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_reload_req)); +} +void devlink_reload_req_free(struct devlink_reload_req *req); + +static inline void +devlink_reload_req_set_bus_name(struct devlink_reload_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_reload_req_set_dev_name(struct devlink_reload_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_reload_req_set_reload_action(struct devlink_reload_req *req, + enum devlink_reload_action reload_action) +{ + req->_present.reload_action = 1; + req->reload_action = reload_action; +} +static inline void +devlink_reload_req_set_reload_limits(struct devlink_reload_req *req, + struct nla_bitfield32 *reload_limits) +{ + req->_present.reload_limits = 1; + memcpy(&req->reload_limits, reload_limits, sizeof(struct nla_bitfield32)); +} +static inline void +devlink_reload_req_set_netns_pid(struct devlink_reload_req *req, + __u32 netns_pid) +{ + req->_present.netns_pid = 1; + req->netns_pid = netns_pid; +} +static inline void +devlink_reload_req_set_netns_fd(struct devlink_reload_req *req, __u32 netns_fd) +{ + req->_present.netns_fd = 1; + req->netns_fd = netns_fd; +} +static inline void +devlink_reload_req_set_netns_id(struct devlink_reload_req *req, __u32 netns_id) +{ + req->_present.netns_id = 1; + req->netns_id = netns_id; +} + +struct devlink_reload_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 reload_actions_performed:1; + } _present; + + char *bus_name; + char *dev_name; + struct nla_bitfield32 reload_actions_performed; +}; + +void devlink_reload_rsp_free(struct devlink_reload_rsp *rsp); + +/* + * Reload devlink. + */ +struct devlink_reload_rsp * +devlink_reload(struct ynl_sock *ys, struct devlink_reload_req *req); + +/* ============== DEVLINK_CMD_PARAM_GET ============== */ +/* DEVLINK_CMD_PARAM_GET - do */ +struct devlink_param_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 param_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *param_name; +}; + +static inline struct devlink_param_get_req *devlink_param_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_param_get_req)); +} +void devlink_param_get_req_free(struct devlink_param_get_req *req); + +static inline void +devlink_param_get_req_set_bus_name(struct devlink_param_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_param_get_req_set_dev_name(struct devlink_param_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_param_get_req_set_param_name(struct devlink_param_get_req *req, + const char *param_name) +{ + free(req->param_name); + req->_present.param_name_len = strlen(param_name); + req->param_name = malloc(req->_present.param_name_len + 1); + memcpy(req->param_name, param_name, req->_present.param_name_len); + req->param_name[req->_present.param_name_len] = 0; +} + +struct devlink_param_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 param_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *param_name; +}; + +void devlink_param_get_rsp_free(struct devlink_param_get_rsp *rsp); + +/* + * Get param instances. + */ +struct devlink_param_get_rsp * +devlink_param_get(struct ynl_sock *ys, struct devlink_param_get_req *req); + +/* DEVLINK_CMD_PARAM_GET - dump */ +struct devlink_param_get_req_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_param_get_req_dump * +devlink_param_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct devlink_param_get_req_dump)); +} +void devlink_param_get_req_dump_free(struct devlink_param_get_req_dump *req); + +static inline void +devlink_param_get_req_dump_set_bus_name(struct devlink_param_get_req_dump *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_param_get_req_dump_set_dev_name(struct devlink_param_get_req_dump *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_param_get_list { + struct devlink_param_get_list *next; + struct devlink_param_get_rsp obj __attribute__ ((aligned (8))); +}; + +void devlink_param_get_list_free(struct devlink_param_get_list *rsp); + +struct devlink_param_get_list * +devlink_param_get_dump(struct ynl_sock *ys, + struct devlink_param_get_req_dump *req); + +/* ============== DEVLINK_CMD_PARAM_SET ============== */ +/* DEVLINK_CMD_PARAM_SET - do */ +struct devlink_param_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 param_name_len; + __u32 param_type:1; + __u32 param_value_cmode:1; + } _present; + + char *bus_name; + char *dev_name; + char *param_name; + __u8 param_type; + enum devlink_param_cmode param_value_cmode; +}; + +static inline struct devlink_param_set_req *devlink_param_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_param_set_req)); +} +void devlink_param_set_req_free(struct devlink_param_set_req *req); + +static inline void +devlink_param_set_req_set_bus_name(struct devlink_param_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_param_set_req_set_dev_name(struct devlink_param_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_param_set_req_set_param_name(struct devlink_param_set_req *req, + const char *param_name) +{ + free(req->param_name); + req->_present.param_name_len = strlen(param_name); + req->param_name = malloc(req->_present.param_name_len + 1); + memcpy(req->param_name, param_name, req->_present.param_name_len); + req->param_name[req->_present.param_name_len] = 0; +} +static inline void +devlink_param_set_req_set_param_type(struct devlink_param_set_req *req, + __u8 param_type) +{ + req->_present.param_type = 1; + req->param_type = param_type; +} +static inline void +devlink_param_set_req_set_param_value_cmode(struct devlink_param_set_req *req, + enum devlink_param_cmode param_value_cmode) +{ + req->_present.param_value_cmode = 1; + req->param_value_cmode = param_value_cmode; +} + +/* + * Set param instances. + */ +int devlink_param_set(struct ynl_sock *ys, struct devlink_param_set_req *req); + +/* ============== DEVLINK_CMD_REGION_GET ============== */ +/* DEVLINK_CMD_REGION_GET - do */ +struct devlink_region_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; +}; + +static inline struct devlink_region_get_req *devlink_region_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_region_get_req)); +} +void devlink_region_get_req_free(struct devlink_region_get_req *req); + +static inline void +devlink_region_get_req_set_bus_name(struct devlink_region_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_region_get_req_set_dev_name(struct devlink_region_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_region_get_req_set_port_index(struct devlink_region_get_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_region_get_req_set_region_name(struct devlink_region_get_req *req, + const char *region_name) +{ + free(req->region_name); + req->_present.region_name_len = strlen(region_name); + req->region_name = malloc(req->_present.region_name_len + 1); + memcpy(req->region_name, region_name, req->_present.region_name_len); + req->region_name[req->_present.region_name_len] = 0; +} + +struct devlink_region_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; +}; + +void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp); + +/* + * Get region instances. + */ +struct devlink_region_get_rsp * +devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req); + +/* DEVLINK_CMD_REGION_GET - dump */ +struct devlink_region_get_req_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_region_get_req_dump * +devlink_region_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct devlink_region_get_req_dump)); +} +void devlink_region_get_req_dump_free(struct devlink_region_get_req_dump *req); + +static inline void +devlink_region_get_req_dump_set_bus_name(struct devlink_region_get_req_dump *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_region_get_req_dump_set_dev_name(struct devlink_region_get_req_dump *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_region_get_list { + struct devlink_region_get_list *next; + struct devlink_region_get_rsp obj __attribute__ ((aligned (8))); +}; + +void devlink_region_get_list_free(struct devlink_region_get_list *rsp); + +struct devlink_region_get_list * +devlink_region_get_dump(struct ynl_sock *ys, + struct devlink_region_get_req_dump *req); + +/* ============== DEVLINK_CMD_REGION_NEW ============== */ +/* DEVLINK_CMD_REGION_NEW - do */ +struct devlink_region_new_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + __u32 region_snapshot_id:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; + __u32 region_snapshot_id; +}; + +static inline struct devlink_region_new_req *devlink_region_new_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_region_new_req)); +} +void devlink_region_new_req_free(struct devlink_region_new_req *req); + +static inline void +devlink_region_new_req_set_bus_name(struct devlink_region_new_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_region_new_req_set_dev_name(struct devlink_region_new_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_region_new_req_set_port_index(struct devlink_region_new_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_region_new_req_set_region_name(struct devlink_region_new_req *req, + const char *region_name) +{ + free(req->region_name); + req->_present.region_name_len = strlen(region_name); + req->region_name = malloc(req->_present.region_name_len + 1); + memcpy(req->region_name, region_name, req->_present.region_name_len); + req->region_name[req->_present.region_name_len] = 0; +} +static inline void +devlink_region_new_req_set_region_snapshot_id(struct devlink_region_new_req *req, + __u32 region_snapshot_id) +{ + req->_present.region_snapshot_id = 1; + req->region_snapshot_id = region_snapshot_id; +} + +struct devlink_region_new_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + __u32 region_snapshot_id:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; + __u32 region_snapshot_id; +}; + +void devlink_region_new_rsp_free(struct devlink_region_new_rsp *rsp); + +/* + * Create region snapshot. + */ +struct devlink_region_new_rsp * +devlink_region_new(struct ynl_sock *ys, struct devlink_region_new_req *req); + +/* ============== DEVLINK_CMD_REGION_DEL ============== */ +/* DEVLINK_CMD_REGION_DEL - do */ +struct devlink_region_del_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + __u32 region_snapshot_id:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; + __u32 region_snapshot_id; +}; + +static inline struct devlink_region_del_req *devlink_region_del_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_region_del_req)); +} +void devlink_region_del_req_free(struct devlink_region_del_req *req); + +static inline void +devlink_region_del_req_set_bus_name(struct devlink_region_del_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_region_del_req_set_dev_name(struct devlink_region_del_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_region_del_req_set_port_index(struct devlink_region_del_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_region_del_req_set_region_name(struct devlink_region_del_req *req, + const char *region_name) +{ + free(req->region_name); + req->_present.region_name_len = strlen(region_name); + req->region_name = malloc(req->_present.region_name_len + 1); + memcpy(req->region_name, region_name, req->_present.region_name_len); + req->region_name[req->_present.region_name_len] = 0; +} +static inline void +devlink_region_del_req_set_region_snapshot_id(struct devlink_region_del_req *req, + __u32 region_snapshot_id) +{ + req->_present.region_snapshot_id = 1; + req->region_snapshot_id = region_snapshot_id; +} + +/* + * Delete region snapshot. + */ +int devlink_region_del(struct ynl_sock *ys, struct devlink_region_del_req *req); + +/* ============== DEVLINK_CMD_REGION_READ ============== */ +/* DEVLINK_CMD_REGION_READ - dump */ +struct devlink_region_read_req_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + __u32 region_snapshot_id:1; + __u32 region_direct:1; + __u32 region_chunk_addr:1; + __u32 region_chunk_len:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; + __u32 region_snapshot_id; + __u64 region_chunk_addr; + __u64 region_chunk_len; +}; + +static inline struct devlink_region_read_req_dump * +devlink_region_read_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct devlink_region_read_req_dump)); +} +void +devlink_region_read_req_dump_free(struct devlink_region_read_req_dump *req); + +static inline void +devlink_region_read_req_dump_set_bus_name(struct devlink_region_read_req_dump *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_region_read_req_dump_set_dev_name(struct devlink_region_read_req_dump *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_region_read_req_dump_set_port_index(struct devlink_region_read_req_dump *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_region_read_req_dump_set_region_name(struct devlink_region_read_req_dump *req, + const char *region_name) +{ + free(req->region_name); + req->_present.region_name_len = strlen(region_name); + req->region_name = malloc(req->_present.region_name_len + 1); + memcpy(req->region_name, region_name, req->_present.region_name_len); + req->region_name[req->_present.region_name_len] = 0; +} +static inline void +devlink_region_read_req_dump_set_region_snapshot_id(struct devlink_region_read_req_dump *req, + __u32 region_snapshot_id) +{ + req->_present.region_snapshot_id = 1; + req->region_snapshot_id = region_snapshot_id; +} +static inline void +devlink_region_read_req_dump_set_region_direct(struct devlink_region_read_req_dump *req) +{ + req->_present.region_direct = 1; +} +static inline void +devlink_region_read_req_dump_set_region_chunk_addr(struct devlink_region_read_req_dump *req, + __u64 region_chunk_addr) +{ + req->_present.region_chunk_addr = 1; + req->region_chunk_addr = region_chunk_addr; +} +static inline void +devlink_region_read_req_dump_set_region_chunk_len(struct devlink_region_read_req_dump *req, + __u64 region_chunk_len) +{ + req->_present.region_chunk_len = 1; + req->region_chunk_len = region_chunk_len; +} + +struct devlink_region_read_rsp_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 region_name_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *region_name; +}; + +struct devlink_region_read_rsp_list { + struct devlink_region_read_rsp_list *next; + struct devlink_region_read_rsp_dump obj __attribute__((aligned(8))); +}; + +void +devlink_region_read_rsp_list_free(struct devlink_region_read_rsp_list *rsp); + +struct devlink_region_read_rsp_list * +devlink_region_read_dump(struct ynl_sock *ys, + struct devlink_region_read_req_dump *req); + +/* ============== DEVLINK_CMD_PORT_PARAM_GET ============== */ +/* DEVLINK_CMD_PORT_PARAM_GET - do */ +struct devlink_port_param_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; +}; + +static inline struct devlink_port_param_get_req * +devlink_port_param_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_port_param_get_req)); +} +void devlink_port_param_get_req_free(struct devlink_port_param_get_req *req); + +static inline void +devlink_port_param_get_req_set_bus_name(struct devlink_port_param_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_port_param_get_req_set_dev_name(struct devlink_port_param_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_port_param_get_req_set_port_index(struct devlink_port_param_get_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} + +struct devlink_port_param_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; +}; + +void devlink_port_param_get_rsp_free(struct devlink_port_param_get_rsp *rsp); + +/* + * Get port param instances. + */ +struct devlink_port_param_get_rsp * +devlink_port_param_get(struct ynl_sock *ys, + struct devlink_port_param_get_req *req); + +/* DEVLINK_CMD_PORT_PARAM_GET - dump */ +struct devlink_port_param_get_list { + struct devlink_port_param_get_list *next; + struct devlink_port_param_get_rsp obj __attribute__((aligned(8))); +}; + +void devlink_port_param_get_list_free(struct devlink_port_param_get_list *rsp); + +struct devlink_port_param_get_list * +devlink_port_param_get_dump(struct ynl_sock *ys); + +/* ============== DEVLINK_CMD_PORT_PARAM_SET ============== */ +/* DEVLINK_CMD_PORT_PARAM_SET - do */ +struct devlink_port_param_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; +}; + +static inline struct devlink_port_param_set_req * +devlink_port_param_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_port_param_set_req)); +} +void devlink_port_param_set_req_free(struct devlink_port_param_set_req *req); + +static inline void +devlink_port_param_set_req_set_bus_name(struct devlink_port_param_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_port_param_set_req_set_dev_name(struct devlink_port_param_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_port_param_set_req_set_port_index(struct devlink_port_param_set_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} + +/* + * Set port param instances. + */ +int devlink_port_param_set(struct ynl_sock *ys, + struct devlink_port_param_set_req *req); + +/* ============== DEVLINK_CMD_INFO_GET ============== */ +/* DEVLINK_CMD_INFO_GET - do */ +struct devlink_info_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_info_get_req)); +} +void devlink_info_get_req_free(struct devlink_info_get_req *req); + +static inline void +devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_info_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 info_driver_name_len; + __u32 info_serial_number_len; + } _present; + + char *bus_name; + char *dev_name; + char *info_driver_name; + char *info_serial_number; + unsigned int n_info_version_fixed; + struct devlink_dl_info_version *info_version_fixed; + unsigned int n_info_version_running; + struct devlink_dl_info_version *info_version_running; + unsigned int n_info_version_stored; + struct devlink_dl_info_version *info_version_stored; +}; + +void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp); + +/* + * Get device information, like driver name, hardware and firmware versions etc. + */ +struct devlink_info_get_rsp * +devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req); + +/* DEVLINK_CMD_INFO_GET - dump */ +struct devlink_info_get_list { + struct devlink_info_get_list *next; + struct devlink_info_get_rsp obj __attribute__ ((aligned (8))); +}; + +void devlink_info_get_list_free(struct devlink_info_get_list *rsp); + +struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys); + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ +struct devlink_health_reporter_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 health_reporter_name_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *health_reporter_name; +}; + +static inline struct devlink_health_reporter_get_req * +devlink_health_reporter_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_health_reporter_get_req)); +} +void +devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req); + +static inline void +devlink_health_reporter_get_req_set_bus_name(struct devlink_health_reporter_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_health_reporter_get_req_set_dev_name(struct devlink_health_reporter_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_health_reporter_get_req_set_port_index(struct devlink_health_reporter_get_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_health_reporter_get_req_set_health_reporter_name(struct devlink_health_reporter_get_req *req, + const char *health_reporter_name) +{ + free(req->health_reporter_name); + req->_present.health_reporter_name_len = strlen(health_reporter_name); + req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); + memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); + req->health_reporter_name[req->_present.health_reporter_name_len] = 0; +} + +struct devlink_health_reporter_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 health_reporter_name_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *health_reporter_name; +}; + +void +devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp); + +/* + * Get health reporter instances. + */ +struct devlink_health_reporter_get_rsp * +devlink_health_reporter_get(struct ynl_sock *ys, + struct devlink_health_reporter_get_req *req); + +/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ +struct devlink_health_reporter_get_req_dump { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; +}; + +static inline struct devlink_health_reporter_get_req_dump * +devlink_health_reporter_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct devlink_health_reporter_get_req_dump)); +} +void +devlink_health_reporter_get_req_dump_free(struct devlink_health_reporter_get_req_dump *req); static inline void -devlink_param_get_req_dump_set_bus_name(struct devlink_param_get_req_dump *req, - const char *bus_name) +devlink_health_reporter_get_req_dump_set_bus_name(struct devlink_health_reporter_get_req_dump *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -919,8 +3404,8 @@ devlink_param_get_req_dump_set_bus_name(struct devlink_param_get_req_dump *req, req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_param_get_req_dump_set_dev_name(struct devlink_param_get_req_dump *req, - const char *dev_name) +devlink_health_reporter_get_req_dump_set_dev_name(struct devlink_health_reporter_get_req_dump *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -928,43 +3413,59 @@ devlink_param_get_req_dump_set_dev_name(struct devlink_param_get_req_dump *req, memcpy(req->dev_name, dev_name, req->_present.dev_name_len); req->dev_name[req->_present.dev_name_len] = 0; } +static inline void +devlink_health_reporter_get_req_dump_set_port_index(struct devlink_health_reporter_get_req_dump *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} -struct devlink_param_get_list { - struct devlink_param_get_list *next; - struct devlink_param_get_rsp obj __attribute__ ((aligned (8))); +struct devlink_health_reporter_get_list { + struct devlink_health_reporter_get_list *next; + struct devlink_health_reporter_get_rsp obj __attribute__ ((aligned (8))); }; -void devlink_param_get_list_free(struct devlink_param_get_list *rsp); +void +devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp); -struct devlink_param_get_list * -devlink_param_get_dump(struct ynl_sock *ys, - struct devlink_param_get_req_dump *req); +struct devlink_health_reporter_get_list * +devlink_health_reporter_get_dump(struct ynl_sock *ys, + struct devlink_health_reporter_get_req_dump *req); -/* ============== DEVLINK_CMD_REGION_GET ============== */ -/* DEVLINK_CMD_REGION_GET - do */ -struct devlink_region_get_req { +/* ============== DEVLINK_CMD_HEALTH_REPORTER_SET ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_SET - do */ +struct devlink_health_reporter_set_req { struct { __u32 bus_name_len; __u32 dev_name_len; __u32 port_index:1; - __u32 region_name_len; + __u32 health_reporter_name_len; + __u32 health_reporter_graceful_period:1; + __u32 health_reporter_auto_recover:1; + __u32 health_reporter_auto_dump:1; } _present; char *bus_name; char *dev_name; __u32 port_index; - char *region_name; + char *health_reporter_name; + __u64 health_reporter_graceful_period; + __u8 health_reporter_auto_recover; + __u8 health_reporter_auto_dump; }; -static inline struct devlink_region_get_req *devlink_region_get_req_alloc(void) +static inline struct devlink_health_reporter_set_req * +devlink_health_reporter_set_req_alloc(void) { - return calloc(1, sizeof(struct devlink_region_get_req)); + return calloc(1, sizeof(struct devlink_health_reporter_set_req)); } -void devlink_region_get_req_free(struct devlink_region_get_req *req); +void +devlink_health_reporter_set_req_free(struct devlink_health_reporter_set_req *req); static inline void -devlink_region_get_req_set_bus_name(struct devlink_region_get_req *req, - const char *bus_name) +devlink_health_reporter_set_req_set_bus_name(struct devlink_health_reporter_set_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -973,8 +3474,8 @@ devlink_region_get_req_set_bus_name(struct devlink_region_get_req *req, req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_region_get_req_set_dev_name(struct devlink_region_get_req *req, - const char *dev_name) +devlink_health_reporter_set_req_set_dev_name(struct devlink_health_reporter_set_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -983,66 +3484,77 @@ devlink_region_get_req_set_dev_name(struct devlink_region_get_req *req, req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_region_get_req_set_port_index(struct devlink_region_get_req *req, - __u32 port_index) +devlink_health_reporter_set_req_set_port_index(struct devlink_health_reporter_set_req *req, + __u32 port_index) { req->_present.port_index = 1; req->port_index = port_index; } static inline void -devlink_region_get_req_set_region_name(struct devlink_region_get_req *req, - const char *region_name) +devlink_health_reporter_set_req_set_health_reporter_name(struct devlink_health_reporter_set_req *req, + const char *health_reporter_name) { - free(req->region_name); - req->_present.region_name_len = strlen(region_name); - req->region_name = malloc(req->_present.region_name_len + 1); - memcpy(req->region_name, region_name, req->_present.region_name_len); - req->region_name[req->_present.region_name_len] = 0; + free(req->health_reporter_name); + req->_present.health_reporter_name_len = strlen(health_reporter_name); + req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); + memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); + req->health_reporter_name[req->_present.health_reporter_name_len] = 0; +} +static inline void +devlink_health_reporter_set_req_set_health_reporter_graceful_period(struct devlink_health_reporter_set_req *req, + __u64 health_reporter_graceful_period) +{ + req->_present.health_reporter_graceful_period = 1; + req->health_reporter_graceful_period = health_reporter_graceful_period; +} +static inline void +devlink_health_reporter_set_req_set_health_reporter_auto_recover(struct devlink_health_reporter_set_req *req, + __u8 health_reporter_auto_recover) +{ + req->_present.health_reporter_auto_recover = 1; + req->health_reporter_auto_recover = health_reporter_auto_recover; +} +static inline void +devlink_health_reporter_set_req_set_health_reporter_auto_dump(struct devlink_health_reporter_set_req *req, + __u8 health_reporter_auto_dump) +{ + req->_present.health_reporter_auto_dump = 1; + req->health_reporter_auto_dump = health_reporter_auto_dump; } - -struct devlink_region_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 port_index:1; - __u32 region_name_len; - } _present; - - char *bus_name; - char *dev_name; - __u32 port_index; - char *region_name; -}; - -void devlink_region_get_rsp_free(struct devlink_region_get_rsp *rsp); /* - * Get region instances. + * Set health reporter instances. */ -struct devlink_region_get_rsp * -devlink_region_get(struct ynl_sock *ys, struct devlink_region_get_req *req); +int devlink_health_reporter_set(struct ynl_sock *ys, + struct devlink_health_reporter_set_req *req); -/* DEVLINK_CMD_REGION_GET - dump */ -struct devlink_region_get_req_dump { +/* ============== DEVLINK_CMD_HEALTH_REPORTER_RECOVER ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_RECOVER - do */ +struct devlink_health_reporter_recover_req { struct { __u32 bus_name_len; __u32 dev_name_len; + __u32 port_index:1; + __u32 health_reporter_name_len; } _present; char *bus_name; char *dev_name; + __u32 port_index; + char *health_reporter_name; }; -static inline struct devlink_region_get_req_dump * -devlink_region_get_req_dump_alloc(void) +static inline struct devlink_health_reporter_recover_req * +devlink_health_reporter_recover_req_alloc(void) { - return calloc(1, sizeof(struct devlink_region_get_req_dump)); + return calloc(1, sizeof(struct devlink_health_reporter_recover_req)); } -void devlink_region_get_req_dump_free(struct devlink_region_get_req_dump *req); +void +devlink_health_reporter_recover_req_free(struct devlink_health_reporter_recover_req *req); static inline void -devlink_region_get_req_dump_set_bus_name(struct devlink_region_get_req_dump *req, - const char *bus_name) +devlink_health_reporter_recover_req_set_bus_name(struct devlink_health_reporter_recover_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -1051,8 +3563,8 @@ devlink_region_get_req_dump_set_bus_name(struct devlink_region_get_req_dump *req req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_region_get_req_dump_set_dev_name(struct devlink_region_get_req_dump *req, - const char *dev_name) +devlink_health_reporter_recover_req_set_dev_name(struct devlink_health_reporter_recover_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -1060,39 +3572,57 @@ devlink_region_get_req_dump_set_dev_name(struct devlink_region_get_req_dump *req memcpy(req->dev_name, dev_name, req->_present.dev_name_len); req->dev_name[req->_present.dev_name_len] = 0; } +static inline void +devlink_health_reporter_recover_req_set_port_index(struct devlink_health_reporter_recover_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_health_reporter_recover_req_set_health_reporter_name(struct devlink_health_reporter_recover_req *req, + const char *health_reporter_name) +{ + free(req->health_reporter_name); + req->_present.health_reporter_name_len = strlen(health_reporter_name); + req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); + memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); + req->health_reporter_name[req->_present.health_reporter_name_len] = 0; +} -struct devlink_region_get_list { - struct devlink_region_get_list *next; - struct devlink_region_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_region_get_list_free(struct devlink_region_get_list *rsp); - -struct devlink_region_get_list * -devlink_region_get_dump(struct ynl_sock *ys, - struct devlink_region_get_req_dump *req); +/* + * Recover health reporter instances. + */ +int devlink_health_reporter_recover(struct ynl_sock *ys, + struct devlink_health_reporter_recover_req *req); -/* ============== DEVLINK_CMD_INFO_GET ============== */ -/* DEVLINK_CMD_INFO_GET - do */ -struct devlink_info_get_req { +/* ============== DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE - do */ +struct devlink_health_reporter_diagnose_req { struct { __u32 bus_name_len; __u32 dev_name_len; + __u32 port_index:1; + __u32 health_reporter_name_len; } _present; char *bus_name; char *dev_name; + __u32 port_index; + char *health_reporter_name; }; -static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void) +static inline struct devlink_health_reporter_diagnose_req * +devlink_health_reporter_diagnose_req_alloc(void) { - return calloc(1, sizeof(struct devlink_info_get_req)); + return calloc(1, sizeof(struct devlink_health_reporter_diagnose_req)); } -void devlink_info_get_req_free(struct devlink_info_get_req *req); +void +devlink_health_reporter_diagnose_req_free(struct devlink_health_reporter_diagnose_req *req); static inline void -devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, - const char *bus_name) +devlink_health_reporter_diagnose_req_set_bus_name(struct devlink_health_reporter_diagnose_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -1101,8 +3631,8 @@ devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, - const char *dev_name) +devlink_health_reporter_diagnose_req_set_dev_name(struct devlink_health_reporter_diagnose_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -1110,48 +3640,33 @@ devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, memcpy(req->dev_name, dev_name, req->_present.dev_name_len); req->dev_name[req->_present.dev_name_len] = 0; } - -struct devlink_info_get_rsp { - struct { - __u32 bus_name_len; - __u32 dev_name_len; - __u32 info_driver_name_len; - __u32 info_serial_number_len; - } _present; - - char *bus_name; - char *dev_name; - char *info_driver_name; - char *info_serial_number; - unsigned int n_info_version_fixed; - struct devlink_dl_info_version *info_version_fixed; - unsigned int n_info_version_running; - struct devlink_dl_info_version *info_version_running; - unsigned int n_info_version_stored; - struct devlink_dl_info_version *info_version_stored; -}; - -void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp); +static inline void +devlink_health_reporter_diagnose_req_set_port_index(struct devlink_health_reporter_diagnose_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_health_reporter_diagnose_req_set_health_reporter_name(struct devlink_health_reporter_diagnose_req *req, + const char *health_reporter_name) +{ + free(req->health_reporter_name); + req->_present.health_reporter_name_len = strlen(health_reporter_name); + req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); + memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); + req->health_reporter_name[req->_present.health_reporter_name_len] = 0; +} /* - * Get device information, like driver name, hardware and firmware versions etc. + * Diagnose health reporter instances. */ -struct devlink_info_get_rsp * -devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req); - -/* DEVLINK_CMD_INFO_GET - dump */ -struct devlink_info_get_list { - struct devlink_info_get_list *next; - struct devlink_info_get_rsp obj __attribute__ ((aligned (8))); -}; - -void devlink_info_get_list_free(struct devlink_info_get_list *rsp); - -struct devlink_info_get_list *devlink_info_get_dump(struct ynl_sock *ys); +int devlink_health_reporter_diagnose(struct ynl_sock *ys, + struct devlink_health_reporter_diagnose_req *req); -/* ============== DEVLINK_CMD_HEALTH_REPORTER_GET ============== */ -/* DEVLINK_CMD_HEALTH_REPORTER_GET - do */ -struct devlink_health_reporter_get_req { +/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET - dump */ +struct devlink_health_reporter_dump_get_req_dump { struct { __u32 bus_name_len; __u32 dev_name_len; @@ -1165,17 +3680,17 @@ struct devlink_health_reporter_get_req { char *health_reporter_name; }; -static inline struct devlink_health_reporter_get_req * -devlink_health_reporter_get_req_alloc(void) +static inline struct devlink_health_reporter_dump_get_req_dump * +devlink_health_reporter_dump_get_req_dump_alloc(void) { - return calloc(1, sizeof(struct devlink_health_reporter_get_req)); + return calloc(1, sizeof(struct devlink_health_reporter_dump_get_req_dump)); } void -devlink_health_reporter_get_req_free(struct devlink_health_reporter_get_req *req); +devlink_health_reporter_dump_get_req_dump_free(struct devlink_health_reporter_dump_get_req_dump *req); static inline void -devlink_health_reporter_get_req_set_bus_name(struct devlink_health_reporter_get_req *req, - const char *bus_name) +devlink_health_reporter_dump_get_req_dump_set_bus_name(struct devlink_health_reporter_dump_get_req_dump *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -1184,8 +3699,8 @@ devlink_health_reporter_get_req_set_bus_name(struct devlink_health_reporter_get_ req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_health_reporter_get_req_set_dev_name(struct devlink_health_reporter_get_req *req, - const char *dev_name) +devlink_health_reporter_dump_get_req_dump_set_dev_name(struct devlink_health_reporter_dump_get_req_dump *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -1194,15 +3709,15 @@ devlink_health_reporter_get_req_set_dev_name(struct devlink_health_reporter_get_ req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_health_reporter_get_req_set_port_index(struct devlink_health_reporter_get_req *req, - __u32 port_index) +devlink_health_reporter_dump_get_req_dump_set_port_index(struct devlink_health_reporter_dump_get_req_dump *req, + __u32 port_index) { req->_present.port_index = 1; req->port_index = port_index; } static inline void -devlink_health_reporter_get_req_set_health_reporter_name(struct devlink_health_reporter_get_req *req, - const char *health_reporter_name) +devlink_health_reporter_dump_get_req_dump_set_health_reporter_name(struct devlink_health_reporter_dump_get_req_dump *req, + const char *health_reporter_name) { free(req->health_reporter_name); req->_present.health_reporter_name_len = strlen(health_reporter_name); @@ -1211,7 +3726,29 @@ devlink_health_reporter_get_req_set_health_reporter_name(struct devlink_health_r req->health_reporter_name[req->_present.health_reporter_name_len] = 0; } -struct devlink_health_reporter_get_rsp { +struct devlink_health_reporter_dump_get_rsp_dump { + struct { + __u32 fmsg:1; + } _present; + + struct devlink_dl_fmsg fmsg; +}; + +struct devlink_health_reporter_dump_get_rsp_list { + struct devlink_health_reporter_dump_get_rsp_list *next; + struct devlink_health_reporter_dump_get_rsp_dump obj __attribute__((aligned(8))); +}; + +void +devlink_health_reporter_dump_get_rsp_list_free(struct devlink_health_reporter_dump_get_rsp_list *rsp); + +struct devlink_health_reporter_dump_get_rsp_list * +devlink_health_reporter_dump_get_dump(struct ynl_sock *ys, + struct devlink_health_reporter_dump_get_req_dump *req); + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR - do */ +struct devlink_health_reporter_dump_clear_req { struct { __u32 bus_name_len; __u32 dev_name_len; @@ -1225,40 +3762,86 @@ struct devlink_health_reporter_get_rsp { char *health_reporter_name; }; +static inline struct devlink_health_reporter_dump_clear_req * +devlink_health_reporter_dump_clear_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_health_reporter_dump_clear_req)); +} void -devlink_health_reporter_get_rsp_free(struct devlink_health_reporter_get_rsp *rsp); +devlink_health_reporter_dump_clear_req_free(struct devlink_health_reporter_dump_clear_req *req); + +static inline void +devlink_health_reporter_dump_clear_req_set_bus_name(struct devlink_health_reporter_dump_clear_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_health_reporter_dump_clear_req_set_dev_name(struct devlink_health_reporter_dump_clear_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_health_reporter_dump_clear_req_set_port_index(struct devlink_health_reporter_dump_clear_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_health_reporter_dump_clear_req_set_health_reporter_name(struct devlink_health_reporter_dump_clear_req *req, + const char *health_reporter_name) +{ + free(req->health_reporter_name); + req->_present.health_reporter_name_len = strlen(health_reporter_name); + req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); + memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); + req->health_reporter_name[req->_present.health_reporter_name_len] = 0; +} /* - * Get health reporter instances. + * Clear dump of health reporter instances. */ -struct devlink_health_reporter_get_rsp * -devlink_health_reporter_get(struct ynl_sock *ys, - struct devlink_health_reporter_get_req *req); +int devlink_health_reporter_dump_clear(struct ynl_sock *ys, + struct devlink_health_reporter_dump_clear_req *req); -/* DEVLINK_CMD_HEALTH_REPORTER_GET - dump */ -struct devlink_health_reporter_get_req_dump { +/* ============== DEVLINK_CMD_FLASH_UPDATE ============== */ +/* DEVLINK_CMD_FLASH_UPDATE - do */ +struct devlink_flash_update_req { struct { __u32 bus_name_len; __u32 dev_name_len; - __u32 port_index:1; + __u32 flash_update_file_name_len; + __u32 flash_update_component_len; + __u32 flash_update_overwrite_mask:1; } _present; char *bus_name; char *dev_name; - __u32 port_index; + char *flash_update_file_name; + char *flash_update_component; + struct nla_bitfield32 flash_update_overwrite_mask; }; -static inline struct devlink_health_reporter_get_req_dump * -devlink_health_reporter_get_req_dump_alloc(void) +static inline struct devlink_flash_update_req * +devlink_flash_update_req_alloc(void) { - return calloc(1, sizeof(struct devlink_health_reporter_get_req_dump)); + return calloc(1, sizeof(struct devlink_flash_update_req)); } -void -devlink_health_reporter_get_req_dump_free(struct devlink_health_reporter_get_req_dump *req); +void devlink_flash_update_req_free(struct devlink_flash_update_req *req); static inline void -devlink_health_reporter_get_req_dump_set_bus_name(struct devlink_health_reporter_get_req_dump *req, - const char *bus_name) +devlink_flash_update_req_set_bus_name(struct devlink_flash_update_req *req, + const char *bus_name) { free(req->bus_name); req->_present.bus_name_len = strlen(bus_name); @@ -1267,8 +3850,8 @@ devlink_health_reporter_get_req_dump_set_bus_name(struct devlink_health_reporter req->bus_name[req->_present.bus_name_len] = 0; } static inline void -devlink_health_reporter_get_req_dump_set_dev_name(struct devlink_health_reporter_get_req_dump *req, - const char *dev_name) +devlink_flash_update_req_set_dev_name(struct devlink_flash_update_req *req, + const char *dev_name) { free(req->dev_name); req->_present.dev_name_len = strlen(dev_name); @@ -1277,24 +3860,38 @@ devlink_health_reporter_get_req_dump_set_dev_name(struct devlink_health_reporter req->dev_name[req->_present.dev_name_len] = 0; } static inline void -devlink_health_reporter_get_req_dump_set_port_index(struct devlink_health_reporter_get_req_dump *req, - __u32 port_index) +devlink_flash_update_req_set_flash_update_file_name(struct devlink_flash_update_req *req, + const char *flash_update_file_name) { - req->_present.port_index = 1; - req->port_index = port_index; + free(req->flash_update_file_name); + req->_present.flash_update_file_name_len = strlen(flash_update_file_name); + req->flash_update_file_name = malloc(req->_present.flash_update_file_name_len + 1); + memcpy(req->flash_update_file_name, flash_update_file_name, req->_present.flash_update_file_name_len); + req->flash_update_file_name[req->_present.flash_update_file_name_len] = 0; +} +static inline void +devlink_flash_update_req_set_flash_update_component(struct devlink_flash_update_req *req, + const char *flash_update_component) +{ + free(req->flash_update_component); + req->_present.flash_update_component_len = strlen(flash_update_component); + req->flash_update_component = malloc(req->_present.flash_update_component_len + 1); + memcpy(req->flash_update_component, flash_update_component, req->_present.flash_update_component_len); + req->flash_update_component[req->_present.flash_update_component_len] = 0; +} +static inline void +devlink_flash_update_req_set_flash_update_overwrite_mask(struct devlink_flash_update_req *req, + struct nla_bitfield32 *flash_update_overwrite_mask) +{ + req->_present.flash_update_overwrite_mask = 1; + memcpy(&req->flash_update_overwrite_mask, flash_update_overwrite_mask, sizeof(struct nla_bitfield32)); } -struct devlink_health_reporter_get_list { - struct devlink_health_reporter_get_list *next; - struct devlink_health_reporter_get_rsp obj __attribute__ ((aligned (8))); -}; - -void -devlink_health_reporter_get_list_free(struct devlink_health_reporter_get_list *rsp); - -struct devlink_health_reporter_get_list * -devlink_health_reporter_get_dump(struct ynl_sock *ys, - struct devlink_health_reporter_get_req_dump *req); +/* + * Flash update devlink instances. + */ +int devlink_flash_update(struct ynl_sock *ys, + struct devlink_flash_update_req *req); /* ============== DEVLINK_CMD_TRAP_GET ============== */ /* DEVLINK_CMD_TRAP_GET - do */ @@ -1417,6 +4014,71 @@ struct devlink_trap_get_list * devlink_trap_get_dump(struct ynl_sock *ys, struct devlink_trap_get_req_dump *req); +/* ============== DEVLINK_CMD_TRAP_SET ============== */ +/* DEVLINK_CMD_TRAP_SET - do */ +struct devlink_trap_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 trap_name_len; + __u32 trap_action:1; + } _present; + + char *bus_name; + char *dev_name; + char *trap_name; + enum devlink_trap_action trap_action; +}; + +static inline struct devlink_trap_set_req *devlink_trap_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_trap_set_req)); +} +void devlink_trap_set_req_free(struct devlink_trap_set_req *req); + +static inline void +devlink_trap_set_req_set_bus_name(struct devlink_trap_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_trap_set_req_set_dev_name(struct devlink_trap_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_trap_set_req_set_trap_name(struct devlink_trap_set_req *req, + const char *trap_name) +{ + free(req->trap_name); + req->_present.trap_name_len = strlen(trap_name); + req->trap_name = malloc(req->_present.trap_name_len + 1); + memcpy(req->trap_name, trap_name, req->_present.trap_name_len); + req->trap_name[req->_present.trap_name_len] = 0; +} +static inline void +devlink_trap_set_req_set_trap_action(struct devlink_trap_set_req *req, + enum devlink_trap_action trap_action) +{ + req->_present.trap_action = 1; + req->trap_action = trap_action; +} + +/* + * Set trap instances. + */ +int devlink_trap_set(struct ynl_sock *ys, struct devlink_trap_set_req *req); + /* ============== DEVLINK_CMD_TRAP_GROUP_GET ============== */ /* DEVLINK_CMD_TRAP_GROUP_GET - do */ struct devlink_trap_group_get_req { @@ -1541,6 +4203,82 @@ struct devlink_trap_group_get_list * devlink_trap_group_get_dump(struct ynl_sock *ys, struct devlink_trap_group_get_req_dump *req); +/* ============== DEVLINK_CMD_TRAP_GROUP_SET ============== */ +/* DEVLINK_CMD_TRAP_GROUP_SET - do */ +struct devlink_trap_group_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 trap_group_name_len; + __u32 trap_action:1; + __u32 trap_policer_id:1; + } _present; + + char *bus_name; + char *dev_name; + char *trap_group_name; + enum devlink_trap_action trap_action; + __u32 trap_policer_id; +}; + +static inline struct devlink_trap_group_set_req * +devlink_trap_group_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_trap_group_set_req)); +} +void devlink_trap_group_set_req_free(struct devlink_trap_group_set_req *req); + +static inline void +devlink_trap_group_set_req_set_bus_name(struct devlink_trap_group_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_trap_group_set_req_set_dev_name(struct devlink_trap_group_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_trap_group_set_req_set_trap_group_name(struct devlink_trap_group_set_req *req, + const char *trap_group_name) +{ + free(req->trap_group_name); + req->_present.trap_group_name_len = strlen(trap_group_name); + req->trap_group_name = malloc(req->_present.trap_group_name_len + 1); + memcpy(req->trap_group_name, trap_group_name, req->_present.trap_group_name_len); + req->trap_group_name[req->_present.trap_group_name_len] = 0; +} +static inline void +devlink_trap_group_set_req_set_trap_action(struct devlink_trap_group_set_req *req, + enum devlink_trap_action trap_action) +{ + req->_present.trap_action = 1; + req->trap_action = trap_action; +} +static inline void +devlink_trap_group_set_req_set_trap_policer_id(struct devlink_trap_group_set_req *req, + __u32 trap_policer_id) +{ + req->_present.trap_policer_id = 1; + req->trap_policer_id = trap_policer_id; +} + +/* + * Set trap group instances. + */ +int devlink_trap_group_set(struct ynl_sock *ys, + struct devlink_trap_group_set_req *req); + /* ============== DEVLINK_CMD_TRAP_POLICER_GET ============== */ /* DEVLINK_CMD_TRAP_POLICER_GET - do */ struct devlink_trap_policer_get_req { @@ -1661,9 +4399,151 @@ struct devlink_trap_policer_get_list { void devlink_trap_policer_get_list_free(struct devlink_trap_policer_get_list *rsp); -struct devlink_trap_policer_get_list * -devlink_trap_policer_get_dump(struct ynl_sock *ys, - struct devlink_trap_policer_get_req_dump *req); +struct devlink_trap_policer_get_list * +devlink_trap_policer_get_dump(struct ynl_sock *ys, + struct devlink_trap_policer_get_req_dump *req); + +/* ============== DEVLINK_CMD_TRAP_POLICER_SET ============== */ +/* DEVLINK_CMD_TRAP_POLICER_SET - do */ +struct devlink_trap_policer_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 trap_policer_id:1; + __u32 trap_policer_rate:1; + __u32 trap_policer_burst:1; + } _present; + + char *bus_name; + char *dev_name; + __u32 trap_policer_id; + __u64 trap_policer_rate; + __u64 trap_policer_burst; +}; + +static inline struct devlink_trap_policer_set_req * +devlink_trap_policer_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_trap_policer_set_req)); +} +void +devlink_trap_policer_set_req_free(struct devlink_trap_policer_set_req *req); + +static inline void +devlink_trap_policer_set_req_set_bus_name(struct devlink_trap_policer_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_trap_policer_set_req_set_dev_name(struct devlink_trap_policer_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_trap_policer_set_req_set_trap_policer_id(struct devlink_trap_policer_set_req *req, + __u32 trap_policer_id) +{ + req->_present.trap_policer_id = 1; + req->trap_policer_id = trap_policer_id; +} +static inline void +devlink_trap_policer_set_req_set_trap_policer_rate(struct devlink_trap_policer_set_req *req, + __u64 trap_policer_rate) +{ + req->_present.trap_policer_rate = 1; + req->trap_policer_rate = trap_policer_rate; +} +static inline void +devlink_trap_policer_set_req_set_trap_policer_burst(struct devlink_trap_policer_set_req *req, + __u64 trap_policer_burst) +{ + req->_present.trap_policer_burst = 1; + req->trap_policer_burst = trap_policer_burst; +} + +/* + * Get trap policer instances. + */ +int devlink_trap_policer_set(struct ynl_sock *ys, + struct devlink_trap_policer_set_req *req); + +/* ============== DEVLINK_CMD_HEALTH_REPORTER_TEST ============== */ +/* DEVLINK_CMD_HEALTH_REPORTER_TEST - do */ +struct devlink_health_reporter_test_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 port_index:1; + __u32 health_reporter_name_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 port_index; + char *health_reporter_name; +}; + +static inline struct devlink_health_reporter_test_req * +devlink_health_reporter_test_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_health_reporter_test_req)); +} +void +devlink_health_reporter_test_req_free(struct devlink_health_reporter_test_req *req); + +static inline void +devlink_health_reporter_test_req_set_bus_name(struct devlink_health_reporter_test_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_health_reporter_test_req_set_dev_name(struct devlink_health_reporter_test_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_health_reporter_test_req_set_port_index(struct devlink_health_reporter_test_req *req, + __u32 port_index) +{ + req->_present.port_index = 1; + req->port_index = port_index; +} +static inline void +devlink_health_reporter_test_req_set_health_reporter_name(struct devlink_health_reporter_test_req *req, + const char *health_reporter_name) +{ + free(req->health_reporter_name); + req->_present.health_reporter_name_len = strlen(health_reporter_name); + req->health_reporter_name = malloc(req->_present.health_reporter_name_len + 1); + memcpy(req->health_reporter_name, health_reporter_name, req->_present.health_reporter_name_len); + req->health_reporter_name[req->_present.health_reporter_name_len] = 0; +} + +/* + * Test health reporter instances. + */ +int devlink_health_reporter_test(struct ynl_sock *ys, + struct devlink_health_reporter_test_req *req); /* ============== DEVLINK_CMD_RATE_GET ============== */ /* DEVLINK_CMD_RATE_GET - do */ @@ -1797,6 +4677,270 @@ struct devlink_rate_get_list * devlink_rate_get_dump(struct ynl_sock *ys, struct devlink_rate_get_req_dump *req); +/* ============== DEVLINK_CMD_RATE_SET ============== */ +/* DEVLINK_CMD_RATE_SET - do */ +struct devlink_rate_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 rate_node_name_len; + __u32 rate_tx_share:1; + __u32 rate_tx_max:1; + __u32 rate_tx_priority:1; + __u32 rate_tx_weight:1; + __u32 rate_parent_node_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *rate_node_name; + __u64 rate_tx_share; + __u64 rate_tx_max; + __u32 rate_tx_priority; + __u32 rate_tx_weight; + char *rate_parent_node_name; +}; + +static inline struct devlink_rate_set_req *devlink_rate_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_rate_set_req)); +} +void devlink_rate_set_req_free(struct devlink_rate_set_req *req); + +static inline void +devlink_rate_set_req_set_bus_name(struct devlink_rate_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_rate_set_req_set_dev_name(struct devlink_rate_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_rate_set_req_set_rate_node_name(struct devlink_rate_set_req *req, + const char *rate_node_name) +{ + free(req->rate_node_name); + req->_present.rate_node_name_len = strlen(rate_node_name); + req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); + memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); + req->rate_node_name[req->_present.rate_node_name_len] = 0; +} +static inline void +devlink_rate_set_req_set_rate_tx_share(struct devlink_rate_set_req *req, + __u64 rate_tx_share) +{ + req->_present.rate_tx_share = 1; + req->rate_tx_share = rate_tx_share; +} +static inline void +devlink_rate_set_req_set_rate_tx_max(struct devlink_rate_set_req *req, + __u64 rate_tx_max) +{ + req->_present.rate_tx_max = 1; + req->rate_tx_max = rate_tx_max; +} +static inline void +devlink_rate_set_req_set_rate_tx_priority(struct devlink_rate_set_req *req, + __u32 rate_tx_priority) +{ + req->_present.rate_tx_priority = 1; + req->rate_tx_priority = rate_tx_priority; +} +static inline void +devlink_rate_set_req_set_rate_tx_weight(struct devlink_rate_set_req *req, + __u32 rate_tx_weight) +{ + req->_present.rate_tx_weight = 1; + req->rate_tx_weight = rate_tx_weight; +} +static inline void +devlink_rate_set_req_set_rate_parent_node_name(struct devlink_rate_set_req *req, + const char *rate_parent_node_name) +{ + free(req->rate_parent_node_name); + req->_present.rate_parent_node_name_len = strlen(rate_parent_node_name); + req->rate_parent_node_name = malloc(req->_present.rate_parent_node_name_len + 1); + memcpy(req->rate_parent_node_name, rate_parent_node_name, req->_present.rate_parent_node_name_len); + req->rate_parent_node_name[req->_present.rate_parent_node_name_len] = 0; +} + +/* + * Set rate instances. + */ +int devlink_rate_set(struct ynl_sock *ys, struct devlink_rate_set_req *req); + +/* ============== DEVLINK_CMD_RATE_NEW ============== */ +/* DEVLINK_CMD_RATE_NEW - do */ +struct devlink_rate_new_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 rate_node_name_len; + __u32 rate_tx_share:1; + __u32 rate_tx_max:1; + __u32 rate_tx_priority:1; + __u32 rate_tx_weight:1; + __u32 rate_parent_node_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *rate_node_name; + __u64 rate_tx_share; + __u64 rate_tx_max; + __u32 rate_tx_priority; + __u32 rate_tx_weight; + char *rate_parent_node_name; +}; + +static inline struct devlink_rate_new_req *devlink_rate_new_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_rate_new_req)); +} +void devlink_rate_new_req_free(struct devlink_rate_new_req *req); + +static inline void +devlink_rate_new_req_set_bus_name(struct devlink_rate_new_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_rate_new_req_set_dev_name(struct devlink_rate_new_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_rate_new_req_set_rate_node_name(struct devlink_rate_new_req *req, + const char *rate_node_name) +{ + free(req->rate_node_name); + req->_present.rate_node_name_len = strlen(rate_node_name); + req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); + memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); + req->rate_node_name[req->_present.rate_node_name_len] = 0; +} +static inline void +devlink_rate_new_req_set_rate_tx_share(struct devlink_rate_new_req *req, + __u64 rate_tx_share) +{ + req->_present.rate_tx_share = 1; + req->rate_tx_share = rate_tx_share; +} +static inline void +devlink_rate_new_req_set_rate_tx_max(struct devlink_rate_new_req *req, + __u64 rate_tx_max) +{ + req->_present.rate_tx_max = 1; + req->rate_tx_max = rate_tx_max; +} +static inline void +devlink_rate_new_req_set_rate_tx_priority(struct devlink_rate_new_req *req, + __u32 rate_tx_priority) +{ + req->_present.rate_tx_priority = 1; + req->rate_tx_priority = rate_tx_priority; +} +static inline void +devlink_rate_new_req_set_rate_tx_weight(struct devlink_rate_new_req *req, + __u32 rate_tx_weight) +{ + req->_present.rate_tx_weight = 1; + req->rate_tx_weight = rate_tx_weight; +} +static inline void +devlink_rate_new_req_set_rate_parent_node_name(struct devlink_rate_new_req *req, + const char *rate_parent_node_name) +{ + free(req->rate_parent_node_name); + req->_present.rate_parent_node_name_len = strlen(rate_parent_node_name); + req->rate_parent_node_name = malloc(req->_present.rate_parent_node_name_len + 1); + memcpy(req->rate_parent_node_name, rate_parent_node_name, req->_present.rate_parent_node_name_len); + req->rate_parent_node_name[req->_present.rate_parent_node_name_len] = 0; +} + +/* + * Create rate instances. + */ +int devlink_rate_new(struct ynl_sock *ys, struct devlink_rate_new_req *req); + +/* ============== DEVLINK_CMD_RATE_DEL ============== */ +/* DEVLINK_CMD_RATE_DEL - do */ +struct devlink_rate_del_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 rate_node_name_len; + } _present; + + char *bus_name; + char *dev_name; + char *rate_node_name; +}; + +static inline struct devlink_rate_del_req *devlink_rate_del_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_rate_del_req)); +} +void devlink_rate_del_req_free(struct devlink_rate_del_req *req); + +static inline void +devlink_rate_del_req_set_bus_name(struct devlink_rate_del_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_rate_del_req_set_dev_name(struct devlink_rate_del_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_rate_del_req_set_rate_node_name(struct devlink_rate_del_req *req, + const char *rate_node_name) +{ + free(req->rate_node_name); + req->_present.rate_node_name_len = strlen(rate_node_name); + req->rate_node_name = malloc(req->_present.rate_node_name_len + 1); + memcpy(req->rate_node_name, rate_node_name, req->_present.rate_node_name_len); + req->rate_node_name[req->_present.rate_node_name_len] = 0; +} + +/* + * Delete rate instances. + */ +int devlink_rate_del(struct ynl_sock *ys, struct devlink_rate_del_req *req); + /* ============== DEVLINK_CMD_LINECARD_GET ============== */ /* DEVLINK_CMD_LINECARD_GET - do */ struct devlink_linecard_get_req { @@ -1917,6 +5061,73 @@ struct devlink_linecard_get_list * devlink_linecard_get_dump(struct ynl_sock *ys, struct devlink_linecard_get_req_dump *req); +/* ============== DEVLINK_CMD_LINECARD_SET ============== */ +/* DEVLINK_CMD_LINECARD_SET - do */ +struct devlink_linecard_set_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 linecard_index:1; + __u32 linecard_type_len; + } _present; + + char *bus_name; + char *dev_name; + __u32 linecard_index; + char *linecard_type; +}; + +static inline struct devlink_linecard_set_req * +devlink_linecard_set_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_linecard_set_req)); +} +void devlink_linecard_set_req_free(struct devlink_linecard_set_req *req); + +static inline void +devlink_linecard_set_req_set_bus_name(struct devlink_linecard_set_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_linecard_set_req_set_dev_name(struct devlink_linecard_set_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_linecard_set_req_set_linecard_index(struct devlink_linecard_set_req *req, + __u32 linecard_index) +{ + req->_present.linecard_index = 1; + req->linecard_index = linecard_index; +} +static inline void +devlink_linecard_set_req_set_linecard_type(struct devlink_linecard_set_req *req, + const char *linecard_type) +{ + free(req->linecard_type); + req->_present.linecard_type_len = strlen(linecard_type); + req->linecard_type = malloc(req->_present.linecard_type_len + 1); + memcpy(req->linecard_type, linecard_type, req->_present.linecard_type_len); + req->linecard_type[req->_present.linecard_type_len] = 0; +} + +/* + * Set line card instances. + */ +int devlink_linecard_set(struct ynl_sock *ys, + struct devlink_linecard_set_req *req); + /* ============== DEVLINK_CMD_SELFTESTS_GET ============== */ /* DEVLINK_CMD_SELFTESTS_GET - do */ struct devlink_selftests_get_req { @@ -1987,4 +5198,58 @@ void devlink_selftests_get_list_free(struct devlink_selftests_get_list *rsp); struct devlink_selftests_get_list * devlink_selftests_get_dump(struct ynl_sock *ys); +/* ============== DEVLINK_CMD_SELFTESTS_RUN ============== */ +/* DEVLINK_CMD_SELFTESTS_RUN - do */ +struct devlink_selftests_run_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 selftests:1; + } _present; + + char *bus_name; + char *dev_name; + struct devlink_dl_selftest_id selftests; +}; + +static inline struct devlink_selftests_run_req * +devlink_selftests_run_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_selftests_run_req)); +} +void devlink_selftests_run_req_free(struct devlink_selftests_run_req *req); + +static inline void +devlink_selftests_run_req_set_bus_name(struct devlink_selftests_run_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_selftests_run_req_set_dev_name(struct devlink_selftests_run_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} +static inline void +devlink_selftests_run_req_set_selftests_flash(struct devlink_selftests_run_req *req) +{ + req->_present.selftests = 1; + req->selftests._present.flash = 1; +} + +/* + * Run device selftest instances. + */ +int devlink_selftests_run(struct ynl_sock *ys, + struct devlink_selftests_run_req *req); + #endif /* _LINUX_DEVLINK_GEN_H */ -- cgit v1.2.3 From 8ab32fa1c7947f4807b1d98af2d411a2587bb841 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Fri, 20 Oct 2023 17:59:51 +0800 Subject: page_pool: update document about fragment API As more drivers begin to use the fragment API, update the document about how to decide which API to use for the driver author. Signed-off-by: Yunsheng Lin CC: Lorenzo Bianconi CC: Alexander Duyck CC: Liang Chen CC: Alexander Lobakin CC: Dima Tisnek Link: https://lore.kernel.org/r/20231020095952.11055-5-linyunsheng@huawei.com Signed-off-by: Jakub Kicinski --- Documentation/networking/page_pool.rst | 4 +- include/net/page_pool/helpers.h | 93 +++++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 215ebc92752c..60993cb56b32 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -58,7 +58,9 @@ a page will cause no race conditions is enough. .. kernel-doc:: include/net/page_pool/helpers.h :identifiers: page_pool_put_page page_pool_put_full_page - page_pool_recycle_direct page_pool_dev_alloc_pages + page_pool_recycle_direct page_pool_free_va + page_pool_dev_alloc_pages page_pool_dev_alloc_frag + page_pool_dev_alloc page_pool_dev_alloc_va page_pool_get_dma_addr page_pool_get_dma_dir .. kernel-doc:: net/core/page_pool.c diff --git a/include/net/page_pool/helpers.h b/include/net/page_pool/helpers.h index 1b76e05dc4d2..4ebd544ae977 100644 --- a/include/net/page_pool/helpers.h +++ b/include/net/page_pool/helpers.h @@ -8,23 +8,46 @@ /** * DOC: page_pool allocator * - * The page_pool allocator is optimized for the XDP mode that - * uses one frame per-page, but it can fallback on the - * regular page allocator APIs. + * The page_pool allocator is optimized for recycling page or page fragment used + * by skb packet and xdp frame. * - * Basic use involves replacing alloc_pages() calls with the - * page_pool_alloc_pages() call. Drivers should use - * page_pool_dev_alloc_pages() replacing dev_alloc_pages(). + * Basic use involves replacing and alloc_pages() calls with page_pool_alloc(), + * which allocate memory with or without page splitting depending on the + * requested memory size. * - * The API keeps track of in-flight pages, in order to let API users know - * when it is safe to free a page_pool object. Thus, API users - * must call page_pool_put_page() to free the page, or attach - * the page to a page_pool-aware object like skbs marked with + * If the driver knows that it always requires full pages or its allocations are + * always smaller than half a page, it can use one of the more specific API + * calls: + * + * 1. page_pool_alloc_pages(): allocate memory without page splitting when + * driver knows that the memory it need is always bigger than half of the page + * allocated from page pool. There is no cache line dirtying for 'struct page' + * when a page is recycled back to the page pool. + * + * 2. page_pool_alloc_frag(): allocate memory with page splitting when driver + * knows that the memory it need is always smaller than or equal to half of the + * page allocated from page pool. Page splitting enables memory saving and thus + * avoids TLB/cache miss for data access, but there also is some cost to + * implement page splitting, mainly some cache line dirtying/bouncing for + * 'struct page' and atomic operation for page->pp_frag_count. + * + * The API keeps track of in-flight pages, in order to let API users know when + * it is safe to free a page_pool object, the API users must call + * page_pool_put_page() or page_pool_free_va() to free the page_pool object, or + * attach the page_pool object to a page_pool-aware object like skbs marked with * skb_mark_for_recycle(). * - * API users must call page_pool_put_page() once on a page, as it - * will either recycle the page, or in case of refcnt > 1, it will - * release the DMA mapping and in-flight state accounting. + * page_pool_put_page() may be called multi times on the same page if a page is + * split into multi fragments. For the last fragment, it will either recycle the + * page, or in case of page->_refcount > 1, it will release the DMA mapping and + * in-flight state accounting. + * + * dma_sync_single_range_for_device() is only called for the last fragment when + * page_pool is created with PP_FLAG_DMA_SYNC_DEV flag, so it depends on the + * last freed fragment to do the sync_for_device operation for all fragments in + * the same page when a page is split, the API user must setup pool->p.max_len + * and pool->p.offset correctly and ensure that page_pool_put_page() is called + * with dma_sync_size being -1 for fragment API. */ #ifndef _NET_PAGE_POOL_HELPERS_H #define _NET_PAGE_POOL_HELPERS_H @@ -73,6 +96,17 @@ static inline struct page *page_pool_dev_alloc_pages(struct page_pool *pool) return page_pool_alloc_pages(pool, gfp); } +/** + * page_pool_dev_alloc_frag() - allocate a page fragment. + * @pool: pool from which to allocate + * @offset: offset to the allocated page + * @size: requested size + * + * Get a page fragment from the page allocator or page_pool caches. + * + * Return: + * Return allocated page fragment, otherwise return NULL. + */ static inline struct page *page_pool_dev_alloc_frag(struct page_pool *pool, unsigned int *offset, unsigned int size) @@ -111,6 +145,19 @@ static inline struct page *page_pool_alloc(struct page_pool *pool, return page; } +/** + * page_pool_dev_alloc() - allocate a page or a page fragment. + * @pool: pool from which to allocate + * @offset: offset to the allocated page + * @size: in as the requested size, out as the allocated size + * + * Get a page or a page fragment from the page allocator or page_pool caches + * depending on the requested size in order to allocate memory with least memory + * utilization and performance penalty. + * + * Return: + * Return allocated page or page fragment, otherwise return NULL. + */ static inline struct page *page_pool_dev_alloc(struct page_pool *pool, unsigned int *offset, unsigned int *size) @@ -134,6 +181,18 @@ static inline void *page_pool_alloc_va(struct page_pool *pool, return page_address(page) + offset; } +/** + * page_pool_dev_alloc_va() - allocate a page or a page fragment and return its + * va. + * @pool: pool from which to allocate + * @size: in as the requested size, out as the allocated size + * + * This is just a thin wrapper around the page_pool_alloc() API, and + * it returns va of the allocated page or page fragment. + * + * Return: + * Return the va for the allocated page or page fragment, otherwise return NULL. + */ static inline void *page_pool_dev_alloc_va(struct page_pool *pool, unsigned int *size) { @@ -281,6 +340,14 @@ static inline void page_pool_recycle_direct(struct page_pool *pool, #define PAGE_POOL_32BIT_ARCH_WITH_64BIT_DMA \ (sizeof(dma_addr_t) > sizeof(unsigned long)) +/** + * page_pool_free_va() - free a va into the page_pool + * @pool: pool from which va was allocated + * @va: va to be freed + * @allow_direct: freed by the consumer, allow lockless caching + * + * Free a va allocated from page_pool_allo_va(). + */ static inline void page_pool_free_va(struct page_pool *pool, void *va, bool allow_direct) { -- cgit v1.2.3 From 52c121f4bf27592530f3fedf123b89ed79397af8 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Mon, 23 Oct 2023 11:17:05 -0700 Subject: tools: ynl: add uns-admin-perm to genetlink legacy this flag maps to GENL_UNS_ADMIN_PERM and will be used by future specs. Acked-by: Paolo Abeni Signed-off-by: Davide Caratti Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231023-send-net-next-20231023-1-v2-1-16b1f701f900@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-legacy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 565bf615b501..d858711f3177 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -337,7 +337,7 @@ properties: description: Command flags. type: array items: - enum: [ admin-perm ] + enum: [ admin-perm, uns-admin-perm ] dont-validate: description: Kernel attribute validation flags. type: array -- cgit v1.2.3 From 0c63ad3795269849782ca24a084952206986d3bf Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Mon, 23 Oct 2023 11:17:06 -0700 Subject: tools: ynl-gen: add support for exact-len validation add support for 'exact-len' validation on netlink attributes. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/340 Acked-by: Matthieu Baerts Signed-off-by: Davide Caratti Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231023-send-net-next-20231023-1-v2-2-16b1f701f900@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 3 +++ Documentation/netlink/genetlink-legacy.yaml | 3 +++ Documentation/netlink/genetlink.yaml | 3 +++ Documentation/netlink/netlink-raw.yaml | 3 +++ tools/net/ynl/ynl-gen-c.py | 28 +++++++++++++++++----------- 5 files changed, 29 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index c72c8a428911..7ef2496d57c8 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -199,6 +199,9 @@ properties: max-len: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' + exact-len: + description: Exact length for a string or a binary attribute. + $ref: '#/$defs/len-or-define' sub-type: *attr-type display-hint: &display-hint description: | diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index d858711f3177..cd5ebe39b52c 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -242,6 +242,9 @@ properties: max-len: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' + exact-len: + description: Exact length for a string or a binary attribute. + $ref: '#/$defs/len-or-define' sub-type: *attr-type display-hint: *display-hint # Start genetlink-c diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 9ceb096b2df2..501ed2e6c8ef 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -172,6 +172,9 @@ properties: max-len: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' + exact-len: + description: Exact length for a string or a binary attribute. + $ref: '#/$defs/len-or-define' sub-type: *attr-type display-hint: &display-hint description: | diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index d976851b80f8..48db31f1d059 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -240,6 +240,9 @@ properties: max-len: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' + exact-len: + description: Exact length for a string or a binary attribute. + $ref: '#/$defs/len-or-define' sub-type: *attr-type display-hint: *display-hint # Start genetlink-c diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 8ae283b1a9bc..0fee68863db4 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -410,10 +410,13 @@ class TypeString(Type): return f'.type = YNL_PT_NUL_STR, ' def _attr_policy(self, policy): - mem = '{ .type = ' + policy - if 'max-len' in self.checks: - mem += ', .len = ' + str(self.get_limit('max-len')) - mem += ', }' + if 'exact-len' in self.checks: + mem = 'NLA_POLICY_EXACT_LEN(' + str(self.checks['exact-len']) + ')' + else: + mem = '{ .type = ' + policy + if 'max-len' in self.checks: + mem += ', .len = ' + str(self.get_limit('max-len')) + mem += ', }' return mem def attr_policy(self, cw): @@ -459,14 +462,17 @@ class TypeBinary(Type): return f'.type = YNL_PT_BINARY,' def _attr_policy(self, policy): - mem = '{ ' - if len(self.checks) == 1 and 'min-len' in self.checks: - mem += '.len = ' + str(self.get_limit('min-len')) - elif len(self.checks) == 0: - mem += '.type = NLA_BINARY' + if 'exact-len' in self.checks: + mem = 'NLA_POLICY_EXACT_LEN(' + str(self.checks['exact-len']) + ')' else: - raise Exception('One or more of binary type checks not implemented, yet') - mem += ', }' + mem = '{ ' + if len(self.checks) == 1 and 'min-len' in self.checks: + mem += '.len = ' + str(self.get_limit('min-len')) + elif len(self.checks) == 0: + mem += '.type = NLA_BINARY' + else: + raise Exception('One or more of binary type checks not implemented, yet') + mem += ', }' return mem def attr_put(self, ri, var): -- cgit v1.2.3 From bc8aeb2045e22fe8fc86b6b4a7d63f61c29734c9 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Mon, 23 Oct 2023 11:17:08 -0700 Subject: Documentation: netlink: add a YAML spec for mptcp it describes most of the current netlink interface (uAPI definitions, doit/dumpit operations and attributes) Link: https://github.com/multipath-tcp/mptcp_net-next/issues/340 Acked-by: Paolo Abeni Signed-off-by: Davide Caratti Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231023-send-net-next-20231023-1-v2-4-16b1f701f900@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/mptcp.yaml | 391 +++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 392 insertions(+) create mode 100644 Documentation/netlink/specs/mptcp.yaml (limited to 'Documentation') diff --git a/Documentation/netlink/specs/mptcp.yaml b/Documentation/netlink/specs/mptcp.yaml new file mode 100644 index 000000000000..ec5c454a87ea --- /dev/null +++ b/Documentation/netlink/specs/mptcp.yaml @@ -0,0 +1,391 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: mptcp_pm +protocol: genetlink-legacy +doc: Multipath TCP. + +c-family-name: mptcp-pm-name +c-version-name: mptcp-pm-ver +max-by-define: true +kernel-policy: per-op + +definitions: + - + type: enum + name: event-type + enum-name: mptcp-event-type + name-prefix: mptcp-event- + entries: + - + name: unspec + doc: unused event + - + name: created + doc: + token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport + A new MPTCP connection has been created. It is the good time to + allocate memory and send ADD_ADDR if needed. Depending on the + traffic-patterns it can take a long time until the + MPTCP_EVENT_ESTABLISHED is sent. + - + name: established + doc: + token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport + A MPTCP connection is established (can start new subflows). + - + name: closed + doc: + token + A MPTCP connection has stopped. + - + name: announced + value: 6 + doc: + token, rem_id, family, daddr4 | daddr6 [, dport] + A new address has been announced by the peer. + - + name: removed + doc: + token, rem_id + An address has been lost by the peer. + - + name: sub-established + value: 10 + doc: + token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, + dport, backup, if_idx [, error] + A new subflow has been established. 'error' should not be set. + - + name: sub-closed + doc: + token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, + dport, backup, if_idx [, error] + A subflow has been closed. An error (copy of sk_err) could be set if an + error has been detected for this subflow. + - + name: sub-priority + value: 13 + doc: + token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, + dport, backup, if_idx [, error] + The priority of a subflow has changed. 'error' should not be set. + - + name: listener-created + value: 15 + doc: + family, sport, saddr4 | saddr6 + A new PM listener is created. + - + name: listener-closed + doc: + family, sport, saddr4 | saddr6 + A PM listener is closed. + +attribute-sets: + - + name: address + name-prefix: mptcp-pm-addr-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: family + type: u16 + - + name: id + type: u8 + - + name: addr4 + type: u32 + byte-order: big-endian + - + name: addr6 + type: binary + checks: + exact-len: 16 + - + name: port + type: u16 + byte-order: big-endian + - + name: flags + type: u32 + - + name: if-idx + type: s32 + - + name: subflow-attribute + name-prefix: mptcp-subflow-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: token-rem + type: u32 + - + name: token-loc + type: u32 + - + name: relwrite-seq + type: u32 + - + name: map-seq + type: u64 + - + name: map-sfseq + type: u32 + - + name: ssn-offset + type: u32 + - + name: map-datalen + type: u16 + - + name: flags + type: u32 + - + name: id-rem + type: u8 + - + name: id-loc + type: u8 + - + name: pad + type: pad + - + name: endpoint + name-prefix: mptcp-pm-endpoint- + attributes: + - + name: addr + type: nest + nested-attributes: address + - + name: attr + name-prefix: mptcp-pm-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: addr + type: nest + nested-attributes: address + - + name: rcv-add-addrs + type: u32 + - + name: subflows + type: u32 + - + name: token + type: u32 + - + name: loc-id + type: u8 + - + name: addr-remote + type: nest + nested-attributes: address + - + name: event-attr + enum-name: mptcp-event-attr + name-prefix: mptcp-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: token + type: u32 + - + name: family + type: u16 + - + name: loc-id + type: u8 + - + name: rem-id + type: u8 + - + name: saddr4 + type: u32 + byte-order: big-endian + - + name: saddr6 + type: binary + checks: + min-len: 16 + - + name: daddr4 + type: u32 + byte-order: big-endian + - + name: daddr6 + type: binary + checks: + min-len: 16 + - + name: sport + type: u16 + byte-order: big-endian + - + name: dport + type: u16 + byte-order: big-endian + - + name: backup + type: u8 + - + name: error + type: u8 + - + name: flags + type: u16 + - + name: timeout + type: u32 + - + name: if_idx + type: u32 + - + name: reset-reason + type: u32 + - + name: reset-flags + type: u32 + - + name: server-side + type: u8 + +operations: + list: + - + name: unspec + doc: unused + value: 0 + - + name: add-addr + doc: Add endpoint + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &add-addr-attrs + request: + attributes: + - addr + - + name: del-addr + doc: Delete endpoint + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: *add-addr-attrs + - + name: get-addr + doc: Get endpoint information + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &get-addr-attrs + request: + attributes: + - addr + reply: + attributes: + - addr + dump: + reply: + attributes: + - addr + - + name: flush-addrs + doc: flush addresses + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: *add-addr-attrs + - + name: set-limits + doc: Set protocol limits + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &mptcp-limits + request: + attributes: + - rcv-add-addrs + - subflows + - + name: get-limits + doc: Get protocol limits + attribute-set: attr + dont-validate: [ strict ] + do: &mptcp-get-limits + request: + attributes: + - rcv-add-addrs + - subflows + reply: + attributes: + - rcv-add-addrs + - subflows + - + name: set-flags + doc: Change endpoint flags + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &mptcp-set-flags + request: + attributes: + - addr + - token + - addr-remote + - + name: announce + doc: announce new sf + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &announce-add + request: + attributes: + - addr + - token + - + name: remove + doc: announce removal + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: + request: + attributes: + - token + - loc-id + - + name: subflow-create + doc: todo + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &sf-create + request: + attributes: + - addr + - token + - addr-remote + - + name: subflow-destroy + doc: todo + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: *sf-create diff --git a/MAINTAINERS b/MAINTAINERS index 36815d2feb33..977de4624fe0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14960,6 +14960,7 @@ W: https://github.com/multipath-tcp/mptcp_net-next/wiki B: https://github.com/multipath-tcp/mptcp_net-next/issues T: git https://github.com/multipath-tcp/mptcp_net-next.git export-net T: git https://github.com/multipath-tcp/mptcp_net-next.git export +F: Documentation/netlink/specs/mptcp.yaml F: Documentation/networking/mptcp-sysctl.rst F: include/net/mptcp.h F: include/trace/events/mptcp.h -- cgit v1.2.3 From 6ca80638b90cec66547011ee1ef79e534589989a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 23 Oct 2023 11:17:28 -0700 Subject: net: dsa: Use conduit and user terms Use more inclusive terms throughout the DSA subsystem by moving away from "master" which is replaced by "conduit" and "slave" which is replaced by "user". No functional changes. Acked-by: Rob Herring Acked-by: Stephen Hemminger Reviewed-by: Vladimir Oltean Signed-off-by: Florian Fainelli Link: https://lore.kernel.org/r/20231023181729.1191071-2-florian.fainelli@broadcom.com Signed-off-by: Jakub Kicinski --- .../bindings/net/dsa/mediatek,mt7530.yaml | 2 +- Documentation/networking/dsa/b53.rst | 14 +- Documentation/networking/dsa/bcm_sf2.rst | 2 +- Documentation/networking/dsa/configuration.rst | 100 +- Documentation/networking/dsa/dsa.rst | 162 +- Documentation/networking/dsa/lan9303.rst | 2 +- Documentation/networking/dsa/sja1105.rst | 6 +- .../boot/dts/marvell/armada-3720-espressobin.dtsi | 2 +- drivers/net/dsa/b53/b53_common.c | 4 +- drivers/net/dsa/b53/b53_mdio.c | 2 +- drivers/net/dsa/bcm_sf2.c | 41 +- drivers/net/dsa/bcm_sf2.h | 2 +- drivers/net/dsa/bcm_sf2_cfp.c | 4 +- drivers/net/dsa/lan9303-core.c | 4 +- drivers/net/dsa/lantiq_gswip.c | 34 +- drivers/net/dsa/microchip/ksz9477.c | 6 +- drivers/net/dsa/microchip/ksz_common.c | 20 +- drivers/net/dsa/microchip/ksz_ptp.c | 2 +- drivers/net/dsa/mt7530.c | 18 +- drivers/net/dsa/mv88e6xxx/chip.c | 4 +- drivers/net/dsa/ocelot/felix.c | 68 +- drivers/net/dsa/ocelot/felix.h | 6 +- drivers/net/dsa/qca/qca8k-8xxx.c | 50 +- drivers/net/dsa/qca/qca8k-common.c | 4 +- drivers/net/dsa/qca/qca8k-leds.c | 6 +- drivers/net/dsa/qca/qca8k.h | 2 +- drivers/net/dsa/realtek/realtek-smi.c | 28 +- drivers/net/dsa/realtek/realtek.h | 2 +- drivers/net/dsa/realtek/rtl8365mb.c | 2 +- drivers/net/dsa/sja1105/sja1105_main.c | 4 +- drivers/net/dsa/xrs700x/xrs700x.c | 12 +- drivers/net/ethernet/broadcom/bcmsysport.c | 2 +- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- drivers/net/ethernet/mediatek/mtk_ppe_offload.c | 2 +- include/linux/dsa/sja1105.h | 2 +- include/net/dsa.h | 56 +- include/net/dsa_stubs.h | 22 +- net/core/dev_ioctl.c | 2 +- net/dsa/Makefile | 6 +- net/dsa/conduit.c | 475 +++ net/dsa/conduit.h | 22 + net/dsa/dsa.c | 224 +- net/dsa/dsa.h | 12 +- net/dsa/master.c | 475 --- net/dsa/master.h | 22 - net/dsa/netlink.c | 14 +- net/dsa/port.c | 124 +- net/dsa/port.h | 4 +- net/dsa/slave.c | 3727 -------------------- net/dsa/slave.h | 69 - net/dsa/switch.c | 20 +- net/dsa/switch.h | 8 +- net/dsa/tag.c | 10 +- net/dsa/tag.h | 26 +- net/dsa/tag_8021q.c | 22 +- net/dsa/tag_8021q.h | 2 +- net/dsa/tag_ar9331.c | 4 +- net/dsa/tag_brcm.c | 14 +- net/dsa/tag_dsa.c | 6 +- net/dsa/tag_gswip.c | 4 +- net/dsa/tag_hellcreek.c | 4 +- net/dsa/tag_ksz.c | 12 +- net/dsa/tag_lan9303.c | 4 +- net/dsa/tag_mtk.c | 4 +- net/dsa/tag_none.c | 6 +- net/dsa/tag_ocelot.c | 22 +- net/dsa/tag_ocelot_8021q.c | 12 +- net/dsa/tag_qca.c | 6 +- net/dsa/tag_rtl4_a.c | 6 +- net/dsa/tag_rtl8_4.c | 6 +- net/dsa/tag_rzn1_a5psw.c | 4 +- net/dsa/tag_sja1105.c | 30 +- net/dsa/tag_trailer.c | 4 +- net/dsa/tag_xrs700x.c | 4 +- net/dsa/user.c | 3727 ++++++++++++++++++++ net/dsa/user.h | 69 + 76 files changed, 4958 insertions(+), 4955 deletions(-) create mode 100644 net/dsa/conduit.c create mode 100644 net/dsa/conduit.h delete mode 100644 net/dsa/master.c delete mode 100644 net/dsa/master.h delete mode 100644 net/dsa/slave.c delete mode 100644 net/dsa/slave.h create mode 100644 net/dsa/user.c create mode 100644 net/dsa/user.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml index 5038818e9f2e..1c2444121e60 100644 --- a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml +++ b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml @@ -60,7 +60,7 @@ description: | Check out example 6. - - Port 5 can be wired to an external phy. Port 5 becomes a DSA slave. + - Port 5 can be wired to an external phy. Port 5 becomes a DSA user port. For the multi-chip module MT7530, the external phy must be wired TX to TX to gmac1 of the SoC for this to work. Ubiquiti EdgeRouter X SFP is wired diff --git a/Documentation/networking/dsa/b53.rst b/Documentation/networking/dsa/b53.rst index b41637cdb82b..1cb3ff648f88 100644 --- a/Documentation/networking/dsa/b53.rst +++ b/Documentation/networking/dsa/b53.rst @@ -52,7 +52,7 @@ VLAN programming would basically change the CPU port's default PVID and make it untagged, undesirable. In difference to the configuration described in :ref:`dsa-vlan-configuration` -the default VLAN 1 has to be removed from the slave interface configuration in +the default VLAN 1 has to be removed from the user interface configuration in single port and gateway configuration, while there is no need to add an extra VLAN configuration in the bridge showcase. @@ -68,13 +68,13 @@ By default packages are tagged with vid 1: ip link add link eth0 name eth0.2 type vlan id 2 ip link add link eth0 name eth0.3 type vlan id 3 - # The master interface needs to be brought up before the slave ports. + # The conduit interface needs to be brought up before the user ports. ip link set eth0 up ip link set eth0.1 up ip link set eth0.2 up ip link set eth0.3 up - # bring up the slave interfaces + # bring up the user interfaces ip link set wan up ip link set lan1 up ip link set lan2 up @@ -113,11 +113,11 @@ bridge # tag traffic on CPU port ip link add link eth0 name eth0.1 type vlan id 1 - # The master interface needs to be brought up before the slave ports. + # The conduit interface needs to be brought up before the user ports. ip link set eth0 up ip link set eth0.1 up - # bring up the slave interfaces + # bring up the user interfaces ip link set wan up ip link set lan1 up ip link set lan2 up @@ -149,12 +149,12 @@ gateway ip link add link eth0 name eth0.1 type vlan id 1 ip link add link eth0 name eth0.2 type vlan id 2 - # The master interface needs to be brought up before the slave ports. + # The conduit interface needs to be brought up before the user ports. ip link set eth0 up ip link set eth0.1 up ip link set eth0.2 up - # bring up the slave interfaces + # bring up the user interfaces ip link set wan up ip link set lan1 up ip link set lan2 up diff --git a/Documentation/networking/dsa/bcm_sf2.rst b/Documentation/networking/dsa/bcm_sf2.rst index dee234039e1e..d2571435696f 100644 --- a/Documentation/networking/dsa/bcm_sf2.rst +++ b/Documentation/networking/dsa/bcm_sf2.rst @@ -67,7 +67,7 @@ MDIO indirect accesses ---------------------- Due to a limitation in how Broadcom switches have been designed, external -Broadcom switches connected to a SF2 require the use of the DSA slave MDIO bus +Broadcom switches connected to a SF2 require the use of the DSA user MDIO bus in order to properly configure them. By default, the SF2 pseudo-PHY address, and an external switch pseudo-PHY address will both be snooping for incoming MDIO transactions, since they are at the same address (30), resulting in some kind of diff --git a/Documentation/networking/dsa/configuration.rst b/Documentation/networking/dsa/configuration.rst index d2934c40f0f1..e6c9719874b0 100644 --- a/Documentation/networking/dsa/configuration.rst +++ b/Documentation/networking/dsa/configuration.rst @@ -31,38 +31,38 @@ at https://www.kernel.org/pub/linux/utils/net/iproute2/ Through DSA every port of a switch is handled like a normal linux Ethernet interface. The CPU port is the switch port connected to an Ethernet MAC chip. -The corresponding linux Ethernet interface is called the master interface. -All other corresponding linux interfaces are called slave interfaces. +The corresponding linux Ethernet interface is called the conduit interface. +All other corresponding linux interfaces are called user interfaces. -The slave interfaces depend on the master interface being up in order for them -to send or receive traffic. Prior to kernel v5.12, the state of the master +The user interfaces depend on the conduit interface being up in order for them +to send or receive traffic. Prior to kernel v5.12, the state of the conduit interface had to be managed explicitly by the user. Starting with kernel v5.12, the behavior is as follows: -- when a DSA slave interface is brought up, the master interface is +- when a DSA user interface is brought up, the conduit interface is automatically brought up. -- when the master interface is brought down, all DSA slave interfaces are +- when the conduit interface is brought down, all DSA user interfaces are automatically brought down. In this documentation the following Ethernet interfaces are used: *eth0* - the master interface + the conduit interface *eth1* - another master interface + another conduit interface *lan1* - a slave interface + a user interface *lan2* - another slave interface + another user interface *lan3* - a third slave interface + a third user interface *wan* - A slave interface dedicated for upstream traffic + A user interface dedicated for upstream traffic Further Ethernet interfaces can be configured similar. The configured IPs and networks are: @@ -96,11 +96,11 @@ without using a VLAN based configuration. ip addr add 192.0.2.5/30 dev lan2 ip addr add 192.0.2.9/30 dev lan3 - # For kernels earlier than v5.12, the master interface needs to be - # brought up manually before the slave ports. + # For kernels earlier than v5.12, the conduit interface needs to be + # brought up manually before the user ports. ip link set eth0 up - # bring up the slave interfaces + # bring up the user interfaces ip link set lan1 up ip link set lan2 up ip link set lan3 up @@ -108,11 +108,11 @@ without using a VLAN based configuration. *bridge* .. code-block:: sh - # For kernels earlier than v5.12, the master interface needs to be - # brought up manually before the slave ports. + # For kernels earlier than v5.12, the conduit interface needs to be + # brought up manually before the user ports. ip link set eth0 up - # bring up the slave interfaces + # bring up the user interfaces ip link set lan1 up ip link set lan2 up ip link set lan3 up @@ -134,11 +134,11 @@ without using a VLAN based configuration. *gateway* .. code-block:: sh - # For kernels earlier than v5.12, the master interface needs to be - # brought up manually before the slave ports. + # For kernels earlier than v5.12, the conduit interface needs to be + # brought up manually before the user ports. ip link set eth0 up - # bring up the slave interfaces + # bring up the user interfaces ip link set wan up ip link set lan1 up ip link set lan2 up @@ -178,14 +178,14 @@ configuration. ip link add link eth0 name eth0.2 type vlan id 2 ip link add link eth0 name eth0.3 type vlan id 3 - # For kernels earlier than v5.12, the master interface needs to be - # brought up manually before the slave ports. + # For kernels earlier than v5.12, the conduit interface needs to be + # brought up manually before the user ports. ip link set eth0 up ip link set eth0.1 up ip link set eth0.2 up ip link set eth0.3 up - # bring up the slave interfaces + # bring up the user interfaces ip link set lan1 up ip link set lan2 up ip link set lan3 up @@ -221,12 +221,12 @@ configuration. # tag traffic on CPU port ip link add link eth0 name eth0.1 type vlan id 1 - # For kernels earlier than v5.12, the master interface needs to be - # brought up manually before the slave ports. + # For kernels earlier than v5.12, the conduit interface needs to be + # brought up manually before the user ports. ip link set eth0 up ip link set eth0.1 up - # bring up the slave interfaces + # bring up the user interfaces ip link set lan1 up ip link set lan2 up ip link set lan3 up @@ -261,13 +261,13 @@ configuration. ip link add link eth0 name eth0.1 type vlan id 1 ip link add link eth0 name eth0.2 type vlan id 2 - # For kernels earlier than v5.12, the master interface needs to be - # brought up manually before the slave ports. + # For kernels earlier than v5.12, the conduit interface needs to be + # brought up manually before the user ports. ip link set eth0 up ip link set eth0.1 up ip link set eth0.2 up - # bring up the slave interfaces + # bring up the user interfaces ip link set wan up ip link set lan1 up ip link set lan2 up @@ -380,22 +380,22 @@ affinities according to the available CPU ports. Secondly, it is possible to perform load balancing between CPU ports on a per packet basis, rather than statically assigning user ports to CPU ports. -This can be achieved by placing the DSA masters under a LAG interface (bonding +This can be achieved by placing the DSA conduits under a LAG interface (bonding or team). DSA monitors this operation and creates a mirror of this software LAG -on the CPU ports facing the physical DSA masters that constitute the LAG slave +on the CPU ports facing the physical DSA conduits that constitute the LAG slave devices. To make use of multiple CPU ports, the firmware (device tree) description of -the switch must mark all the links between CPU ports and their DSA masters +the switch must mark all the links between CPU ports and their DSA conduits using the ``ethernet`` reference/phandle. At startup, only a single CPU port -and DSA master will be used - the numerically first port from the firmware +and DSA conduit will be used - the numerically first port from the firmware description which has an ``ethernet`` property. It is up to the user to -configure the system for the switch to use other masters. +configure the system for the switch to use other conduits. DSA uses the ``rtnl_link_ops`` mechanism (with a "dsa" ``kind``) to allow -changing the DSA master of a user port. The ``IFLA_DSA_MASTER`` u32 netlink -attribute contains the ifindex of the master device that handles each slave -device. The DSA master must be a valid candidate based on firmware node +changing the DSA conduit of a user port. The ``IFLA_DSA_MASTER`` u32 netlink +attribute contains the ifindex of the conduit device that handles each user +device. The DSA conduit must be a valid candidate based on firmware node information, or a LAG interface which contains only slaves which are valid candidates. @@ -403,7 +403,7 @@ Using iproute2, the following manipulations are possible: .. code-block:: sh - # See the DSA master in current use + # See the DSA conduit in current use ip -d link show dev swp0 (...) dsa master eth0 @@ -414,7 +414,7 @@ Using iproute2, the following manipulations are possible: ip link set swp2 type dsa master eth1 ip link set swp3 type dsa master eth0 - # CPU ports in LAG, using explicit assignment of the DSA master + # CPU ports in LAG, using explicit assignment of the DSA conduit ip link add bond0 type bond mode balance-xor && ip link set bond0 up ip link set eth1 down && ip link set eth1 master bond0 ip link set swp0 type dsa master bond0 @@ -426,7 +426,7 @@ Using iproute2, the following manipulations are possible: (...) dsa master bond0 - # CPU ports in LAG, relying on implicit migration of the DSA master + # CPU ports in LAG, relying on implicit migration of the DSA conduit ip link add bond0 type bond mode balance-xor && ip link set bond0 up ip link set eth0 down && ip link set eth0 master bond0 ip link set eth1 down && ip link set eth1 master bond0 @@ -436,23 +436,23 @@ Using iproute2, the following manipulations are possible: Notice that in the case of CPU ports under a LAG, the use of the ``IFLA_DSA_MASTER`` netlink attribute is not strictly needed, but rather, DSA -reacts to the ``IFLA_MASTER`` attribute change of its present master (``eth0``) +reacts to the ``IFLA_MASTER`` attribute change of its present conduit (``eth0``) and migrates all user ports to the new upper of ``eth0``, ``bond0``. Similarly, when ``bond0`` is destroyed using ``RTM_DELLINK``, DSA migrates the user ports -that were assigned to this interface to the first physical DSA master which is +that were assigned to this interface to the first physical DSA conduit which is eligible, based on the firmware description (it effectively reverts to the startup configuration). In a setup with more than 2 physical CPU ports, it is therefore possible to mix -static user to CPU port assignment with LAG between DSA masters. It is not -possible to statically assign a user port towards a DSA master that has any -upper interfaces (this includes LAG devices - the master must always be the LAG +static user to CPU port assignment with LAG between DSA conduits. It is not +possible to statically assign a user port towards a DSA conduit that has any +upper interfaces (this includes LAG devices - the conduit must always be the LAG in this case). -Live changing of the DSA master (and thus CPU port) affinity of a user port is +Live changing of the DSA conduit (and thus CPU port) affinity of a user port is permitted, in order to allow dynamic redistribution in response to traffic. -Physical DSA masters are allowed to join and leave at any time a LAG interface -used as a DSA master; however, DSA will reject a LAG interface as a valid -candidate for being a DSA master unless it has at least one physical DSA master +Physical DSA conduits are allowed to join and leave at any time a LAG interface +used as a DSA conduit; however, DSA will reject a LAG interface as a valid +candidate for being a DSA conduit unless it has at least one physical DSA conduit as a slave device. diff --git a/Documentation/networking/dsa/dsa.rst b/Documentation/networking/dsa/dsa.rst index a94ddf83348a..7b2e69cd7ef0 100644 --- a/Documentation/networking/dsa/dsa.rst +++ b/Documentation/networking/dsa/dsa.rst @@ -25,7 +25,7 @@ presence of a management port connected to an Ethernet controller capable of receiving Ethernet frames from the switch. This is a very common setup for all kinds of Ethernet switches found in Small Home and Office products: routers, gateways, or even top-of-rack switches. This host Ethernet controller will -be later referred to as "master" and "cpu" in DSA terminology and code. +be later referred to as "conduit" and "cpu" in DSA terminology and code. The D in DSA stands for Distributed, because the subsystem has been designed with the ability to configure and manage cascaded switches on top of each other @@ -35,7 +35,7 @@ of multiple switches connected to each other is called a "switch tree". For each front-panel port, DSA creates specialized network devices which are used as controlling and data-flowing endpoints for use by the Linux networking -stack. These specialized network interfaces are referred to as "slave" network +stack. These specialized network interfaces are referred to as "user" network interfaces in DSA terminology and code. The ideal case for using DSA is when an Ethernet switch supports a "switch tag" @@ -56,12 +56,16 @@ Note that DSA does not currently create network interfaces for the "cpu" and - the "cpu" port is the Ethernet switch facing side of the management controller, and as such, would create a duplication of feature, since you - would get two interfaces for the same conduit: master netdev, and "cpu" netdev + would get two interfaces for the same conduit: conduit netdev, and "cpu" netdev - the "dsa" port(s) are just conduits between two or more switches, and as such cannot really be used as proper network interfaces either, only the downstream, or the top-most upstream interface makes sense with that model +NB: for the past 15 years, the DSA subsystem had been making use of the terms +"master" (rather than "conduit") and "slave" (rather than "user"). These terms +have been removed from the DSA codebase and phased out of the uAPI. + Switch tagging protocols ------------------------ @@ -80,14 +84,14 @@ methods of the ``struct dsa_device_ops`` structure, which are detailed below. Tagging protocols generally fall in one of three categories: 1. The switch-specific frame header is located before the Ethernet header, - shifting to the right (from the perspective of the DSA master's frame + shifting to the right (from the perspective of the DSA conduit's frame parser) the MAC DA, MAC SA, EtherType and the entire L2 payload. 2. The switch-specific frame header is located before the EtherType, keeping - the MAC DA and MAC SA in place from the DSA master's perspective, but + the MAC DA and MAC SA in place from the DSA conduit's perspective, but shifting the 'real' EtherType and L2 payload to the right. 3. The switch-specific frame header is located at the tail of the packet, keeping all frame headers in place and not altering the view of the packet - that the DSA master's frame parser has. + that the DSA conduit's frame parser has. A tagging protocol may tag all packets with switch tags of the same length, or the tag length might vary (for example packets with PTP timestamps might @@ -95,7 +99,7 @@ require an extended switch tag, or there might be one tag length on TX and a different one on RX). Either way, the tagging protocol driver must populate the ``struct dsa_device_ops::needed_headroom`` and/or ``struct dsa_device_ops::needed_tailroom`` with the length in octets of the longest switch frame header/trailer. The DSA -framework will automatically adjust the MTU of the master interface to +framework will automatically adjust the MTU of the conduit interface to accommodate for this extra size in order for DSA user ports to support the standard MTU (L2 payload length) of 1500 octets. The ``needed_headroom`` and ``needed_tailroom`` properties are also used to request from the network stack, @@ -140,18 +144,18 @@ adding or removing the ``ETH_P_EDSA`` EtherType and some padding octets). It is possible to construct cascaded setups of DSA switches even if their tagging protocols are not compatible with one another. In this case, there are no DSA links in this fabric, and each switch constitutes a disjoint DSA switch -tree. The DSA links are viewed as simply a pair of a DSA master (the out-facing +tree. The DSA links are viewed as simply a pair of a DSA conduit (the out-facing port of the upstream DSA switch) and a CPU port (the in-facing port of the downstream DSA switch). The tagging protocol of the attached DSA switch tree can be viewed through the -``dsa/tagging`` sysfs attribute of the DSA master:: +``dsa/tagging`` sysfs attribute of the DSA conduit:: cat /sys/class/net/eth0/dsa/tagging If the hardware and driver are capable, the tagging protocol of the DSA switch tree can be changed at runtime. This is done by writing the new tagging -protocol name to the same sysfs device attribute as above (the DSA master and +protocol name to the same sysfs device attribute as above (the DSA conduit and all attached switch ports must be down while doing this). It is desirable that all tagging protocols are testable with the ``dsa_loop`` @@ -159,7 +163,7 @@ mockup driver, which can be attached to any network interface. The goal is that any network interface should be capable of transmitting the same packet in the same way, and the tagger should decode the same received packet in the same way regardless of the driver used for the switch control path, and the driver used -for the DSA master. +for the DSA conduit. The transmission of a packet goes through the tagger's ``xmit`` function. The passed ``struct sk_buff *skb`` has ``skb->data`` pointing at @@ -183,44 +187,44 @@ virtual DSA user network interface corresponding to the physical front-facing switch port that the packet was received on. Since tagging protocols in category 1 and 2 break software (and most often also -hardware) packet dissection on the DSA master, features such as RPS (Receive -Packet Steering) on the DSA master would be broken. The DSA framework deals +hardware) packet dissection on the DSA conduit, features such as RPS (Receive +Packet Steering) on the DSA conduit would be broken. The DSA framework deals with this by hooking into the flow dissector and shifting the offset at which -the IP header is to be found in the tagged frame as seen by the DSA master. +the IP header is to be found in the tagged frame as seen by the DSA conduit. This behavior is automatic based on the ``overhead`` value of the tagging protocol. If not all packets are of equal size, the tagger can implement the ``flow_dissect`` method of the ``struct dsa_device_ops`` and override this default behavior by specifying the correct offset incurred by each individual RX packet. Tail taggers do not cause issues to the flow dissector. -Checksum offload should work with category 1 and 2 taggers when the DSA master +Checksum offload should work with category 1 and 2 taggers when the DSA conduit driver declares NETIF_F_HW_CSUM in vlan_features and looks at csum_start and csum_offset. For those cases, DSA will shift the checksum start and offset by -the tag size. If the DSA master driver still uses the legacy NETIF_F_IP_CSUM +the tag size. If the DSA conduit driver still uses the legacy NETIF_F_IP_CSUM or NETIF_F_IPV6_CSUM in vlan_features, the offload might only work if the offload hardware already expects that specific tag (perhaps due to matching -vendors). DSA slaves inherit those flags from the master port, and it is up to +vendors). DSA user ports inherit those flags from the conduit, and it is up to the driver to correctly fall back to software checksum when the IP header is not where the hardware expects. If that check is ineffective, the packets might go to the network without a proper checksum (the checksum field will have the pseudo IP header sum). For category 3, when the offload hardware does not already expect the switch tag in use, the checksum must be calculated before any -tag is inserted (i.e. inside the tagger). Otherwise, the DSA master would +tag is inserted (i.e. inside the tagger). Otherwise, the DSA conduit would include the tail tag in the (software or hardware) checksum calculation. Then, when the tag gets stripped by the switch during transmission, it will leave an incorrect IP checksum in place. Due to various reasons (most common being category 1 taggers being associated -with DSA-unaware masters, mangling what the master perceives as MAC DA), the -tagging protocol may require the DSA master to operate in promiscuous mode, to +with DSA-unaware conduits, mangling what the conduit perceives as MAC DA), the +tagging protocol may require the DSA conduit to operate in promiscuous mode, to receive all frames regardless of the value of the MAC DA. This can be done by -setting the ``promisc_on_master`` property of the ``struct dsa_device_ops``. -Note that this assumes a DSA-unaware master driver, which is the norm. +setting the ``promisc_on_conduit`` property of the ``struct dsa_device_ops``. +Note that this assumes a DSA-unaware conduit driver, which is the norm. -Master network devices ----------------------- +Conduit network devices +----------------------- -Master network devices are regular, unmodified Linux network device drivers for +Conduit network devices are regular, unmodified Linux network device drivers for the CPU/management Ethernet interface. Such a driver might occasionally need to know whether DSA is enabled (e.g.: to enable/disable specific offload features), but the DSA subsystem has been proven to work with industry standard drivers: @@ -232,14 +236,14 @@ Ethernet switch. Networking stack hooks ---------------------- -When a master netdev is used with DSA, a small hook is placed in the +When a conduit netdev is used with DSA, a small hook is placed in the networking stack is in order to have the DSA subsystem process the Ethernet switch specific tagging protocol. DSA accomplishes this by registering a specific (and fake) Ethernet type (later becoming ``skb->protocol``) with the networking stack, this is also known as a ``ptype`` or ``packet_type``. A typical Ethernet Frame receive sequence looks like this: -Master network device (e.g.: e1000e): +Conduit network device (e.g.: e1000e): 1. Receive interrupt fires: @@ -269,16 +273,16 @@ Master network device (e.g.: e1000e): - inspect and strip switch tag protocol to determine originating port - locate per-port network device - - invoke ``eth_type_trans()`` with the DSA slave network device + - invoke ``eth_type_trans()`` with the DSA user network device - invoked ``netif_receive_skb()`` -Past this point, the DSA slave network devices get delivered regular Ethernet +Past this point, the DSA user network devices get delivered regular Ethernet frames that can be processed by the networking stack. -Slave network devices ---------------------- +User network devices +-------------------- -Slave network devices created by DSA are stacked on top of their master network +User network devices created by DSA are stacked on top of their conduit network device, each of these network interfaces will be responsible for being a controlling and data-flowing end-point for each front-panel port of the switch. These interfaces are specialized in order to: @@ -289,31 +293,31 @@ These interfaces are specialized in order to: Wake-on-LAN, register dumps... - manage external/internal PHY: link, auto-negotiation, etc. -These slave network devices have custom net_device_ops and ethtool_ops function +These user network devices have custom net_device_ops and ethtool_ops function pointers which allow DSA to introduce a level of layering between the networking stack/ethtool and the switch driver implementation. -Upon frame transmission from these slave network devices, DSA will look up which +Upon frame transmission from these user network devices, DSA will look up which switch tagging protocol is currently registered with these network devices and invoke a specific transmit routine which takes care of adding the relevant switch tag in the Ethernet frames. -These frames are then queued for transmission using the master network device +These frames are then queued for transmission using the conduit network device ``ndo_start_xmit()`` function. Since they contain the appropriate switch tag, the Ethernet switch will be able to process these incoming frames from the management interface and deliver them to the physical switch port. When using multiple CPU ports, it is possible to stack a LAG (bonding/team) -device between the DSA slave devices and the physical DSA masters. The LAG -device is thus also a DSA master, but the LAG slave devices continue to be DSA -masters as well (just with no user port assigned to them; this is needed for -recovery in case the LAG DSA master disappears). Thus, the data path of the LAG -DSA master is used asymmetrically. On RX, the ``ETH_P_XDSA`` handler, which -calls ``dsa_switch_rcv()``, is invoked early (on the physical DSA master; -LAG slave). Therefore, the RX data path of the LAG DSA master is not used. -On the other hand, TX takes place linearly: ``dsa_slave_xmit`` calls -``dsa_enqueue_skb``, which calls ``dev_queue_xmit`` towards the LAG DSA master. -The latter calls ``dev_queue_xmit`` towards one physical DSA master or the +device between the DSA user devices and the physical DSA conduits. The LAG +device is thus also a DSA conduit, but the LAG slave devices continue to be DSA +conduits as well (just with no user port assigned to them; this is needed for +recovery in case the LAG DSA conduit disappears). Thus, the data path of the LAG +DSA conduit is used asymmetrically. On RX, the ``ETH_P_XDSA`` handler, which +calls ``dsa_switch_rcv()``, is invoked early (on the physical DSA conduit; +LAG slave). Therefore, the RX data path of the LAG DSA conduit is not used. +On the other hand, TX takes place linearly: ``dsa_user_xmit`` calls +``dsa_enqueue_skb``, which calls ``dev_queue_xmit`` towards the LAG DSA conduit. +The latter calls ``dev_queue_xmit`` towards one physical DSA conduit or the other, and in both cases, the packet exits the system through a hardware path towards the switch. @@ -352,11 +356,11 @@ perspective:: || swp0 | | swp1 | | swp2 | | swp3 || ++------+-+------+-+------+-+------++ -Slave MDIO bus --------------- +User MDIO bus +------------- -In order to be able to read to/from a switch PHY built into it, DSA creates a -slave MDIO bus which allows a specific switch driver to divert and intercept +In order to be able to read to/from a switch PHY built into it, DSA creates an +user MDIO bus which allows a specific switch driver to divert and intercept MDIO reads/writes towards specific PHY addresses. In most MDIO-connected switches, these functions would utilize direct or indirect PHY addressing mode to return standard MII registers from the switch builtin PHYs, allowing the PHY @@ -364,7 +368,7 @@ library and/or to return link status, link partner pages, auto-negotiation results, etc. For Ethernet switches which have both external and internal MDIO buses, the -slave MII bus can be utilized to mux/demux MDIO reads and writes towards either +user MII bus can be utilized to mux/demux MDIO reads and writes towards either internal or external MDIO devices this switch might be connected to: internal PHYs, external PHYs, or even external switches. @@ -381,10 +385,10 @@ DSA data structures are defined in ``include/net/dsa.h`` as well as - ``dsa_platform_data``: platform device configuration data which can reference a collection of dsa_chip_data structures if multiple switches are cascaded, - the master network device this switch tree is attached to needs to be + the conduit network device this switch tree is attached to needs to be referenced -- ``dsa_switch_tree``: structure assigned to the master network device under +- ``dsa_switch_tree``: structure assigned to the conduit network device under ``dsa_ptr``, this structure references a dsa_platform_data structure as well as the tagging protocol supported by the switch tree, and which receive/transmit function hooks should be invoked, information about the directly attached @@ -392,7 +396,7 @@ DSA data structures are defined in ``include/net/dsa.h`` as well as referenced to address individual switches in the tree. - ``dsa_switch``: structure describing a switch device in the tree, referencing - a ``dsa_switch_tree`` as a backpointer, slave network devices, master network + a ``dsa_switch_tree`` as a backpointer, user network devices, conduit network device, and a reference to the backing``dsa_switch_ops`` - ``dsa_switch_ops``: structure referencing function pointers, see below for a @@ -404,7 +408,7 @@ Design limitations Lack of CPU/DSA network devices ------------------------------- -DSA does not currently create slave network devices for the CPU or DSA ports, as +DSA does not currently create user network devices for the CPU or DSA ports, as described before. This might be an issue in the following cases: - inability to fetch switch CPU port statistics counters using ethtool, which @@ -419,7 +423,7 @@ described before. This might be an issue in the following cases: Common pitfalls using DSA setups -------------------------------- -Once a master network device is configured to use DSA (dev->dsa_ptr becomes +Once a conduit network device is configured to use DSA (dev->dsa_ptr becomes non-NULL), and the switch behind it expects a tagging protocol, this network interface can only exclusively be used as a conduit interface. Sending packets directly through this interface (e.g.: opening a socket using this interface) @@ -440,7 +444,7 @@ DSA currently leverages the following subsystems: MDIO/PHY library ---------------- -Slave network devices exposed by DSA may or may not be interfacing with PHY +User network devices exposed by DSA may or may not be interfacing with PHY devices (``struct phy_device`` as defined in ``include/linux/phy.h)``, but the DSA subsystem deals with all possible combinations: @@ -450,7 +454,7 @@ subsystem deals with all possible combinations: - special, non-autonegotiated or non MDIO-managed PHY devices: SFPs, MoCA; a.k.a fixed PHYs -The PHY configuration is done by the ``dsa_slave_phy_setup()`` function and the +The PHY configuration is done by the ``dsa_user_phy_setup()`` function and the logic basically looks like this: - if Device Tree is used, the PHY device is looked up using the standard @@ -463,7 +467,7 @@ logic basically looks like this: and connected transparently using the special fixed MDIO bus driver - finally, if the PHY is built into the switch, as is very common with - standalone switch packages, the PHY is probed using the slave MII bus created + standalone switch packages, the PHY is probed using the user MII bus created by DSA @@ -472,7 +476,7 @@ SWITCHDEV DSA directly utilizes SWITCHDEV when interfacing with the bridge layer, and more specifically with its VLAN filtering portion when configuring VLANs on top -of per-port slave network devices. As of today, the only SWITCHDEV objects +of per-port user network devices. As of today, the only SWITCHDEV objects supported by DSA are the FDB and VLAN objects. Devlink @@ -589,8 +593,8 @@ is torn down when the first switch unregisters. It is mandatory for DSA switch drivers to implement the ``shutdown()`` callback of their respective bus, and call ``dsa_switch_shutdown()`` from it (a minimal version of the full teardown performed by ``dsa_unregister_switch()``). -The reason is that DSA keeps a reference on the master net device, and if the -driver for the master device decides to unbind on shutdown, DSA's reference +The reason is that DSA keeps a reference on the conduit net device, and if the +driver for the conduit device decides to unbind on shutdown, DSA's reference will block that operation from finalizing. Either ``dsa_switch_shutdown()`` or ``dsa_unregister_switch()`` must be called, @@ -615,7 +619,7 @@ Switch configuration tag formats. - ``change_tag_protocol``: when the default tagging protocol has compatibility - problems with the master or other issues, the driver may support changing it + problems with the conduit or other issues, the driver may support changing it at runtime, either through a device tree property or through sysfs. In that case, further calls to ``get_tag_protocol`` should report the protocol in current use. @@ -643,22 +647,22 @@ Switch configuration PHY cannot be found. In this case, probing of the DSA switch continues without that particular port. -- ``port_change_master``: method through which the affinity (association used +- ``port_change_conduit``: method through which the affinity (association used for traffic termination purposes) between a user port and a CPU port can be changed. By default all user ports from a tree are assigned to the first available CPU port that makes sense for them (most of the times this means the user ports of a tree are all assigned to the same CPU port, except for H topologies as described in commit 2c0b03258b8b). The ``port`` argument - represents the index of the user port, and the ``master`` argument represents - the new DSA master ``net_device``. The CPU port associated with the new - master can be retrieved by looking at ``struct dsa_port *cpu_dp = - master->dsa_ptr``. Additionally, the master can also be a LAG device where - all the slave devices are physical DSA masters. LAG DSA masters also have a - valid ``master->dsa_ptr`` pointer, however this is not unique, but rather a - duplicate of the first physical DSA master's (LAG slave) ``dsa_ptr``. In case - of a LAG DSA master, a further call to ``port_lag_join`` will be emitted + represents the index of the user port, and the ``conduit`` argument represents + the new DSA conduit ``net_device``. The CPU port associated with the new + conduit can be retrieved by looking at ``struct dsa_port *cpu_dp = + conduit->dsa_ptr``. Additionally, the conduit can also be a LAG device where + all the slave devices are physical DSA conduits. LAG DSA also have a + valid ``conduit->dsa_ptr`` pointer, however this is not unique, but rather a + duplicate of the first physical DSA conduit's (LAG slave) ``dsa_ptr``. In case + of a LAG DSA conduit, a further call to ``port_lag_join`` will be emitted separately for the physical CPU ports associated with the physical DSA - masters, requesting them to create a hardware LAG associated with the LAG + conduits, requesting them to create a hardware LAG associated with the LAG interface. PHY devices and link management @@ -670,16 +674,16 @@ PHY devices and link management should return a 32-bit bitmask of "flags" that is private between the switch driver and the Ethernet PHY driver in ``drivers/net/phy/\*``. -- ``phy_read``: Function invoked by the DSA slave MDIO bus when attempting to read +- ``phy_read``: Function invoked by the DSA user MDIO bus when attempting to read the switch port MDIO registers. If unavailable, return 0xffff for each read. For builtin switch Ethernet PHYs, this function should allow reading the link status, auto-negotiation results, link partner pages, etc. -- ``phy_write``: Function invoked by the DSA slave MDIO bus when attempting to write +- ``phy_write``: Function invoked by the DSA user MDIO bus when attempting to write to the switch port MDIO registers. If unavailable return a negative error code. -- ``adjust_link``: Function invoked by the PHY library when a slave network device +- ``adjust_link``: Function invoked by the PHY library when a user network device is attached to a PHY device. This function is responsible for appropriately configuring the switch port link parameters: speed, duplex, pause based on what the ``phy_device`` is providing. @@ -698,14 +702,14 @@ Ethtool operations typically return statistics strings, private flags strings, etc. - ``get_ethtool_stats``: ethtool function used to query per-port statistics and - return their values. DSA overlays slave network devices general statistics: + return their values. DSA overlays user network devices general statistics: RX/TX counters from the network device, with switch driver specific statistics per port - ``get_sset_count``: ethtool function used to query the number of statistics items - ``get_wol``: ethtool function used to obtain Wake-on-LAN settings per-port, this - function may for certain implementations also query the master network device + function may for certain implementations also query the conduit network device Wake-on-LAN settings if this interface needs to participate in Wake-on-LAN - ``set_wol``: ethtool function used to configure Wake-on-LAN settings per-port, @@ -747,13 +751,13 @@ Power management should resume all Ethernet switch activities and re-configure the switch to be in a fully active state -- ``port_enable``: function invoked by the DSA slave network device ndo_open +- ``port_enable``: function invoked by the DSA user network device ndo_open function when a port is administratively brought up, this function should fully enable a given switch port. DSA takes care of marking the port with ``BR_STATE_BLOCKING`` if the port is a bridge member, or ``BR_STATE_FORWARDING`` if it was not, and propagating these changes down to the hardware -- ``port_disable``: function invoked by the DSA slave network device ndo_close +- ``port_disable``: function invoked by the DSA user network device ndo_close function when a port is administratively brought down, this function should fully disable a given switch port. DSA takes care of marking the port with ``BR_STATE_DISABLED`` and propagating changes to the hardware if this port is diff --git a/Documentation/networking/dsa/lan9303.rst b/Documentation/networking/dsa/lan9303.rst index e3c820db28ad..ab81b4e0139e 100644 --- a/Documentation/networking/dsa/lan9303.rst +++ b/Documentation/networking/dsa/lan9303.rst @@ -4,7 +4,7 @@ LAN9303 Ethernet switch driver The LAN9303 is a three port 10/100 Mbps ethernet switch with integrated phys for the two external ethernet ports. The third port is an RMII/MII interface to a -host master network interface (e.g. fixed link). +host conduit network interface (e.g. fixed link). Driver details diff --git a/Documentation/networking/dsa/sja1105.rst b/Documentation/networking/dsa/sja1105.rst index e0219c1452ab..8ab60eef07d4 100644 --- a/Documentation/networking/dsa/sja1105.rst +++ b/Documentation/networking/dsa/sja1105.rst @@ -79,7 +79,7 @@ The hardware tags all traffic internally with a port-based VLAN (pvid), or it decodes the VLAN information from the 802.1Q tag. Advanced VLAN classification is not possible. Once attributed a VLAN tag, frames are checked against the port's membership rules and dropped at ingress if they don't match any VLAN. -This behavior is available when switch ports are enslaved to a bridge with +This behavior is available when switch ports join a bridge with ``vlan_filtering 1``. Normally the hardware is not configurable with respect to VLAN awareness, but @@ -122,7 +122,7 @@ on egress. Using ``vlan_filtering=1``, the behavior is the other way around: offloaded flows can be steered to TX queues based on the VLAN PCP, but the DSA net devices are no longer able to do that. To inject frames into a hardware TX queue with VLAN awareness active, it is necessary to create a VLAN -sub-interface on the DSA master port, and send normal (0x8100) VLAN-tagged +sub-interface on the DSA conduit port, and send normal (0x8100) VLAN-tagged towards the switch, with the VLAN PCP bits set appropriately. Management traffic (having DMAC 01-80-C2-xx-xx-xx or 01-19-1B-xx-xx-xx) is the @@ -389,7 +389,7 @@ MDIO bus and PHY management The SJA1105 does not have an MDIO bus and does not perform in-band AN either. Therefore there is no link state notification coming from the switch device. A board would need to hook up the PHYs connected to the switch to any other -MDIO bus available to Linux within the system (e.g. to the DSA master's MDIO +MDIO bus available to Linux within the system (e.g. to the DSA conduit's MDIO bus). Link state management then works by the driver manually keeping in sync (over SPI commands) the MAC link speed with the settings negotiated by the PHY. diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi index 5fc613d24151..49cbdb55b4b3 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi @@ -13,7 +13,7 @@ / { aliases { ethernet0 = ð0; - /* for dsa slave device */ + /* for DSA user port device */ ethernet1 = &switch0port1; ethernet2 = &switch0port2; ethernet3 = &switch0port3; diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 4e27dc913cf7..0d628b35fd5c 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -757,7 +757,7 @@ int b53_configure_vlan(struct dsa_switch *ds) /* Create an untagged VLAN entry for the default PVID in case * CONFIG_VLAN_8021Q is disabled and there are no calls to - * dsa_slave_vlan_rx_add_vid() to create the default VLAN + * dsa_user_vlan_rx_add_vid() to create the default VLAN * entry. Do this only when the tagging protocol is not * DSA_TAG_PROTO_NONE */ @@ -958,7 +958,7 @@ static struct phy_device *b53_get_phy_device(struct dsa_switch *ds, int port) return NULL; } - return mdiobus_get_phy(ds->slave_mii_bus, port); + return mdiobus_get_phy(ds->user_mii_bus, port); } void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index 4d55d8d18376..897e5e8b3d69 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -329,7 +329,7 @@ static int b53_mdio_probe(struct mdio_device *mdiodev) * layer setup */ if (of_machine_is_compatible("brcm,bcm7445d0") && - strcmp(mdiodev->bus->name, "sf2 slave mii")) + strcmp(mdiodev->bus->name, "sf2 user mii")) return -EPROBE_DEFER; dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus); diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 326937e91f52..cadee5505c29 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -623,19 +623,19 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds) priv->master_mii_dn = dn; - priv->slave_mii_bus = mdiobus_alloc(); - if (!priv->slave_mii_bus) { + priv->user_mii_bus = mdiobus_alloc(); + if (!priv->user_mii_bus) { err = -ENOMEM; goto err_put_master_mii_bus_dev; } - priv->slave_mii_bus->priv = priv; - priv->slave_mii_bus->name = "sf2 slave mii"; - priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read; - priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write; - snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d", + priv->user_mii_bus->priv = priv; + priv->user_mii_bus->name = "sf2 user mii"; + priv->user_mii_bus->read = bcm_sf2_sw_mdio_read; + priv->user_mii_bus->write = bcm_sf2_sw_mdio_write; + snprintf(priv->user_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d", index++); - priv->slave_mii_bus->dev.of_node = dn; + priv->user_mii_bus->dev.of_node = dn; /* Include the pseudo-PHY address to divert reads towards our * workaround. This is only required for 7445D0, since 7445E0 @@ -653,9 +653,9 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds) priv->indir_phy_mask = 0; ds->phys_mii_mask = priv->indir_phy_mask; - ds->slave_mii_bus = priv->slave_mii_bus; - priv->slave_mii_bus->parent = ds->dev->parent; - priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask; + ds->user_mii_bus = priv->user_mii_bus; + priv->user_mii_bus->parent = ds->dev->parent; + priv->user_mii_bus->phy_mask = ~priv->indir_phy_mask; /* We need to make sure that of_phy_connect() will not work by * removing the 'phandle' and 'linux,phandle' properties and @@ -682,14 +682,14 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds) phy_device_remove(phydev); } - err = mdiobus_register(priv->slave_mii_bus); + err = mdiobus_register(priv->user_mii_bus); if (err && dn) - goto err_free_slave_mii_bus; + goto err_free_user_mii_bus; return 0; -err_free_slave_mii_bus: - mdiobus_free(priv->slave_mii_bus); +err_free_user_mii_bus: + mdiobus_free(priv->user_mii_bus); err_put_master_mii_bus_dev: put_device(&priv->master_mii_bus->dev); err_of_node_put: @@ -699,10 +699,9 @@ err_of_node_put: static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv) { - mdiobus_unregister(priv->slave_mii_bus); - mdiobus_free(priv->slave_mii_bus); + mdiobus_unregister(priv->user_mii_bus); + mdiobus_free(priv->user_mii_bus); put_device(&priv->master_mii_bus->dev); - of_node_put(priv->master_mii_dn); } static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port) @@ -915,7 +914,7 @@ static void bcm_sf2_sw_fixed_state(struct dsa_switch *ds, int port, * state machine and make it go in PHY_FORCING state instead. */ if (!status->link) - netif_carrier_off(dsa_to_port(ds, port)->slave); + netif_carrier_off(dsa_to_port(ds, port)->user); status->duplex = DUPLEX_FULL; } else { status->link = true; @@ -989,7 +988,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); + struct net_device *p = dsa_port_to_conduit(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_wolinfo pwol = { }; @@ -1013,7 +1012,7 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); + struct net_device *p = dsa_port_to_conduit(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; struct ethtool_wolinfo pwol = { }; diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h index 00afc94ce522..424f896b5a6f 100644 --- a/drivers/net/dsa/bcm_sf2.h +++ b/drivers/net/dsa/bcm_sf2.h @@ -108,7 +108,7 @@ struct bcm_sf2_priv { /* Master and slave MDIO bus controller */ unsigned int indir_phy_mask; struct device_node *master_mii_dn; - struct mii_bus *slave_mii_bus; + struct mii_bus *user_mii_bus; struct mii_bus *master_mii_bus; /* Bitmask of ports needing BRCM tags */ diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index c4010b7bf089..c88ee3dd4299 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -1102,7 +1102,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv, int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc, u32 *rule_locs) { - struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); + struct net_device *p = dsa_port_to_conduit(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; @@ -1145,7 +1145,7 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc) { - struct net_device *p = dsa_port_to_master(dsa_to_port(ds, port)); + struct net_device *p = dsa_port_to_conduit(dsa_to_port(ds, port)); struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index ee67adeb2cdb..fcb20eac332a 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1084,7 +1084,7 @@ static int lan9303_port_enable(struct dsa_switch *ds, int port, if (!dsa_port_is_user(dp)) return 0; - vlan_vid_add(dsa_port_to_master(dp), htons(ETH_P_8021Q), port); + vlan_vid_add(dsa_port_to_conduit(dp), htons(ETH_P_8021Q), port); return lan9303_enable_processing_port(chip, port); } @@ -1097,7 +1097,7 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port) if (!dsa_port_is_user(dp)) return; - vlan_vid_del(dsa_port_to_master(dp), htons(ETH_P_8021Q), port); + vlan_vid_del(dsa_port_to_conduit(dp), htons(ETH_P_8021Q), port); lan9303_disable_processing_port(chip, port); lan9303_phy_write(ds, chip->phy_addr_base + port, MII_BMCR, BMCR_PDOWN); diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 1a2d5797bf98..9c185c9f0963 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -510,22 +510,22 @@ static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np) struct dsa_switch *ds = priv->ds; int err; - ds->slave_mii_bus = mdiobus_alloc(); - if (!ds->slave_mii_bus) + ds->user_mii_bus = mdiobus_alloc(); + if (!ds->user_mii_bus) return -ENOMEM; - ds->slave_mii_bus->priv = priv; - ds->slave_mii_bus->read = gswip_mdio_rd; - ds->slave_mii_bus->write = gswip_mdio_wr; - ds->slave_mii_bus->name = "lantiq,xrx200-mdio"; - snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii", + ds->user_mii_bus->priv = priv; + ds->user_mii_bus->read = gswip_mdio_rd; + ds->user_mii_bus->write = gswip_mdio_wr; + ds->user_mii_bus->name = "lantiq,xrx200-mdio"; + snprintf(ds->user_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(priv->dev)); - ds->slave_mii_bus->parent = priv->dev; - ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; + ds->user_mii_bus->parent = priv->dev; + ds->user_mii_bus->phy_mask = ~ds->phys_mii_mask; - err = of_mdiobus_register(ds->slave_mii_bus, mdio_np); + err = of_mdiobus_register(ds->user_mii_bus, mdio_np); if (err) - mdiobus_free(ds->slave_mii_bus); + mdiobus_free(ds->user_mii_bus); return err; } @@ -2196,8 +2196,8 @@ disable_switch: dsa_unregister_switch(priv->ds); mdio_bus: if (mdio_np) { - mdiobus_unregister(priv->ds->slave_mii_bus); - mdiobus_free(priv->ds->slave_mii_bus); + mdiobus_unregister(priv->ds->user_mii_bus); + mdiobus_free(priv->ds->user_mii_bus); } put_mdio_node: of_node_put(mdio_np); @@ -2219,10 +2219,10 @@ static void gswip_remove(struct platform_device *pdev) dsa_unregister_switch(priv->ds); - if (priv->ds->slave_mii_bus) { - mdiobus_unregister(priv->ds->slave_mii_bus); - of_node_put(priv->ds->slave_mii_bus->dev.of_node); - mdiobus_free(priv->ds->slave_mii_bus); + if (priv->ds->user_mii_bus) { + mdiobus_unregister(priv->ds->user_mii_bus); + of_node_put(priv->ds->user_mii_bus->dev.of_node); + mdiobus_free(priv->ds->user_mii_bus); } for (i = 0; i < priv->num_gphy_fw; i++) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index cde8ef33d029..a8b0e528b804 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1170,7 +1170,7 @@ int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val) void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr) { struct ksz_device *dev = ds->priv; - struct net_device *slave; + struct net_device *user; struct dsa_port *hsr_dp; u8 data, hsr_ports = 0; @@ -1202,8 +1202,8 @@ void ksz9477_hsr_join(struct dsa_switch *ds, int port, struct net_device *hsr) ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, PORT_SRC_ADDR_FILTER, true); /* Setup HW supported features for lan HSR ports */ - slave = dsa_to_port(ds, port)->slave; - slave->features |= KSZ9477_SUPPORTED_HSR_FEATURES; + user = dsa_to_port(ds, port)->user; + user->features |= KSZ9477_SUPPORTED_HSR_FEATURES; } void ksz9477_hsr_leave(struct dsa_switch *ds, int port, struct net_device *hsr) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b800ace40ce1..a8025ff988ec 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1945,14 +1945,14 @@ static int ksz_irq_phy_setup(struct ksz_device *dev) ret = irq; goto out; } - ds->slave_mii_bus->irq[phy] = irq; + ds->user_mii_bus->irq[phy] = irq; } } return 0; out: while (phy--) if (BIT(phy) & ds->phys_mii_mask) - irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); + irq_dispose_mapping(ds->user_mii_bus->irq[phy]); return ret; } @@ -1964,7 +1964,7 @@ static void ksz_irq_phy_free(struct ksz_device *dev) for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) if (BIT(phy) & ds->phys_mii_mask) - irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); + irq_dispose_mapping(ds->user_mii_bus->irq[phy]); } static int ksz_mdio_register(struct ksz_device *dev) @@ -1987,12 +1987,12 @@ static int ksz_mdio_register(struct ksz_device *dev) bus->priv = dev; bus->read = ksz_sw_mdio_read; bus->write = ksz_sw_mdio_write; - bus->name = "ksz slave smi"; + bus->name = "ksz user smi"; snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); bus->parent = ds->dev; bus->phy_mask = ~ds->phys_mii_mask; - ds->slave_mii_bus = bus; + ds->user_mii_bus = bus; if (dev->irq > 0) { ret = ksz_irq_phy_setup(dev); @@ -2344,7 +2344,7 @@ static void ksz_mib_read_work(struct work_struct *work) if (!p->read) { const struct dsa_port *dp = dsa_to_port(dev->ds, i); - if (!netif_carrier_ok(dp->slave)) + if (!netif_carrier_ok(dp->user)) mib->cnt_ptr = dev->info->reg_mib_cnt; } port_r_cnt(dev, i); @@ -2464,7 +2464,7 @@ static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, mutex_lock(&mib->cnt_mutex); /* Only read dropped counters if no link. */ - if (!netif_carrier_ok(dp->slave)) + if (!netif_carrier_ok(dp->user)) mib->cnt_ptr = dev->info->reg_mib_cnt; port_r_cnt(dev, port); memcpy(buf, mib->counters, dev->info->mib_cnt * sizeof(u64)); @@ -2574,7 +2574,7 @@ static int ksz_port_setup(struct dsa_switch *ds, int port) if (!dsa_is_user_port(ds, port)) return 0; - /* setup slave port */ + /* setup user port */ dev->dev_ops->port_setup(dev, port, false); /* port_stp_state_set() will be called after to enable the port so @@ -3567,8 +3567,8 @@ static int ksz_port_set_mac_address(struct dsa_switch *ds, int port, static int ksz_switch_macaddr_get(struct dsa_switch *ds, int port, struct netlink_ext_ack *extack) { - struct net_device *slave = dsa_to_port(ds, port)->slave; - const unsigned char *addr = slave->dev_addr; + struct net_device *user = dsa_to_port(ds, port)->user; + const unsigned char *addr = user->dev_addr; struct ksz_switch_macaddr *switch_macaddr; struct ksz_device *dev = ds->priv; const u16 *regs = dev->info->regs; diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 4e22a695a64c..1fe105913c75 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -557,7 +557,7 @@ static void ksz_ptp_txtstamp_skb(struct ksz_device *dev, struct skb_shared_hwtstamps hwtstamps = {}; int ret; - /* timeout must include DSA master to transmit data, tstamp latency, + /* timeout must include DSA conduit to transmit data, tstamp latency, * IRQ latency and time for reading the time stamp. */ ret = wait_for_completion_timeout(&prt->tstamp_msg_comp, diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index ecf5d3deb36e..d27c6b70a2f6 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1113,7 +1113,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) u32 val; /* When a new MTU is set, DSA always set the CPU port's MTU to the - * largest MTU of the slave ports. Because the switch only has a global + * largest MTU of the user ports. Because the switch only has a global * RX length register, only allowing CPU port here is enough. */ if (!dsa_is_cpu_port(ds, port)) @@ -2069,7 +2069,7 @@ mt7530_setup_mdio_irq(struct mt7530_priv *priv) unsigned int irq; irq = irq_create_mapping(priv->irq_domain, p); - ds->slave_mii_bus->irq[p] = irq; + ds->user_mii_bus->irq[p] = irq; } } } @@ -2163,7 +2163,7 @@ mt7530_setup_mdio(struct mt7530_priv *priv) if (!bus) return -ENOMEM; - ds->slave_mii_bus = bus; + ds->user_mii_bus = bus; bus->priv = priv; bus->name = KBUILD_MODNAME "-mii"; snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++); @@ -2200,20 +2200,20 @@ mt7530_setup(struct dsa_switch *ds) u32 id, val; int ret, i; - /* The parent node of master netdev which holds the common system + /* The parent node of conduit netdev which holds the common system * controller also is the container for two GMACs nodes representing * as two netdev instances. */ dsa_switch_for_each_cpu_port(cpu_dp, ds) { - dn = cpu_dp->master->dev.of_node->parent; + dn = cpu_dp->conduit->dev.of_node->parent; /* It doesn't matter which CPU port is found first, - * their masters should share the same parent OF node + * their conduits should share the same parent OF node */ break; } if (!dn) { - dev_err(ds->dev, "parent OF node of DSA master not found"); + dev_err(ds->dev, "parent OF node of DSA conduit not found"); return -EINVAL; } @@ -2488,7 +2488,7 @@ mt7531_setup(struct dsa_switch *ds) if (mt7531_dual_sgmii_supported(priv)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII; - /* Let ds->slave_mii_bus be able to access external phy. */ + /* Let ds->user_mii_bus be able to access external phy. */ mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK, MT7531_EXT_P_MDC_11); mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK, @@ -2717,7 +2717,7 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: dp = dsa_to_port(ds, port); - phydev = dp->slave->phydev; + phydev = dp->user->phydev; return mt7531_rgmii_setup(priv, port, interface, phydev); case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_NA: diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index ab434a77b059..42b1acaca33a 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2486,7 +2486,7 @@ static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, else member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; - /* net/dsa/slave.c will call dsa_port_vlan_add() for the affected port + /* net/dsa/user.c will call dsa_port_vlan_add() for the affected port * and then the CPU port. Do not warn for duplicates for the CPU port. */ warn = !dsa_is_cpu_port(ds, port) && !dsa_is_dsa_port(ds, port); @@ -3719,7 +3719,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) return err; chip->ds = ds; - ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); + ds->user_mii_bus = mv88e6xxx_default_mdio_bus(chip); /* Since virtual bridges are mapped in the PVT, the number we support * depends on the physical switch topology. We need to let DSA figure diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 9a3e5ec16972..61e95487732d 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -42,22 +42,22 @@ static struct net_device *felix_classify_db(struct dsa_db db) } } -static int felix_cpu_port_for_master(struct dsa_switch *ds, - struct net_device *master) +static int felix_cpu_port_for_conduit(struct dsa_switch *ds, + struct net_device *conduit) { struct ocelot *ocelot = ds->priv; struct dsa_port *cpu_dp; int lag; - if (netif_is_lag_master(master)) { + if (netif_is_lag_master(conduit)) { mutex_lock(&ocelot->fwd_domain_lock); - lag = ocelot_bond_get_id(ocelot, master); + lag = ocelot_bond_get_id(ocelot, conduit); mutex_unlock(&ocelot->fwd_domain_lock); return lag; } - cpu_dp = master->dsa_ptr; + cpu_dp = conduit->dsa_ptr; return cpu_dp->index; } @@ -366,7 +366,7 @@ static int felix_update_trapping_destinations(struct dsa_switch *ds, * is the mode through which frames can be injected from and extracted to an * external CPU, over Ethernet. In NXP SoCs, the "external CPU" is the ARM CPU * running Linux, and this forms a DSA setup together with the enetc or fman - * DSA master. + * DSA conduit. */ static void felix_npi_port_init(struct ocelot *ocelot, int port) { @@ -441,16 +441,16 @@ static unsigned long felix_tag_npi_get_host_fwd_mask(struct dsa_switch *ds) return BIT(ocelot->num_phys_ports); } -static int felix_tag_npi_change_master(struct dsa_switch *ds, int port, - struct net_device *master, - struct netlink_ext_ack *extack) +static int felix_tag_npi_change_conduit(struct dsa_switch *ds, int port, + struct net_device *conduit, + struct netlink_ext_ack *extack) { struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; struct ocelot *ocelot = ds->priv; - if (netif_is_lag_master(master)) { + if (netif_is_lag_master(conduit)) { NL_SET_ERR_MSG_MOD(extack, - "LAG DSA master only supported using ocelot-8021q"); + "LAG DSA conduit only supported using ocelot-8021q"); return -EOPNOTSUPP; } @@ -459,24 +459,24 @@ static int felix_tag_npi_change_master(struct dsa_switch *ds, int port, * come back up until they're all changed to the new one. */ dsa_switch_for_each_user_port(other_dp, ds) { - struct net_device *slave = other_dp->slave; + struct net_device *user = other_dp->user; - if (other_dp != dp && (slave->flags & IFF_UP) && - dsa_port_to_master(other_dp) != master) { + if (other_dp != dp && (user->flags & IFF_UP) && + dsa_port_to_conduit(other_dp) != conduit) { NL_SET_ERR_MSG_MOD(extack, - "Cannot change while old master still has users"); + "Cannot change while old conduit still has users"); return -EOPNOTSUPP; } } felix_npi_port_deinit(ocelot, ocelot->npi); - felix_npi_port_init(ocelot, felix_cpu_port_for_master(ds, master)); + felix_npi_port_init(ocelot, felix_cpu_port_for_conduit(ds, conduit)); return 0; } /* Alternatively to using the NPI functionality, that same hardware MAC - * connected internally to the enetc or fman DSA master can be configured to + * connected internally to the enetc or fman DSA conduit can be configured to * use the software-defined tag_8021q frame format. As far as the hardware is * concerned, it thinks it is a "dumb switch" - the queues of the CPU port * module are now disconnected from it, but can still be accessed through @@ -486,7 +486,7 @@ static const struct felix_tag_proto_ops felix_tag_npi_proto_ops = { .setup = felix_tag_npi_setup, .teardown = felix_tag_npi_teardown, .get_host_fwd_mask = felix_tag_npi_get_host_fwd_mask, - .change_master = felix_tag_npi_change_master, + .change_conduit = felix_tag_npi_change_conduit, }; static int felix_tag_8021q_setup(struct dsa_switch *ds) @@ -561,11 +561,11 @@ static unsigned long felix_tag_8021q_get_host_fwd_mask(struct dsa_switch *ds) return dsa_cpu_ports(ds); } -static int felix_tag_8021q_change_master(struct dsa_switch *ds, int port, - struct net_device *master, - struct netlink_ext_ack *extack) +static int felix_tag_8021q_change_conduit(struct dsa_switch *ds, int port, + struct net_device *conduit, + struct netlink_ext_ack *extack) { - int cpu = felix_cpu_port_for_master(ds, master); + int cpu = felix_cpu_port_for_conduit(ds, conduit); struct ocelot *ocelot = ds->priv; ocelot_port_unassign_dsa_8021q_cpu(ocelot, port); @@ -578,7 +578,7 @@ static const struct felix_tag_proto_ops felix_tag_8021q_proto_ops = { .setup = felix_tag_8021q_setup, .teardown = felix_tag_8021q_teardown, .get_host_fwd_mask = felix_tag_8021q_get_host_fwd_mask, - .change_master = felix_tag_8021q_change_master, + .change_conduit = felix_tag_8021q_change_conduit, }; static void felix_set_host_flood(struct dsa_switch *ds, unsigned long mask, @@ -741,14 +741,14 @@ static void felix_port_set_host_flood(struct dsa_switch *ds, int port, !!felix->host_flood_mc_mask, true); } -static int felix_port_change_master(struct dsa_switch *ds, int port, - struct net_device *master, - struct netlink_ext_ack *extack) +static int felix_port_change_conduit(struct dsa_switch *ds, int port, + struct net_device *conduit, + struct netlink_ext_ack *extack) { struct ocelot *ocelot = ds->priv; struct felix *felix = ocelot_to_felix(ocelot); - return felix->tag_proto_ops->change_master(ds, port, master, extack); + return felix->tag_proto_ops->change_conduit(ds, port, conduit, extack); } static int felix_set_ageing_time(struct dsa_switch *ds, @@ -953,7 +953,7 @@ static int felix_lag_join(struct dsa_switch *ds, int port, if (!dsa_is_cpu_port(ds, port)) return 0; - return felix_port_change_master(ds, port, lag.dev, extack); + return felix_port_change_conduit(ds, port, lag.dev, extack); } static int felix_lag_leave(struct dsa_switch *ds, int port, @@ -967,7 +967,7 @@ static int felix_lag_leave(struct dsa_switch *ds, int port, if (!dsa_is_cpu_port(ds, port)) return 0; - return felix_port_change_master(ds, port, lag.dev, NULL); + return felix_port_change_conduit(ds, port, lag.dev, NULL); } static int felix_lag_change(struct dsa_switch *ds, int port) @@ -1116,10 +1116,10 @@ static int felix_port_enable(struct dsa_switch *ds, int port, return 0; if (ocelot->npi >= 0) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); - if (felix_cpu_port_for_master(ds, master) != ocelot->npi) { - dev_err(ds->dev, "Multiple masters are not allowed\n"); + if (felix_cpu_port_for_conduit(ds, conduit) != ocelot->npi) { + dev_err(ds->dev, "Multiple conduits are not allowed\n"); return -EINVAL; } } @@ -2164,7 +2164,7 @@ const struct dsa_switch_ops felix_switch_ops = { .port_add_dscp_prio = felix_port_add_dscp_prio, .port_del_dscp_prio = felix_port_del_dscp_prio, .port_set_host_flood = felix_port_set_host_flood, - .port_change_master = felix_port_change_master, + .port_change_conduit = felix_port_change_conduit, }; EXPORT_SYMBOL_GPL(felix_switch_ops); @@ -2176,7 +2176,7 @@ struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port) if (!dsa_is_user_port(ds, port)) return NULL; - return dsa_to_port(ds, port)->slave; + return dsa_to_port(ds, port)->user; } EXPORT_SYMBOL_GPL(felix_port_to_netdev); diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index 1d4befe7cfe8..dbf5872fe367 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -77,9 +77,9 @@ struct felix_tag_proto_ops { int (*setup)(struct dsa_switch *ds); void (*teardown)(struct dsa_switch *ds); unsigned long (*get_host_fwd_mask)(struct dsa_switch *ds); - int (*change_master)(struct dsa_switch *ds, int port, - struct net_device *master, - struct netlink_ext_ack *extack); + int (*change_conduit)(struct dsa_switch *ds, int port, + struct net_device *conduit, + struct netlink_ext_ack *extack); }; extern const struct dsa_switch_ops felix_switch_ops; diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 4ce68e655a63..ec57d9d52072 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -323,14 +323,14 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) mutex_lock(&mgmt_eth_data->mutex); - /* Check mgmt_master if is operational */ - if (!priv->mgmt_master) { + /* Check if the mgmt_conduit if is operational */ + if (!priv->mgmt_conduit) { kfree_skb(skb); mutex_unlock(&mgmt_eth_data->mutex); return -EINVAL; } - skb->dev = priv->mgmt_master; + skb->dev = priv->mgmt_conduit; reinit_completion(&mgmt_eth_data->rw_done); @@ -375,14 +375,14 @@ static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) mutex_lock(&mgmt_eth_data->mutex); - /* Check mgmt_master if is operational */ - if (!priv->mgmt_master) { + /* Check if the mgmt_conduit if is operational */ + if (!priv->mgmt_conduit) { kfree_skb(skb); mutex_unlock(&mgmt_eth_data->mutex); return -EINVAL; } - skb->dev = priv->mgmt_master; + skb->dev = priv->mgmt_conduit; reinit_completion(&mgmt_eth_data->rw_done); @@ -508,7 +508,7 @@ qca8k_bulk_read(void *ctx, const void *reg_buf, size_t reg_len, struct qca8k_priv *priv = ctx; u32 reg = *(u16 *)reg_buf; - if (priv->mgmt_master && + if (priv->mgmt_conduit && !qca8k_read_eth(priv, reg, val_buf, val_len)) return 0; @@ -531,7 +531,7 @@ qca8k_bulk_gather_write(void *ctx, const void *reg_buf, size_t reg_len, u32 reg = *(u16 *)reg_buf; u32 *val = (u32 *)val_buf; - if (priv->mgmt_master && + if (priv->mgmt_conduit && !qca8k_write_eth(priv, reg, val, val_len)) return 0; @@ -626,7 +626,7 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, struct sk_buff *write_skb, *clear_skb, *read_skb; struct qca8k_mgmt_eth_data *mgmt_eth_data; u32 write_val, clear_val = 0, val; - struct net_device *mgmt_master; + struct net_device *mgmt_conduit; int ret, ret1; bool ack; @@ -683,18 +683,18 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, */ mutex_lock(&mgmt_eth_data->mutex); - /* Check if mgmt_master is operational */ - mgmt_master = priv->mgmt_master; - if (!mgmt_master) { + /* Check if mgmt_conduit is operational */ + mgmt_conduit = priv->mgmt_conduit; + if (!mgmt_conduit) { mutex_unlock(&mgmt_eth_data->mutex); mutex_unlock(&priv->bus->mdio_lock); ret = -EINVAL; - goto err_mgmt_master; + goto err_mgmt_conduit; } - read_skb->dev = mgmt_master; - clear_skb->dev = mgmt_master; - write_skb->dev = mgmt_master; + read_skb->dev = mgmt_conduit; + clear_skb->dev = mgmt_conduit; + write_skb->dev = mgmt_conduit; reinit_completion(&mgmt_eth_data->rw_done); @@ -780,7 +780,7 @@ exit: return ret; /* Error handling before lock */ -err_mgmt_master: +err_mgmt_conduit: kfree_skb(read_skb); err_read_skb: kfree_skb(clear_skb); @@ -959,12 +959,12 @@ qca8k_mdio_register(struct qca8k_priv *priv) ds->dst->index, ds->index); bus->parent = ds->dev; bus->phy_mask = ~ds->phys_mii_mask; - ds->slave_mii_bus = bus; + ds->user_mii_bus = bus; /* Check if the devicetree declare the port:phy mapping */ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); if (of_device_is_available(mdio)) { - bus->name = "qca8k slave mii"; + bus->name = "qca8k user mii"; bus->read = qca8k_internal_mdio_read; bus->write = qca8k_internal_mdio_write; return devm_of_mdiobus_register(priv->dev, bus, mdio); @@ -973,7 +973,7 @@ qca8k_mdio_register(struct qca8k_priv *priv) /* If a mapping can't be found the legacy mapping is used, * using the qca8k_port_to_phy function */ - bus->name = "qca8k-legacy slave mii"; + bus->name = "qca8k-legacy user mii"; bus->read = qca8k_legacy_mdio_read; bus->write = qca8k_legacy_mdio_write; return devm_mdiobus_register(priv->dev, bus); @@ -1728,10 +1728,10 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port, } static void -qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, - bool operational) +qca8k_conduit_change(struct dsa_switch *ds, const struct net_device *conduit, + bool operational) { - struct dsa_port *dp = master->dsa_ptr; + struct dsa_port *dp = conduit->dsa_ptr; struct qca8k_priv *priv = ds->priv; /* Ethernet MIB/MDIO is only supported for CPU port 0 */ @@ -1741,7 +1741,7 @@ qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, mutex_lock(&priv->mgmt_eth_data.mutex); mutex_lock(&priv->mib_eth_data.mutex); - priv->mgmt_master = operational ? (struct net_device *)master : NULL; + priv->mgmt_conduit = operational ? (struct net_device *)conduit : NULL; mutex_unlock(&priv->mib_eth_data.mutex); mutex_unlock(&priv->mgmt_eth_data.mutex); @@ -2016,7 +2016,7 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .get_phy_flags = qca8k_get_phy_flags, .port_lag_join = qca8k_port_lag_join, .port_lag_leave = qca8k_port_lag_leave, - .master_state_change = qca8k_master_change, + .conduit_state_change = qca8k_conduit_change, .connect_tag_protocol = qca8k_connect_tag_protocol, }; diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index 9ff0a3c1cb91..9243eff8918d 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -499,7 +499,7 @@ void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, u32 hi = 0; int ret; - if (priv->mgmt_master && priv->info->ops->autocast_mib && + if (priv->mgmt_conduit && priv->info->ops->autocast_mib && priv->info->ops->autocast_mib(ds, port, data) > 0) return; @@ -761,7 +761,7 @@ int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) int ret; /* We have only have a general MTU setting. - * DSA always set the CPU port's MTU to the largest MTU of the slave + * DSA always set the CPU port's MTU to the largest MTU of the user * ports. * Setting MTU just for the CPU port is sufficient to correctly set a * value for every port. diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c index e8c16e76e34b..90e30c2909e4 100644 --- a/drivers/net/dsa/qca/qca8k-leds.c +++ b/drivers/net/dsa/qca/qca8k-leds.c @@ -356,8 +356,8 @@ static struct device *qca8k_cled_hw_control_get_device(struct led_classdev *ldev dp = dsa_to_port(priv->ds, qca8k_phy_to_port(led->port_num)); if (!dp) return NULL; - if (dp->slave) - return &dp->slave->dev; + if (dp->user) + return &dp->user->dev; return NULL; } @@ -429,7 +429,7 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p init_data.default_label = ":port"; init_data.fwnode = led; init_data.devname_mandatory = true; - init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->slave_mii_bus->id, + init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->user_mii_bus->id, port_num); if (!init_data.devicename) return -ENOMEM; diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index 8f88b7db384d..2ac7e88f8da5 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -458,7 +458,7 @@ struct qca8k_priv { struct mutex reg_mutex; struct device *dev; struct gpio_desc *reset_gpio; - struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + struct net_device *mgmt_conduit; /* Track if mdio/mib Ethernet is available */ struct qca8k_mgmt_eth_data mgmt_eth_data; struct qca8k_mib_eth_data mib_eth_data; struct qca8k_mdio_cache mdio_cache; diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index bfd11591faf4..755546ed8db6 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -378,25 +378,25 @@ static int realtek_smi_setup_mdio(struct dsa_switch *ds) return -ENODEV; } - priv->slave_mii_bus = devm_mdiobus_alloc(priv->dev); - if (!priv->slave_mii_bus) { + priv->user_mii_bus = devm_mdiobus_alloc(priv->dev); + if (!priv->user_mii_bus) { ret = -ENOMEM; goto err_put_node; } - priv->slave_mii_bus->priv = priv; - priv->slave_mii_bus->name = "SMI slave MII"; - priv->slave_mii_bus->read = realtek_smi_mdio_read; - priv->slave_mii_bus->write = realtek_smi_mdio_write; - snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", + priv->user_mii_bus->priv = priv; + priv->user_mii_bus->name = "SMI user MII"; + priv->user_mii_bus->read = realtek_smi_mdio_read; + priv->user_mii_bus->write = realtek_smi_mdio_write; + snprintf(priv->user_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); - priv->slave_mii_bus->dev.of_node = mdio_np; - priv->slave_mii_bus->parent = priv->dev; - ds->slave_mii_bus = priv->slave_mii_bus; + priv->user_mii_bus->dev.of_node = mdio_np; + priv->user_mii_bus->parent = priv->dev; + ds->user_mii_bus = priv->user_mii_bus; - ret = devm_of_mdiobus_register(priv->dev, priv->slave_mii_bus, mdio_np); + ret = devm_of_mdiobus_register(priv->dev, priv->user_mii_bus, mdio_np); if (ret) { dev_err(priv->dev, "unable to register MDIO bus %s\n", - priv->slave_mii_bus->id); + priv->user_mii_bus->id); goto err_put_node; } @@ -514,8 +514,8 @@ static void realtek_smi_remove(struct platform_device *pdev) return; dsa_unregister_switch(priv->ds); - if (priv->slave_mii_bus) - of_node_put(priv->slave_mii_bus->dev.of_node); + if (priv->user_mii_bus) + of_node_put(priv->user_mii_bus->dev.of_node); /* leave the device reset asserted */ if (priv->reset) diff --git a/drivers/net/dsa/realtek/realtek.h b/drivers/net/dsa/realtek/realtek.h index 4fa7c6ba874a..790488e9c667 100644 --- a/drivers/net/dsa/realtek/realtek.h +++ b/drivers/net/dsa/realtek/realtek.h @@ -54,7 +54,7 @@ struct realtek_priv { struct regmap *map; struct regmap *map_nolock; struct mutex map_lock; - struct mii_bus *slave_mii_bus; + struct mii_bus *user_mii_bus; struct mii_bus *bus; int mdio_addr; diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index d171c18dd354..0875e4fc9f57 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -1144,7 +1144,7 @@ static int rtl8365mb_port_change_mtu(struct dsa_switch *ds, int port, int frame_size; /* When a new MTU is set, DSA always sets the CPU port's MTU to the - * largest MTU of the slave ports. Because the switch only has a global + * largest MTU of the user ports. Because the switch only has a global * RX length register, only allowing CPU port here is enough. */ if (!dsa_is_cpu_port(ds, port)) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 1a367e64bc3b..74cee39d73df 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2688,7 +2688,7 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot, } /* Transfer skb to the host port. */ - dsa_enqueue_skb(skb, dsa_to_port(ds, port)->slave); + dsa_enqueue_skb(skb, dsa_to_port(ds, port)->user); /* Wait until the switch has processed the frame */ do { @@ -3081,7 +3081,7 @@ static int sja1105_port_bridge_flags(struct dsa_switch *ds, int port, * ref_clk pin. So port clocking needs to be initialized early, before * connecting to PHYs is attempted, otherwise they won't respond through MDIO. * Setting correct PHY link speed does not matter now. - * But dsa_slave_phy_setup is called later than sja1105_setup, so the PHY + * But dsa_user_phy_setup is called later than sja1105_setup, so the PHY * bindings are not yet parsed by DSA core. We need to parse early so that we * can populate the xMII mode parameters table. */ diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c index 5b02e9e426fd..96db032b478f 100644 --- a/drivers/net/dsa/xrs700x/xrs700x.c +++ b/drivers/net/dsa/xrs700x/xrs700x.c @@ -554,7 +554,7 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port, unsigned int val = XRS_HSR_CFG_HSR_PRP; struct dsa_port *partner = NULL, *dp; struct xrs700x *priv = ds->priv; - struct net_device *slave; + struct net_device *user; int ret, i, hsr_pair[2]; enum hsr_version ver; bool fwd = false; @@ -638,8 +638,8 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port, hsr_pair[0] = port; hsr_pair[1] = partner->index; for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) { - slave = dsa_to_port(ds, hsr_pair[i])->slave; - slave->features |= XRS7000X_SUPPORTED_HSR_FEATURES; + user = dsa_to_port(ds, hsr_pair[i])->user; + user->features |= XRS7000X_SUPPORTED_HSR_FEATURES; } return 0; @@ -650,7 +650,7 @@ static int xrs700x_hsr_leave(struct dsa_switch *ds, int port, { struct dsa_port *partner = NULL, *dp; struct xrs700x *priv = ds->priv; - struct net_device *slave; + struct net_device *user; int i, hsr_pair[2]; unsigned int val; @@ -692,8 +692,8 @@ static int xrs700x_hsr_leave(struct dsa_switch *ds, int port, hsr_pair[0] = port; hsr_pair[1] = partner->index; for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) { - slave = dsa_to_port(ds, hsr_pair[i])->slave; - slave->features &= ~XRS7000X_SUPPORTED_HSR_FEATURES; + user = dsa_to_port(ds, hsr_pair[i])->user; + user->features &= ~XRS7000X_SUPPORTED_HSR_FEATURES; } return 0; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index ab096795e805..c9faa8540859 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2430,7 +2430,7 @@ static int bcm_sysport_netdevice_event(struct notifier_block *nb, if (dev->netdev_ops != &bcm_sysport_netdev_ops) return NOTIFY_DONE; - if (!dsa_slave_dev_check(info->upper_dev)) + if (!dsa_user_dev_check(info->upper_dev)) return NOTIFY_DONE; if (info->linking) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 60d49b0f595f..3cf6589cfdac 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -3329,7 +3329,7 @@ static int mtk_device_event(struct notifier_block *n, unsigned long event, void return NOTIFY_DONE; found: - if (!dsa_slave_dev_check(dev)) + if (!dsa_user_dev_check(dev)) return NOTIFY_DONE; if (__ethtool_get_link_ksettings(dev, &s)) diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index e073d2b5542c..fbb5e9d5af13 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -175,7 +175,7 @@ mtk_flow_get_dsa_port(struct net_device **dev) if (dp->cpu_dp->tag_ops->proto != DSA_TAG_PROTO_MTK) return -ENODEV; - *dev = dsa_port_to_master(dp); + *dev = dsa_port_to_conduit(dp); return dp->index; #else diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h index c177322f793d..b9dd35d4b8f5 100644 --- a/include/linux/dsa/sja1105.h +++ b/include/linux/dsa/sja1105.h @@ -28,7 +28,7 @@ /* Source and Destination MAC of follow-up meta frames. * Whereas the choice of SMAC only affects the unique identification of the * switch as sender of meta frames, the DMAC must be an address that is present - * in the DSA master port's multicast MAC filter. + * in the DSA conduit port's multicast MAC filter. * 01-80-C2-00-00-0E is a good choice for this, as all profiles of IEEE 1588 * over L2 use this address for some purpose already. */ diff --git a/include/net/dsa.h b/include/net/dsa.h index d98439ea6146..82135fbdb1e6 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -102,11 +102,11 @@ struct dsa_device_ops { const char *name; enum dsa_tag_protocol proto; /* Some tagging protocols either mangle or shift the destination MAC - * address, in which case the DSA master would drop packets on ingress + * address, in which case the DSA conduit would drop packets on ingress * if what it understands out of the destination MAC address is not in * its RX filter. */ - bool promisc_on_master; + bool promisc_on_conduit; }; struct dsa_lag { @@ -236,12 +236,12 @@ struct dsa_bridge { }; struct dsa_port { - /* A CPU port is physically connected to a master device. - * A user port exposed to userspace has a slave device. + /* A CPU port is physically connected to a conduit device. A user port + * exposes a network device to user-space, called 'user' here. */ union { - struct net_device *master; - struct net_device *slave; + struct net_device *conduit; + struct net_device *user; }; /* Copy of the tagging protocol operations, for quicker access @@ -249,7 +249,7 @@ struct dsa_port { */ const struct dsa_device_ops *tag_ops; - /* Copies for faster access in master receive hot path */ + /* Copies for faster access in conduit receive hot path */ struct dsa_switch_tree *dst; struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev); @@ -281,9 +281,9 @@ struct dsa_port { u8 lag_tx_enabled:1; - /* Master state bits, valid only on CPU ports */ - u8 master_admin_up:1; - u8 master_oper_up:1; + /* conduit state bits, valid only on CPU ports */ + u8 conduit_admin_up:1; + u8 conduit_oper_up:1; /* Valid only on user ports */ u8 cpu_port_in_lag:1; @@ -303,7 +303,7 @@ struct dsa_port { struct list_head list; /* - * Original copy of the master netdev ethtool_ops + * Original copy of the conduit netdev ethtool_ops */ const struct ethtool_ops *orig_ethtool_ops; @@ -452,10 +452,10 @@ struct dsa_switch { const struct dsa_switch_ops *ops; /* - * Slave mii_bus and devices for the individual ports. + * User mii_bus and devices for the individual ports. */ u32 phys_mii_mask; - struct mii_bus *slave_mii_bus; + struct mii_bus *user_mii_bus; /* Ageing Time limits in msecs */ unsigned int ageing_time_min; @@ -520,10 +520,10 @@ static inline bool dsa_port_is_unused(struct dsa_port *dp) return dp->type == DSA_PORT_TYPE_UNUSED; } -static inline bool dsa_port_master_is_operational(struct dsa_port *dp) +static inline bool dsa_port_conduit_is_operational(struct dsa_port *dp) { - return dsa_port_is_cpu(dp) && dp->master_admin_up && - dp->master_oper_up; + return dsa_port_is_cpu(dp) && dp->conduit_admin_up && + dp->conduit_oper_up; } static inline bool dsa_is_unused_port(struct dsa_switch *ds, int p) @@ -713,12 +713,12 @@ static inline bool dsa_port_offloads_lag(struct dsa_port *dp, return dsa_port_lag_dev_get(dp) == lag->dev; } -static inline struct net_device *dsa_port_to_master(const struct dsa_port *dp) +static inline struct net_device *dsa_port_to_conduit(const struct dsa_port *dp) { if (dp->cpu_port_in_lag) return dsa_port_lag_dev_get(dp->cpu_dp); - return dp->cpu_dp->master; + return dp->cpu_dp->conduit; } static inline @@ -732,7 +732,7 @@ struct net_device *dsa_port_to_bridge_port(const struct dsa_port *dp) else if (dp->hsr_dev) return dp->hsr_dev; - return dp->slave; + return dp->user; } static inline struct net_device * @@ -834,9 +834,9 @@ struct dsa_switch_ops { int (*connect_tag_protocol)(struct dsa_switch *ds, enum dsa_tag_protocol proto); - int (*port_change_master)(struct dsa_switch *ds, int port, - struct net_device *master, - struct netlink_ext_ack *extack); + int (*port_change_conduit)(struct dsa_switch *ds, int port, + struct net_device *conduit, + struct netlink_ext_ack *extack); /* Optional switch-wide initialization and destruction methods */ int (*setup)(struct dsa_switch *ds); @@ -1233,11 +1233,11 @@ struct dsa_switch_ops { int (*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid); /* - * DSA master tracking operations + * DSA conduit tracking operations */ - void (*master_state_change)(struct dsa_switch *ds, - const struct net_device *master, - bool operational); + void (*conduit_state_change)(struct dsa_switch *ds, + const struct net_device *conduit, + bool operational); }; #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \ @@ -1374,9 +1374,9 @@ static inline int dsa_switch_resume(struct dsa_switch *ds) #endif /* CONFIG_PM_SLEEP */ #if IS_ENABLED(CONFIG_NET_DSA) -bool dsa_slave_dev_check(const struct net_device *dev); +bool dsa_user_dev_check(const struct net_device *dev); #else -static inline bool dsa_slave_dev_check(const struct net_device *dev) +static inline bool dsa_user_dev_check(const struct net_device *dev) { return false; } diff --git a/include/net/dsa_stubs.h b/include/net/dsa_stubs.h index 361811750a54..6f384897f287 100644 --- a/include/net/dsa_stubs.h +++ b/include/net/dsa_stubs.h @@ -13,14 +13,14 @@ extern const struct dsa_stubs *dsa_stubs; struct dsa_stubs { - int (*master_hwtstamp_validate)(struct net_device *dev, - const struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack); + int (*conduit_hwtstamp_validate)(struct net_device *dev, + const struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack); }; -static inline int dsa_master_hwtstamp_validate(struct net_device *dev, - const struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack) +static inline int dsa_conduit_hwtstamp_validate(struct net_device *dev, + const struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { if (!netdev_uses_dsa(dev)) return 0; @@ -29,18 +29,18 @@ static inline int dsa_master_hwtstamp_validate(struct net_device *dev, * netdev_uses_dsa() returns true, the dsa_core module is still * registered, and so, dsa_unregister_stubs() couldn't have run. * For netdev_uses_dsa() to start returning false, it would imply that - * dsa_master_teardown() has executed, which requires rtnl_lock(). + * dsa_conduit_teardown() has executed, which requires rtnl_lock(). */ ASSERT_RTNL(); - return dsa_stubs->master_hwtstamp_validate(dev, config, extack); + return dsa_stubs->conduit_hwtstamp_validate(dev, config, extack); } #else -static inline int dsa_master_hwtstamp_validate(struct net_device *dev, - const struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack) +static inline int dsa_conduit_hwtstamp_validate(struct net_device *dev, + const struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { return 0; } diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index b46aedc36939..feeddf95f450 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -382,7 +382,7 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr) if (err) return err; - err = dsa_master_hwtstamp_validate(dev, &kernel_cfg, &extack); + err = dsa_conduit_hwtstamp_validate(dev, &kernel_cfg, &extack); if (err) { if (extack._msg) netdev_err(dev, "%s\n", extack._msg); diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 12e305824a96..8a1894a42552 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -8,16 +8,16 @@ endif # the core obj-$(CONFIG_NET_DSA) += dsa_core.o dsa_core-y += \ + conduit.o \ devlink.o \ dsa.o \ - master.o \ netlink.o \ port.o \ - slave.o \ switch.o \ tag.o \ tag_8021q.o \ - trace.o + trace.o \ + user.o # tagging formats obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c new file mode 100644 index 000000000000..3dfdb3cb47dc --- /dev/null +++ b/net/dsa/conduit.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Handling of a conduit device, switching frames via its switch fabric CPU port + * + * Copyright (c) 2017 Savoir-faire Linux Inc. + * Vivien Didelot + */ + +#include +#include +#include +#include + +#include "conduit.h" +#include "dsa.h" +#include "port.h" +#include "tag.h" + +static int dsa_conduit_get_regs_len(struct net_device *dev) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + int port = cpu_dp->index; + int ret = 0; + int len; + + if (ops->get_regs_len) { + len = ops->get_regs_len(dev); + if (len < 0) + return len; + ret += len; + } + + ret += sizeof(struct ethtool_drvinfo); + ret += sizeof(struct ethtool_regs); + + if (ds->ops->get_regs_len) { + len = ds->ops->get_regs_len(ds, port); + if (len < 0) + return len; + ret += len; + } + + return ret; +} + +static void dsa_conduit_get_regs(struct net_device *dev, + struct ethtool_regs *regs, void *data) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + struct ethtool_drvinfo *cpu_info; + struct ethtool_regs *cpu_regs; + int port = cpu_dp->index; + int len; + + if (ops->get_regs_len && ops->get_regs) { + len = ops->get_regs_len(dev); + if (len < 0) + return; + regs->len = len; + ops->get_regs(dev, regs, data); + data += regs->len; + } + + cpu_info = (struct ethtool_drvinfo *)data; + strscpy(cpu_info->driver, "dsa", sizeof(cpu_info->driver)); + data += sizeof(*cpu_info); + cpu_regs = (struct ethtool_regs *)data; + data += sizeof(*cpu_regs); + + if (ds->ops->get_regs_len && ds->ops->get_regs) { + len = ds->ops->get_regs_len(ds, port); + if (len < 0) + return; + cpu_regs->len = len; + ds->ops->get_regs(ds, port, cpu_regs, data); + } +} + +static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + int port = cpu_dp->index; + int count = 0; + + if (ops->get_sset_count && ops->get_ethtool_stats) { + count = ops->get_sset_count(dev, ETH_SS_STATS); + ops->get_ethtool_stats(dev, stats, data); + } + + if (ds->ops->get_ethtool_stats) + ds->ops->get_ethtool_stats(ds, port, data + count); +} + +static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + int port = cpu_dp->index; + int count = 0; + + if (dev->phydev && !ops->get_ethtool_phy_stats) { + count = phy_ethtool_get_sset_count(dev->phydev); + if (count >= 0) + phy_ethtool_get_stats(dev->phydev, stats, data); + } else if (ops->get_sset_count && ops->get_ethtool_phy_stats) { + count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); + ops->get_ethtool_phy_stats(dev, stats, data); + } + + if (count < 0) + count = 0; + + if (ds->ops->get_ethtool_phy_stats) + ds->ops->get_ethtool_phy_stats(ds, port, data + count); +} + +static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + int count = 0; + + if (sset == ETH_SS_PHY_STATS && dev->phydev && + !ops->get_ethtool_phy_stats) + count = phy_ethtool_get_sset_count(dev->phydev); + else if (ops->get_sset_count) + count = ops->get_sset_count(dev, sset); + + if (count < 0) + count = 0; + + if (ds->ops->get_sset_count) + count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); + + return count; +} + +static void dsa_conduit_get_strings(struct net_device *dev, uint32_t stringset, + uint8_t *data) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; + struct dsa_switch *ds = cpu_dp->ds; + int port = cpu_dp->index; + int len = ETH_GSTRING_LEN; + int mcount = 0, count, i; + uint8_t pfx[4]; + uint8_t *ndata; + + snprintf(pfx, sizeof(pfx), "p%.2d", port); + /* We do not want to be NULL-terminated, since this is a prefix */ + pfx[sizeof(pfx) - 1] = '_'; + + if (stringset == ETH_SS_PHY_STATS && dev->phydev && + !ops->get_ethtool_phy_stats) { + mcount = phy_ethtool_get_sset_count(dev->phydev); + if (mcount < 0) + mcount = 0; + else + phy_ethtool_get_strings(dev->phydev, data); + } else if (ops->get_sset_count && ops->get_strings) { + mcount = ops->get_sset_count(dev, stringset); + if (mcount < 0) + mcount = 0; + ops->get_strings(dev, stringset, data); + } + + if (ds->ops->get_strings) { + ndata = data + mcount * len; + /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle + * the output after to prepend our CPU port prefix we + * constructed earlier + */ + ds->ops->get_strings(ds, port, stringset, ndata); + count = ds->ops->get_sset_count(ds, port, stringset); + if (count < 0) + return; + for (i = 0; i < count; i++) { + memmove(ndata + (i * len + sizeof(pfx)), + ndata + i * len, len - sizeof(pfx)); + memcpy(ndata + i * len, pfx, sizeof(pfx)); + } + } +} + +/* Deny PTP operations on conduit if there is at least one switch in the tree + * that is PTP capable. + */ +int __dsa_conduit_hwtstamp_validate(struct net_device *dev, + const struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + struct dsa_switch *ds = cpu_dp->ds; + struct dsa_switch_tree *dst; + struct dsa_port *dp; + + dst = ds->dst; + + list_for_each_entry(dp, &dst->ports, list) { + if (dsa_port_supports_hwtstamp(dp)) { + NL_SET_ERR_MSG(extack, + "HW timestamping not allowed on DSA conduit when switch supports the operation"); + return -EBUSY; + } + } + + return 0; +} + +static int dsa_conduit_ethtool_setup(struct net_device *dev) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + struct dsa_switch *ds = cpu_dp->ds; + struct ethtool_ops *ops; + + if (netif_is_lag_master(dev)) + return 0; + + ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + + cpu_dp->orig_ethtool_ops = dev->ethtool_ops; + if (cpu_dp->orig_ethtool_ops) + memcpy(ops, cpu_dp->orig_ethtool_ops, sizeof(*ops)); + + ops->get_regs_len = dsa_conduit_get_regs_len; + ops->get_regs = dsa_conduit_get_regs; + ops->get_sset_count = dsa_conduit_get_sset_count; + ops->get_ethtool_stats = dsa_conduit_get_ethtool_stats; + ops->get_strings = dsa_conduit_get_strings; + ops->get_ethtool_phy_stats = dsa_conduit_get_ethtool_phy_stats; + + dev->ethtool_ops = ops; + + return 0; +} + +static void dsa_conduit_ethtool_teardown(struct net_device *dev) +{ + struct dsa_port *cpu_dp = dev->dsa_ptr; + + if (netif_is_lag_master(dev)) + return; + + dev->ethtool_ops = cpu_dp->orig_ethtool_ops; + cpu_dp->orig_ethtool_ops = NULL; +} + +/* Keep the conduit always promiscuous if the tagging protocol requires that + * (garbles MAC DA) or if it doesn't support unicast filtering, case in which + * it would revert to promiscuous mode as soon as we call dev_uc_add() on it + * anyway. + */ +static void dsa_conduit_set_promiscuity(struct net_device *dev, int inc) +{ + const struct dsa_device_ops *ops = dev->dsa_ptr->tag_ops; + + if ((dev->priv_flags & IFF_UNICAST_FLT) && !ops->promisc_on_conduit) + return; + + ASSERT_RTNL(); + + dev_set_promiscuity(dev, inc); +} + +static ssize_t tagging_show(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct net_device *dev = to_net_dev(d); + struct dsa_port *cpu_dp = dev->dsa_ptr; + + return sysfs_emit(buf, "%s\n", + dsa_tag_protocol_to_str(cpu_dp->tag_ops)); +} + +static ssize_t tagging_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + const struct dsa_device_ops *new_tag_ops, *old_tag_ops; + const char *end = strchrnul(buf, '\n'), *name; + struct net_device *dev = to_net_dev(d); + struct dsa_port *cpu_dp = dev->dsa_ptr; + size_t len = end - buf; + int err; + + /* Empty string passed */ + if (!len) + return -ENOPROTOOPT; + + name = kstrndup(buf, len, GFP_KERNEL); + if (!name) + return -ENOMEM; + + old_tag_ops = cpu_dp->tag_ops; + new_tag_ops = dsa_tag_driver_get_by_name(name); + kfree(name); + /* Bad tagger name? */ + if (IS_ERR(new_tag_ops)) + return PTR_ERR(new_tag_ops); + + if (new_tag_ops == old_tag_ops) + /* Drop the temporarily held duplicate reference, since + * the DSA switch tree uses this tagger. + */ + goto out; + + err = dsa_tree_change_tag_proto(cpu_dp->ds->dst, new_tag_ops, + old_tag_ops); + if (err) { + /* On failure the old tagger is restored, so we don't need the + * driver for the new one. + */ + dsa_tag_driver_put(new_tag_ops); + return err; + } + + /* On success we no longer need the module for the old tagging protocol + */ +out: + dsa_tag_driver_put(old_tag_ops); + return count; +} +static DEVICE_ATTR_RW(tagging); + +static struct attribute *dsa_user_attrs[] = { + &dev_attr_tagging.attr, + NULL +}; + +static const struct attribute_group dsa_group = { + .name = "dsa", + .attrs = dsa_user_attrs, +}; + +static void dsa_conduit_reset_mtu(struct net_device *dev) +{ + int err; + + err = dev_set_mtu(dev, ETH_DATA_LEN); + if (err) + netdev_dbg(dev, + "Unable to reset MTU to exclude DSA overheads\n"); +} + +int dsa_conduit_setup(struct net_device *dev, struct dsa_port *cpu_dp) +{ + const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops; + struct dsa_switch *ds = cpu_dp->ds; + struct device_link *consumer_link; + int mtu, ret; + + mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops); + + /* The DSA conduit must use SET_NETDEV_DEV for this to work. */ + if (!netif_is_lag_master(dev)) { + consumer_link = device_link_add(ds->dev, dev->dev.parent, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!consumer_link) + netdev_err(dev, + "Failed to create a device link to DSA switch %s\n", + dev_name(ds->dev)); + } + + /* The switch driver may not implement ->port_change_mtu(), case in + * which dsa_user_change_mtu() will not update the conduit MTU either, + * so we need to do that here. + */ + ret = dev_set_mtu(dev, mtu); + if (ret) + netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n", + ret, mtu); + + /* If we use a tagging format that doesn't have an ethertype + * field, make sure that all packets from this point on get + * sent to the tag format's receive function. + */ + wmb(); + + dev->dsa_ptr = cpu_dp; + + dsa_conduit_set_promiscuity(dev, 1); + + ret = dsa_conduit_ethtool_setup(dev); + if (ret) + goto out_err_reset_promisc; + + ret = sysfs_create_group(&dev->dev.kobj, &dsa_group); + if (ret) + goto out_err_ethtool_teardown; + + return ret; + +out_err_ethtool_teardown: + dsa_conduit_ethtool_teardown(dev); +out_err_reset_promisc: + dsa_conduit_set_promiscuity(dev, -1); + return ret; +} + +void dsa_conduit_teardown(struct net_device *dev) +{ + sysfs_remove_group(&dev->dev.kobj, &dsa_group); + dsa_conduit_ethtool_teardown(dev); + dsa_conduit_reset_mtu(dev); + dsa_conduit_set_promiscuity(dev, -1); + + dev->dsa_ptr = NULL; + + /* If we used a tagging format that doesn't have an ethertype + * field, make sure that all packets from this point get sent + * without the tag and go through the regular receive path. + */ + wmb(); +} + +int dsa_conduit_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp, + struct netdev_lag_upper_info *uinfo, + struct netlink_ext_ack *extack) +{ + bool conduit_setup = false; + int err; + + if (!netdev_uses_dsa(lag_dev)) { + err = dsa_conduit_setup(lag_dev, cpu_dp); + if (err) + return err; + + conduit_setup = true; + } + + err = dsa_port_lag_join(cpu_dp, lag_dev, uinfo, extack); + if (err) { + NL_SET_ERR_MSG_WEAK_MOD(extack, "CPU port failed to join LAG"); + goto out_conduit_teardown; + } + + return 0; + +out_conduit_teardown: + if (conduit_setup) + dsa_conduit_teardown(lag_dev); + return err; +} + +/* Tear down a conduit if there isn't any other user port on it, + * optionally also destroying LAG information. + */ +void dsa_conduit_lag_teardown(struct net_device *lag_dev, + struct dsa_port *cpu_dp) +{ + struct net_device *upper; + struct list_head *iter; + + dsa_port_lag_leave(cpu_dp, lag_dev); + + netdev_for_each_upper_dev_rcu(lag_dev, upper, iter) + if (dsa_user_dev_check(upper)) + return; + + dsa_conduit_teardown(lag_dev); +} diff --git a/net/dsa/conduit.h b/net/dsa/conduit.h new file mode 100644 index 000000000000..31f8834f54bb --- /dev/null +++ b/net/dsa/conduit.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __DSA_CONDUIT_H +#define __DSA_CONDUIT_H + +struct dsa_port; +struct net_device; +struct netdev_lag_upper_info; +struct netlink_ext_ack; + +int dsa_conduit_setup(struct net_device *dev, struct dsa_port *cpu_dp); +void dsa_conduit_teardown(struct net_device *dev); +int dsa_conduit_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp, + struct netdev_lag_upper_info *uinfo, + struct netlink_ext_ack *extack); +void dsa_conduit_lag_teardown(struct net_device *lag_dev, + struct dsa_port *cpu_dp); +int __dsa_conduit_hwtstamp_validate(struct net_device *dev, + const struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack); + +#endif diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ccbdb98109f8..ac7be864e80d 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -20,14 +20,14 @@ #include #include +#include "conduit.h" #include "devlink.h" #include "dsa.h" -#include "master.h" #include "netlink.h" #include "port.h" -#include "slave.h" #include "switch.h" #include "tag.h" +#include "user.h" #define DSA_MAX_NUM_OFFLOADING_BRIDGES BITS_PER_LONG @@ -365,18 +365,18 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) return NULL; } -struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst) +struct net_device *dsa_tree_find_first_conduit(struct dsa_switch_tree *dst) { struct device_node *ethernet; - struct net_device *master; + struct net_device *conduit; struct dsa_port *cpu_dp; cpu_dp = dsa_tree_find_first_cpu(dst); ethernet = of_parse_phandle(cpu_dp->dn, "ethernet", 0); - master = of_find_net_device_by_node(ethernet); + conduit = of_find_net_device_by_node(ethernet); of_node_put(ethernet); - return master; + return conduit; } /* Assign the default CPU port (the first one in the tree) to all ports of the @@ -517,7 +517,7 @@ static int dsa_port_setup(struct dsa_port *dp) break; case DSA_PORT_TYPE_USER: of_get_mac_address(dp->dn, dp->mac); - err = dsa_slave_create(dp); + err = dsa_user_create(dp); break; } @@ -554,9 +554,9 @@ static void dsa_port_teardown(struct dsa_port *dp) dsa_shared_port_link_unregister_of(dp); break; case DSA_PORT_TYPE_USER: - if (dp->slave) { - dsa_slave_destroy(dp->slave); - dp->slave = NULL; + if (dp->user) { + dsa_user_destroy(dp->user); + dp->user = NULL; } break; } @@ -632,9 +632,9 @@ static int dsa_switch_setup(struct dsa_switch *ds) if (ds->setup) return 0; - /* Initialize ds->phys_mii_mask before registering the slave MDIO bus + /* Initialize ds->phys_mii_mask before registering the user MDIO bus * driver and before ops->setup() has run, since the switch drivers and - * the slave MDIO bus driver rely on these values for probing PHY + * the user MDIO bus driver rely on these values for probing PHY * devices or not */ ds->phys_mii_mask |= dsa_user_ports(ds); @@ -657,21 +657,21 @@ static int dsa_switch_setup(struct dsa_switch *ds) if (err) goto teardown; - if (!ds->slave_mii_bus && ds->ops->phy_read) { - ds->slave_mii_bus = mdiobus_alloc(); - if (!ds->slave_mii_bus) { + if (!ds->user_mii_bus && ds->ops->phy_read) { + ds->user_mii_bus = mdiobus_alloc(); + if (!ds->user_mii_bus) { err = -ENOMEM; goto teardown; } - dsa_slave_mii_bus_init(ds); + dsa_user_mii_bus_init(ds); dn = of_get_child_by_name(ds->dev->of_node, "mdio"); - err = of_mdiobus_register(ds->slave_mii_bus, dn); + err = of_mdiobus_register(ds->user_mii_bus, dn); of_node_put(dn); if (err < 0) - goto free_slave_mii_bus; + goto free_user_mii_bus; } dsa_switch_devlink_register(ds); @@ -679,9 +679,9 @@ static int dsa_switch_setup(struct dsa_switch *ds) ds->setup = true; return 0; -free_slave_mii_bus: - if (ds->slave_mii_bus && ds->ops->phy_read) - mdiobus_free(ds->slave_mii_bus); +free_user_mii_bus: + if (ds->user_mii_bus && ds->ops->phy_read) + mdiobus_free(ds->user_mii_bus); teardown: if (ds->ops->teardown) ds->ops->teardown(ds); @@ -699,10 +699,10 @@ static void dsa_switch_teardown(struct dsa_switch *ds) dsa_switch_devlink_unregister(ds); - if (ds->slave_mii_bus && ds->ops->phy_read) { - mdiobus_unregister(ds->slave_mii_bus); - mdiobus_free(ds->slave_mii_bus); - ds->slave_mii_bus = NULL; + if (ds->user_mii_bus && ds->ops->phy_read) { + mdiobus_unregister(ds->user_mii_bus); + mdiobus_free(ds->user_mii_bus); + ds->user_mii_bus = NULL; } dsa_switch_teardown_tag_protocol(ds); @@ -793,7 +793,7 @@ static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) return err; } -static int dsa_tree_setup_master(struct dsa_switch_tree *dst) +static int dsa_tree_setup_conduit(struct dsa_switch_tree *dst) { struct dsa_port *cpu_dp; int err = 0; @@ -801,18 +801,18 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst) rtnl_lock(); dsa_tree_for_each_cpu_port(cpu_dp, dst) { - struct net_device *master = cpu_dp->master; - bool admin_up = (master->flags & IFF_UP) && - !qdisc_tx_is_noop(master); + struct net_device *conduit = cpu_dp->conduit; + bool admin_up = (conduit->flags & IFF_UP) && + !qdisc_tx_is_noop(conduit); - err = dsa_master_setup(master, cpu_dp); + err = dsa_conduit_setup(conduit, cpu_dp); if (err) break; - /* Replay master state event */ - dsa_tree_master_admin_state_change(dst, master, admin_up); - dsa_tree_master_oper_state_change(dst, master, - netif_oper_up(master)); + /* Replay conduit state event */ + dsa_tree_conduit_admin_state_change(dst, conduit, admin_up); + dsa_tree_conduit_oper_state_change(dst, conduit, + netif_oper_up(conduit)); } rtnl_unlock(); @@ -820,22 +820,22 @@ static int dsa_tree_setup_master(struct dsa_switch_tree *dst) return err; } -static void dsa_tree_teardown_master(struct dsa_switch_tree *dst) +static void dsa_tree_teardown_conduit(struct dsa_switch_tree *dst) { struct dsa_port *cpu_dp; rtnl_lock(); dsa_tree_for_each_cpu_port(cpu_dp, dst) { - struct net_device *master = cpu_dp->master; + struct net_device *conduit = cpu_dp->conduit; /* Synthesizing an "admin down" state is sufficient for - * the switches to get a notification if the master is + * the switches to get a notification if the conduit is * currently up and running. */ - dsa_tree_master_admin_state_change(dst, master, false); + dsa_tree_conduit_admin_state_change(dst, conduit, false); - dsa_master_teardown(master); + dsa_conduit_teardown(conduit); } rtnl_unlock(); @@ -894,13 +894,13 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst) if (err) goto teardown_switches; - err = dsa_tree_setup_master(dst); + err = dsa_tree_setup_conduit(dst); if (err) goto teardown_ports; err = dsa_tree_setup_lags(dst); if (err) - goto teardown_master; + goto teardown_conduit; dst->setup = true; @@ -908,8 +908,8 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst) return 0; -teardown_master: - dsa_tree_teardown_master(dst); +teardown_conduit: + dsa_tree_teardown_conduit(dst); teardown_ports: dsa_tree_teardown_ports(dst); teardown_switches: @@ -929,7 +929,7 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) dsa_tree_teardown_lags(dst); - dsa_tree_teardown_master(dst); + dsa_tree_teardown_conduit(dst); dsa_tree_teardown_ports(dst); @@ -978,7 +978,7 @@ out_disconnect: return err; } -/* Since the dsa/tagging sysfs device attribute is per master, the assumption +/* Since the dsa/tagging sysfs device attribute is per conduit, the assumption * is that all DSA switches within a tree share the same tagger, otherwise * they would have formed disjoint trees (different "dsa,member" values). */ @@ -999,10 +999,10 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst, * restriction, there needs to be another mutex which serializes this. */ dsa_tree_for_each_user_port(dp, dst) { - if (dsa_port_to_master(dp)->flags & IFF_UP) + if (dsa_port_to_conduit(dp)->flags & IFF_UP) goto out_unlock; - if (dp->slave->flags & IFF_UP) + if (dp->user->flags & IFF_UP) goto out_unlock; } @@ -1028,62 +1028,62 @@ out_unlock: return err; } -static void dsa_tree_master_state_change(struct dsa_switch_tree *dst, - struct net_device *master) +static void dsa_tree_conduit_state_change(struct dsa_switch_tree *dst, + struct net_device *conduit) { - struct dsa_notifier_master_state_info info; - struct dsa_port *cpu_dp = master->dsa_ptr; + struct dsa_notifier_conduit_state_info info; + struct dsa_port *cpu_dp = conduit->dsa_ptr; - info.master = master; - info.operational = dsa_port_master_is_operational(cpu_dp); + info.conduit = conduit; + info.operational = dsa_port_conduit_is_operational(cpu_dp); - dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info); + dsa_tree_notify(dst, DSA_NOTIFIER_CONDUIT_STATE_CHANGE, &info); } -void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst, - struct net_device *master, - bool up) +void dsa_tree_conduit_admin_state_change(struct dsa_switch_tree *dst, + struct net_device *conduit, + bool up) { - struct dsa_port *cpu_dp = master->dsa_ptr; + struct dsa_port *cpu_dp = conduit->dsa_ptr; bool notify = false; - /* Don't keep track of admin state on LAG DSA masters, - * but rather just of physical DSA masters + /* Don't keep track of admin state on LAG DSA conduits, + * but rather just of physical DSA conduits */ - if (netif_is_lag_master(master)) + if (netif_is_lag_master(conduit)) return; - if ((dsa_port_master_is_operational(cpu_dp)) != - (up && cpu_dp->master_oper_up)) + if ((dsa_port_conduit_is_operational(cpu_dp)) != + (up && cpu_dp->conduit_oper_up)) notify = true; - cpu_dp->master_admin_up = up; + cpu_dp->conduit_admin_up = up; if (notify) - dsa_tree_master_state_change(dst, master); + dsa_tree_conduit_state_change(dst, conduit); } -void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst, - struct net_device *master, - bool up) +void dsa_tree_conduit_oper_state_change(struct dsa_switch_tree *dst, + struct net_device *conduit, + bool up) { - struct dsa_port *cpu_dp = master->dsa_ptr; + struct dsa_port *cpu_dp = conduit->dsa_ptr; bool notify = false; - /* Don't keep track of oper state on LAG DSA masters, - * but rather just of physical DSA masters + /* Don't keep track of oper state on LAG DSA conduits, + * but rather just of physical DSA conduits */ - if (netif_is_lag_master(master)) + if (netif_is_lag_master(conduit)) return; - if ((dsa_port_master_is_operational(cpu_dp)) != - (cpu_dp->master_admin_up && up)) + if ((dsa_port_conduit_is_operational(cpu_dp)) != + (cpu_dp->conduit_admin_up && up)) notify = true; - cpu_dp->master_oper_up = up; + cpu_dp->conduit_oper_up = up; if (notify) - dsa_tree_master_state_change(dst, master); + dsa_tree_conduit_state_change(dst, conduit); } static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) @@ -1129,7 +1129,7 @@ static int dsa_port_parse_dsa(struct dsa_port *dp) } static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp, - struct net_device *master) + struct net_device *conduit) { enum dsa_tag_protocol tag_protocol = DSA_TAG_PROTO_NONE; struct dsa_switch *mds, *ds = dp->ds; @@ -1140,21 +1140,21 @@ static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp, * happens the switch driver may want to know if its tagging protocol * is going to work in such a configuration. */ - if (dsa_slave_dev_check(master)) { - mdp = dsa_slave_to_port(master); + if (dsa_user_dev_check(conduit)) { + mdp = dsa_user_to_port(conduit); mds = mdp->ds; mdp_upstream = dsa_upstream_port(mds, mdp->index); tag_protocol = mds->ops->get_tag_protocol(mds, mdp_upstream, DSA_TAG_PROTO_NONE); } - /* If the master device is not itself a DSA slave in a disjoint DSA + /* If the conduit device is not itself a DSA user in a disjoint DSA * tree, then return immediately. */ return ds->ops->get_tag_protocol(ds, dp->index, tag_protocol); } -static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master, +static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *conduit, const char *user_protocol) { const struct dsa_device_ops *tag_ops = NULL; @@ -1163,7 +1163,7 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master, enum dsa_tag_protocol default_proto; /* Find out which protocol the switch would prefer. */ - default_proto = dsa_get_tag_protocol(dp, master); + default_proto = dsa_get_tag_protocol(dp, conduit); if (dst->default_proto) { if (dst->default_proto != default_proto) { dev_err(ds->dev, @@ -1218,7 +1218,7 @@ static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *master, dst->tag_ops = tag_ops; } - dp->master = master; + dp->conduit = conduit; dp->type = DSA_PORT_TYPE_CPU; dsa_port_set_tag_protocol(dp, dst->tag_ops); dp->dst = dst; @@ -1248,16 +1248,16 @@ static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) dp->dn = dn; if (ethernet) { - struct net_device *master; + struct net_device *conduit; const char *user_protocol; - master = of_find_net_device_by_node(ethernet); + conduit = of_find_net_device_by_node(ethernet); of_node_put(ethernet); - if (!master) + if (!conduit) return -EPROBE_DEFER; user_protocol = of_get_property(dn, "dsa-tag-protocol", NULL); - return dsa_port_parse_cpu(dp, master, user_protocol); + return dsa_port_parse_cpu(dp, conduit, user_protocol); } if (link) @@ -1412,15 +1412,15 @@ static int dsa_port_parse(struct dsa_port *dp, const char *name, struct device *dev) { if (!strcmp(name, "cpu")) { - struct net_device *master; + struct net_device *conduit; - master = dsa_dev_to_net_device(dev); - if (!master) + conduit = dsa_dev_to_net_device(dev); + if (!conduit) return -EPROBE_DEFER; - dev_put(master); + dev_put(conduit); - return dsa_port_parse_cpu(dp, master, NULL); + return dsa_port_parse_cpu(dp, conduit, NULL); } if (!strcmp(name, "dsa")) @@ -1566,14 +1566,14 @@ void dsa_unregister_switch(struct dsa_switch *ds) } EXPORT_SYMBOL_GPL(dsa_unregister_switch); -/* If the DSA master chooses to unregister its net_device on .shutdown, DSA is +/* If the DSA conduit chooses to unregister its net_device on .shutdown, DSA is * blocking that operation from completion, due to the dev_hold taken inside - * netdev_upper_dev_link. Unlink the DSA slave interfaces from being uppers of - * the DSA master, so that the system can reboot successfully. + * netdev_upper_dev_link. Unlink the DSA user interfaces from being uppers of + * the DSA conduit, so that the system can reboot successfully. */ void dsa_switch_shutdown(struct dsa_switch *ds) { - struct net_device *master, *slave_dev; + struct net_device *conduit, *user_dev; struct dsa_port *dp; mutex_lock(&dsa2_mutex); @@ -1584,17 +1584,17 @@ void dsa_switch_shutdown(struct dsa_switch *ds) rtnl_lock(); dsa_switch_for_each_user_port(dp, ds) { - master = dsa_port_to_master(dp); - slave_dev = dp->slave; + conduit = dsa_port_to_conduit(dp); + user_dev = dp->user; - netdev_upper_dev_unlink(master, slave_dev); + netdev_upper_dev_unlink(conduit, user_dev); } - /* Disconnect from further netdevice notifiers on the master, + /* Disconnect from further netdevice notifiers on the conduit, * since netdev_uses_dsa() will now return false. */ dsa_switch_for_each_cpu_port(dp, ds) - dp->master->dsa_ptr = NULL; + dp->conduit->dsa_ptr = NULL; rtnl_unlock(); out: @@ -1605,7 +1605,7 @@ EXPORT_SYMBOL_GPL(dsa_switch_shutdown); #ifdef CONFIG_PM_SLEEP static bool dsa_port_is_initialized(const struct dsa_port *dp) { - return dp->type == DSA_PORT_TYPE_USER && dp->slave; + return dp->type == DSA_PORT_TYPE_USER && dp->user; } int dsa_switch_suspend(struct dsa_switch *ds) @@ -1613,12 +1613,12 @@ int dsa_switch_suspend(struct dsa_switch *ds) struct dsa_port *dp; int ret = 0; - /* Suspend slave network devices */ + /* Suspend user network devices */ dsa_switch_for_each_port(dp, ds) { if (!dsa_port_is_initialized(dp)) continue; - ret = dsa_slave_suspend(dp->slave); + ret = dsa_user_suspend(dp->user); if (ret) return ret; } @@ -1641,12 +1641,12 @@ int dsa_switch_resume(struct dsa_switch *ds) if (ret) return ret; - /* Resume slave network devices */ + /* Resume user network devices */ dsa_switch_for_each_port(dp, ds) { if (!dsa_port_is_initialized(dp)) continue; - ret = dsa_slave_resume(dp->slave); + ret = dsa_user_resume(dp->user); if (ret) return ret; } @@ -1658,10 +1658,10 @@ EXPORT_SYMBOL_GPL(dsa_switch_resume); struct dsa_port *dsa_port_from_netdev(struct net_device *netdev) { - if (!netdev || !dsa_slave_dev_check(netdev)) + if (!netdev || !dsa_user_dev_check(netdev)) return ERR_PTR(-ENODEV); - return dsa_slave_to_port(netdev); + return dsa_user_to_port(netdev); } EXPORT_SYMBOL_GPL(dsa_port_from_netdev); @@ -1726,7 +1726,7 @@ bool dsa_mdb_present_in_other_db(struct dsa_switch *ds, int port, EXPORT_SYMBOL_GPL(dsa_mdb_present_in_other_db); static const struct dsa_stubs __dsa_stubs = { - .master_hwtstamp_validate = __dsa_master_hwtstamp_validate, + .conduit_hwtstamp_validate = __dsa_conduit_hwtstamp_validate, }; static void dsa_register_stubs(void) @@ -1748,7 +1748,7 @@ static int __init dsa_init_module(void) if (!dsa_owq) return -ENOMEM; - rc = dsa_slave_register_notifier(); + rc = dsa_user_register_notifier(); if (rc) goto register_notifier_fail; @@ -1763,7 +1763,7 @@ static int __init dsa_init_module(void) return 0; netlink_register_fail: - dsa_slave_unregister_notifier(); + dsa_user_unregister_notifier(); dev_remove_pack(&dsa_pack_type); register_notifier_fail: destroy_workqueue(dsa_owq); @@ -1778,7 +1778,7 @@ static void __exit dsa_cleanup_module(void) rtnl_link_unregister(&dsa_link_ops); - dsa_slave_unregister_notifier(); + dsa_user_unregister_notifier(); dev_remove_pack(&dsa_pack_type); destroy_workqueue(dsa_owq); } diff --git a/net/dsa/dsa.h b/net/dsa/dsa.h index b7e17ae1094d..3cc7823e9ef3 100644 --- a/net/dsa/dsa.h +++ b/net/dsa/dsa.h @@ -21,16 +21,16 @@ void dsa_lag_map(struct dsa_switch_tree *dst, struct dsa_lag *lag); void dsa_lag_unmap(struct dsa_switch_tree *dst, struct dsa_lag *lag); struct dsa_lag *dsa_tree_lag_find(struct dsa_switch_tree *dst, const struct net_device *lag_dev); -struct net_device *dsa_tree_find_first_master(struct dsa_switch_tree *dst); +struct net_device *dsa_tree_find_first_conduit(struct dsa_switch_tree *dst); int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst, const struct dsa_device_ops *tag_ops, const struct dsa_device_ops *old_tag_ops); -void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst, - struct net_device *master, +void dsa_tree_conduit_admin_state_change(struct dsa_switch_tree *dst, + struct net_device *conduit, + bool up); +void dsa_tree_conduit_oper_state_change(struct dsa_switch_tree *dst, + struct net_device *conduit, bool up); -void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst, - struct net_device *master, - bool up); unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max); void dsa_bridge_num_put(const struct net_device *bridge_dev, unsigned int bridge_num); diff --git a/net/dsa/master.c b/net/dsa/master.c deleted file mode 100644 index 6be89ab0cc01..000000000000 --- a/net/dsa/master.c +++ /dev/null @@ -1,475 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Handling of a master device, switching frames via its switch fabric CPU port - * - * Copyright (c) 2017 Savoir-faire Linux Inc. - * Vivien Didelot - */ - -#include -#include -#include -#include - -#include "dsa.h" -#include "master.h" -#include "port.h" -#include "tag.h" - -static int dsa_master_get_regs_len(struct net_device *dev) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; - struct dsa_switch *ds = cpu_dp->ds; - int port = cpu_dp->index; - int ret = 0; - int len; - - if (ops->get_regs_len) { - len = ops->get_regs_len(dev); - if (len < 0) - return len; - ret += len; - } - - ret += sizeof(struct ethtool_drvinfo); - ret += sizeof(struct ethtool_regs); - - if (ds->ops->get_regs_len) { - len = ds->ops->get_regs_len(ds, port); - if (len < 0) - return len; - ret += len; - } - - return ret; -} - -static void dsa_master_get_regs(struct net_device *dev, - struct ethtool_regs *regs, void *data) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; - struct dsa_switch *ds = cpu_dp->ds; - struct ethtool_drvinfo *cpu_info; - struct ethtool_regs *cpu_regs; - int port = cpu_dp->index; - int len; - - if (ops->get_regs_len && ops->get_regs) { - len = ops->get_regs_len(dev); - if (len < 0) - return; - regs->len = len; - ops->get_regs(dev, regs, data); - data += regs->len; - } - - cpu_info = (struct ethtool_drvinfo *)data; - strscpy(cpu_info->driver, "dsa", sizeof(cpu_info->driver)); - data += sizeof(*cpu_info); - cpu_regs = (struct ethtool_regs *)data; - data += sizeof(*cpu_regs); - - if (ds->ops->get_regs_len && ds->ops->get_regs) { - len = ds->ops->get_regs_len(ds, port); - if (len < 0) - return; - cpu_regs->len = len; - ds->ops->get_regs(ds, port, cpu_regs, data); - } -} - -static void dsa_master_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, - uint64_t *data) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; - struct dsa_switch *ds = cpu_dp->ds; - int port = cpu_dp->index; - int count = 0; - - if (ops->get_sset_count && ops->get_ethtool_stats) { - count = ops->get_sset_count(dev, ETH_SS_STATS); - ops->get_ethtool_stats(dev, stats, data); - } - - if (ds->ops->get_ethtool_stats) - ds->ops->get_ethtool_stats(ds, port, data + count); -} - -static void dsa_master_get_ethtool_phy_stats(struct net_device *dev, - struct ethtool_stats *stats, - uint64_t *data) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; - struct dsa_switch *ds = cpu_dp->ds; - int port = cpu_dp->index; - int count = 0; - - if (dev->phydev && !ops->get_ethtool_phy_stats) { - count = phy_ethtool_get_sset_count(dev->phydev); - if (count >= 0) - phy_ethtool_get_stats(dev->phydev, stats, data); - } else if (ops->get_sset_count && ops->get_ethtool_phy_stats) { - count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); - ops->get_ethtool_phy_stats(dev, stats, data); - } - - if (count < 0) - count = 0; - - if (ds->ops->get_ethtool_phy_stats) - ds->ops->get_ethtool_phy_stats(ds, port, data + count); -} - -static int dsa_master_get_sset_count(struct net_device *dev, int sset) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; - struct dsa_switch *ds = cpu_dp->ds; - int count = 0; - - if (sset == ETH_SS_PHY_STATS && dev->phydev && - !ops->get_ethtool_phy_stats) - count = phy_ethtool_get_sset_count(dev->phydev); - else if (ops->get_sset_count) - count = ops->get_sset_count(dev, sset); - - if (count < 0) - count = 0; - - if (ds->ops->get_sset_count) - count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); - - return count; -} - -static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset, - uint8_t *data) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; - struct dsa_switch *ds = cpu_dp->ds; - int port = cpu_dp->index; - int len = ETH_GSTRING_LEN; - int mcount = 0, count, i; - uint8_t pfx[4]; - uint8_t *ndata; - - snprintf(pfx, sizeof(pfx), "p%.2d", port); - /* We do not want to be NULL-terminated, since this is a prefix */ - pfx[sizeof(pfx) - 1] = '_'; - - if (stringset == ETH_SS_PHY_STATS && dev->phydev && - !ops->get_ethtool_phy_stats) { - mcount = phy_ethtool_get_sset_count(dev->phydev); - if (mcount < 0) - mcount = 0; - else - phy_ethtool_get_strings(dev->phydev, data); - } else if (ops->get_sset_count && ops->get_strings) { - mcount = ops->get_sset_count(dev, stringset); - if (mcount < 0) - mcount = 0; - ops->get_strings(dev, stringset, data); - } - - if (ds->ops->get_strings) { - ndata = data + mcount * len; - /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle - * the output after to prepend our CPU port prefix we - * constructed earlier - */ - ds->ops->get_strings(ds, port, stringset, ndata); - count = ds->ops->get_sset_count(ds, port, stringset); - if (count < 0) - return; - for (i = 0; i < count; i++) { - memmove(ndata + (i * len + sizeof(pfx)), - ndata + i * len, len - sizeof(pfx)); - memcpy(ndata + i * len, pfx, sizeof(pfx)); - } - } -} - -/* Deny PTP operations on master if there is at least one switch in the tree - * that is PTP capable. - */ -int __dsa_master_hwtstamp_validate(struct net_device *dev, - const struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - struct dsa_switch *ds = cpu_dp->ds; - struct dsa_switch_tree *dst; - struct dsa_port *dp; - - dst = ds->dst; - - list_for_each_entry(dp, &dst->ports, list) { - if (dsa_port_supports_hwtstamp(dp)) { - NL_SET_ERR_MSG(extack, - "HW timestamping not allowed on DSA master when switch supports the operation"); - return -EBUSY; - } - } - - return 0; -} - -static int dsa_master_ethtool_setup(struct net_device *dev) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - struct dsa_switch *ds = cpu_dp->ds; - struct ethtool_ops *ops; - - if (netif_is_lag_master(dev)) - return 0; - - ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL); - if (!ops) - return -ENOMEM; - - cpu_dp->orig_ethtool_ops = dev->ethtool_ops; - if (cpu_dp->orig_ethtool_ops) - memcpy(ops, cpu_dp->orig_ethtool_ops, sizeof(*ops)); - - ops->get_regs_len = dsa_master_get_regs_len; - ops->get_regs = dsa_master_get_regs; - ops->get_sset_count = dsa_master_get_sset_count; - ops->get_ethtool_stats = dsa_master_get_ethtool_stats; - ops->get_strings = dsa_master_get_strings; - ops->get_ethtool_phy_stats = dsa_master_get_ethtool_phy_stats; - - dev->ethtool_ops = ops; - - return 0; -} - -static void dsa_master_ethtool_teardown(struct net_device *dev) -{ - struct dsa_port *cpu_dp = dev->dsa_ptr; - - if (netif_is_lag_master(dev)) - return; - - dev->ethtool_ops = cpu_dp->orig_ethtool_ops; - cpu_dp->orig_ethtool_ops = NULL; -} - -/* Keep the master always promiscuous if the tagging protocol requires that - * (garbles MAC DA) or if it doesn't support unicast filtering, case in which - * it would revert to promiscuous mode as soon as we call dev_uc_add() on it - * anyway. - */ -static void dsa_master_set_promiscuity(struct net_device *dev, int inc) -{ - const struct dsa_device_ops *ops = dev->dsa_ptr->tag_ops; - - if ((dev->priv_flags & IFF_UNICAST_FLT) && !ops->promisc_on_master) - return; - - ASSERT_RTNL(); - - dev_set_promiscuity(dev, inc); -} - -static ssize_t tagging_show(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct net_device *dev = to_net_dev(d); - struct dsa_port *cpu_dp = dev->dsa_ptr; - - return sysfs_emit(buf, "%s\n", - dsa_tag_protocol_to_str(cpu_dp->tag_ops)); -} - -static ssize_t tagging_store(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - const struct dsa_device_ops *new_tag_ops, *old_tag_ops; - const char *end = strchrnul(buf, '\n'), *name; - struct net_device *dev = to_net_dev(d); - struct dsa_port *cpu_dp = dev->dsa_ptr; - size_t len = end - buf; - int err; - - /* Empty string passed */ - if (!len) - return -ENOPROTOOPT; - - name = kstrndup(buf, len, GFP_KERNEL); - if (!name) - return -ENOMEM; - - old_tag_ops = cpu_dp->tag_ops; - new_tag_ops = dsa_tag_driver_get_by_name(name); - kfree(name); - /* Bad tagger name? */ - if (IS_ERR(new_tag_ops)) - return PTR_ERR(new_tag_ops); - - if (new_tag_ops == old_tag_ops) - /* Drop the temporarily held duplicate reference, since - * the DSA switch tree uses this tagger. - */ - goto out; - - err = dsa_tree_change_tag_proto(cpu_dp->ds->dst, new_tag_ops, - old_tag_ops); - if (err) { - /* On failure the old tagger is restored, so we don't need the - * driver for the new one. - */ - dsa_tag_driver_put(new_tag_ops); - return err; - } - - /* On success we no longer need the module for the old tagging protocol - */ -out: - dsa_tag_driver_put(old_tag_ops); - return count; -} -static DEVICE_ATTR_RW(tagging); - -static struct attribute *dsa_slave_attrs[] = { - &dev_attr_tagging.attr, - NULL -}; - -static const struct attribute_group dsa_group = { - .name = "dsa", - .attrs = dsa_slave_attrs, -}; - -static void dsa_master_reset_mtu(struct net_device *dev) -{ - int err; - - err = dev_set_mtu(dev, ETH_DATA_LEN); - if (err) - netdev_dbg(dev, - "Unable to reset MTU to exclude DSA overheads\n"); -} - -int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) -{ - const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops; - struct dsa_switch *ds = cpu_dp->ds; - struct device_link *consumer_link; - int mtu, ret; - - mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops); - - /* The DSA master must use SET_NETDEV_DEV for this to work. */ - if (!netif_is_lag_master(dev)) { - consumer_link = device_link_add(ds->dev, dev->dev.parent, - DL_FLAG_AUTOREMOVE_CONSUMER); - if (!consumer_link) - netdev_err(dev, - "Failed to create a device link to DSA switch %s\n", - dev_name(ds->dev)); - } - - /* The switch driver may not implement ->port_change_mtu(), case in - * which dsa_slave_change_mtu() will not update the master MTU either, - * so we need to do that here. - */ - ret = dev_set_mtu(dev, mtu); - if (ret) - netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n", - ret, mtu); - - /* If we use a tagging format that doesn't have an ethertype - * field, make sure that all packets from this point on get - * sent to the tag format's receive function. - */ - wmb(); - - dev->dsa_ptr = cpu_dp; - - dsa_master_set_promiscuity(dev, 1); - - ret = dsa_master_ethtool_setup(dev); - if (ret) - goto out_err_reset_promisc; - - ret = sysfs_create_group(&dev->dev.kobj, &dsa_group); - if (ret) - goto out_err_ethtool_teardown; - - return ret; - -out_err_ethtool_teardown: - dsa_master_ethtool_teardown(dev); -out_err_reset_promisc: - dsa_master_set_promiscuity(dev, -1); - return ret; -} - -void dsa_master_teardown(struct net_device *dev) -{ - sysfs_remove_group(&dev->dev.kobj, &dsa_group); - dsa_master_ethtool_teardown(dev); - dsa_master_reset_mtu(dev); - dsa_master_set_promiscuity(dev, -1); - - dev->dsa_ptr = NULL; - - /* If we used a tagging format that doesn't have an ethertype - * field, make sure that all packets from this point get sent - * without the tag and go through the regular receive path. - */ - wmb(); -} - -int dsa_master_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp, - struct netdev_lag_upper_info *uinfo, - struct netlink_ext_ack *extack) -{ - bool master_setup = false; - int err; - - if (!netdev_uses_dsa(lag_dev)) { - err = dsa_master_setup(lag_dev, cpu_dp); - if (err) - return err; - - master_setup = true; - } - - err = dsa_port_lag_join(cpu_dp, lag_dev, uinfo, extack); - if (err) { - NL_SET_ERR_MSG_WEAK_MOD(extack, "CPU port failed to join LAG"); - goto out_master_teardown; - } - - return 0; - -out_master_teardown: - if (master_setup) - dsa_master_teardown(lag_dev); - return err; -} - -/* Tear down a master if there isn't any other user port on it, - * optionally also destroying LAG information. - */ -void dsa_master_lag_teardown(struct net_device *lag_dev, - struct dsa_port *cpu_dp) -{ - struct net_device *upper; - struct list_head *iter; - - dsa_port_lag_leave(cpu_dp, lag_dev); - - netdev_for_each_upper_dev_rcu(lag_dev, upper, iter) - if (dsa_slave_dev_check(upper)) - return; - - dsa_master_teardown(lag_dev); -} diff --git a/net/dsa/master.h b/net/dsa/master.h deleted file mode 100644 index 76e39d3ec909..000000000000 --- a/net/dsa/master.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef __DSA_MASTER_H -#define __DSA_MASTER_H - -struct dsa_port; -struct net_device; -struct netdev_lag_upper_info; -struct netlink_ext_ack; - -int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp); -void dsa_master_teardown(struct net_device *dev); -int dsa_master_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp, - struct netdev_lag_upper_info *uinfo, - struct netlink_ext_ack *extack); -void dsa_master_lag_teardown(struct net_device *lag_dev, - struct dsa_port *cpu_dp); -int __dsa_master_hwtstamp_validate(struct net_device *dev, - const struct kernel_hwtstamp_config *config, - struct netlink_ext_ack *extack); - -#endif diff --git a/net/dsa/netlink.c b/net/dsa/netlink.c index bd4bbaf851de..f56f90a25b99 100644 --- a/net/dsa/netlink.c +++ b/net/dsa/netlink.c @@ -5,7 +5,7 @@ #include #include "netlink.h" -#include "slave.h" +#include "user.h" static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = { [IFLA_DSA_MASTER] = { .type = NLA_U32 }, @@ -22,13 +22,13 @@ static int dsa_changelink(struct net_device *dev, struct nlattr *tb[], if (data[IFLA_DSA_MASTER]) { u32 ifindex = nla_get_u32(data[IFLA_DSA_MASTER]); - struct net_device *master; + struct net_device *conduit; - master = __dev_get_by_index(dev_net(dev), ifindex); - if (!master) + conduit = __dev_get_by_index(dev_net(dev), ifindex); + if (!conduit) return -EINVAL; - err = dsa_slave_change_master(dev, master, extack); + err = dsa_user_change_conduit(dev, conduit, extack); if (err) return err; } @@ -44,9 +44,9 @@ static size_t dsa_get_size(const struct net_device *dev) static int dsa_fill_info(struct sk_buff *skb, const struct net_device *dev) { - struct net_device *master = dsa_slave_to_master(dev); + struct net_device *conduit = dsa_user_to_conduit(dev); - if (nla_put_u32(skb, IFLA_DSA_MASTER, master->ifindex)) + if (nla_put_u32(skb, IFLA_DSA_MASTER, conduit->ifindex)) return -EMSGSIZE; return 0; diff --git a/net/dsa/port.c b/net/dsa/port.c index 6e0d000a97c4..c42dac87671b 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -14,9 +14,9 @@ #include "dsa.h" #include "port.h" -#include "slave.h" #include "switch.h" #include "tag_8021q.h" +#include "user.h" /** * dsa_port_notify - Notify the switching fabric of changes to a port @@ -289,7 +289,7 @@ static void dsa_port_reset_vlan_filtering(struct dsa_port *dp, } /* If the bridge was vlan_filtering, the bridge core doesn't trigger an - * event for changing vlan_filtering setting upon slave ports leaving + * event for changing vlan_filtering setting upon user ports leaving * it. That is a good thing, because that lets us handle it and also * handle the case where the switch's vlan_filtering setting is global * (not per port). When that happens, the correct moment to trigger the @@ -489,7 +489,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, .dp = dp, .extack = extack, }; - struct net_device *dev = dp->slave; + struct net_device *dev = dp->user; struct net_device *brport_dev; int err; @@ -514,8 +514,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, dp->bridge->tx_fwd_offload = info.tx_fwd_offload; err = switchdev_bridge_port_offload(brport_dev, dev, dp, - &dsa_slave_switchdev_notifier, - &dsa_slave_switchdev_blocking_notifier, + &dsa_user_switchdev_notifier, + &dsa_user_switchdev_blocking_notifier, dp->bridge->tx_fwd_offload, extack); if (err) goto out_rollback_unbridge; @@ -528,8 +528,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, out_rollback_unoffload: switchdev_bridge_port_unoffload(brport_dev, dp, - &dsa_slave_switchdev_notifier, - &dsa_slave_switchdev_blocking_notifier); + &dsa_user_switchdev_notifier, + &dsa_user_switchdev_blocking_notifier); dsa_flush_workqueue(); out_rollback_unbridge: dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info); @@ -547,8 +547,8 @@ void dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br) return; switchdev_bridge_port_unoffload(brport_dev, dp, - &dsa_slave_switchdev_notifier, - &dsa_slave_switchdev_blocking_notifier); + &dsa_user_switchdev_notifier, + &dsa_user_switchdev_blocking_notifier); dsa_flush_workqueue(); } @@ -741,10 +741,10 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp, */ if (vlan_filtering && dsa_port_is_user(dp)) { struct net_device *br = dsa_port_bridge_dev_get(dp); - struct net_device *upper_dev, *slave = dp->slave; + struct net_device *upper_dev, *user = dp->user; struct list_head *iter; - netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) { + netdev_for_each_upper_dev_rcu(user, upper_dev, iter) { struct bridge_vlan_info br_info; u16 vid; @@ -803,9 +803,9 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, if (!ds->ops->port_vlan_filtering) return -EOPNOTSUPP; - /* We are called from dsa_slave_switchdev_blocking_event(), + /* We are called from dsa_user_switchdev_blocking_event(), * which is not under rcu_read_lock(), unlike - * dsa_slave_switchdev_event(). + * dsa_user_switchdev_event(). */ rcu_read_lock(); apply = dsa_port_can_apply_vlan_filtering(dp, vlan_filtering, extack); @@ -827,24 +827,24 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, ds->vlan_filtering = vlan_filtering; dsa_switch_for_each_user_port(other_dp, ds) { - struct net_device *slave = other_dp->slave; + struct net_device *user = other_dp->user; /* We might be called in the unbind path, so not - * all slave devices might still be registered. + * all user devices might still be registered. */ - if (!slave) + if (!user) continue; - err = dsa_slave_manage_vlan_filtering(slave, - vlan_filtering); + err = dsa_user_manage_vlan_filtering(user, + vlan_filtering); if (err) goto restore; } } else { dp->vlan_filtering = vlan_filtering; - err = dsa_slave_manage_vlan_filtering(dp->slave, - vlan_filtering); + err = dsa_user_manage_vlan_filtering(dp->user, + vlan_filtering); if (err) goto restore; } @@ -863,7 +863,7 @@ restore: } /* This enforces legacy behavior for switch drivers which assume they can't - * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0 + * receive VLAN configuration when joining a bridge with vlan_filtering=0 */ bool dsa_port_skip_vlan_configuration(struct dsa_port *dp) { @@ -1047,7 +1047,7 @@ int dsa_port_standalone_host_fdb_add(struct dsa_port *dp, int dsa_port_bridge_host_fdb_add(struct dsa_port *dp, const unsigned char *addr, u16 vid) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); struct dsa_db db = { .type = DSA_DB_BRIDGE, .bridge = *dp->bridge, @@ -1057,12 +1057,12 @@ int dsa_port_bridge_host_fdb_add(struct dsa_port *dp, if (!dp->ds->fdb_isolation) db.bridge.num = 0; - /* Avoid a call to __dev_set_promiscuity() on the master, which + /* Avoid a call to __dev_set_promiscuity() on the conduit, which * requires rtnl_lock(), since we can't guarantee that is held here, * and we can't take it either. */ - if (master->priv_flags & IFF_UNICAST_FLT) { - err = dev_uc_add(master, addr); + if (conduit->priv_flags & IFF_UNICAST_FLT) { + err = dev_uc_add(conduit, addr); if (err) return err; } @@ -1098,7 +1098,7 @@ int dsa_port_standalone_host_fdb_del(struct dsa_port *dp, int dsa_port_bridge_host_fdb_del(struct dsa_port *dp, const unsigned char *addr, u16 vid) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); struct dsa_db db = { .type = DSA_DB_BRIDGE, .bridge = *dp->bridge, @@ -1108,8 +1108,8 @@ int dsa_port_bridge_host_fdb_del(struct dsa_port *dp, if (!dp->ds->fdb_isolation) db.bridge.num = 0; - if (master->priv_flags & IFF_UNICAST_FLT) { - err = dev_uc_del(master, addr); + if (conduit->priv_flags & IFF_UNICAST_FLT) { + err = dev_uc_del(conduit, addr); if (err) return err; } @@ -1229,7 +1229,7 @@ int dsa_port_standalone_host_mdb_add(const struct dsa_port *dp, int dsa_port_bridge_host_mdb_add(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); struct dsa_db db = { .type = DSA_DB_BRIDGE, .bridge = *dp->bridge, @@ -1239,7 +1239,7 @@ int dsa_port_bridge_host_mdb_add(const struct dsa_port *dp, if (!dp->ds->fdb_isolation) db.bridge.num = 0; - err = dev_mc_add(master, mdb->addr); + err = dev_mc_add(conduit, mdb->addr); if (err) return err; @@ -1273,7 +1273,7 @@ int dsa_port_standalone_host_mdb_del(const struct dsa_port *dp, int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); struct dsa_db db = { .type = DSA_DB_BRIDGE, .bridge = *dp->bridge, @@ -1283,7 +1283,7 @@ int dsa_port_bridge_host_mdb_del(const struct dsa_port *dp, if (!dp->ds->fdb_isolation) db.bridge.num = 0; - err = dev_mc_del(master, mdb->addr); + err = dev_mc_del(conduit, mdb->addr); if (err) return err; @@ -1318,7 +1318,7 @@ int dsa_port_host_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan, struct netlink_ext_ack *extack) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); struct dsa_notifier_vlan_info info = { .dp = dp, .vlan = vlan, @@ -1330,7 +1330,7 @@ int dsa_port_host_vlan_add(struct dsa_port *dp, if (err && err != -EOPNOTSUPP) return err; - vlan_vid_add(master, htons(ETH_P_8021Q), vlan->vid); + vlan_vid_add(conduit, htons(ETH_P_8021Q), vlan->vid); return err; } @@ -1338,7 +1338,7 @@ int dsa_port_host_vlan_add(struct dsa_port *dp, int dsa_port_host_vlan_del(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan) { - struct net_device *master = dsa_port_to_master(dp); + struct net_device *conduit = dsa_port_to_conduit(dp); struct dsa_notifier_vlan_info info = { .dp = dp, .vlan = vlan, @@ -1349,7 +1349,7 @@ int dsa_port_host_vlan_del(struct dsa_port *dp, if (err && err != -EOPNOTSUPP) return err; - vlan_vid_del(master, htons(ETH_P_8021Q), vlan->vid); + vlan_vid_del(conduit, htons(ETH_P_8021Q), vlan->vid); return err; } @@ -1398,24 +1398,24 @@ int dsa_port_mrp_del_ring_role(const struct dsa_port *dp, return ds->ops->port_mrp_del_ring_role(ds, dp->index, mrp); } -static int dsa_port_assign_master(struct dsa_port *dp, - struct net_device *master, - struct netlink_ext_ack *extack, - bool fail_on_err) +static int dsa_port_assign_conduit(struct dsa_port *dp, + struct net_device *conduit, + struct netlink_ext_ack *extack, + bool fail_on_err) { struct dsa_switch *ds = dp->ds; int port = dp->index, err; - err = ds->ops->port_change_master(ds, port, master, extack); + err = ds->ops->port_change_conduit(ds, port, conduit, extack); if (err && !fail_on_err) - dev_err(ds->dev, "port %d failed to assign master %s: %pe\n", - port, master->name, ERR_PTR(err)); + dev_err(ds->dev, "port %d failed to assign conduit %s: %pe\n", + port, conduit->name, ERR_PTR(err)); if (err && fail_on_err) return err; - dp->cpu_dp = master->dsa_ptr; - dp->cpu_port_in_lag = netif_is_lag_master(master); + dp->cpu_dp = conduit->dsa_ptr; + dp->cpu_port_in_lag = netif_is_lag_master(conduit); return 0; } @@ -1428,12 +1428,12 @@ static int dsa_port_assign_master(struct dsa_port *dp, * the old CPU port before changing it, and restore it on errors during the * bringup of the new one. */ -int dsa_port_change_master(struct dsa_port *dp, struct net_device *master, - struct netlink_ext_ack *extack) +int dsa_port_change_conduit(struct dsa_port *dp, struct net_device *conduit, + struct netlink_ext_ack *extack) { struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp); - struct net_device *old_master = dsa_port_to_master(dp); - struct net_device *dev = dp->slave; + struct net_device *old_conduit = dsa_port_to_conduit(dp); + struct net_device *dev = dp->user; struct dsa_switch *ds = dp->ds; bool vlan_filtering; int err, tmp; @@ -1454,7 +1454,7 @@ int dsa_port_change_master(struct dsa_port *dp, struct net_device *master, */ vlan_filtering = dsa_port_is_vlan_filtering(dp); if (vlan_filtering) { - err = dsa_slave_manage_vlan_filtering(dev, false); + err = dsa_user_manage_vlan_filtering(dev, false); if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed to remove standalone VLANs"); @@ -1465,16 +1465,16 @@ int dsa_port_change_master(struct dsa_port *dp, struct net_device *master, /* Standalone addresses, and addresses of upper interfaces like * VLAN, LAG, HSR need to be migrated. */ - dsa_slave_unsync_ha(dev); + dsa_user_unsync_ha(dev); - err = dsa_port_assign_master(dp, master, extack, true); + err = dsa_port_assign_conduit(dp, conduit, extack, true); if (err) goto rewind_old_addrs; - dsa_slave_sync_ha(dev); + dsa_user_sync_ha(dev); if (vlan_filtering) { - err = dsa_slave_manage_vlan_filtering(dev, true); + err = dsa_user_manage_vlan_filtering(dev, true); if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed to restore standalone VLANs"); @@ -1495,19 +1495,19 @@ int dsa_port_change_master(struct dsa_port *dp, struct net_device *master, rewind_new_vlan: if (vlan_filtering) - dsa_slave_manage_vlan_filtering(dev, false); + dsa_user_manage_vlan_filtering(dev, false); rewind_new_addrs: - dsa_slave_unsync_ha(dev); + dsa_user_unsync_ha(dev); - dsa_port_assign_master(dp, old_master, NULL, false); + dsa_port_assign_conduit(dp, old_conduit, NULL, false); /* Restore the objects on the old CPU port */ rewind_old_addrs: - dsa_slave_sync_ha(dev); + dsa_user_sync_ha(dev); if (vlan_filtering) { - tmp = dsa_slave_manage_vlan_filtering(dev, true); + tmp = dsa_user_manage_vlan_filtering(dev, true); if (tmp) { dev_err(ds->dev, "port %d failed to restore standalone VLANs: %pe\n", @@ -1620,7 +1620,7 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config, struct dsa_switch *ds = dp->ds; if (dsa_port_is_user(dp)) - phydev = dp->slave->phydev; + phydev = dp->user->phydev; if (!ds->ops->phylink_mac_link_down) { if (ds->ops->adjust_link && phydev) @@ -1808,7 +1808,7 @@ err_phy_connect: * their type. * * User ports with no phy-handle or fixed-link are expected to connect to an - * internal PHY located on the ds->slave_mii_bus at an MDIO address equal to + * internal PHY located on the ds->user_mii_bus at an MDIO address equal to * the port number. This description is still actively supported. * * Shared (CPU and DSA) ports with no phy-handle or fixed-link are expected to @@ -1829,7 +1829,7 @@ err_phy_connect: * a fixed-link, a phy-handle, or a managed = "in-band-status" property. * It becomes the responsibility of the driver to ensure that these ports * operate at the maximum speed (whatever this means) and will interoperate - * with the DSA master or other cascade port, since phylink methods will not be + * with the DSA conduit or other cascade port, since phylink methods will not be * invoked for them. * * If you are considering expanding this table for newly introduced switches, diff --git a/net/dsa/port.h b/net/dsa/port.h index 334879964e2c..6bc3291573c0 100644 --- a/net/dsa/port.h +++ b/net/dsa/port.h @@ -109,7 +109,7 @@ void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr); int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast); void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast); void dsa_port_set_host_flood(struct dsa_port *dp, bool uc, bool mc); -int dsa_port_change_master(struct dsa_port *dp, struct net_device *master, - struct netlink_ext_ack *extack); +int dsa_port_change_conduit(struct dsa_port *dp, struct net_device *conduit, + struct netlink_ext_ack *extack); #endif diff --git a/net/dsa/slave.c b/net/dsa/slave.c deleted file mode 100644 index 4c3e502d7e16..000000000000 --- a/net/dsa/slave.c +++ /dev/null @@ -1,3727 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * net/dsa/slave.c - Slave device handling - * Copyright (c) 2008-2009 Marvell Semiconductor - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dsa.h" -#include "port.h" -#include "master.h" -#include "netlink.h" -#include "slave.h" -#include "switch.h" -#include "tag.h" - -struct dsa_switchdev_event_work { - struct net_device *dev; - struct net_device *orig_dev; - struct work_struct work; - unsigned long event; - /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and - * SWITCHDEV_FDB_DEL_TO_DEVICE - */ - unsigned char addr[ETH_ALEN]; - u16 vid; - bool host_addr; -}; - -enum dsa_standalone_event { - DSA_UC_ADD, - DSA_UC_DEL, - DSA_MC_ADD, - DSA_MC_DEL, -}; - -struct dsa_standalone_event_work { - struct work_struct work; - struct net_device *dev; - enum dsa_standalone_event event; - unsigned char addr[ETH_ALEN]; - u16 vid; -}; - -struct dsa_host_vlan_rx_filtering_ctx { - struct net_device *dev; - const unsigned char *addr; - enum dsa_standalone_event event; -}; - -static bool dsa_switch_supports_uc_filtering(struct dsa_switch *ds) -{ - return ds->ops->port_fdb_add && ds->ops->port_fdb_del && - ds->fdb_isolation && !ds->vlan_filtering_is_global && - !ds->needs_standalone_vlan_filtering; -} - -static bool dsa_switch_supports_mc_filtering(struct dsa_switch *ds) -{ - return ds->ops->port_mdb_add && ds->ops->port_mdb_del && - ds->fdb_isolation && !ds->vlan_filtering_is_global && - !ds->needs_standalone_vlan_filtering; -} - -static void dsa_slave_standalone_event_work(struct work_struct *work) -{ - struct dsa_standalone_event_work *standalone_work = - container_of(work, struct dsa_standalone_event_work, work); - const unsigned char *addr = standalone_work->addr; - struct net_device *dev = standalone_work->dev; - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_mdb mdb; - struct dsa_switch *ds = dp->ds; - u16 vid = standalone_work->vid; - int err; - - switch (standalone_work->event) { - case DSA_UC_ADD: - err = dsa_port_standalone_host_fdb_add(dp, addr, vid); - if (err) { - dev_err(ds->dev, - "port %d failed to add %pM vid %d to fdb: %d\n", - dp->index, addr, vid, err); - break; - } - break; - - case DSA_UC_DEL: - err = dsa_port_standalone_host_fdb_del(dp, addr, vid); - if (err) { - dev_err(ds->dev, - "port %d failed to delete %pM vid %d from fdb: %d\n", - dp->index, addr, vid, err); - } - - break; - case DSA_MC_ADD: - ether_addr_copy(mdb.addr, addr); - mdb.vid = vid; - - err = dsa_port_standalone_host_mdb_add(dp, &mdb); - if (err) { - dev_err(ds->dev, - "port %d failed to add %pM vid %d to mdb: %d\n", - dp->index, addr, vid, err); - break; - } - break; - case DSA_MC_DEL: - ether_addr_copy(mdb.addr, addr); - mdb.vid = vid; - - err = dsa_port_standalone_host_mdb_del(dp, &mdb); - if (err) { - dev_err(ds->dev, - "port %d failed to delete %pM vid %d from mdb: %d\n", - dp->index, addr, vid, err); - } - - break; - } - - kfree(standalone_work); -} - -static int dsa_slave_schedule_standalone_work(struct net_device *dev, - enum dsa_standalone_event event, - const unsigned char *addr, - u16 vid) -{ - struct dsa_standalone_event_work *standalone_work; - - standalone_work = kzalloc(sizeof(*standalone_work), GFP_ATOMIC); - if (!standalone_work) - return -ENOMEM; - - INIT_WORK(&standalone_work->work, dsa_slave_standalone_event_work); - standalone_work->event = event; - standalone_work->dev = dev; - - ether_addr_copy(standalone_work->addr, addr); - standalone_work->vid = vid; - - dsa_schedule_work(&standalone_work->work); - - return 0; -} - -static int dsa_slave_host_vlan_rx_filtering(void *arg, int vid) -{ - struct dsa_host_vlan_rx_filtering_ctx *ctx = arg; - - return dsa_slave_schedule_standalone_work(ctx->dev, ctx->event, - ctx->addr, vid); -} - -static int dsa_slave_vlan_for_each(struct net_device *dev, - int (*cb)(void *arg, int vid), void *arg) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_vlan *v; - int err; - - lockdep_assert_held(&dev->addr_list_lock); - - err = cb(arg, 0); - if (err) - return err; - - list_for_each_entry(v, &dp->user_vlans, list) { - err = cb(arg, v->vid); - if (err) - return err; - } - - return 0; -} - -static int dsa_slave_sync_uc(struct net_device *dev, - const unsigned char *addr) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_host_vlan_rx_filtering_ctx ctx = { - .dev = dev, - .addr = addr, - .event = DSA_UC_ADD, - }; - - dev_uc_add(master, addr); - - if (!dsa_switch_supports_uc_filtering(dp->ds)) - return 0; - - return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, - &ctx); -} - -static int dsa_slave_unsync_uc(struct net_device *dev, - const unsigned char *addr) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_host_vlan_rx_filtering_ctx ctx = { - .dev = dev, - .addr = addr, - .event = DSA_UC_DEL, - }; - - dev_uc_del(master, addr); - - if (!dsa_switch_supports_uc_filtering(dp->ds)) - return 0; - - return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, - &ctx); -} - -static int dsa_slave_sync_mc(struct net_device *dev, - const unsigned char *addr) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_host_vlan_rx_filtering_ctx ctx = { - .dev = dev, - .addr = addr, - .event = DSA_MC_ADD, - }; - - dev_mc_add(master, addr); - - if (!dsa_switch_supports_mc_filtering(dp->ds)) - return 0; - - return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, - &ctx); -} - -static int dsa_slave_unsync_mc(struct net_device *dev, - const unsigned char *addr) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_host_vlan_rx_filtering_ctx ctx = { - .dev = dev, - .addr = addr, - .event = DSA_MC_DEL, - }; - - dev_mc_del(master, addr); - - if (!dsa_switch_supports_mc_filtering(dp->ds)) - return 0; - - return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, - &ctx); -} - -void dsa_slave_sync_ha(struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - struct netdev_hw_addr *ha; - - netif_addr_lock_bh(dev); - - netdev_for_each_synced_mc_addr(ha, dev) - dsa_slave_sync_mc(dev, ha->addr); - - netdev_for_each_synced_uc_addr(ha, dev) - dsa_slave_sync_uc(dev, ha->addr); - - netif_addr_unlock_bh(dev); - - if (dsa_switch_supports_uc_filtering(ds) || - dsa_switch_supports_mc_filtering(ds)) - dsa_flush_workqueue(); -} - -void dsa_slave_unsync_ha(struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - struct netdev_hw_addr *ha; - - netif_addr_lock_bh(dev); - - netdev_for_each_synced_uc_addr(ha, dev) - dsa_slave_unsync_uc(dev, ha->addr); - - netdev_for_each_synced_mc_addr(ha, dev) - dsa_slave_unsync_mc(dev, ha->addr); - - netif_addr_unlock_bh(dev); - - if (dsa_switch_supports_uc_filtering(ds) || - dsa_switch_supports_mc_filtering(ds)) - dsa_flush_workqueue(); -} - -/* slave mii_bus handling ***************************************************/ -static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) -{ - struct dsa_switch *ds = bus->priv; - - if (ds->phys_mii_mask & (1 << addr)) - return ds->ops->phy_read(ds, addr, reg); - - return 0xffff; -} - -static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) -{ - struct dsa_switch *ds = bus->priv; - - if (ds->phys_mii_mask & (1 << addr)) - return ds->ops->phy_write(ds, addr, reg, val); - - return 0; -} - -void dsa_slave_mii_bus_init(struct dsa_switch *ds) -{ - ds->slave_mii_bus->priv = (void *)ds; - ds->slave_mii_bus->name = "dsa slave smi"; - ds->slave_mii_bus->read = dsa_slave_phy_read; - ds->slave_mii_bus->write = dsa_slave_phy_write; - snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", - ds->dst->index, ds->index); - ds->slave_mii_bus->parent = ds->dev; - ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; -} - - -/* slave device handling ****************************************************/ -static int dsa_slave_get_iflink(const struct net_device *dev) -{ - return dsa_slave_to_master(dev)->ifindex; -} - -static int dsa_slave_open(struct net_device *dev) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int err; - - err = dev_open(master, NULL); - if (err < 0) { - netdev_err(dev, "failed to open master %s\n", master->name); - goto out; - } - - if (dsa_switch_supports_uc_filtering(ds)) { - err = dsa_port_standalone_host_fdb_add(dp, dev->dev_addr, 0); - if (err) - goto out; - } - - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { - err = dev_uc_add(master, dev->dev_addr); - if (err < 0) - goto del_host_addr; - } - - err = dsa_port_enable_rt(dp, dev->phydev); - if (err) - goto del_unicast; - - return 0; - -del_unicast: - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) - dev_uc_del(master, dev->dev_addr); -del_host_addr: - if (dsa_switch_supports_uc_filtering(ds)) - dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); -out: - return err; -} - -static int dsa_slave_close(struct net_device *dev) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - dsa_port_disable_rt(dp); - - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) - dev_uc_del(master, dev->dev_addr); - - if (dsa_switch_supports_uc_filtering(ds)) - dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); - - return 0; -} - -static void dsa_slave_manage_host_flood(struct net_device *dev) -{ - bool mc = dev->flags & (IFF_PROMISC | IFF_ALLMULTI); - struct dsa_port *dp = dsa_slave_to_port(dev); - bool uc = dev->flags & IFF_PROMISC; - - dsa_port_set_host_flood(dp, uc, mc); -} - -static void dsa_slave_change_rx_flags(struct net_device *dev, int change) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (change & IFF_ALLMULTI) - dev_set_allmulti(master, - dev->flags & IFF_ALLMULTI ? 1 : -1); - if (change & IFF_PROMISC) - dev_set_promiscuity(master, - dev->flags & IFF_PROMISC ? 1 : -1); - - if (dsa_switch_supports_uc_filtering(ds) && - dsa_switch_supports_mc_filtering(ds)) - dsa_slave_manage_host_flood(dev); -} - -static void dsa_slave_set_rx_mode(struct net_device *dev) -{ - __dev_mc_sync(dev, dsa_slave_sync_mc, dsa_slave_unsync_mc); - __dev_uc_sync(dev, dsa_slave_sync_uc, dsa_slave_unsync_uc); -} - -static int dsa_slave_set_mac_address(struct net_device *dev, void *a) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - struct sockaddr *addr = a; - int err; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - if (ds->ops->port_set_mac_address) { - err = ds->ops->port_set_mac_address(ds, dp->index, - addr->sa_data); - if (err) - return err; - } - - /* If the port is down, the address isn't synced yet to hardware or - * to the DSA master, so there is nothing to change. - */ - if (!(dev->flags & IFF_UP)) - goto out_change_dev_addr; - - if (dsa_switch_supports_uc_filtering(ds)) { - err = dsa_port_standalone_host_fdb_add(dp, addr->sa_data, 0); - if (err) - return err; - } - - if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { - err = dev_uc_add(master, addr->sa_data); - if (err < 0) - goto del_unicast; - } - - if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) - dev_uc_del(master, dev->dev_addr); - - if (dsa_switch_supports_uc_filtering(ds)) - dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); - -out_change_dev_addr: - eth_hw_addr_set(dev, addr->sa_data); - - return 0; - -del_unicast: - if (dsa_switch_supports_uc_filtering(ds)) - dsa_port_standalone_host_fdb_del(dp, addr->sa_data, 0); - - return err; -} - -struct dsa_slave_dump_ctx { - struct net_device *dev; - struct sk_buff *skb; - struct netlink_callback *cb; - int idx; -}; - -static int -dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid, - bool is_static, void *data) -{ - struct dsa_slave_dump_ctx *dump = data; - u32 portid = NETLINK_CB(dump->cb->skb).portid; - u32 seq = dump->cb->nlh->nlmsg_seq; - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - if (dump->idx < dump->cb->args[2]) - goto skip; - - nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, - sizeof(*ndm), NLM_F_MULTI); - if (!nlh) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = AF_BRIDGE; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = NTF_SELF; - ndm->ndm_type = 0; - ndm->ndm_ifindex = dump->dev->ifindex; - ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; - - if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) - goto nla_put_failure; - - if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) - goto nla_put_failure; - - nlmsg_end(dump->skb, nlh); - -skip: - dump->idx++; - return 0; - -nla_put_failure: - nlmsg_cancel(dump->skb, nlh); - return -EMSGSIZE; -} - -static int -dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *dev, struct net_device *filter_dev, - int *idx) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_slave_dump_ctx dump = { - .dev = dev, - .skb = skb, - .cb = cb, - .idx = *idx, - }; - int err; - - err = dsa_port_fdb_dump(dp, dsa_slave_port_fdb_do_dump, &dump); - *idx = dump.idx; - - return err; -} - -static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; - int port = p->dp->index; - - /* Pass through to switch driver if it supports timestamping */ - switch (cmd) { - case SIOCGHWTSTAMP: - if (ds->ops->port_hwtstamp_get) - return ds->ops->port_hwtstamp_get(ds, port, ifr); - break; - case SIOCSHWTSTAMP: - if (ds->ops->port_hwtstamp_set) - return ds->ops->port_hwtstamp_set(ds, port, ifr); - break; - } - - return phylink_mii_ioctl(p->dp->pl, ifr, cmd); -} - -static int dsa_slave_port_attr_set(struct net_device *dev, const void *ctx, - const struct switchdev_attr *attr, - struct netlink_ext_ack *extack) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - int ret; - - if (ctx && ctx != dp) - return 0; - - switch (attr->id) { - case SWITCHDEV_ATTR_ID_PORT_STP_STATE: - if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_set_state(dp, attr->u.stp_state, true); - break; - case SWITCHDEV_ATTR_ID_PORT_MST_STATE: - if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_set_mst_state(dp, &attr->u.mst_state, extack); - break; - case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: - if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, - extack); - break; - case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: - if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_ageing_time(dp, attr->u.ageing_time); - break; - case SWITCHDEV_ATTR_ID_BRIDGE_MST: - if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_mst_enable(dp, attr->u.mst, extack); - break; - case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: - if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, - extack); - break; - case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: - if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack); - break; - case SWITCHDEV_ATTR_ID_VLAN_MSTI: - if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) - return -EOPNOTSUPP; - - ret = dsa_port_vlan_msti(dp, &attr->u.vlan_msti); - break; - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - -/* Must be called under rcu_read_lock() */ -static int -dsa_slave_vlan_check_for_8021q_uppers(struct net_device *slave, - const struct switchdev_obj_port_vlan *vlan) -{ - struct net_device *upper_dev; - struct list_head *iter; - - netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) { - u16 vid; - - if (!is_vlan_dev(upper_dev)) - continue; - - vid = vlan_dev_vlan_id(upper_dev); - if (vid == vlan->vid) - return -EBUSY; - } - - return 0; -} - -static int dsa_slave_vlan_add(struct net_device *dev, - const struct switchdev_obj *obj, - struct netlink_ext_ack *extack) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_vlan *vlan; - int err; - - if (dsa_port_skip_vlan_configuration(dp)) { - NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); - return 0; - } - - vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); - - /* Deny adding a bridge VLAN when there is already an 802.1Q upper with - * the same VID. - */ - if (br_vlan_enabled(dsa_port_bridge_dev_get(dp))) { - rcu_read_lock(); - err = dsa_slave_vlan_check_for_8021q_uppers(dev, vlan); - rcu_read_unlock(); - if (err) { - NL_SET_ERR_MSG_MOD(extack, - "Port already has a VLAN upper with this VID"); - return err; - } - } - - return dsa_port_vlan_add(dp, vlan, extack); -} - -/* Offload a VLAN installed on the bridge or on a foreign interface by - * installing it as a VLAN towards the CPU port. - */ -static int dsa_slave_host_vlan_add(struct net_device *dev, - const struct switchdev_obj *obj, - struct netlink_ext_ack *extack) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_vlan vlan; - - /* Do nothing if this is a software bridge */ - if (!dp->bridge) - return -EOPNOTSUPP; - - if (dsa_port_skip_vlan_configuration(dp)) { - NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); - return 0; - } - - vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj); - - /* Even though drivers often handle CPU membership in special ways, - * it doesn't make sense to program a PVID, so clear this flag. - */ - vlan.flags &= ~BRIDGE_VLAN_INFO_PVID; - - return dsa_port_host_vlan_add(dp, &vlan, extack); -} - -static int dsa_slave_port_obj_add(struct net_device *dev, const void *ctx, - const struct switchdev_obj *obj, - struct netlink_ext_ack *extack) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - int err; - - if (ctx && ctx != dp) - return 0; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_MDB: - if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - case SWITCHDEV_OBJ_ID_HOST_MDB: - if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_bridge_host_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - case SWITCHDEV_OBJ_ID_PORT_VLAN: - if (dsa_port_offloads_bridge_port(dp, obj->orig_dev)) - err = dsa_slave_vlan_add(dev, obj, extack); - else - err = dsa_slave_host_vlan_add(dev, obj, extack); - break; - case SWITCHDEV_OBJ_ID_MRP: - if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_mrp_add(dp, SWITCHDEV_OBJ_MRP(obj)); - break; - case SWITCHDEV_OBJ_ID_RING_ROLE_MRP: - if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_mrp_add_ring_role(dp, - SWITCHDEV_OBJ_RING_ROLE_MRP(obj)); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static int dsa_slave_vlan_del(struct net_device *dev, - const struct switchdev_obj *obj) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_vlan *vlan; - - if (dsa_port_skip_vlan_configuration(dp)) - return 0; - - vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); - - return dsa_port_vlan_del(dp, vlan); -} - -static int dsa_slave_host_vlan_del(struct net_device *dev, - const struct switchdev_obj *obj) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_vlan *vlan; - - /* Do nothing if this is a software bridge */ - if (!dp->bridge) - return -EOPNOTSUPP; - - if (dsa_port_skip_vlan_configuration(dp)) - return 0; - - vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); - - return dsa_port_host_vlan_del(dp, vlan); -} - -static int dsa_slave_port_obj_del(struct net_device *dev, const void *ctx, - const struct switchdev_obj *obj) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - int err; - - if (ctx && ctx != dp) - return 0; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_MDB: - if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - case SWITCHDEV_OBJ_ID_HOST_MDB: - if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_bridge_host_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); - break; - case SWITCHDEV_OBJ_ID_PORT_VLAN: - if (dsa_port_offloads_bridge_port(dp, obj->orig_dev)) - err = dsa_slave_vlan_del(dev, obj); - else - err = dsa_slave_host_vlan_del(dev, obj); - break; - case SWITCHDEV_OBJ_ID_MRP: - if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_mrp_del(dp, SWITCHDEV_OBJ_MRP(obj)); - break; - case SWITCHDEV_OBJ_ID_RING_ROLE_MRP: - if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) - return -EOPNOTSUPP; - - err = dsa_port_mrp_del_ring_role(dp, - SWITCHDEV_OBJ_RING_ROLE_MRP(obj)); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev, - struct sk_buff *skb) -{ -#ifdef CONFIG_NET_POLL_CONTROLLER - struct dsa_slave_priv *p = netdev_priv(dev); - - return netpoll_send_skb(p->netpoll, skb); -#else - BUG(); - return NETDEV_TX_OK; -#endif -} - -static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p, - struct sk_buff *skb) -{ - struct dsa_switch *ds = p->dp->ds; - - if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) - return; - - if (!ds->ops->port_txtstamp) - return; - - ds->ops->port_txtstamp(ds, p->dp->index, skb); -} - -netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev) -{ - /* SKB for netpoll still need to be mangled with the protocol-specific - * tag to be successfully transmitted - */ - if (unlikely(netpoll_tx_running(dev))) - return dsa_slave_netpoll_send_skb(dev, skb); - - /* Queue the SKB for transmission on the parent interface, but - * do not modify its EtherType - */ - skb->dev = dsa_slave_to_master(dev); - dev_queue_xmit(skb); - - return NETDEV_TX_OK; -} -EXPORT_SYMBOL_GPL(dsa_enqueue_skb); - -static int dsa_realloc_skb(struct sk_buff *skb, struct net_device *dev) -{ - int needed_headroom = dev->needed_headroom; - int needed_tailroom = dev->needed_tailroom; - - /* For tail taggers, we need to pad short frames ourselves, to ensure - * that the tail tag does not fail at its role of being at the end of - * the packet, once the master interface pads the frame. Account for - * that pad length here, and pad later. - */ - if (unlikely(needed_tailroom && skb->len < ETH_ZLEN)) - needed_tailroom += ETH_ZLEN - skb->len; - /* skb_headroom() returns unsigned int... */ - needed_headroom = max_t(int, needed_headroom - skb_headroom(skb), 0); - needed_tailroom = max_t(int, needed_tailroom - skb_tailroom(skb), 0); - - if (likely(!needed_headroom && !needed_tailroom && !skb_cloned(skb))) - /* No reallocation needed, yay! */ - return 0; - - return pskb_expand_head(skb, needed_headroom, needed_tailroom, - GFP_ATOMIC); -} - -static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct sk_buff *nskb; - - dev_sw_netstats_tx_add(dev, 1, skb->len); - - memset(skb->cb, 0, sizeof(skb->cb)); - - /* Handle tx timestamp if any */ - dsa_skb_tx_timestamp(p, skb); - - if (dsa_realloc_skb(skb, dev)) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - /* needed_tailroom should still be 'warm' in the cache line from - * dsa_realloc_skb(), which has also ensured that padding is safe. - */ - if (dev->needed_tailroom) - eth_skb_pad(skb); - - /* Transmit function may have to reallocate the original SKB, - * in which case it must have freed it. Only free it here on error. - */ - nskb = p->xmit(skb, dev); - if (!nskb) { - kfree_skb(skb); - return NETDEV_TX_OK; - } - - return dsa_enqueue_skb(nskb, dev); -} - -/* ethtool operations *******************************************************/ - -static void dsa_slave_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *drvinfo) -{ - strscpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver)); - strscpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); - strscpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info)); -} - -static int dsa_slave_get_regs_len(struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_regs_len) - return ds->ops->get_regs_len(ds, dp->index); - - return -EOPNOTSUPP; -} - -static void -dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_regs) - ds->ops->get_regs(ds, dp->index, regs, _p); -} - -static int dsa_slave_nway_reset(struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - return phylink_ethtool_nway_reset(dp->pl); -} - -static int dsa_slave_get_eeprom_len(struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->cd && ds->cd->eeprom_len) - return ds->cd->eeprom_len; - - if (ds->ops->get_eeprom_len) - return ds->ops->get_eeprom_len(ds); - - return 0; -} - -static int dsa_slave_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_eeprom) - return ds->ops->get_eeprom(ds, eeprom, data); - - return -EOPNOTSUPP; -} - -static int dsa_slave_set_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->set_eeprom) - return ds->ops->set_eeprom(ds, eeprom, data); - - return -EOPNOTSUPP; -} - -static void dsa_slave_get_strings(struct net_device *dev, - uint32_t stringset, uint8_t *data) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (stringset == ETH_SS_STATS) { - int len = ETH_GSTRING_LEN; - - strscpy_pad(data, "tx_packets", len); - strscpy_pad(data + len, "tx_bytes", len); - strscpy_pad(data + 2 * len, "rx_packets", len); - strscpy_pad(data + 3 * len, "rx_bytes", len); - if (ds->ops->get_strings) - ds->ops->get_strings(ds, dp->index, stringset, - data + 4 * len); - } else if (stringset == ETH_SS_TEST) { - net_selftest_get_strings(data); - } - -} - -static void dsa_slave_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, - uint64_t *data) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - struct pcpu_sw_netstats *s; - unsigned int start; - int i; - - for_each_possible_cpu(i) { - u64 tx_packets, tx_bytes, rx_packets, rx_bytes; - - s = per_cpu_ptr(dev->tstats, i); - do { - start = u64_stats_fetch_begin(&s->syncp); - tx_packets = u64_stats_read(&s->tx_packets); - tx_bytes = u64_stats_read(&s->tx_bytes); - rx_packets = u64_stats_read(&s->rx_packets); - rx_bytes = u64_stats_read(&s->rx_bytes); - } while (u64_stats_fetch_retry(&s->syncp, start)); - data[0] += tx_packets; - data[1] += tx_bytes; - data[2] += rx_packets; - data[3] += rx_bytes; - } - if (ds->ops->get_ethtool_stats) - ds->ops->get_ethtool_stats(ds, dp->index, data + 4); -} - -static int dsa_slave_get_sset_count(struct net_device *dev, int sset) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (sset == ETH_SS_STATS) { - int count = 0; - - if (ds->ops->get_sset_count) { - count = ds->ops->get_sset_count(ds, dp->index, sset); - if (count < 0) - return count; - } - - return count + 4; - } else if (sset == ETH_SS_TEST) { - return net_selftest_get_count(); - } - - return -EOPNOTSUPP; -} - -static void dsa_slave_get_eth_phy_stats(struct net_device *dev, - struct ethtool_eth_phy_stats *phy_stats) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_eth_phy_stats) - ds->ops->get_eth_phy_stats(ds, dp->index, phy_stats); -} - -static void dsa_slave_get_eth_mac_stats(struct net_device *dev, - struct ethtool_eth_mac_stats *mac_stats) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_eth_mac_stats) - ds->ops->get_eth_mac_stats(ds, dp->index, mac_stats); -} - -static void -dsa_slave_get_eth_ctrl_stats(struct net_device *dev, - struct ethtool_eth_ctrl_stats *ctrl_stats) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_eth_ctrl_stats) - ds->ops->get_eth_ctrl_stats(ds, dp->index, ctrl_stats); -} - -static void -dsa_slave_get_rmon_stats(struct net_device *dev, - struct ethtool_rmon_stats *rmon_stats, - const struct ethtool_rmon_hist_range **ranges) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_rmon_stats) - ds->ops->get_rmon_stats(ds, dp->index, rmon_stats, ranges); -} - -static void dsa_slave_net_selftest(struct net_device *ndev, - struct ethtool_test *etest, u64 *buf) -{ - struct dsa_port *dp = dsa_slave_to_port(ndev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->self_test) { - ds->ops->self_test(ds, dp->index, etest, buf); - return; - } - - net_selftest(ndev, etest, buf); -} - -static int dsa_slave_get_mm(struct net_device *dev, - struct ethtool_mm_state *state) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (!ds->ops->get_mm) - return -EOPNOTSUPP; - - return ds->ops->get_mm(ds, dp->index, state); -} - -static int dsa_slave_set_mm(struct net_device *dev, struct ethtool_mm_cfg *cfg, - struct netlink_ext_ack *extack) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (!ds->ops->set_mm) - return -EOPNOTSUPP; - - return ds->ops->set_mm(ds, dp->index, cfg, extack); -} - -static void dsa_slave_get_mm_stats(struct net_device *dev, - struct ethtool_mm_stats *stats) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_mm_stats) - ds->ops->get_mm_stats(ds, dp->index, stats); -} - -static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - phylink_ethtool_get_wol(dp->pl, w); - - if (ds->ops->get_wol) - ds->ops->get_wol(ds, dp->index, w); -} - -static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int ret = -EOPNOTSUPP; - - phylink_ethtool_set_wol(dp->pl, w); - - if (ds->ops->set_wol) - ret = ds->ops->set_wol(ds, dp->index, w); - - return ret; -} - -static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int ret; - - /* Port's PHY and MAC both need to be EEE capable */ - if (!dev->phydev || !dp->pl) - return -ENODEV; - - if (!ds->ops->set_mac_eee) - return -EOPNOTSUPP; - - ret = ds->ops->set_mac_eee(ds, dp->index, e); - if (ret) - return ret; - - return phylink_ethtool_set_eee(dp->pl, e); -} - -static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int ret; - - /* Port's PHY and MAC both need to be EEE capable */ - if (!dev->phydev || !dp->pl) - return -ENODEV; - - if (!ds->ops->get_mac_eee) - return -EOPNOTSUPP; - - ret = ds->ops->get_mac_eee(ds, dp->index, e); - if (ret) - return ret; - - return phylink_ethtool_get_eee(dp->pl, e); -} - -static int dsa_slave_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - return phylink_ethtool_ksettings_get(dp->pl, cmd); -} - -static int dsa_slave_set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - return phylink_ethtool_ksettings_set(dp->pl, cmd); -} - -static void dsa_slave_get_pause_stats(struct net_device *dev, - struct ethtool_pause_stats *pause_stats) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_pause_stats) - ds->ops->get_pause_stats(ds, dp->index, pause_stats); -} - -static void dsa_slave_get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *pause) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - phylink_ethtool_get_pauseparam(dp->pl, pause); -} - -static int dsa_slave_set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *pause) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - return phylink_ethtool_set_pauseparam(dp->pl, pause); -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static int dsa_slave_netpoll_setup(struct net_device *dev, - struct netpoll_info *ni) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_slave_priv *p = netdev_priv(dev); - struct netpoll *netpoll; - int err = 0; - - netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); - if (!netpoll) - return -ENOMEM; - - err = __netpoll_setup(netpoll, master); - if (err) { - kfree(netpoll); - goto out; - } - - p->netpoll = netpoll; -out: - return err; -} - -static void dsa_slave_netpoll_cleanup(struct net_device *dev) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct netpoll *netpoll = p->netpoll; - - if (!netpoll) - return; - - p->netpoll = NULL; - - __netpoll_free(netpoll); -} - -static void dsa_slave_poll_controller(struct net_device *dev) -{ -} -#endif - -static struct dsa_mall_tc_entry * -dsa_slave_mall_tc_entry_find(struct net_device *dev, unsigned long cookie) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_mall_tc_entry *mall_tc_entry; - - list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) - if (mall_tc_entry->cookie == cookie) - return mall_tc_entry; - - return NULL; -} - -static int -dsa_slave_add_cls_matchall_mirred(struct net_device *dev, - struct tc_cls_matchall_offload *cls, - bool ingress) -{ - struct netlink_ext_ack *extack = cls->common.extack; - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_mall_mirror_tc_entry *mirror; - struct dsa_mall_tc_entry *mall_tc_entry; - struct dsa_switch *ds = dp->ds; - struct flow_action_entry *act; - struct dsa_port *to_dp; - int err; - - if (!ds->ops->port_mirror_add) - return -EOPNOTSUPP; - - if (!flow_action_basic_hw_stats_check(&cls->rule->action, - cls->common.extack)) - return -EOPNOTSUPP; - - act = &cls->rule->action.entries[0]; - - if (!act->dev) - return -EINVAL; - - if (!dsa_slave_dev_check(act->dev)) - return -EOPNOTSUPP; - - mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); - if (!mall_tc_entry) - return -ENOMEM; - - mall_tc_entry->cookie = cls->cookie; - mall_tc_entry->type = DSA_PORT_MALL_MIRROR; - mirror = &mall_tc_entry->mirror; - - to_dp = dsa_slave_to_port(act->dev); - - mirror->to_local_port = to_dp->index; - mirror->ingress = ingress; - - err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress, extack); - if (err) { - kfree(mall_tc_entry); - return err; - } - - list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); - - return err; -} - -static int -dsa_slave_add_cls_matchall_police(struct net_device *dev, - struct tc_cls_matchall_offload *cls, - bool ingress) -{ - struct netlink_ext_ack *extack = cls->common.extack; - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_mall_policer_tc_entry *policer; - struct dsa_mall_tc_entry *mall_tc_entry; - struct dsa_switch *ds = dp->ds; - struct flow_action_entry *act; - int err; - - if (!ds->ops->port_policer_add) { - NL_SET_ERR_MSG_MOD(extack, - "Policing offload not implemented"); - return -EOPNOTSUPP; - } - - if (!ingress) { - NL_SET_ERR_MSG_MOD(extack, - "Only supported on ingress qdisc"); - return -EOPNOTSUPP; - } - - if (!flow_action_basic_hw_stats_check(&cls->rule->action, - cls->common.extack)) - return -EOPNOTSUPP; - - list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) { - if (mall_tc_entry->type == DSA_PORT_MALL_POLICER) { - NL_SET_ERR_MSG_MOD(extack, - "Only one port policer allowed"); - return -EEXIST; - } - } - - act = &cls->rule->action.entries[0]; - - mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); - if (!mall_tc_entry) - return -ENOMEM; - - mall_tc_entry->cookie = cls->cookie; - mall_tc_entry->type = DSA_PORT_MALL_POLICER; - policer = &mall_tc_entry->policer; - policer->rate_bytes_per_sec = act->police.rate_bytes_ps; - policer->burst = act->police.burst; - - err = ds->ops->port_policer_add(ds, dp->index, policer); - if (err) { - kfree(mall_tc_entry); - return err; - } - - list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); - - return err; -} - -static int dsa_slave_add_cls_matchall(struct net_device *dev, - struct tc_cls_matchall_offload *cls, - bool ingress) -{ - int err = -EOPNOTSUPP; - - if (cls->common.protocol == htons(ETH_P_ALL) && - flow_offload_has_one_action(&cls->rule->action) && - cls->rule->action.entries[0].id == FLOW_ACTION_MIRRED) - err = dsa_slave_add_cls_matchall_mirred(dev, cls, ingress); - else if (flow_offload_has_one_action(&cls->rule->action) && - cls->rule->action.entries[0].id == FLOW_ACTION_POLICE) - err = dsa_slave_add_cls_matchall_police(dev, cls, ingress); - - return err; -} - -static void dsa_slave_del_cls_matchall(struct net_device *dev, - struct tc_cls_matchall_offload *cls) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_mall_tc_entry *mall_tc_entry; - struct dsa_switch *ds = dp->ds; - - mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie); - if (!mall_tc_entry) - return; - - list_del(&mall_tc_entry->list); - - switch (mall_tc_entry->type) { - case DSA_PORT_MALL_MIRROR: - if (ds->ops->port_mirror_del) - ds->ops->port_mirror_del(ds, dp->index, - &mall_tc_entry->mirror); - break; - case DSA_PORT_MALL_POLICER: - if (ds->ops->port_policer_del) - ds->ops->port_policer_del(ds, dp->index); - break; - default: - WARN_ON(1); - } - - kfree(mall_tc_entry); -} - -static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev, - struct tc_cls_matchall_offload *cls, - bool ingress) -{ - if (cls->common.chain_index) - return -EOPNOTSUPP; - - switch (cls->command) { - case TC_CLSMATCHALL_REPLACE: - return dsa_slave_add_cls_matchall(dev, cls, ingress); - case TC_CLSMATCHALL_DESTROY: - dsa_slave_del_cls_matchall(dev, cls); - return 0; - default: - return -EOPNOTSUPP; - } -} - -static int dsa_slave_add_cls_flower(struct net_device *dev, - struct flow_cls_offload *cls, - bool ingress) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int port = dp->index; - - if (!ds->ops->cls_flower_add) - return -EOPNOTSUPP; - - return ds->ops->cls_flower_add(ds, port, cls, ingress); -} - -static int dsa_slave_del_cls_flower(struct net_device *dev, - struct flow_cls_offload *cls, - bool ingress) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int port = dp->index; - - if (!ds->ops->cls_flower_del) - return -EOPNOTSUPP; - - return ds->ops->cls_flower_del(ds, port, cls, ingress); -} - -static int dsa_slave_stats_cls_flower(struct net_device *dev, - struct flow_cls_offload *cls, - bool ingress) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int port = dp->index; - - if (!ds->ops->cls_flower_stats) - return -EOPNOTSUPP; - - return ds->ops->cls_flower_stats(ds, port, cls, ingress); -} - -static int dsa_slave_setup_tc_cls_flower(struct net_device *dev, - struct flow_cls_offload *cls, - bool ingress) -{ - switch (cls->command) { - case FLOW_CLS_REPLACE: - return dsa_slave_add_cls_flower(dev, cls, ingress); - case FLOW_CLS_DESTROY: - return dsa_slave_del_cls_flower(dev, cls, ingress); - case FLOW_CLS_STATS: - return dsa_slave_stats_cls_flower(dev, cls, ingress); - default: - return -EOPNOTSUPP; - } -} - -static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data, - void *cb_priv, bool ingress) -{ - struct net_device *dev = cb_priv; - - if (!tc_can_offload(dev)) - return -EOPNOTSUPP; - - switch (type) { - case TC_SETUP_CLSMATCHALL: - return dsa_slave_setup_tc_cls_matchall(dev, type_data, ingress); - case TC_SETUP_CLSFLOWER: - return dsa_slave_setup_tc_cls_flower(dev, type_data, ingress); - default: - return -EOPNOTSUPP; - } -} - -static int dsa_slave_setup_tc_block_cb_ig(enum tc_setup_type type, - void *type_data, void *cb_priv) -{ - return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, true); -} - -static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type, - void *type_data, void *cb_priv) -{ - return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, false); -} - -static LIST_HEAD(dsa_slave_block_cb_list); - -static int dsa_slave_setup_tc_block(struct net_device *dev, - struct flow_block_offload *f) -{ - struct flow_block_cb *block_cb; - flow_setup_cb_t *cb; - - if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) - cb = dsa_slave_setup_tc_block_cb_ig; - else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) - cb = dsa_slave_setup_tc_block_cb_eg; - else - return -EOPNOTSUPP; - - f->driver_block_list = &dsa_slave_block_cb_list; - - switch (f->command) { - case FLOW_BLOCK_BIND: - if (flow_block_cb_is_busy(cb, dev, &dsa_slave_block_cb_list)) - return -EBUSY; - - block_cb = flow_block_cb_alloc(cb, dev, dev, NULL); - if (IS_ERR(block_cb)) - return PTR_ERR(block_cb); - - flow_block_cb_add(block_cb, f); - list_add_tail(&block_cb->driver_list, &dsa_slave_block_cb_list); - return 0; - case FLOW_BLOCK_UNBIND: - block_cb = flow_block_cb_lookup(f->block, cb, dev); - if (!block_cb) - return -ENOENT; - - flow_block_cb_remove(block_cb, f); - list_del(&block_cb->driver_list); - return 0; - default: - return -EOPNOTSUPP; - } -} - -static int dsa_slave_setup_ft_block(struct dsa_switch *ds, int port, - void *type_data) -{ - struct net_device *master = dsa_port_to_master(dsa_to_port(ds, port)); - - if (!master->netdev_ops->ndo_setup_tc) - return -EOPNOTSUPP; - - return master->netdev_ops->ndo_setup_tc(master, TC_SETUP_FT, type_data); -} - -static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type, - void *type_data) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - switch (type) { - case TC_SETUP_BLOCK: - return dsa_slave_setup_tc_block(dev, type_data); - case TC_SETUP_FT: - return dsa_slave_setup_ft_block(ds, dp->index, type_data); - default: - break; - } - - if (!ds->ops->port_setup_tc) - return -EOPNOTSUPP; - - return ds->ops->port_setup_tc(ds, dp->index, type, type_data); -} - -static int dsa_slave_get_rxnfc(struct net_device *dev, - struct ethtool_rxnfc *nfc, u32 *rule_locs) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (!ds->ops->get_rxnfc) - return -EOPNOTSUPP; - - return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs); -} - -static int dsa_slave_set_rxnfc(struct net_device *dev, - struct ethtool_rxnfc *nfc) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (!ds->ops->set_rxnfc) - return -EOPNOTSUPP; - - return ds->ops->set_rxnfc(ds, dp->index, nfc); -} - -static int dsa_slave_get_ts_info(struct net_device *dev, - struct ethtool_ts_info *ts) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; - - if (!ds->ops->get_ts_info) - return -EOPNOTSUPP; - - return ds->ops->get_ts_info(ds, p->dp->index, ts); -} - -static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, - u16 vid) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_vlan vlan = { - .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, - .vid = vid, - /* This API only allows programming tagged, non-PVID VIDs */ - .flags = 0, - }; - struct netlink_ext_ack extack = {0}; - struct dsa_switch *ds = dp->ds; - struct netdev_hw_addr *ha; - struct dsa_vlan *v; - int ret; - - /* User port... */ - ret = dsa_port_vlan_add(dp, &vlan, &extack); - if (ret) { - if (extack._msg) - netdev_err(dev, "%s\n", extack._msg); - return ret; - } - - /* And CPU port... */ - ret = dsa_port_host_vlan_add(dp, &vlan, &extack); - if (ret) { - if (extack._msg) - netdev_err(dev, "CPU port %d: %s\n", dp->cpu_dp->index, - extack._msg); - return ret; - } - - if (!dsa_switch_supports_uc_filtering(ds) && - !dsa_switch_supports_mc_filtering(ds)) - return 0; - - v = kzalloc(sizeof(*v), GFP_KERNEL); - if (!v) { - ret = -ENOMEM; - goto rollback; - } - - netif_addr_lock_bh(dev); - - v->vid = vid; - list_add_tail(&v->list, &dp->user_vlans); - - if (dsa_switch_supports_mc_filtering(ds)) { - netdev_for_each_synced_mc_addr(ha, dev) { - dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD, - ha->addr, vid); - } - } - - if (dsa_switch_supports_uc_filtering(ds)) { - netdev_for_each_synced_uc_addr(ha, dev) { - dsa_slave_schedule_standalone_work(dev, DSA_UC_ADD, - ha->addr, vid); - } - } - - netif_addr_unlock_bh(dev); - - dsa_flush_workqueue(); - - return 0; - -rollback: - dsa_port_host_vlan_del(dp, &vlan); - dsa_port_vlan_del(dp, &vlan); - - return ret; -} - -static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, - u16 vid) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct switchdev_obj_port_vlan vlan = { - .vid = vid, - /* This API only allows programming tagged, non-PVID VIDs */ - .flags = 0, - }; - struct dsa_switch *ds = dp->ds; - struct netdev_hw_addr *ha; - struct dsa_vlan *v; - int err; - - err = dsa_port_vlan_del(dp, &vlan); - if (err) - return err; - - err = dsa_port_host_vlan_del(dp, &vlan); - if (err) - return err; - - if (!dsa_switch_supports_uc_filtering(ds) && - !dsa_switch_supports_mc_filtering(ds)) - return 0; - - netif_addr_lock_bh(dev); - - v = dsa_vlan_find(&dp->user_vlans, &vlan); - if (!v) { - netif_addr_unlock_bh(dev); - return -ENOENT; - } - - list_del(&v->list); - kfree(v); - - if (dsa_switch_supports_mc_filtering(ds)) { - netdev_for_each_synced_mc_addr(ha, dev) { - dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, - ha->addr, vid); - } - } - - if (dsa_switch_supports_uc_filtering(ds)) { - netdev_for_each_synced_uc_addr(ha, dev) { - dsa_slave_schedule_standalone_work(dev, DSA_UC_DEL, - ha->addr, vid); - } - } - - netif_addr_unlock_bh(dev); - - dsa_flush_workqueue(); - - return 0; -} - -static int dsa_slave_restore_vlan(struct net_device *vdev, int vid, void *arg) -{ - __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); - - return dsa_slave_vlan_rx_add_vid(arg, proto, vid); -} - -static int dsa_slave_clear_vlan(struct net_device *vdev, int vid, void *arg) -{ - __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); - - return dsa_slave_vlan_rx_kill_vid(arg, proto, vid); -} - -/* Keep the VLAN RX filtering list in sync with the hardware only if VLAN - * filtering is enabled. The baseline is that only ports that offload a - * VLAN-aware bridge are VLAN-aware, and standalone ports are VLAN-unaware, - * but there are exceptions for quirky hardware. - * - * If ds->vlan_filtering_is_global = true, then standalone ports which share - * the same switch with other ports that offload a VLAN-aware bridge are also - * inevitably VLAN-aware. - * - * To summarize, a DSA switch port offloads: - * - * - If standalone (this includes software bridge, software LAG): - * - if ds->needs_standalone_vlan_filtering = true, OR if - * (ds->vlan_filtering_is_global = true AND there are bridges spanning - * this switch chip which have vlan_filtering=1) - * - the 8021q upper VLANs - * - else (standalone VLAN filtering is not needed, VLAN filtering is not - * global, or it is, but no port is under a VLAN-aware bridge): - * - no VLAN (any 8021q upper is a software VLAN) - * - * - If under a vlan_filtering=0 bridge which it offload: - * - if ds->configure_vlan_while_not_filtering = true (default): - * - the bridge VLANs. These VLANs are committed to hardware but inactive. - * - else (deprecated): - * - no VLAN. The bridge VLANs are not restored when VLAN awareness is - * enabled, so this behavior is broken and discouraged. - * - * - If under a vlan_filtering=1 bridge which it offload: - * - the bridge VLANs - * - the 8021q upper VLANs - */ -int dsa_slave_manage_vlan_filtering(struct net_device *slave, - bool vlan_filtering) -{ - int err; - - if (vlan_filtering) { - slave->features |= NETIF_F_HW_VLAN_CTAG_FILTER; - - err = vlan_for_each(slave, dsa_slave_restore_vlan, slave); - if (err) { - vlan_for_each(slave, dsa_slave_clear_vlan, slave); - slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; - return err; - } - } else { - err = vlan_for_each(slave, dsa_slave_clear_vlan, slave); - if (err) - return err; - - slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; - } - - return 0; -} - -struct dsa_hw_port { - struct list_head list; - struct net_device *dev; - int old_mtu; -}; - -static int dsa_hw_port_list_set_mtu(struct list_head *hw_port_list, int mtu) -{ - const struct dsa_hw_port *p; - int err; - - list_for_each_entry(p, hw_port_list, list) { - if (p->dev->mtu == mtu) - continue; - - err = dev_set_mtu(p->dev, mtu); - if (err) - goto rollback; - } - - return 0; - -rollback: - list_for_each_entry_continue_reverse(p, hw_port_list, list) { - if (p->dev->mtu == p->old_mtu) - continue; - - if (dev_set_mtu(p->dev, p->old_mtu)) - netdev_err(p->dev, "Failed to restore MTU\n"); - } - - return err; -} - -static void dsa_hw_port_list_free(struct list_head *hw_port_list) -{ - struct dsa_hw_port *p, *n; - - list_for_each_entry_safe(p, n, hw_port_list, list) - kfree(p); -} - -/* Make the hardware datapath to/from @dev limited to a common MTU */ -static void dsa_bridge_mtu_normalization(struct dsa_port *dp) -{ - struct list_head hw_port_list; - struct dsa_switch_tree *dst; - int min_mtu = ETH_MAX_MTU; - struct dsa_port *other_dp; - int err; - - if (!dp->ds->mtu_enforcement_ingress) - return; - - if (!dp->bridge) - return; - - INIT_LIST_HEAD(&hw_port_list); - - /* Populate the list of ports that are part of the same bridge - * as the newly added/modified port - */ - list_for_each_entry(dst, &dsa_tree_list, list) { - list_for_each_entry(other_dp, &dst->ports, list) { - struct dsa_hw_port *hw_port; - struct net_device *slave; - - if (other_dp->type != DSA_PORT_TYPE_USER) - continue; - - if (!dsa_port_bridge_same(dp, other_dp)) - continue; - - if (!other_dp->ds->mtu_enforcement_ingress) - continue; - - slave = other_dp->slave; - - if (min_mtu > slave->mtu) - min_mtu = slave->mtu; - - hw_port = kzalloc(sizeof(*hw_port), GFP_KERNEL); - if (!hw_port) - goto out; - - hw_port->dev = slave; - hw_port->old_mtu = slave->mtu; - - list_add(&hw_port->list, &hw_port_list); - } - } - - /* Attempt to configure the entire hardware bridge to the newly added - * interface's MTU first, regardless of whether the intention of the - * user was to raise or lower it. - */ - err = dsa_hw_port_list_set_mtu(&hw_port_list, dp->slave->mtu); - if (!err) - goto out; - - /* Clearly that didn't work out so well, so just set the minimum MTU on - * all hardware bridge ports now. If this fails too, then all ports will - * still have their old MTU rolled back anyway. - */ - dsa_hw_port_list_set_mtu(&hw_port_list, min_mtu); - -out: - dsa_hw_port_list_free(&hw_port_list); -} - -int dsa_slave_change_mtu(struct net_device *dev, int new_mtu) -{ - struct net_device *master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_port *cpu_dp = dp->cpu_dp; - struct dsa_switch *ds = dp->ds; - struct dsa_port *other_dp; - int largest_mtu = 0; - int new_master_mtu; - int old_master_mtu; - int mtu_limit; - int overhead; - int cpu_mtu; - int err; - - if (!ds->ops->port_change_mtu) - return -EOPNOTSUPP; - - dsa_tree_for_each_user_port(other_dp, ds->dst) { - int slave_mtu; - - /* During probe, this function will be called for each slave - * device, while not all of them have been allocated. That's - * ok, it doesn't change what the maximum is, so ignore it. - */ - if (!other_dp->slave) - continue; - - /* Pretend that we already applied the setting, which we - * actually haven't (still haven't done all integrity checks) - */ - if (dp == other_dp) - slave_mtu = new_mtu; - else - slave_mtu = other_dp->slave->mtu; - - if (largest_mtu < slave_mtu) - largest_mtu = slave_mtu; - } - - overhead = dsa_tag_protocol_overhead(cpu_dp->tag_ops); - mtu_limit = min_t(int, master->max_mtu, dev->max_mtu + overhead); - old_master_mtu = master->mtu; - new_master_mtu = largest_mtu + overhead; - if (new_master_mtu > mtu_limit) - return -ERANGE; - - /* If the master MTU isn't over limit, there's no need to check the CPU - * MTU, since that surely isn't either. - */ - cpu_mtu = largest_mtu; - - /* Start applying stuff */ - if (new_master_mtu != old_master_mtu) { - err = dev_set_mtu(master, new_master_mtu); - if (err < 0) - goto out_master_failed; - - /* We only need to propagate the MTU of the CPU port to - * upstream switches, so emit a notifier which updates them. - */ - err = dsa_port_mtu_change(cpu_dp, cpu_mtu); - if (err) - goto out_cpu_failed; - } - - err = ds->ops->port_change_mtu(ds, dp->index, new_mtu); - if (err) - goto out_port_failed; - - dev->mtu = new_mtu; - - dsa_bridge_mtu_normalization(dp); - - return 0; - -out_port_failed: - if (new_master_mtu != old_master_mtu) - dsa_port_mtu_change(cpu_dp, old_master_mtu - overhead); -out_cpu_failed: - if (new_master_mtu != old_master_mtu) - dev_set_mtu(master, old_master_mtu); -out_master_failed: - return err; -} - -static int __maybe_unused -dsa_slave_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - unsigned long mask, new_prio; - int err, port = dp->index; - - if (!ds->ops->port_set_default_prio) - return -EOPNOTSUPP; - - err = dcb_ieee_setapp(dev, app); - if (err) - return err; - - mask = dcb_ieee_getapp_mask(dev, app); - new_prio = __fls(mask); - - err = ds->ops->port_set_default_prio(ds, port, new_prio); - if (err) { - dcb_ieee_delapp(dev, app); - return err; - } - - return 0; -} - -static int __maybe_unused -dsa_slave_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - unsigned long mask, new_prio; - int err, port = dp->index; - u8 dscp = app->protocol; - - if (!ds->ops->port_add_dscp_prio) - return -EOPNOTSUPP; - - if (dscp >= 64) { - netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n", - dscp); - return -EINVAL; - } - - err = dcb_ieee_setapp(dev, app); - if (err) - return err; - - mask = dcb_ieee_getapp_mask(dev, app); - new_prio = __fls(mask); - - err = ds->ops->port_add_dscp_prio(ds, port, dscp, new_prio); - if (err) { - dcb_ieee_delapp(dev, app); - return err; - } - - return 0; -} - -static int __maybe_unused dsa_slave_dcbnl_ieee_setapp(struct net_device *dev, - struct dcb_app *app) -{ - switch (app->selector) { - case IEEE_8021QAZ_APP_SEL_ETHERTYPE: - switch (app->protocol) { - case 0: - return dsa_slave_dcbnl_set_default_prio(dev, app); - default: - return -EOPNOTSUPP; - } - break; - case IEEE_8021QAZ_APP_SEL_DSCP: - return dsa_slave_dcbnl_add_dscp_prio(dev, app); - default: - return -EOPNOTSUPP; - } -} - -static int __maybe_unused -dsa_slave_dcbnl_del_default_prio(struct net_device *dev, struct dcb_app *app) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - unsigned long mask, new_prio; - int err, port = dp->index; - - if (!ds->ops->port_set_default_prio) - return -EOPNOTSUPP; - - err = dcb_ieee_delapp(dev, app); - if (err) - return err; - - mask = dcb_ieee_getapp_mask(dev, app); - new_prio = mask ? __fls(mask) : 0; - - err = ds->ops->port_set_default_prio(ds, port, new_prio); - if (err) { - dcb_ieee_setapp(dev, app); - return err; - } - - return 0; -} - -static int __maybe_unused -dsa_slave_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int err, port = dp->index; - u8 dscp = app->protocol; - - if (!ds->ops->port_del_dscp_prio) - return -EOPNOTSUPP; - - err = dcb_ieee_delapp(dev, app); - if (err) - return err; - - err = ds->ops->port_del_dscp_prio(ds, port, dscp, app->priority); - if (err) { - dcb_ieee_setapp(dev, app); - return err; - } - - return 0; -} - -static int __maybe_unused dsa_slave_dcbnl_ieee_delapp(struct net_device *dev, - struct dcb_app *app) -{ - switch (app->selector) { - case IEEE_8021QAZ_APP_SEL_ETHERTYPE: - switch (app->protocol) { - case 0: - return dsa_slave_dcbnl_del_default_prio(dev, app); - default: - return -EOPNOTSUPP; - } - break; - case IEEE_8021QAZ_APP_SEL_DSCP: - return dsa_slave_dcbnl_del_dscp_prio(dev, app); - default: - return -EOPNOTSUPP; - } -} - -/* Pre-populate the DCB application priority table with the priorities - * configured during switch setup, which we read from hardware here. - */ -static int dsa_slave_dcbnl_init(struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - int port = dp->index; - int err; - - if (ds->ops->port_get_default_prio) { - int prio = ds->ops->port_get_default_prio(ds, port); - struct dcb_app app = { - .selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE, - .protocol = 0, - .priority = prio, - }; - - if (prio < 0) - return prio; - - err = dcb_ieee_setapp(dev, &app); - if (err) - return err; - } - - if (ds->ops->port_get_dscp_prio) { - int protocol; - - for (protocol = 0; protocol < 64; protocol++) { - struct dcb_app app = { - .selector = IEEE_8021QAZ_APP_SEL_DSCP, - .protocol = protocol, - }; - int prio; - - prio = ds->ops->port_get_dscp_prio(ds, port, protocol); - if (prio == -EOPNOTSUPP) - continue; - if (prio < 0) - return prio; - - app.priority = prio; - - err = dcb_ieee_setapp(dev, &app); - if (err) - return err; - } - } - - return 0; -} - -static const struct ethtool_ops dsa_slave_ethtool_ops = { - .get_drvinfo = dsa_slave_get_drvinfo, - .get_regs_len = dsa_slave_get_regs_len, - .get_regs = dsa_slave_get_regs, - .nway_reset = dsa_slave_nway_reset, - .get_link = ethtool_op_get_link, - .get_eeprom_len = dsa_slave_get_eeprom_len, - .get_eeprom = dsa_slave_get_eeprom, - .set_eeprom = dsa_slave_set_eeprom, - .get_strings = dsa_slave_get_strings, - .get_ethtool_stats = dsa_slave_get_ethtool_stats, - .get_sset_count = dsa_slave_get_sset_count, - .get_eth_phy_stats = dsa_slave_get_eth_phy_stats, - .get_eth_mac_stats = dsa_slave_get_eth_mac_stats, - .get_eth_ctrl_stats = dsa_slave_get_eth_ctrl_stats, - .get_rmon_stats = dsa_slave_get_rmon_stats, - .set_wol = dsa_slave_set_wol, - .get_wol = dsa_slave_get_wol, - .set_eee = dsa_slave_set_eee, - .get_eee = dsa_slave_get_eee, - .get_link_ksettings = dsa_slave_get_link_ksettings, - .set_link_ksettings = dsa_slave_set_link_ksettings, - .get_pause_stats = dsa_slave_get_pause_stats, - .get_pauseparam = dsa_slave_get_pauseparam, - .set_pauseparam = dsa_slave_set_pauseparam, - .get_rxnfc = dsa_slave_get_rxnfc, - .set_rxnfc = dsa_slave_set_rxnfc, - .get_ts_info = dsa_slave_get_ts_info, - .self_test = dsa_slave_net_selftest, - .get_mm = dsa_slave_get_mm, - .set_mm = dsa_slave_set_mm, - .get_mm_stats = dsa_slave_get_mm_stats, -}; - -static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = { - .ieee_setapp = dsa_slave_dcbnl_ieee_setapp, - .ieee_delapp = dsa_slave_dcbnl_ieee_delapp, -}; - -static void dsa_slave_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *s) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - - if (ds->ops->get_stats64) - ds->ops->get_stats64(ds, dp->index, s); - else - dev_get_tstats64(dev, s); -} - -static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx, - struct net_device_path *path) -{ - struct dsa_port *dp = dsa_slave_to_port(ctx->dev); - struct net_device *master = dsa_port_to_master(dp); - struct dsa_port *cpu_dp = dp->cpu_dp; - - path->dev = ctx->dev; - path->type = DEV_PATH_DSA; - path->dsa.proto = cpu_dp->tag_ops->proto; - path->dsa.port = dp->index; - ctx->dev = master; - - return 0; -} - -static const struct net_device_ops dsa_slave_netdev_ops = { - .ndo_open = dsa_slave_open, - .ndo_stop = dsa_slave_close, - .ndo_start_xmit = dsa_slave_xmit, - .ndo_change_rx_flags = dsa_slave_change_rx_flags, - .ndo_set_rx_mode = dsa_slave_set_rx_mode, - .ndo_set_mac_address = dsa_slave_set_mac_address, - .ndo_fdb_dump = dsa_slave_fdb_dump, - .ndo_eth_ioctl = dsa_slave_ioctl, - .ndo_get_iflink = dsa_slave_get_iflink, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_netpoll_setup = dsa_slave_netpoll_setup, - .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup, - .ndo_poll_controller = dsa_slave_poll_controller, -#endif - .ndo_setup_tc = dsa_slave_setup_tc, - .ndo_get_stats64 = dsa_slave_get_stats64, - .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, - .ndo_change_mtu = dsa_slave_change_mtu, - .ndo_fill_forward_path = dsa_slave_fill_forward_path, -}; - -static struct device_type dsa_type = { - .name = "dsa", -}; - -void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up) -{ - const struct dsa_port *dp = dsa_to_port(ds, port); - - if (dp->pl) - phylink_mac_change(dp->pl, up); -} -EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change); - -static void dsa_slave_phylink_fixed_state(struct phylink_config *config, - struct phylink_link_state *state) -{ - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); - struct dsa_switch *ds = dp->ds; - - /* No need to check that this operation is valid, the callback would - * not be called if it was not. - */ - ds->ops->phylink_fixed_state(ds, dp->index, state); -} - -/* slave device setup *******************************************************/ -static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr, - u32 flags) -{ - struct dsa_port *dp = dsa_slave_to_port(slave_dev); - struct dsa_switch *ds = dp->ds; - - slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr); - if (!slave_dev->phydev) { - netdev_err(slave_dev, "no phy at %d\n", addr); - return -ENODEV; - } - - slave_dev->phydev->dev_flags |= flags; - - return phylink_connect_phy(dp->pl, slave_dev->phydev); -} - -static int dsa_slave_phy_setup(struct net_device *slave_dev) -{ - struct dsa_port *dp = dsa_slave_to_port(slave_dev); - struct device_node *port_dn = dp->dn; - struct dsa_switch *ds = dp->ds; - u32 phy_flags = 0; - int ret; - - dp->pl_config.dev = &slave_dev->dev; - dp->pl_config.type = PHYLINK_NETDEV; - - /* The get_fixed_state callback takes precedence over polling the - * link GPIO in PHYLINK (see phylink_get_fixed_state). Only set - * this if the switch provides such a callback. - */ - if (ds->ops->phylink_fixed_state) { - dp->pl_config.get_fixed_state = dsa_slave_phylink_fixed_state; - dp->pl_config.poll_fixed_state = true; - } - - ret = dsa_port_phylink_create(dp); - if (ret) - return ret; - - if (ds->ops->get_phy_flags) - phy_flags = ds->ops->get_phy_flags(ds, dp->index); - - ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); - if (ret == -ENODEV && ds->slave_mii_bus) { - /* We could not connect to a designated PHY or SFP, so try to - * use the switch internal MDIO bus instead - */ - ret = dsa_slave_phy_connect(slave_dev, dp->index, phy_flags); - } - if (ret) { - netdev_err(slave_dev, "failed to connect to PHY: %pe\n", - ERR_PTR(ret)); - dsa_port_phylink_destroy(dp); - } - - return ret; -} - -void dsa_slave_setup_tagger(struct net_device *slave) -{ - struct dsa_port *dp = dsa_slave_to_port(slave); - struct net_device *master = dsa_port_to_master(dp); - struct dsa_slave_priv *p = netdev_priv(slave); - const struct dsa_port *cpu_dp = dp->cpu_dp; - const struct dsa_switch *ds = dp->ds; - - slave->needed_headroom = cpu_dp->tag_ops->needed_headroom; - slave->needed_tailroom = cpu_dp->tag_ops->needed_tailroom; - /* Try to save one extra realloc later in the TX path (in the master) - * by also inheriting the master's needed headroom and tailroom. - * The 8021q driver also does this. - */ - slave->needed_headroom += master->needed_headroom; - slave->needed_tailroom += master->needed_tailroom; - - p->xmit = cpu_dp->tag_ops->xmit; - - slave->features = master->vlan_features | NETIF_F_HW_TC; - slave->hw_features |= NETIF_F_HW_TC; - slave->features |= NETIF_F_LLTX; - if (slave->needed_tailroom) - slave->features &= ~(NETIF_F_SG | NETIF_F_FRAGLIST); - if (ds->needs_standalone_vlan_filtering) - slave->features |= NETIF_F_HW_VLAN_CTAG_FILTER; -} - -int dsa_slave_suspend(struct net_device *slave_dev) -{ - struct dsa_port *dp = dsa_slave_to_port(slave_dev); - - if (!netif_running(slave_dev)) - return 0; - - netif_device_detach(slave_dev); - - rtnl_lock(); - phylink_stop(dp->pl); - rtnl_unlock(); - - return 0; -} - -int dsa_slave_resume(struct net_device *slave_dev) -{ - struct dsa_port *dp = dsa_slave_to_port(slave_dev); - - if (!netif_running(slave_dev)) - return 0; - - netif_device_attach(slave_dev); - - rtnl_lock(); - phylink_start(dp->pl); - rtnl_unlock(); - - return 0; -} - -int dsa_slave_create(struct dsa_port *port) -{ - struct net_device *master = dsa_port_to_master(port); - struct dsa_switch *ds = port->ds; - struct net_device *slave_dev; - struct dsa_slave_priv *p; - const char *name; - int assign_type; - int ret; - - if (!ds->num_tx_queues) - ds->num_tx_queues = 1; - - if (port->name) { - name = port->name; - assign_type = NET_NAME_PREDICTABLE; - } else { - name = "eth%d"; - assign_type = NET_NAME_ENUM; - } - - slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name, - assign_type, ether_setup, - ds->num_tx_queues, 1); - if (slave_dev == NULL) - return -ENOMEM; - - slave_dev->rtnl_link_ops = &dsa_link_ops; - slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; -#if IS_ENABLED(CONFIG_DCB) - slave_dev->dcbnl_ops = &dsa_slave_dcbnl_ops; -#endif - if (!is_zero_ether_addr(port->mac)) - eth_hw_addr_set(slave_dev, port->mac); - else - eth_hw_addr_inherit(slave_dev, master); - slave_dev->priv_flags |= IFF_NO_QUEUE; - if (dsa_switch_supports_uc_filtering(ds)) - slave_dev->priv_flags |= IFF_UNICAST_FLT; - slave_dev->netdev_ops = &dsa_slave_netdev_ops; - if (ds->ops->port_max_mtu) - slave_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index); - SET_NETDEV_DEVTYPE(slave_dev, &dsa_type); - - SET_NETDEV_DEV(slave_dev, port->ds->dev); - SET_NETDEV_DEVLINK_PORT(slave_dev, &port->devlink_port); - slave_dev->dev.of_node = port->dn; - slave_dev->vlan_features = master->vlan_features; - - p = netdev_priv(slave_dev); - slave_dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!slave_dev->tstats) { - free_netdev(slave_dev); - return -ENOMEM; - } - - ret = gro_cells_init(&p->gcells, slave_dev); - if (ret) - goto out_free; - - p->dp = port; - INIT_LIST_HEAD(&p->mall_tc_list); - port->slave = slave_dev; - dsa_slave_setup_tagger(slave_dev); - - netif_carrier_off(slave_dev); - - ret = dsa_slave_phy_setup(slave_dev); - if (ret) { - netdev_err(slave_dev, - "error %d setting up PHY for tree %d, switch %d, port %d\n", - ret, ds->dst->index, ds->index, port->index); - goto out_gcells; - } - - rtnl_lock(); - - ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); - if (ret && ret != -EOPNOTSUPP) - dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", - ret, ETH_DATA_LEN, port->index); - - ret = register_netdevice(slave_dev); - if (ret) { - netdev_err(master, "error %d registering interface %s\n", - ret, slave_dev->name); - rtnl_unlock(); - goto out_phy; - } - - if (IS_ENABLED(CONFIG_DCB)) { - ret = dsa_slave_dcbnl_init(slave_dev); - if (ret) { - netdev_err(slave_dev, - "failed to initialize DCB: %pe\n", - ERR_PTR(ret)); - rtnl_unlock(); - goto out_unregister; - } - } - - ret = netdev_upper_dev_link(master, slave_dev, NULL); - - rtnl_unlock(); - - if (ret) - goto out_unregister; - - return 0; - -out_unregister: - unregister_netdev(slave_dev); -out_phy: - rtnl_lock(); - phylink_disconnect_phy(p->dp->pl); - rtnl_unlock(); - dsa_port_phylink_destroy(p->dp); -out_gcells: - gro_cells_destroy(&p->gcells); -out_free: - free_percpu(slave_dev->tstats); - free_netdev(slave_dev); - port->slave = NULL; - return ret; -} - -void dsa_slave_destroy(struct net_device *slave_dev) -{ - struct net_device *master = dsa_slave_to_master(slave_dev); - struct dsa_port *dp = dsa_slave_to_port(slave_dev); - struct dsa_slave_priv *p = netdev_priv(slave_dev); - - netif_carrier_off(slave_dev); - rtnl_lock(); - netdev_upper_dev_unlink(master, slave_dev); - unregister_netdevice(slave_dev); - phylink_disconnect_phy(dp->pl); - rtnl_unlock(); - - dsa_port_phylink_destroy(dp); - gro_cells_destroy(&p->gcells); - free_percpu(slave_dev->tstats); - free_netdev(slave_dev); -} - -int dsa_slave_change_master(struct net_device *dev, struct net_device *master, - struct netlink_ext_ack *extack) -{ - struct net_device *old_master = dsa_slave_to_master(dev); - struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch *ds = dp->ds; - struct net_device *upper; - struct list_head *iter; - int err; - - if (master == old_master) - return 0; - - if (!ds->ops->port_change_master) { - NL_SET_ERR_MSG_MOD(extack, - "Driver does not support changing DSA master"); - return -EOPNOTSUPP; - } - - if (!netdev_uses_dsa(master)) { - NL_SET_ERR_MSG_MOD(extack, - "Interface not eligible as DSA master"); - return -EOPNOTSUPP; - } - - netdev_for_each_upper_dev_rcu(master, upper, iter) { - if (dsa_slave_dev_check(upper)) - continue; - if (netif_is_bridge_master(upper)) - continue; - NL_SET_ERR_MSG_MOD(extack, "Cannot join master with unknown uppers"); - return -EOPNOTSUPP; - } - - /* Since we allow live-changing the DSA master, plus we auto-open the - * DSA master when the user port opens => we need to ensure that the - * new DSA master is open too. - */ - if (dev->flags & IFF_UP) { - err = dev_open(master, extack); - if (err) - return err; - } - - netdev_upper_dev_unlink(old_master, dev); - - err = netdev_upper_dev_link(master, dev, extack); - if (err) - goto out_revert_old_master_unlink; - - err = dsa_port_change_master(dp, master, extack); - if (err) - goto out_revert_master_link; - - /* Update the MTU of the new CPU port through cross-chip notifiers */ - err = dsa_slave_change_mtu(dev, dev->mtu); - if (err && err != -EOPNOTSUPP) { - netdev_warn(dev, - "nonfatal error updating MTU with new master: %pe\n", - ERR_PTR(err)); - } - - /* If the port doesn't have its own MAC address and relies on the DSA - * master's one, inherit it again from the new DSA master. - */ - if (is_zero_ether_addr(dp->mac)) - eth_hw_addr_inherit(dev, master); - - return 0; - -out_revert_master_link: - netdev_upper_dev_unlink(master, dev); -out_revert_old_master_unlink: - netdev_upper_dev_link(old_master, dev, NULL); - return err; -} - -bool dsa_slave_dev_check(const struct net_device *dev) -{ - return dev->netdev_ops == &dsa_slave_netdev_ops; -} -EXPORT_SYMBOL_GPL(dsa_slave_dev_check); - -static int dsa_slave_changeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct netlink_ext_ack *extack; - int err = NOTIFY_DONE; - - if (!dsa_slave_dev_check(dev)) - return err; - - extack = netdev_notifier_info_to_extack(&info->info); - - if (netif_is_bridge_master(info->upper_dev)) { - if (info->linking) { - err = dsa_port_bridge_join(dp, info->upper_dev, extack); - if (!err) - dsa_bridge_mtu_normalization(dp); - if (err == -EOPNOTSUPP) { - NL_SET_ERR_MSG_WEAK_MOD(extack, - "Offloading not supported"); - err = 0; - } - err = notifier_from_errno(err); - } else { - dsa_port_bridge_leave(dp, info->upper_dev); - err = NOTIFY_OK; - } - } else if (netif_is_lag_master(info->upper_dev)) { - if (info->linking) { - err = dsa_port_lag_join(dp, info->upper_dev, - info->upper_info, extack); - if (err == -EOPNOTSUPP) { - NL_SET_ERR_MSG_WEAK_MOD(extack, - "Offloading not supported"); - err = 0; - } - err = notifier_from_errno(err); - } else { - dsa_port_lag_leave(dp, info->upper_dev); - err = NOTIFY_OK; - } - } else if (is_hsr_master(info->upper_dev)) { - if (info->linking) { - err = dsa_port_hsr_join(dp, info->upper_dev, extack); - if (err == -EOPNOTSUPP) { - NL_SET_ERR_MSG_WEAK_MOD(extack, - "Offloading not supported"); - err = 0; - } - err = notifier_from_errno(err); - } else { - dsa_port_hsr_leave(dp, info->upper_dev); - err = NOTIFY_OK; - } - } - - return err; -} - -static int dsa_slave_prechangeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - if (!dsa_slave_dev_check(dev)) - return NOTIFY_DONE; - - if (netif_is_bridge_master(info->upper_dev) && !info->linking) - dsa_port_pre_bridge_leave(dp, info->upper_dev); - else if (netif_is_lag_master(info->upper_dev) && !info->linking) - dsa_port_pre_lag_leave(dp, info->upper_dev); - /* dsa_port_pre_hsr_leave is not yet necessary since hsr cannot be - * meaningfully enslaved to a bridge yet - */ - - return NOTIFY_DONE; -} - -static int -dsa_slave_lag_changeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct net_device *lower; - struct list_head *iter; - int err = NOTIFY_DONE; - struct dsa_port *dp; - - if (!netif_is_lag_master(dev)) - return err; - - netdev_for_each_lower_dev(dev, lower, iter) { - if (!dsa_slave_dev_check(lower)) - continue; - - dp = dsa_slave_to_port(lower); - if (!dp->lag) - /* Software LAG */ - continue; - - err = dsa_slave_changeupper(lower, info); - if (notifier_to_errno(err)) - break; - } - - return err; -} - -/* Same as dsa_slave_lag_changeupper() except that it calls - * dsa_slave_prechangeupper() - */ -static int -dsa_slave_lag_prechangeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct net_device *lower; - struct list_head *iter; - int err = NOTIFY_DONE; - struct dsa_port *dp; - - if (!netif_is_lag_master(dev)) - return err; - - netdev_for_each_lower_dev(dev, lower, iter) { - if (!dsa_slave_dev_check(lower)) - continue; - - dp = dsa_slave_to_port(lower); - if (!dp->lag) - /* Software LAG */ - continue; - - err = dsa_slave_prechangeupper(lower, info); - if (notifier_to_errno(err)) - break; - } - - return err; -} - -static int -dsa_prevent_bridging_8021q_upper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct netlink_ext_ack *ext_ack; - struct net_device *slave, *br; - struct dsa_port *dp; - - ext_ack = netdev_notifier_info_to_extack(&info->info); - - if (!is_vlan_dev(dev)) - return NOTIFY_DONE; - - slave = vlan_dev_real_dev(dev); - if (!dsa_slave_dev_check(slave)) - return NOTIFY_DONE; - - dp = dsa_slave_to_port(slave); - br = dsa_port_bridge_dev_get(dp); - if (!br) - return NOTIFY_DONE; - - /* Deny enslaving a VLAN device into a VLAN-aware bridge */ - if (br_vlan_enabled(br) && - netif_is_bridge_master(info->upper_dev) && info->linking) { - NL_SET_ERR_MSG_MOD(ext_ack, - "Cannot enslave VLAN device into VLAN aware bridge"); - return notifier_from_errno(-EINVAL); - } - - return NOTIFY_DONE; -} - -static int -dsa_slave_check_8021q_upper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - struct net_device *br = dsa_port_bridge_dev_get(dp); - struct bridge_vlan_info br_info; - struct netlink_ext_ack *extack; - int err = NOTIFY_DONE; - u16 vid; - - if (!br || !br_vlan_enabled(br)) - return NOTIFY_DONE; - - extack = netdev_notifier_info_to_extack(&info->info); - vid = vlan_dev_vlan_id(info->upper_dev); - - /* br_vlan_get_info() returns -EINVAL or -ENOENT if the - * device, respectively the VID is not found, returning - * 0 means success, which is a failure for us here. - */ - err = br_vlan_get_info(br, vid, &br_info); - if (err == 0) { - NL_SET_ERR_MSG_MOD(extack, - "This VLAN is already configured by the bridge"); - return notifier_from_errno(-EBUSY); - } - - return NOTIFY_DONE; -} - -static int -dsa_slave_prechangeupper_sanity_check(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct dsa_switch *ds; - struct dsa_port *dp; - int err; - - if (!dsa_slave_dev_check(dev)) - return dsa_prevent_bridging_8021q_upper(dev, info); - - dp = dsa_slave_to_port(dev); - ds = dp->ds; - - if (ds->ops->port_prechangeupper) { - err = ds->ops->port_prechangeupper(ds, dp->index, info); - if (err) - return notifier_from_errno(err); - } - - if (is_vlan_dev(info->upper_dev)) - return dsa_slave_check_8021q_upper(dev, info); - - return NOTIFY_DONE; -} - -/* To be eligible as a DSA master, a LAG must have all lower interfaces be - * eligible DSA masters. Additionally, all LAG slaves must be DSA masters of - * switches in the same switch tree. - */ -static int dsa_lag_master_validate(struct net_device *lag_dev, - struct netlink_ext_ack *extack) -{ - struct net_device *lower1, *lower2; - struct list_head *iter1, *iter2; - - netdev_for_each_lower_dev(lag_dev, lower1, iter1) { - netdev_for_each_lower_dev(lag_dev, lower2, iter2) { - if (!netdev_uses_dsa(lower1) || - !netdev_uses_dsa(lower2)) { - NL_SET_ERR_MSG_MOD(extack, - "All LAG ports must be eligible as DSA masters"); - return notifier_from_errno(-EINVAL); - } - - if (lower1 == lower2) - continue; - - if (!dsa_port_tree_same(lower1->dsa_ptr, - lower2->dsa_ptr)) { - NL_SET_ERR_MSG_MOD(extack, - "LAG contains DSA masters of disjoint switch trees"); - return notifier_from_errno(-EINVAL); - } - } - } - - return NOTIFY_DONE; -} - -static int -dsa_master_prechangeupper_sanity_check(struct net_device *master, - struct netdev_notifier_changeupper_info *info) -{ - struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); - - if (!netdev_uses_dsa(master)) - return NOTIFY_DONE; - - if (!info->linking) - return NOTIFY_DONE; - - /* Allow DSA switch uppers */ - if (dsa_slave_dev_check(info->upper_dev)) - return NOTIFY_DONE; - - /* Allow bridge uppers of DSA masters, subject to further - * restrictions in dsa_bridge_prechangelower_sanity_check() - */ - if (netif_is_bridge_master(info->upper_dev)) - return NOTIFY_DONE; - - /* Allow LAG uppers, subject to further restrictions in - * dsa_lag_master_prechangelower_sanity_check() - */ - if (netif_is_lag_master(info->upper_dev)) - return dsa_lag_master_validate(info->upper_dev, extack); - - NL_SET_ERR_MSG_MOD(extack, - "DSA master cannot join unknown upper interfaces"); - return notifier_from_errno(-EBUSY); -} - -static int -dsa_lag_master_prechangelower_sanity_check(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); - struct net_device *lag_dev = info->upper_dev; - struct net_device *lower; - struct list_head *iter; - - if (!netdev_uses_dsa(lag_dev) || !netif_is_lag_master(lag_dev)) - return NOTIFY_DONE; - - if (!info->linking) - return NOTIFY_DONE; - - if (!netdev_uses_dsa(dev)) { - NL_SET_ERR_MSG(extack, - "Only DSA masters can join a LAG DSA master"); - return notifier_from_errno(-EINVAL); - } - - netdev_for_each_lower_dev(lag_dev, lower, iter) { - if (!dsa_port_tree_same(dev->dsa_ptr, lower->dsa_ptr)) { - NL_SET_ERR_MSG(extack, - "Interface is DSA master for a different switch tree than this LAG"); - return notifier_from_errno(-EINVAL); - } - - break; - } - - return NOTIFY_DONE; -} - -/* Don't allow bridging of DSA masters, since the bridge layer rx_handler - * prevents the DSA fake ethertype handler to be invoked, so we don't get the - * chance to strip off and parse the DSA switch tag protocol header (the bridge - * layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these - * frames). - * The only case where that would not be an issue is when bridging can already - * be offloaded, such as when the DSA master is itself a DSA or plain switchdev - * port, and is bridged only with other ports from the same hardware device. - */ -static int -dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower, - struct netdev_notifier_changeupper_info *info) -{ - struct net_device *br = info->upper_dev; - struct netlink_ext_ack *extack; - struct net_device *lower; - struct list_head *iter; - - if (!netif_is_bridge_master(br)) - return NOTIFY_DONE; - - if (!info->linking) - return NOTIFY_DONE; - - extack = netdev_notifier_info_to_extack(&info->info); - - netdev_for_each_lower_dev(br, lower, iter) { - if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower)) - continue; - - if (!netdev_port_same_parent_id(lower, new_lower)) { - NL_SET_ERR_MSG(extack, - "Cannot do software bridging with a DSA master"); - return notifier_from_errno(-EINVAL); - } - } - - return NOTIFY_DONE; -} - -static void dsa_tree_migrate_ports_from_lag_master(struct dsa_switch_tree *dst, - struct net_device *lag_dev) -{ - struct net_device *new_master = dsa_tree_find_first_master(dst); - struct dsa_port *dp; - int err; - - dsa_tree_for_each_user_port(dp, dst) { - if (dsa_port_to_master(dp) != lag_dev) - continue; - - err = dsa_slave_change_master(dp->slave, new_master, NULL); - if (err) { - netdev_err(dp->slave, - "failed to restore master to %s: %pe\n", - new_master->name, ERR_PTR(err)); - } - } -} - -static int dsa_master_lag_join(struct net_device *master, - struct net_device *lag_dev, - struct netdev_lag_upper_info *uinfo, - struct netlink_ext_ack *extack) -{ - struct dsa_port *cpu_dp = master->dsa_ptr; - struct dsa_switch_tree *dst = cpu_dp->dst; - struct dsa_port *dp; - int err; - - err = dsa_master_lag_setup(lag_dev, cpu_dp, uinfo, extack); - if (err) - return err; - - dsa_tree_for_each_user_port(dp, dst) { - if (dsa_port_to_master(dp) != master) - continue; - - err = dsa_slave_change_master(dp->slave, lag_dev, extack); - if (err) - goto restore; - } - - return 0; - -restore: - dsa_tree_for_each_user_port_continue_reverse(dp, dst) { - if (dsa_port_to_master(dp) != lag_dev) - continue; - - err = dsa_slave_change_master(dp->slave, master, NULL); - if (err) { - netdev_err(dp->slave, - "failed to restore master to %s: %pe\n", - master->name, ERR_PTR(err)); - } - } - - dsa_master_lag_teardown(lag_dev, master->dsa_ptr); - - return err; -} - -static void dsa_master_lag_leave(struct net_device *master, - struct net_device *lag_dev) -{ - struct dsa_port *dp, *cpu_dp = lag_dev->dsa_ptr; - struct dsa_switch_tree *dst = cpu_dp->dst; - struct dsa_port *new_cpu_dp = NULL; - struct net_device *lower; - struct list_head *iter; - - netdev_for_each_lower_dev(lag_dev, lower, iter) { - if (netdev_uses_dsa(lower)) { - new_cpu_dp = lower->dsa_ptr; - break; - } - } - - if (new_cpu_dp) { - /* Update the CPU port of the user ports still under the LAG - * so that dsa_port_to_master() continues to work properly - */ - dsa_tree_for_each_user_port(dp, dst) - if (dsa_port_to_master(dp) == lag_dev) - dp->cpu_dp = new_cpu_dp; - - /* Update the index of the virtual CPU port to match the lowest - * physical CPU port - */ - lag_dev->dsa_ptr = new_cpu_dp; - wmb(); - } else { - /* If the LAG DSA master has no ports left, migrate back all - * user ports to the first physical CPU port - */ - dsa_tree_migrate_ports_from_lag_master(dst, lag_dev); - } - - /* This DSA master has left its LAG in any case, so let - * the CPU port leave the hardware LAG as well - */ - dsa_master_lag_teardown(lag_dev, master->dsa_ptr); -} - -static int dsa_master_changeupper(struct net_device *dev, - struct netdev_notifier_changeupper_info *info) -{ - struct netlink_ext_ack *extack; - int err = NOTIFY_DONE; - - if (!netdev_uses_dsa(dev)) - return err; - - extack = netdev_notifier_info_to_extack(&info->info); - - if (netif_is_lag_master(info->upper_dev)) { - if (info->linking) { - err = dsa_master_lag_join(dev, info->upper_dev, - info->upper_info, extack); - err = notifier_from_errno(err); - } else { - dsa_master_lag_leave(dev, info->upper_dev); - err = NOTIFY_OK; - } - } - - return err; -} - -static int dsa_slave_netdevice_event(struct notifier_block *nb, - unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - switch (event) { - case NETDEV_PRECHANGEUPPER: { - struct netdev_notifier_changeupper_info *info = ptr; - int err; - - err = dsa_slave_prechangeupper_sanity_check(dev, info); - if (notifier_to_errno(err)) - return err; - - err = dsa_master_prechangeupper_sanity_check(dev, info); - if (notifier_to_errno(err)) - return err; - - err = dsa_lag_master_prechangelower_sanity_check(dev, info); - if (notifier_to_errno(err)) - return err; - - err = dsa_bridge_prechangelower_sanity_check(dev, info); - if (notifier_to_errno(err)) - return err; - - err = dsa_slave_prechangeupper(dev, ptr); - if (notifier_to_errno(err)) - return err; - - err = dsa_slave_lag_prechangeupper(dev, ptr); - if (notifier_to_errno(err)) - return err; - - break; - } - case NETDEV_CHANGEUPPER: { - int err; - - err = dsa_slave_changeupper(dev, ptr); - if (notifier_to_errno(err)) - return err; - - err = dsa_slave_lag_changeupper(dev, ptr); - if (notifier_to_errno(err)) - return err; - - err = dsa_master_changeupper(dev, ptr); - if (notifier_to_errno(err)) - return err; - - break; - } - case NETDEV_CHANGELOWERSTATE: { - struct netdev_notifier_changelowerstate_info *info = ptr; - struct dsa_port *dp; - int err = 0; - - if (dsa_slave_dev_check(dev)) { - dp = dsa_slave_to_port(dev); - - err = dsa_port_lag_change(dp, info->lower_state_info); - } - - /* Mirror LAG port events on DSA masters that are in - * a LAG towards their respective switch CPU ports - */ - if (netdev_uses_dsa(dev)) { - dp = dev->dsa_ptr; - - err = dsa_port_lag_change(dp, info->lower_state_info); - } - - return notifier_from_errno(err); - } - case NETDEV_CHANGE: - case NETDEV_UP: { - /* Track state of master port. - * DSA driver may require the master port (and indirectly - * the tagger) to be available for some special operation. - */ - if (netdev_uses_dsa(dev)) { - struct dsa_port *cpu_dp = dev->dsa_ptr; - struct dsa_switch_tree *dst = cpu_dp->ds->dst; - - /* Track when the master port is UP */ - dsa_tree_master_oper_state_change(dst, dev, - netif_oper_up(dev)); - - /* Track when the master port is ready and can accept - * packet. - * NETDEV_UP event is not enough to flag a port as ready. - * We also have to wait for linkwatch_do_dev to dev_activate - * and emit a NETDEV_CHANGE event. - * We check if a master port is ready by checking if the dev - * have a qdisc assigned and is not noop. - */ - dsa_tree_master_admin_state_change(dst, dev, - !qdisc_tx_is_noop(dev)); - - return NOTIFY_OK; - } - - return NOTIFY_DONE; - } - case NETDEV_GOING_DOWN: { - struct dsa_port *dp, *cpu_dp; - struct dsa_switch_tree *dst; - LIST_HEAD(close_list); - - if (!netdev_uses_dsa(dev)) - return NOTIFY_DONE; - - cpu_dp = dev->dsa_ptr; - dst = cpu_dp->ds->dst; - - dsa_tree_master_admin_state_change(dst, dev, false); - - list_for_each_entry(dp, &dst->ports, list) { - if (!dsa_port_is_user(dp)) - continue; - - if (dp->cpu_dp != cpu_dp) - continue; - - list_add(&dp->slave->close_list, &close_list); - } - - dev_close_many(&close_list, true); - - return NOTIFY_OK; - } - default: - break; - } - - return NOTIFY_DONE; -} - -static void -dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) -{ - struct switchdev_notifier_fdb_info info = {}; - - info.addr = switchdev_work->addr; - info.vid = switchdev_work->vid; - info.offloaded = true; - call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, - switchdev_work->orig_dev, &info.info, NULL); -} - -static void dsa_slave_switchdev_event_work(struct work_struct *work) -{ - struct dsa_switchdev_event_work *switchdev_work = - container_of(work, struct dsa_switchdev_event_work, work); - const unsigned char *addr = switchdev_work->addr; - struct net_device *dev = switchdev_work->dev; - u16 vid = switchdev_work->vid; - struct dsa_switch *ds; - struct dsa_port *dp; - int err; - - dp = dsa_slave_to_port(dev); - ds = dp->ds; - - switch (switchdev_work->event) { - case SWITCHDEV_FDB_ADD_TO_DEVICE: - if (switchdev_work->host_addr) - err = dsa_port_bridge_host_fdb_add(dp, addr, vid); - else if (dp->lag) - err = dsa_port_lag_fdb_add(dp, addr, vid); - else - err = dsa_port_fdb_add(dp, addr, vid); - if (err) { - dev_err(ds->dev, - "port %d failed to add %pM vid %d to fdb: %d\n", - dp->index, addr, vid, err); - break; - } - dsa_fdb_offload_notify(switchdev_work); - break; - - case SWITCHDEV_FDB_DEL_TO_DEVICE: - if (switchdev_work->host_addr) - err = dsa_port_bridge_host_fdb_del(dp, addr, vid); - else if (dp->lag) - err = dsa_port_lag_fdb_del(dp, addr, vid); - else - err = dsa_port_fdb_del(dp, addr, vid); - if (err) { - dev_err(ds->dev, - "port %d failed to delete %pM vid %d from fdb: %d\n", - dp->index, addr, vid, err); - } - - break; - } - - kfree(switchdev_work); -} - -static bool dsa_foreign_dev_check(const struct net_device *dev, - const struct net_device *foreign_dev) -{ - const struct dsa_port *dp = dsa_slave_to_port(dev); - struct dsa_switch_tree *dst = dp->ds->dst; - - if (netif_is_bridge_master(foreign_dev)) - return !dsa_tree_offloads_bridge_dev(dst, foreign_dev); - - if (netif_is_bridge_port(foreign_dev)) - return !dsa_tree_offloads_bridge_port(dst, foreign_dev); - - /* Everything else is foreign */ - return true; -} - -static int dsa_slave_fdb_event(struct net_device *dev, - struct net_device *orig_dev, - unsigned long event, const void *ctx, - const struct switchdev_notifier_fdb_info *fdb_info) -{ - struct dsa_switchdev_event_work *switchdev_work; - struct dsa_port *dp = dsa_slave_to_port(dev); - bool host_addr = fdb_info->is_local; - struct dsa_switch *ds = dp->ds; - - if (ctx && ctx != dp) - return 0; - - if (!dp->bridge) - return 0; - - if (switchdev_fdb_is_dynamically_learned(fdb_info)) { - if (dsa_port_offloads_bridge_port(dp, orig_dev)) - return 0; - - /* FDB entries learned by the software bridge or by foreign - * bridge ports should be installed as host addresses only if - * the driver requests assisted learning. - */ - if (!ds->assisted_learning_on_cpu_port) - return 0; - } - - /* Also treat FDB entries on foreign interfaces bridged with us as host - * addresses. - */ - if (dsa_foreign_dev_check(dev, orig_dev)) - host_addr = true; - - /* Check early that we're not doing work in vain. - * Host addresses on LAG ports still require regular FDB ops, - * since the CPU port isn't in a LAG. - */ - if (dp->lag && !host_addr) { - if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del) - return -EOPNOTSUPP; - } else { - if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del) - return -EOPNOTSUPP; - } - - switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); - if (!switchdev_work) - return -ENOMEM; - - netdev_dbg(dev, "%s FDB entry towards %s, addr %pM vid %d%s\n", - event == SWITCHDEV_FDB_ADD_TO_DEVICE ? "Adding" : "Deleting", - orig_dev->name, fdb_info->addr, fdb_info->vid, - host_addr ? " as host address" : ""); - - INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work); - switchdev_work->event = event; - switchdev_work->dev = dev; - switchdev_work->orig_dev = orig_dev; - - ether_addr_copy(switchdev_work->addr, fdb_info->addr); - switchdev_work->vid = fdb_info->vid; - switchdev_work->host_addr = host_addr; - - dsa_schedule_work(&switchdev_work->work); - - return 0; -} - -/* Called under rcu_read_lock() */ -static int dsa_slave_switchdev_event(struct notifier_block *unused, - unsigned long event, void *ptr) -{ - struct net_device *dev = switchdev_notifier_info_to_dev(ptr); - int err; - - switch (event) { - case SWITCHDEV_PORT_ATTR_SET: - err = switchdev_handle_port_attr_set(dev, ptr, - dsa_slave_dev_check, - dsa_slave_port_attr_set); - return notifier_from_errno(err); - case SWITCHDEV_FDB_ADD_TO_DEVICE: - case SWITCHDEV_FDB_DEL_TO_DEVICE: - err = switchdev_handle_fdb_event_to_device(dev, event, ptr, - dsa_slave_dev_check, - dsa_foreign_dev_check, - dsa_slave_fdb_event); - return notifier_from_errno(err); - default: - return NOTIFY_DONE; - } - - return NOTIFY_OK; -} - -static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused, - unsigned long event, void *ptr) -{ - struct net_device *dev = switchdev_notifier_info_to_dev(ptr); - int err; - - switch (event) { - case SWITCHDEV_PORT_OBJ_ADD: - err = switchdev_handle_port_obj_add_foreign(dev, ptr, - dsa_slave_dev_check, - dsa_foreign_dev_check, - dsa_slave_port_obj_add); - return notifier_from_errno(err); - case SWITCHDEV_PORT_OBJ_DEL: - err = switchdev_handle_port_obj_del_foreign(dev, ptr, - dsa_slave_dev_check, - dsa_foreign_dev_check, - dsa_slave_port_obj_del); - return notifier_from_errno(err); - case SWITCHDEV_PORT_ATTR_SET: - err = switchdev_handle_port_attr_set(dev, ptr, - dsa_slave_dev_check, - dsa_slave_port_attr_set); - return notifier_from_errno(err); - } - - return NOTIFY_DONE; -} - -static struct notifier_block dsa_slave_nb __read_mostly = { - .notifier_call = dsa_slave_netdevice_event, -}; - -struct notifier_block dsa_slave_switchdev_notifier = { - .notifier_call = dsa_slave_switchdev_event, -}; - -struct notifier_block dsa_slave_switchdev_blocking_notifier = { - .notifier_call = dsa_slave_switchdev_blocking_event, -}; - -int dsa_slave_register_notifier(void) -{ - struct notifier_block *nb; - int err; - - err = register_netdevice_notifier(&dsa_slave_nb); - if (err) - return err; - - err = register_switchdev_notifier(&dsa_slave_switchdev_notifier); - if (err) - goto err_switchdev_nb; - - nb = &dsa_slave_switchdev_blocking_notifier; - err = register_switchdev_blocking_notifier(nb); - if (err) - goto err_switchdev_blocking_nb; - - return 0; - -err_switchdev_blocking_nb: - unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); -err_switchdev_nb: - unregister_netdevice_notifier(&dsa_slave_nb); - return err; -} - -void dsa_slave_unregister_notifier(void) -{ - struct notifier_block *nb; - int err; - - nb = &dsa_slave_switchdev_blocking_notifier; - err = unregister_switchdev_blocking_notifier(nb); - if (err) - pr_err("DSA: failed to unregister switchdev blocking notifier (%d)\n", err); - - err = unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); - if (err) - pr_err("DSA: failed to unregister switchdev notifier (%d)\n", err); - - err = unregister_netdevice_notifier(&dsa_slave_nb); - if (err) - pr_err("DSA: failed to unregister slave notifier (%d)\n", err); -} diff --git a/net/dsa/slave.h b/net/dsa/slave.h deleted file mode 100644 index d0abe609e00d..000000000000 --- a/net/dsa/slave.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef __DSA_SLAVE_H -#define __DSA_SLAVE_H - -#include -#include -#include -#include -#include -#include -#include - -struct net_device; -struct netlink_ext_ack; - -extern struct notifier_block dsa_slave_switchdev_notifier; -extern struct notifier_block dsa_slave_switchdev_blocking_notifier; - -struct dsa_slave_priv { - /* Copy of CPU port xmit for faster access in slave transmit hot path */ - struct sk_buff * (*xmit)(struct sk_buff *skb, - struct net_device *dev); - - struct gro_cells gcells; - - /* DSA port data, such as switch, port index, etc. */ - struct dsa_port *dp; - -#ifdef CONFIG_NET_POLL_CONTROLLER - struct netpoll *netpoll; -#endif - - /* TC context */ - struct list_head mall_tc_list; -}; - -void dsa_slave_mii_bus_init(struct dsa_switch *ds); -int dsa_slave_create(struct dsa_port *dp); -void dsa_slave_destroy(struct net_device *slave_dev); -int dsa_slave_suspend(struct net_device *slave_dev); -int dsa_slave_resume(struct net_device *slave_dev); -int dsa_slave_register_notifier(void); -void dsa_slave_unregister_notifier(void); -void dsa_slave_sync_ha(struct net_device *dev); -void dsa_slave_unsync_ha(struct net_device *dev); -void dsa_slave_setup_tagger(struct net_device *slave); -int dsa_slave_change_mtu(struct net_device *dev, int new_mtu); -int dsa_slave_change_master(struct net_device *dev, struct net_device *master, - struct netlink_ext_ack *extack); -int dsa_slave_manage_vlan_filtering(struct net_device *dev, - bool vlan_filtering); - -static inline struct dsa_port *dsa_slave_to_port(const struct net_device *dev) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - - return p->dp; -} - -static inline struct net_device * -dsa_slave_to_master(const struct net_device *dev) -{ - struct dsa_port *dp = dsa_slave_to_port(dev); - - return dsa_port_to_master(dp); -} - -#endif diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 1a42f9317334..3d2feeea897b 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -15,10 +15,10 @@ #include "dsa.h" #include "netlink.h" #include "port.h" -#include "slave.h" #include "switch.h" #include "tag_8021q.h" #include "trace.h" +#include "user.h" static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds, unsigned int ageing_time) @@ -894,12 +894,12 @@ static int dsa_switch_change_tag_proto(struct dsa_switch *ds, * bits that depend on the tagger, such as the MTU. */ dsa_switch_for_each_user_port(dp, ds) { - struct net_device *slave = dp->slave; + struct net_device *user = dp->user; - dsa_slave_setup_tagger(slave); + dsa_user_setup_tagger(user); /* rtnl_mutex is held in dsa_tree_change_tag_proto */ - dsa_slave_change_mtu(slave, slave->mtu); + dsa_user_change_mtu(user, user->mtu); } return 0; @@ -960,13 +960,13 @@ dsa_switch_disconnect_tag_proto(struct dsa_switch *ds, } static int -dsa_switch_master_state_change(struct dsa_switch *ds, - struct dsa_notifier_master_state_info *info) +dsa_switch_conduit_state_change(struct dsa_switch *ds, + struct dsa_notifier_conduit_state_info *info) { - if (!ds->ops->master_state_change) + if (!ds->ops->conduit_state_change) return 0; - ds->ops->master_state_change(ds, info->master, info->operational); + ds->ops->conduit_state_change(ds, info->conduit, info->operational); return 0; } @@ -1056,8 +1056,8 @@ static int dsa_switch_event(struct notifier_block *nb, case DSA_NOTIFIER_TAG_8021Q_VLAN_DEL: err = dsa_switch_tag_8021q_vlan_del(ds, info); break; - case DSA_NOTIFIER_MASTER_STATE_CHANGE: - err = dsa_switch_master_state_change(ds, info); + case DSA_NOTIFIER_CONDUIT_STATE_CHANGE: + err = dsa_switch_conduit_state_change(ds, info); break; default: err = -EOPNOTSUPP; diff --git a/net/dsa/switch.h b/net/dsa/switch.h index ea034677da15..be0a2749cd97 100644 --- a/net/dsa/switch.h +++ b/net/dsa/switch.h @@ -34,7 +34,7 @@ enum { DSA_NOTIFIER_TAG_PROTO_DISCONNECT, DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, - DSA_NOTIFIER_MASTER_STATE_CHANGE, + DSA_NOTIFIER_CONDUIT_STATE_CHANGE, }; /* DSA_NOTIFIER_AGEING_TIME */ @@ -105,9 +105,9 @@ struct dsa_notifier_tag_8021q_vlan_info { u16 vid; }; -/* DSA_NOTIFIER_MASTER_STATE_CHANGE */ -struct dsa_notifier_master_state_info { - const struct net_device *master; +/* DSA_NOTIFIER_CONDUIT_STATE_CHANGE */ +struct dsa_notifier_conduit_state_info { + const struct net_device *conduit; bool operational; }; diff --git a/net/dsa/tag.c b/net/dsa/tag.c index 5105a5ff58fa..6e402d49afd3 100644 --- a/net/dsa/tag.c +++ b/net/dsa/tag.c @@ -13,8 +13,8 @@ #include #include -#include "slave.h" #include "tag.h" +#include "user.h" static LIST_HEAD(dsa_tag_drivers_list); static DEFINE_MUTEX(dsa_tag_drivers_lock); @@ -27,7 +27,7 @@ static DEFINE_MUTEX(dsa_tag_drivers_lock); * switch, the DSA driver owning the interface to which the packet is * delivered is never notified unless we do so here. */ -static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p, +static bool dsa_skb_defer_rx_timestamp(struct dsa_user_priv *p, struct sk_buff *skb) { struct dsa_switch *ds = p->dp->ds; @@ -57,7 +57,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, struct metadata_dst *md_dst = skb_metadata_dst(skb); struct dsa_port *cpu_dp = dev->dsa_ptr; struct sk_buff *nskb = NULL; - struct dsa_slave_priv *p; + struct dsa_user_priv *p; if (unlikely(!cpu_dp)) { kfree_skb(skb); @@ -75,7 +75,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, if (!skb_has_extensions(skb)) skb->slow_gro = 0; - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (likely(skb->dev)) { dsa_default_offload_fwd_mark(skb); nskb = skb; @@ -94,7 +94,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - if (unlikely(!dsa_slave_dev_check(skb->dev))) { + if (unlikely(!dsa_user_dev_check(skb->dev))) { /* Packet is to be injected directly on an upper * device, e.g. a team/bond, so skip all DSA-port * specific actions. diff --git a/net/dsa/tag.h b/net/dsa/tag.h index 32d12f4a9d73..f6b9c73718df 100644 --- a/net/dsa/tag.h +++ b/net/dsa/tag.h @@ -9,7 +9,7 @@ #include #include "port.h" -#include "slave.h" +#include "user.h" struct dsa_tag_driver { const struct dsa_device_ops *ops; @@ -29,7 +29,7 @@ static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops) return ops->needed_headroom + ops->needed_tailroom; } -static inline struct net_device *dsa_master_find_slave(struct net_device *dev, +static inline struct net_device *dsa_conduit_find_user(struct net_device *dev, int device, int port) { struct dsa_port *cpu_dp = dev->dsa_ptr; @@ -39,7 +39,7 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev, list_for_each_entry(dp, &dst->ports, list) if (dp->ds->index == device && dp->index == port && dp->type == DSA_PORT_TYPE_USER) - return dp->slave; + return dp->user; return NULL; } @@ -49,7 +49,7 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev, */ static inline struct sk_buff *dsa_untag_bridge_pvid(struct sk_buff *skb) { - struct dsa_port *dp = dsa_slave_to_port(skb->dev); + struct dsa_port *dp = dsa_user_to_port(skb->dev); struct net_device *br = dsa_port_bridge_dev_get(dp); struct net_device *dev = skb->dev; struct net_device *upper_dev; @@ -107,12 +107,12 @@ static inline struct sk_buff *dsa_untag_bridge_pvid(struct sk_buff *skb) * to support termination through the bridge. */ static inline struct net_device * -dsa_find_designated_bridge_port_by_vid(struct net_device *master, u16 vid) +dsa_find_designated_bridge_port_by_vid(struct net_device *conduit, u16 vid) { - struct dsa_port *cpu_dp = master->dsa_ptr; + struct dsa_port *cpu_dp = conduit->dsa_ptr; struct dsa_switch_tree *dst = cpu_dp->dst; struct bridge_vlan_info vinfo; - struct net_device *slave; + struct net_device *user; struct dsa_port *dp; int err; @@ -134,13 +134,13 @@ dsa_find_designated_bridge_port_by_vid(struct net_device *master, u16 vid) if (dp->cpu_dp != cpu_dp) continue; - slave = dp->slave; + user = dp->user; - err = br_vlan_get_info_rcu(slave, vid, &vinfo); + err = br_vlan_get_info_rcu(user, vid, &vinfo); if (err) continue; - return slave; + return user; } return NULL; @@ -155,7 +155,7 @@ dsa_find_designated_bridge_port_by_vid(struct net_device *master, u16 vid) */ static inline void dsa_default_offload_fwd_mark(struct sk_buff *skb) { - struct dsa_port *dp = dsa_slave_to_port(skb->dev); + struct dsa_port *dp = dsa_user_to_port(skb->dev); skb->offload_fwd_mark = !!(dp->bridge); } @@ -215,9 +215,9 @@ static inline void dsa_alloc_etype_header(struct sk_buff *skb, int len) memmove(skb->data, skb->data + len, 2 * ETH_ALEN); } -/* On RX, eth_type_trans() on the DSA master pulls ETH_HLEN bytes starting from +/* On RX, eth_type_trans() on the DSA conduit pulls ETH_HLEN bytes starting from * skb_mac_header(skb), which leaves skb->data pointing at the first byte after - * what the DSA master perceives as the EtherType (the beginning of the L3 + * what the DSA conduit perceives as the EtherType (the beginning of the L3 * protocol). Since DSA EtherType header taggers treat the EtherType as part of * the DSA tag itself, and the EtherType is 2 bytes in length, the DSA header * is located 2 bytes behind skb->data. Note that EtherType in this context diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index cbdfc392f7e0..71b26ae6db39 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -73,7 +73,7 @@ struct dsa_tag_8021q_vlan { struct dsa_8021q_context { struct dsa_switch *ds; struct list_head vlans; - /* EtherType of RX VID, used for filtering on master interface */ + /* EtherType of RX VID, used for filtering on conduit interface */ __be16 proto; }; @@ -338,7 +338,7 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port) struct dsa_8021q_context *ctx = ds->tag_8021q_ctx; struct dsa_port *dp = dsa_to_port(ds, port); u16 vid = dsa_tag_8021q_standalone_vid(dp); - struct net_device *master; + struct net_device *conduit; int err; /* The CPU port is implicitly configured by @@ -347,7 +347,7 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port) if (!dsa_port_is_user(dp)) return 0; - master = dsa_port_to_master(dp); + conduit = dsa_port_to_conduit(dp); err = dsa_port_tag_8021q_vlan_add(dp, vid, false); if (err) { @@ -357,8 +357,8 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port) return err; } - /* Add the VLAN to the master's RX filter. */ - vlan_vid_add(master, ctx->proto, vid); + /* Add the VLAN to the conduit's RX filter. */ + vlan_vid_add(conduit, ctx->proto, vid); return err; } @@ -368,7 +368,7 @@ static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port) struct dsa_8021q_context *ctx = ds->tag_8021q_ctx; struct dsa_port *dp = dsa_to_port(ds, port); u16 vid = dsa_tag_8021q_standalone_vid(dp); - struct net_device *master; + struct net_device *conduit; /* The CPU port is implicitly configured by * configuring the front-panel ports @@ -376,11 +376,11 @@ static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port) if (!dsa_port_is_user(dp)) return; - master = dsa_port_to_master(dp); + conduit = dsa_port_to_conduit(dp); dsa_port_tag_8021q_vlan_del(dp, vid, false); - vlan_vid_del(master, ctx->proto, vid); + vlan_vid_del(conduit, ctx->proto, vid); } static int dsa_tag_8021q_setup(struct dsa_switch *ds) @@ -468,10 +468,10 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, } EXPORT_SYMBOL_GPL(dsa_8021q_xmit); -struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master, +struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *conduit, int vbid) { - struct dsa_port *cpu_dp = master->dsa_ptr; + struct dsa_port *cpu_dp = conduit->dsa_ptr; struct dsa_switch_tree *dst = cpu_dp->dst; struct dsa_port *dp; @@ -490,7 +490,7 @@ struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master, continue; if (dsa_port_bridge_num_get(dp) == vbid) - return dp->slave; + return dp->user; } return NULL; diff --git a/net/dsa/tag_8021q.h b/net/dsa/tag_8021q.h index b75cbaa028ef..41f7167ac520 100644 --- a/net/dsa/tag_8021q.h +++ b/net/dsa/tag_8021q.h @@ -16,7 +16,7 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id, int *vbid); -struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master, +struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *conduit, int vbid); int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds, diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c index 7f3b7d730b85..92ce67b93a58 100644 --- a/net/dsa/tag_ar9331.c +++ b/net/dsa/tag_ar9331.c @@ -29,7 +29,7 @@ static struct sk_buff *ar9331_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); __le16 *phdr; u16 hdr; @@ -74,7 +74,7 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb, /* Get source port information */ port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr); - skb->dev = dsa_master_find_slave(ndev, 0, port); + skb->dev = dsa_conduit_find_user(ndev, 0, port); if (!skb->dev) return NULL; diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index cacdafb41200..83d283a5d27e 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -85,7 +85,7 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb, struct net_device *dev, unsigned int offset) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); u16 queue = skb_get_queue_mapping(skb); u8 *brcm_tag; @@ -96,7 +96,7 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb, * (including FCS and tag) because the length verification is done after * the Broadcom tag is stripped off the ingress packet. * - * Let dsa_slave_xmit() free the SKB + * Let dsa_user_xmit() free the SKB */ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false)) return NULL; @@ -119,7 +119,7 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb, brcm_tag[2] = BRCM_IG_DSTMAP2_MASK; brcm_tag[3] = (1 << dp->index) & BRCM_IG_DSTMAP1_MASK; - /* Now tell the master network device about the desired output queue + /* Now tell the conduit network device about the desired output queue * as well */ skb_set_queue_mapping(skb, BRCM_TAG_SET_PORT_QUEUE(dp->index, queue)); @@ -164,7 +164,7 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb, /* Locate which port this is coming from */ source_port = brcm_tag[3] & BRCM_EG_PID_MASK; - skb->dev = dsa_master_find_slave(dev, 0, source_port); + skb->dev = dsa_conduit_find_user(dev, 0, source_port); if (!skb->dev) return NULL; @@ -216,7 +216,7 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME); static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); u8 *brcm_tag; /* The Ethernet switch we are interfaced with needs packets to be at @@ -226,7 +226,7 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, * (including FCS and tag) because the length verification is done after * the Broadcom tag is stripped off the ingress packet. * - * Let dsa_slave_xmit() free the SKB + * Let dsa_user_xmit() free the SKB */ if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) return NULL; @@ -264,7 +264,7 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, source_port = brcm_tag[5] & BRCM_LEG_PORT_ID; - skb->dev = dsa_master_find_slave(dev, 0, source_port); + skb->dev = dsa_conduit_find_user(dev, 0, source_port); if (!skb->dev) return NULL; diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index 1fd7fa26db64..8ed52dd663ab 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -129,7 +129,7 @@ enum dsa_code { static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev, u8 extra) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); struct net_device *br_dev; u8 tag_dev, tag_port; enum dsa_cmd cmd; @@ -267,14 +267,14 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev, lag = dsa_lag_by_id(cpu_dp->dst, source_port + 1); skb->dev = lag ? lag->dev : NULL; } else { - skb->dev = dsa_master_find_slave(dev, source_device, + skb->dev = dsa_conduit_find_user(dev, source_device, source_port); } if (!skb->dev) return NULL; - /* When using LAG offload, skb->dev is not a DSA slave interface, + /* When using LAG offload, skb->dev is not a DSA user interface, * so we cannot call dsa_default_offload_fwd_mark and we need to * special-case it. */ diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c index e279cd9057b0..3539141b5350 100644 --- a/net/dsa/tag_gswip.c +++ b/net/dsa/tag_gswip.c @@ -61,7 +61,7 @@ static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); u8 *gswip_tag; skb_push(skb, GSWIP_TX_HEADER_LEN); @@ -89,7 +89,7 @@ static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, /* Get source port information */ port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) return NULL; diff --git a/net/dsa/tag_hellcreek.c b/net/dsa/tag_hellcreek.c index 03a1fb9c87a9..6e233cd0aa38 100644 --- a/net/dsa/tag_hellcreek.c +++ b/net/dsa/tag_hellcreek.c @@ -20,7 +20,7 @@ static struct sk_buff *hellcreek_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); u8 *tag; /* Calculate checksums (if required) before adding the trailer tag to @@ -45,7 +45,7 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb, u8 *tag = skb_tail_pointer(skb) - HELLCREEK_TAG_LEN; unsigned int port = tag[0] & 0x03; - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) { netdev_warn_once(dev, "Failed to get source port: %d\n", port); return NULL; diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 3632e47dea9e..9be341fa88f0 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -87,7 +87,7 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, struct net_device *dev, unsigned int port, unsigned int len) { - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) return NULL; @@ -119,7 +119,7 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); struct ethhdr *hdr; u8 *tag; @@ -256,7 +256,7 @@ static struct sk_buff *ksz_defer_xmit(struct dsa_port *dp, struct sk_buff *skb) return NULL; kthread_init_work(&xmit_work->work, xmit_work_fn); - /* Increase refcount so the kfree_skb in dsa_slave_xmit + /* Increase refcount so the kfree_skb in dsa_user_xmit * won't really free the packet. */ xmit_work->dp = dp; @@ -272,7 +272,7 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, { u16 queue_mapping = skb_get_queue_mapping(skb); u8 prio = netdev_txq_to_tc(dev, queue_mapping); - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); struct ethhdr *hdr; __be16 *tag; u16 val; @@ -344,7 +344,7 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, { u16 queue_mapping = skb_get_queue_mapping(skb); u8 prio = netdev_txq_to_tc(dev, queue_mapping); - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); struct ethhdr *hdr; u8 *tag; @@ -410,7 +410,7 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb, { u16 queue_mapping = skb_get_queue_mapping(skb); u8 prio = netdev_txq_to_tc(dev, queue_mapping); - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); const struct ethhdr *hdr = eth_hdr(skb); __be16 *tag; u16 val; diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c index c25f5536706b..1ed8ee24855d 100644 --- a/net/dsa/tag_lan9303.c +++ b/net/dsa/tag_lan9303.c @@ -56,7 +56,7 @@ static int lan9303_xmit_use_arl(struct dsa_port *dp, u8 *dest_addr) static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); __be16 *lan9303_tag; u16 tag; @@ -99,7 +99,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev) source_port = lan9303_tag1 & 0x3; - skb->dev = dsa_master_find_slave(dev, 0, source_port); + skb->dev = dsa_conduit_find_user(dev, 0, source_port); if (!skb->dev) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n"); return NULL; diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c index 40af80452747..2483785f6ab1 100644 --- a/net/dsa/tag_mtk.c +++ b/net/dsa/tag_mtk.c @@ -23,7 +23,7 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); u8 xmit_tpid; u8 *mtk_tag; @@ -85,7 +85,7 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev) /* Get source port information */ port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK); - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) return NULL; diff --git a/net/dsa/tag_none.c b/net/dsa/tag_none.c index d2fd179c4227..9a473624db50 100644 --- a/net/dsa/tag_none.c +++ b/net/dsa/tag_none.c @@ -12,8 +12,8 @@ #define NONE_NAME "none" -static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb, - struct net_device *dev) +static struct sk_buff *dsa_user_notag_xmit(struct sk_buff *skb, + struct net_device *dev) { /* Just return the original SKB */ return skb; @@ -22,7 +22,7 @@ static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb, static const struct dsa_device_ops none_ops = { .name = NONE_NAME, .proto = DSA_TAG_PROTO_NONE, - .xmit = dsa_slave_notag_xmit, + .xmit = dsa_user_notag_xmit, }; module_dsa_tag_driver(none_ops); diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c index 20bf7074d5a6..ef2f8fffb2c7 100644 --- a/net/dsa/tag_ocelot.c +++ b/net/dsa/tag_ocelot.c @@ -45,7 +45,7 @@ static void ocelot_xmit_get_vlan_info(struct sk_buff *skb, struct dsa_port *dp, static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev, __be32 ifh_prefix, void **ifh) { - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); struct dsa_switch *ds = dp->ds; u64 vlan_tci, tag_type; void *injection; @@ -79,7 +79,7 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev, static struct sk_buff *ocelot_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); void *injection; ocelot_xmit_common(skb, netdev, cpu_to_be32(0x8880000a), &injection); @@ -91,7 +91,7 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, static struct sk_buff *seville_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); void *injection; ocelot_xmit_common(skb, netdev, cpu_to_be32(0x88800005), &injection); @@ -111,12 +111,12 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, u16 vlan_tpid; u64 rew_val; - /* Revert skb->data by the amount consumed by the DSA master, + /* Revert skb->data by the amount consumed by the DSA conduit, * so it points to the beginning of the frame. */ skb_push(skb, ETH_HLEN); /* We don't care about the short prefix, it is just for easy entrance - * into the DSA master's RX filter. Discard it now by moving it into + * into the DSA conduit's RX filter. Discard it now by moving it into * the headroom. */ skb_pull(skb, OCELOT_SHORT_PREFIX_LEN); @@ -141,12 +141,12 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, ocelot_xfh_get_vlan_tci(extraction, &vlan_tci); ocelot_xfh_get_rew_val(extraction, &rew_val); - skb->dev = dsa_master_find_slave(netdev, 0, src_port); + skb->dev = dsa_conduit_find_user(netdev, 0, src_port); if (!skb->dev) /* The switch will reflect back some frames sent through - * sockets opened on the bare DSA master. These will come back + * sockets opened on the bare DSA conduit. These will come back * with src_port equal to the index of the CPU port, for which - * there is no slave registered. So don't print any error + * there is no user registered. So don't print any error * message here (ignore and drop those frames). */ return NULL; @@ -170,7 +170,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, * equal to the pvid of the ingress port and should not be used for * processing. */ - dp = dsa_slave_to_port(skb->dev); + dp = dsa_user_to_port(skb->dev); vlan_tpid = tag_type ? ETH_P_8021AD : ETH_P_8021Q; if (dsa_port_is_vlan_filtering(dp) && @@ -192,7 +192,7 @@ static const struct dsa_device_ops ocelot_netdev_ops = { .xmit = ocelot_xmit, .rcv = ocelot_rcv, .needed_headroom = OCELOT_TOTAL_TAG_LEN, - .promisc_on_master = true, + .promisc_on_conduit = true, }; DSA_TAG_DRIVER(ocelot_netdev_ops); @@ -204,7 +204,7 @@ static const struct dsa_device_ops seville_netdev_ops = { .xmit = seville_xmit, .rcv = ocelot_rcv, .needed_headroom = OCELOT_TOTAL_TAG_LEN, - .promisc_on_master = true, + .promisc_on_conduit = true, }; DSA_TAG_DRIVER(seville_netdev_ops); diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c index 1f0b8c20eba5..210039320888 100644 --- a/net/dsa/tag_ocelot_8021q.c +++ b/net/dsa/tag_ocelot_8021q.c @@ -37,8 +37,8 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp, return NULL; /* PTP over IP packets need UDP checksumming. We may have inherited - * NETIF_F_HW_CSUM from the DSA master, but these packets are not sent - * through the DSA master, so calculate the checksum here. + * NETIF_F_HW_CSUM from the DSA conduit, but these packets are not sent + * through the DSA conduit, so calculate the checksum here. */ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) return NULL; @@ -49,7 +49,7 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp, /* Calls felix_port_deferred_xmit in felix.c */ kthread_init_work(&xmit_work->work, xmit_work_fn); - /* Increase refcount so the kfree_skb in dsa_slave_xmit + /* Increase refcount so the kfree_skb in dsa_user_xmit * won't really free the packet. */ xmit_work->dp = dp; @@ -63,7 +63,7 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp, static struct sk_buff *ocelot_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); u16 queue_mapping = skb_get_queue_mapping(skb); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); u16 tx_vid = dsa_tag_8021q_standalone_vid(dp); @@ -83,7 +83,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, dsa_8021q_rcv(skb, &src_port, &switch_id, NULL); - skb->dev = dsa_master_find_slave(netdev, switch_id, src_port); + skb->dev = dsa_conduit_find_user(netdev, switch_id, src_port); if (!skb->dev) return NULL; @@ -130,7 +130,7 @@ static const struct dsa_device_ops ocelot_8021q_netdev_ops = { .connect = ocelot_connect, .disconnect = ocelot_disconnect, .needed_headroom = VLAN_HLEN, - .promisc_on_master = true, + .promisc_on_conduit = true, }; MODULE_LICENSE("GPL v2"); diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index e5ff7c34e577..6514aa7993ce 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -14,7 +14,7 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); __be16 *phdr; u16 hdr; @@ -78,7 +78,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) /* Get source port information */ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr); - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) return NULL; @@ -116,7 +116,7 @@ static const struct dsa_device_ops qca_netdev_ops = { .xmit = qca_tag_xmit, .rcv = qca_tag_rcv, .needed_headroom = QCA_HDR_LEN, - .promisc_on_master = true, + .promisc_on_conduit = true, }; MODULE_LICENSE("GPL"); diff --git a/net/dsa/tag_rtl4_a.c b/net/dsa/tag_rtl4_a.c index c327314b95e3..4da5bad1a7aa 100644 --- a/net/dsa/tag_rtl4_a.c +++ b/net/dsa/tag_rtl4_a.c @@ -36,7 +36,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); __be16 *p; u8 *tag; u16 out; @@ -97,9 +97,9 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb, } port = protport & 0xff; - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) { - netdev_dbg(dev, "could not find slave for port %d\n", port); + netdev_dbg(dev, "could not find user for port %d\n", port); return NULL; } diff --git a/net/dsa/tag_rtl8_4.c b/net/dsa/tag_rtl8_4.c index 4f67834fd121..07e857debabf 100644 --- a/net/dsa/tag_rtl8_4.c +++ b/net/dsa/tag_rtl8_4.c @@ -103,7 +103,7 @@ static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev, void *tag) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); __be16 tag16[RTL8_4_TAG_LEN / 2]; /* Set Realtek EtherType */ @@ -180,10 +180,10 @@ static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev, /* Parse TX (switch->CPU) */ port = FIELD_GET(RTL8_4_TX, ntohs(tag16[3])); - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) { dev_warn_ratelimited(&dev->dev, - "could not find slave for port %d\n", + "could not find user for port %d\n", port); return -ENOENT; } diff --git a/net/dsa/tag_rzn1_a5psw.c b/net/dsa/tag_rzn1_a5psw.c index 437a6820ac42..2ce866b45615 100644 --- a/net/dsa/tag_rzn1_a5psw.c +++ b/net/dsa/tag_rzn1_a5psw.c @@ -39,7 +39,7 @@ struct a5psw_tag { static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); struct a5psw_tag *ptag; u32 data2_val; @@ -90,7 +90,7 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb, port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data)); - skb->dev = dsa_master_find_slave(dev, 0, port); + skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) return NULL; diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index ade3eeb2f3e6..1fffe8c2b589 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -157,7 +157,7 @@ static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp, return NULL; kthread_init_work(&xmit_work->work, xmit_work_fn); - /* Increase refcount so the kfree_skb in dsa_slave_xmit + /* Increase refcount so the kfree_skb in dsa_user_xmit * won't really free the packet. */ xmit_work->dp = dp; @@ -210,7 +210,7 @@ static u16 sja1105_xmit_tpid(struct dsa_port *dp) static struct sk_buff *sja1105_imprecise_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); unsigned int bridge_num = dsa_port_bridge_num_get(dp); struct net_device *br = dsa_port_bridge_dev_get(dp); u16 tx_vid; @@ -235,7 +235,7 @@ static struct sk_buff *sja1105_imprecise_xmit(struct sk_buff *skb, /* Transform untagged control packets into pvid-tagged control packets so that * all packets sent by this tagger are VLAN-tagged and we can configure the - * switch to drop untagged packets coming from the DSA master. + * switch to drop untagged packets coming from the DSA conduit. */ static struct sk_buff *sja1105_pvid_tag_control_pkt(struct dsa_port *dp, struct sk_buff *skb, u8 pcp) @@ -266,7 +266,7 @@ static struct sk_buff *sja1105_pvid_tag_control_pkt(struct dsa_port *dp, static struct sk_buff *sja1105_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); u16 queue_mapping = skb_get_queue_mapping(skb); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); u16 tx_vid = dsa_tag_8021q_standalone_vid(dp); @@ -294,7 +294,7 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb, struct net_device *netdev) { struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone; - struct dsa_port *dp = dsa_slave_to_port(netdev); + struct dsa_port *dp = dsa_user_to_port(netdev); u16 queue_mapping = skb_get_queue_mapping(skb); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); u16 tx_vid = dsa_tag_8021q_standalone_vid(dp); @@ -383,7 +383,7 @@ static struct sk_buff * Buffer it until we get its meta frame. */ if (is_link_local) { - struct dsa_port *dp = dsa_slave_to_port(skb->dev); + struct dsa_port *dp = dsa_user_to_port(skb->dev); struct sja1105_tagger_private *priv; struct dsa_switch *ds = dp->ds; @@ -396,7 +396,7 @@ static struct sk_buff if (priv->stampable_skb) { dev_err_ratelimited(ds->dev, "Expected meta frame, is %12llx " - "in the DSA master multicast filter?\n", + "in the DSA conduit multicast filter?\n", SJA1105_META_DMAC); kfree_skb(priv->stampable_skb); } @@ -417,7 +417,7 @@ static struct sk_buff * frame, which serves no further purpose). */ } else if (is_meta) { - struct dsa_port *dp = dsa_slave_to_port(skb->dev); + struct dsa_port *dp = dsa_user_to_port(skb->dev); struct sja1105_tagger_private *priv; struct dsa_switch *ds = dp->ds; struct sk_buff *stampable_skb; @@ -550,7 +550,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, } if (source_port != -1 && switch_id != -1) - skb->dev = dsa_master_find_slave(netdev, switch_id, source_port); + skb->dev = dsa_conduit_find_user(netdev, switch_id, source_port); else if (vbid >= 1) skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid); else @@ -573,16 +573,16 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header) int switch_id = SJA1110_RX_HEADER_SWITCH_ID(rx_header); int n_ts = SJA1110_RX_HEADER_N_TS(rx_header); struct sja1105_tagger_data *tagger_data; - struct net_device *master = skb->dev; + struct net_device *conduit = skb->dev; struct dsa_port *cpu_dp; struct dsa_switch *ds; int i; - cpu_dp = master->dsa_ptr; + cpu_dp = conduit->dsa_ptr; ds = dsa_switch_find(cpu_dp->dst->index, switch_id); if (!ds) { net_err_ratelimited("%s: cannot find switch id %d\n", - master->name, switch_id); + conduit->name, switch_id); return NULL; } @@ -649,7 +649,7 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb, /* skb->len counts from skb->data, while start_of_padding * counts from the destination MAC address. Right now skb->data - * is still as set by the DSA master, so to trim away the + * is still as set by the DSA conduit, so to trim away the * padding and trailer we need to account for the fact that * skb->data points to skb_mac_header(skb) + ETH_HLEN. */ @@ -698,7 +698,7 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb, else if (source_port == -1 || switch_id == -1) skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid); else - skb->dev = dsa_master_find_slave(netdev, switch_id, source_port); + skb->dev = dsa_conduit_find_user(netdev, switch_id, source_port); if (!skb->dev) { netdev_warn(netdev, "Couldn't decode source port\n"); return NULL; @@ -778,7 +778,7 @@ static const struct dsa_device_ops sja1105_netdev_ops = { .disconnect = sja1105_disconnect, .needed_headroom = VLAN_HLEN, .flow_dissect = sja1105_flow_dissect, - .promisc_on_master = true, + .promisc_on_conduit = true, }; DSA_TAG_DRIVER(sja1105_netdev_ops); diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index 7361b9106382..1ebb25a8b140 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -14,7 +14,7 @@ static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_port *dp = dsa_user_to_port(dev); u8 *trailer; trailer = skb_put(skb, 4); @@ -41,7 +41,7 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev) source_port = trailer[1] & 7; - skb->dev = dsa_master_find_slave(dev, 0, source_port); + skb->dev = dsa_conduit_find_user(dev, 0, source_port); if (!skb->dev) return NULL; diff --git a/net/dsa/tag_xrs700x.c b/net/dsa/tag_xrs700x.c index af19969f9bc4..c9c163598ef2 100644 --- a/net/dsa/tag_xrs700x.c +++ b/net/dsa/tag_xrs700x.c @@ -13,7 +13,7 @@ static struct sk_buff *xrs700x_xmit(struct sk_buff *skb, struct net_device *dev) { - struct dsa_port *partner, *dp = dsa_slave_to_port(dev); + struct dsa_port *partner, *dp = dsa_user_to_port(dev); u8 *trailer; trailer = skb_put(skb, 1); @@ -39,7 +39,7 @@ static struct sk_buff *xrs700x_rcv(struct sk_buff *skb, struct net_device *dev) if (source_port < 0) return NULL; - skb->dev = dsa_master_find_slave(dev, 0, source_port); + skb->dev = dsa_conduit_find_user(dev, 0, source_port); if (!skb->dev) return NULL; diff --git a/net/dsa/user.c b/net/dsa/user.c new file mode 100644 index 000000000000..d438884a4eb0 --- /dev/null +++ b/net/dsa/user.c @@ -0,0 +1,3727 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * net/dsa/user.c - user device handling + * Copyright (c) 2008-2009 Marvell Semiconductor + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "conduit.h" +#include "dsa.h" +#include "netlink.h" +#include "port.h" +#include "switch.h" +#include "tag.h" +#include "user.h" + +struct dsa_switchdev_event_work { + struct net_device *dev; + struct net_device *orig_dev; + struct work_struct work; + unsigned long event; + /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and + * SWITCHDEV_FDB_DEL_TO_DEVICE + */ + unsigned char addr[ETH_ALEN]; + u16 vid; + bool host_addr; +}; + +enum dsa_standalone_event { + DSA_UC_ADD, + DSA_UC_DEL, + DSA_MC_ADD, + DSA_MC_DEL, +}; + +struct dsa_standalone_event_work { + struct work_struct work; + struct net_device *dev; + enum dsa_standalone_event event; + unsigned char addr[ETH_ALEN]; + u16 vid; +}; + +struct dsa_host_vlan_rx_filtering_ctx { + struct net_device *dev; + const unsigned char *addr; + enum dsa_standalone_event event; +}; + +static bool dsa_switch_supports_uc_filtering(struct dsa_switch *ds) +{ + return ds->ops->port_fdb_add && ds->ops->port_fdb_del && + ds->fdb_isolation && !ds->vlan_filtering_is_global && + !ds->needs_standalone_vlan_filtering; +} + +static bool dsa_switch_supports_mc_filtering(struct dsa_switch *ds) +{ + return ds->ops->port_mdb_add && ds->ops->port_mdb_del && + ds->fdb_isolation && !ds->vlan_filtering_is_global && + !ds->needs_standalone_vlan_filtering; +} + +static void dsa_user_standalone_event_work(struct work_struct *work) +{ + struct dsa_standalone_event_work *standalone_work = + container_of(work, struct dsa_standalone_event_work, work); + const unsigned char *addr = standalone_work->addr; + struct net_device *dev = standalone_work->dev; + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_mdb mdb; + struct dsa_switch *ds = dp->ds; + u16 vid = standalone_work->vid; + int err; + + switch (standalone_work->event) { + case DSA_UC_ADD: + err = dsa_port_standalone_host_fdb_add(dp, addr, vid); + if (err) { + dev_err(ds->dev, + "port %d failed to add %pM vid %d to fdb: %d\n", + dp->index, addr, vid, err); + break; + } + break; + + case DSA_UC_DEL: + err = dsa_port_standalone_host_fdb_del(dp, addr, vid); + if (err) { + dev_err(ds->dev, + "port %d failed to delete %pM vid %d from fdb: %d\n", + dp->index, addr, vid, err); + } + + break; + case DSA_MC_ADD: + ether_addr_copy(mdb.addr, addr); + mdb.vid = vid; + + err = dsa_port_standalone_host_mdb_add(dp, &mdb); + if (err) { + dev_err(ds->dev, + "port %d failed to add %pM vid %d to mdb: %d\n", + dp->index, addr, vid, err); + break; + } + break; + case DSA_MC_DEL: + ether_addr_copy(mdb.addr, addr); + mdb.vid = vid; + + err = dsa_port_standalone_host_mdb_del(dp, &mdb); + if (err) { + dev_err(ds->dev, + "port %d failed to delete %pM vid %d from mdb: %d\n", + dp->index, addr, vid, err); + } + + break; + } + + kfree(standalone_work); +} + +static int dsa_user_schedule_standalone_work(struct net_device *dev, + enum dsa_standalone_event event, + const unsigned char *addr, + u16 vid) +{ + struct dsa_standalone_event_work *standalone_work; + + standalone_work = kzalloc(sizeof(*standalone_work), GFP_ATOMIC); + if (!standalone_work) + return -ENOMEM; + + INIT_WORK(&standalone_work->work, dsa_user_standalone_event_work); + standalone_work->event = event; + standalone_work->dev = dev; + + ether_addr_copy(standalone_work->addr, addr); + standalone_work->vid = vid; + + dsa_schedule_work(&standalone_work->work); + + return 0; +} + +static int dsa_user_host_vlan_rx_filtering(void *arg, int vid) +{ + struct dsa_host_vlan_rx_filtering_ctx *ctx = arg; + + return dsa_user_schedule_standalone_work(ctx->dev, ctx->event, + ctx->addr, vid); +} + +static int dsa_user_vlan_for_each(struct net_device *dev, + int (*cb)(void *arg, int vid), void *arg) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_vlan *v; + int err; + + lockdep_assert_held(&dev->addr_list_lock); + + err = cb(arg, 0); + if (err) + return err; + + list_for_each_entry(v, &dp->user_vlans, list) { + err = cb(arg, v->vid); + if (err) + return err; + } + + return 0; +} + +static int dsa_user_sync_uc(struct net_device *dev, + const unsigned char *addr) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_host_vlan_rx_filtering_ctx ctx = { + .dev = dev, + .addr = addr, + .event = DSA_UC_ADD, + }; + + dev_uc_add(conduit, addr); + + if (!dsa_switch_supports_uc_filtering(dp->ds)) + return 0; + + return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, + &ctx); +} + +static int dsa_user_unsync_uc(struct net_device *dev, + const unsigned char *addr) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_host_vlan_rx_filtering_ctx ctx = { + .dev = dev, + .addr = addr, + .event = DSA_UC_DEL, + }; + + dev_uc_del(conduit, addr); + + if (!dsa_switch_supports_uc_filtering(dp->ds)) + return 0; + + return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, + &ctx); +} + +static int dsa_user_sync_mc(struct net_device *dev, + const unsigned char *addr) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_host_vlan_rx_filtering_ctx ctx = { + .dev = dev, + .addr = addr, + .event = DSA_MC_ADD, + }; + + dev_mc_add(conduit, addr); + + if (!dsa_switch_supports_mc_filtering(dp->ds)) + return 0; + + return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, + &ctx); +} + +static int dsa_user_unsync_mc(struct net_device *dev, + const unsigned char *addr) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_host_vlan_rx_filtering_ctx ctx = { + .dev = dev, + .addr = addr, + .event = DSA_MC_DEL, + }; + + dev_mc_del(conduit, addr); + + if (!dsa_switch_supports_mc_filtering(dp->ds)) + return 0; + + return dsa_user_vlan_for_each(dev, dsa_user_host_vlan_rx_filtering, + &ctx); +} + +void dsa_user_sync_ha(struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + struct netdev_hw_addr *ha; + + netif_addr_lock_bh(dev); + + netdev_for_each_synced_mc_addr(ha, dev) + dsa_user_sync_mc(dev, ha->addr); + + netdev_for_each_synced_uc_addr(ha, dev) + dsa_user_sync_uc(dev, ha->addr); + + netif_addr_unlock_bh(dev); + + if (dsa_switch_supports_uc_filtering(ds) || + dsa_switch_supports_mc_filtering(ds)) + dsa_flush_workqueue(); +} + +void dsa_user_unsync_ha(struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + struct netdev_hw_addr *ha; + + netif_addr_lock_bh(dev); + + netdev_for_each_synced_uc_addr(ha, dev) + dsa_user_unsync_uc(dev, ha->addr); + + netdev_for_each_synced_mc_addr(ha, dev) + dsa_user_unsync_mc(dev, ha->addr); + + netif_addr_unlock_bh(dev); + + if (dsa_switch_supports_uc_filtering(ds) || + dsa_switch_supports_mc_filtering(ds)) + dsa_flush_workqueue(); +} + +/* user mii_bus handling ***************************************************/ +static int dsa_user_phy_read(struct mii_bus *bus, int addr, int reg) +{ + struct dsa_switch *ds = bus->priv; + + if (ds->phys_mii_mask & (1 << addr)) + return ds->ops->phy_read(ds, addr, reg); + + return 0xffff; +} + +static int dsa_user_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct dsa_switch *ds = bus->priv; + + if (ds->phys_mii_mask & (1 << addr)) + return ds->ops->phy_write(ds, addr, reg, val); + + return 0; +} + +void dsa_user_mii_bus_init(struct dsa_switch *ds) +{ + ds->user_mii_bus->priv = (void *)ds; + ds->user_mii_bus->name = "dsa user smi"; + ds->user_mii_bus->read = dsa_user_phy_read; + ds->user_mii_bus->write = dsa_user_phy_write; + snprintf(ds->user_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", + ds->dst->index, ds->index); + ds->user_mii_bus->parent = ds->dev; + ds->user_mii_bus->phy_mask = ~ds->phys_mii_mask; +} + + +/* user device handling ****************************************************/ +static int dsa_user_get_iflink(const struct net_device *dev) +{ + return dsa_user_to_conduit(dev)->ifindex; +} + +static int dsa_user_open(struct net_device *dev) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int err; + + err = dev_open(conduit, NULL); + if (err < 0) { + netdev_err(dev, "failed to open conduit %s\n", conduit->name); + goto out; + } + + if (dsa_switch_supports_uc_filtering(ds)) { + err = dsa_port_standalone_host_fdb_add(dp, dev->dev_addr, 0); + if (err) + goto out; + } + + if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) { + err = dev_uc_add(conduit, dev->dev_addr); + if (err < 0) + goto del_host_addr; + } + + err = dsa_port_enable_rt(dp, dev->phydev); + if (err) + goto del_unicast; + + return 0; + +del_unicast: + if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) + dev_uc_del(conduit, dev->dev_addr); +del_host_addr: + if (dsa_switch_supports_uc_filtering(ds)) + dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); +out: + return err; +} + +static int dsa_user_close(struct net_device *dev) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + dsa_port_disable_rt(dp); + + if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) + dev_uc_del(conduit, dev->dev_addr); + + if (dsa_switch_supports_uc_filtering(ds)) + dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); + + return 0; +} + +static void dsa_user_manage_host_flood(struct net_device *dev) +{ + bool mc = dev->flags & (IFF_PROMISC | IFF_ALLMULTI); + struct dsa_port *dp = dsa_user_to_port(dev); + bool uc = dev->flags & IFF_PROMISC; + + dsa_port_set_host_flood(dp, uc, mc); +} + +static void dsa_user_change_rx_flags(struct net_device *dev, int change) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (change & IFF_ALLMULTI) + dev_set_allmulti(conduit, + dev->flags & IFF_ALLMULTI ? 1 : -1); + if (change & IFF_PROMISC) + dev_set_promiscuity(conduit, + dev->flags & IFF_PROMISC ? 1 : -1); + + if (dsa_switch_supports_uc_filtering(ds) && + dsa_switch_supports_mc_filtering(ds)) + dsa_user_manage_host_flood(dev); +} + +static void dsa_user_set_rx_mode(struct net_device *dev) +{ + __dev_mc_sync(dev, dsa_user_sync_mc, dsa_user_unsync_mc); + __dev_uc_sync(dev, dsa_user_sync_uc, dsa_user_unsync_uc); +} + +static int dsa_user_set_mac_address(struct net_device *dev, void *a) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + struct sockaddr *addr = a; + int err; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + if (ds->ops->port_set_mac_address) { + err = ds->ops->port_set_mac_address(ds, dp->index, + addr->sa_data); + if (err) + return err; + } + + /* If the port is down, the address isn't synced yet to hardware or + * to the DSA conduit, so there is nothing to change. + */ + if (!(dev->flags & IFF_UP)) + goto out_change_dev_addr; + + if (dsa_switch_supports_uc_filtering(ds)) { + err = dsa_port_standalone_host_fdb_add(dp, addr->sa_data, 0); + if (err) + return err; + } + + if (!ether_addr_equal(addr->sa_data, conduit->dev_addr)) { + err = dev_uc_add(conduit, addr->sa_data); + if (err < 0) + goto del_unicast; + } + + if (!ether_addr_equal(dev->dev_addr, conduit->dev_addr)) + dev_uc_del(conduit, dev->dev_addr); + + if (dsa_switch_supports_uc_filtering(ds)) + dsa_port_standalone_host_fdb_del(dp, dev->dev_addr, 0); + +out_change_dev_addr: + eth_hw_addr_set(dev, addr->sa_data); + + return 0; + +del_unicast: + if (dsa_switch_supports_uc_filtering(ds)) + dsa_port_standalone_host_fdb_del(dp, addr->sa_data, 0); + + return err; +} + +struct dsa_user_dump_ctx { + struct net_device *dev; + struct sk_buff *skb; + struct netlink_callback *cb; + int idx; +}; + +static int +dsa_user_port_fdb_do_dump(const unsigned char *addr, u16 vid, + bool is_static, void *data) +{ + struct dsa_user_dump_ctx *dump = data; + u32 portid = NETLINK_CB(dump->cb->skb).portid; + u32 seq = dump->cb->nlh->nlmsg_seq; + struct nlmsghdr *nlh; + struct ndmsg *ndm; + + if (dump->idx < dump->cb->args[2]) + goto skip; + + nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, + sizeof(*ndm), NLM_F_MULTI); + if (!nlh) + return -EMSGSIZE; + + ndm = nlmsg_data(nlh); + ndm->ndm_family = AF_BRIDGE; + ndm->ndm_pad1 = 0; + ndm->ndm_pad2 = 0; + ndm->ndm_flags = NTF_SELF; + ndm->ndm_type = 0; + ndm->ndm_ifindex = dump->dev->ifindex; + ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; + + if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) + goto nla_put_failure; + + if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) + goto nla_put_failure; + + nlmsg_end(dump->skb, nlh); + +skip: + dump->idx++; + return 0; + +nla_put_failure: + nlmsg_cancel(dump->skb, nlh); + return -EMSGSIZE; +} + +static int +dsa_user_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, + struct net_device *dev, struct net_device *filter_dev, + int *idx) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_user_dump_ctx dump = { + .dev = dev, + .skb = skb, + .cb = cb, + .idx = *idx, + }; + int err; + + err = dsa_port_fdb_dump(dp, dsa_user_port_fdb_do_dump, &dump); + *idx = dump.idx; + + return err; +} + +static int dsa_user_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct dsa_user_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->dp->ds; + int port = p->dp->index; + + /* Pass through to switch driver if it supports timestamping */ + switch (cmd) { + case SIOCGHWTSTAMP: + if (ds->ops->port_hwtstamp_get) + return ds->ops->port_hwtstamp_get(ds, port, ifr); + break; + case SIOCSHWTSTAMP: + if (ds->ops->port_hwtstamp_set) + return ds->ops->port_hwtstamp_set(ds, port, ifr); + break; + } + + return phylink_mii_ioctl(p->dp->pl, ifr, cmd); +} + +static int dsa_user_port_attr_set(struct net_device *dev, const void *ctx, + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + int ret; + + if (ctx && ctx != dp) + return 0; + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: + if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_set_state(dp, attr->u.stp_state, true); + break; + case SWITCHDEV_ATTR_ID_PORT_MST_STATE: + if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_set_mst_state(dp, &attr->u.mst_state, extack); + break; + case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: + if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, + extack); + break; + case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: + if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_ageing_time(dp, attr->u.ageing_time); + break; + case SWITCHDEV_ATTR_ID_BRIDGE_MST: + if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_mst_enable(dp, attr->u.mst, extack); + break; + case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: + if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, + extack); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack); + break; + case SWITCHDEV_ATTR_ID_VLAN_MSTI: + if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) + return -EOPNOTSUPP; + + ret = dsa_port_vlan_msti(dp, &attr->u.vlan_msti); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +/* Must be called under rcu_read_lock() */ +static int +dsa_user_vlan_check_for_8021q_uppers(struct net_device *user, + const struct switchdev_obj_port_vlan *vlan) +{ + struct net_device *upper_dev; + struct list_head *iter; + + netdev_for_each_upper_dev_rcu(user, upper_dev, iter) { + u16 vid; + + if (!is_vlan_dev(upper_dev)) + continue; + + vid = vlan_dev_vlan_id(upper_dev); + if (vid == vlan->vid) + return -EBUSY; + } + + return 0; +} + +static int dsa_user_vlan_add(struct net_device *dev, + const struct switchdev_obj *obj, + struct netlink_ext_ack *extack) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_vlan *vlan; + int err; + + if (dsa_port_skip_vlan_configuration(dp)) { + NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); + return 0; + } + + vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + + /* Deny adding a bridge VLAN when there is already an 802.1Q upper with + * the same VID. + */ + if (br_vlan_enabled(dsa_port_bridge_dev_get(dp))) { + rcu_read_lock(); + err = dsa_user_vlan_check_for_8021q_uppers(dev, vlan); + rcu_read_unlock(); + if (err) { + NL_SET_ERR_MSG_MOD(extack, + "Port already has a VLAN upper with this VID"); + return err; + } + } + + return dsa_port_vlan_add(dp, vlan, extack); +} + +/* Offload a VLAN installed on the bridge or on a foreign interface by + * installing it as a VLAN towards the CPU port. + */ +static int dsa_user_host_vlan_add(struct net_device *dev, + const struct switchdev_obj *obj, + struct netlink_ext_ack *extack) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_vlan vlan; + + /* Do nothing if this is a software bridge */ + if (!dp->bridge) + return -EOPNOTSUPP; + + if (dsa_port_skip_vlan_configuration(dp)) { + NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); + return 0; + } + + vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj); + + /* Even though drivers often handle CPU membership in special ways, + * it doesn't make sense to program a PVID, so clear this flag. + */ + vlan.flags &= ~BRIDGE_VLAN_INFO_PVID; + + return dsa_port_host_vlan_add(dp, &vlan, extack); +} + +static int dsa_user_port_obj_add(struct net_device *dev, const void *ctx, + const struct switchdev_obj *obj, + struct netlink_ext_ack *extack) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + int err; + + if (ctx && ctx != dp) + return 0; + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_MDB: + if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); + break; + case SWITCHDEV_OBJ_ID_HOST_MDB: + if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_bridge_host_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); + break; + case SWITCHDEV_OBJ_ID_PORT_VLAN: + if (dsa_port_offloads_bridge_port(dp, obj->orig_dev)) + err = dsa_user_vlan_add(dev, obj, extack); + else + err = dsa_user_host_vlan_add(dev, obj, extack); + break; + case SWITCHDEV_OBJ_ID_MRP: + if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_mrp_add(dp, SWITCHDEV_OBJ_MRP(obj)); + break; + case SWITCHDEV_OBJ_ID_RING_ROLE_MRP: + if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_mrp_add_ring_role(dp, + SWITCHDEV_OBJ_RING_ROLE_MRP(obj)); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int dsa_user_vlan_del(struct net_device *dev, + const struct switchdev_obj *obj) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_vlan *vlan; + + if (dsa_port_skip_vlan_configuration(dp)) + return 0; + + vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + + return dsa_port_vlan_del(dp, vlan); +} + +static int dsa_user_host_vlan_del(struct net_device *dev, + const struct switchdev_obj *obj) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_vlan *vlan; + + /* Do nothing if this is a software bridge */ + if (!dp->bridge) + return -EOPNOTSUPP; + + if (dsa_port_skip_vlan_configuration(dp)) + return 0; + + vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + + return dsa_port_host_vlan_del(dp, vlan); +} + +static int dsa_user_port_obj_del(struct net_device *dev, const void *ctx, + const struct switchdev_obj *obj) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + int err; + + if (ctx && ctx != dp) + return 0; + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_MDB: + if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); + break; + case SWITCHDEV_OBJ_ID_HOST_MDB: + if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_bridge_host_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); + break; + case SWITCHDEV_OBJ_ID_PORT_VLAN: + if (dsa_port_offloads_bridge_port(dp, obj->orig_dev)) + err = dsa_user_vlan_del(dev, obj); + else + err = dsa_user_host_vlan_del(dev, obj); + break; + case SWITCHDEV_OBJ_ID_MRP: + if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_mrp_del(dp, SWITCHDEV_OBJ_MRP(obj)); + break; + case SWITCHDEV_OBJ_ID_RING_ROLE_MRP: + if (!dsa_port_offloads_bridge_dev(dp, obj->orig_dev)) + return -EOPNOTSUPP; + + err = dsa_port_mrp_del_ring_role(dp, + SWITCHDEV_OBJ_RING_ROLE_MRP(obj)); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static inline netdev_tx_t dsa_user_netpoll_send_skb(struct net_device *dev, + struct sk_buff *skb) +{ +#ifdef CONFIG_NET_POLL_CONTROLLER + struct dsa_user_priv *p = netdev_priv(dev); + + return netpoll_send_skb(p->netpoll, skb); +#else + BUG(); + return NETDEV_TX_OK; +#endif +} + +static void dsa_skb_tx_timestamp(struct dsa_user_priv *p, + struct sk_buff *skb) +{ + struct dsa_switch *ds = p->dp->ds; + + if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) + return; + + if (!ds->ops->port_txtstamp) + return; + + ds->ops->port_txtstamp(ds, p->dp->index, skb); +} + +netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev) +{ + /* SKB for netpoll still need to be mangled with the protocol-specific + * tag to be successfully transmitted + */ + if (unlikely(netpoll_tx_running(dev))) + return dsa_user_netpoll_send_skb(dev, skb); + + /* Queue the SKB for transmission on the parent interface, but + * do not modify its EtherType + */ + skb->dev = dsa_user_to_conduit(dev); + dev_queue_xmit(skb); + + return NETDEV_TX_OK; +} +EXPORT_SYMBOL_GPL(dsa_enqueue_skb); + +static int dsa_realloc_skb(struct sk_buff *skb, struct net_device *dev) +{ + int needed_headroom = dev->needed_headroom; + int needed_tailroom = dev->needed_tailroom; + + /* For tail taggers, we need to pad short frames ourselves, to ensure + * that the tail tag does not fail at its role of being at the end of + * the packet, once the conduit interface pads the frame. Account for + * that pad length here, and pad later. + */ + if (unlikely(needed_tailroom && skb->len < ETH_ZLEN)) + needed_tailroom += ETH_ZLEN - skb->len; + /* skb_headroom() returns unsigned int... */ + needed_headroom = max_t(int, needed_headroom - skb_headroom(skb), 0); + needed_tailroom = max_t(int, needed_tailroom - skb_tailroom(skb), 0); + + if (likely(!needed_headroom && !needed_tailroom && !skb_cloned(skb))) + /* No reallocation needed, yay! */ + return 0; + + return pskb_expand_head(skb, needed_headroom, needed_tailroom, + GFP_ATOMIC); +} + +static netdev_tx_t dsa_user_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dsa_user_priv *p = netdev_priv(dev); + struct sk_buff *nskb; + + dev_sw_netstats_tx_add(dev, 1, skb->len); + + memset(skb->cb, 0, sizeof(skb->cb)); + + /* Handle tx timestamp if any */ + dsa_skb_tx_timestamp(p, skb); + + if (dsa_realloc_skb(skb, dev)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + /* needed_tailroom should still be 'warm' in the cache line from + * dsa_realloc_skb(), which has also ensured that padding is safe. + */ + if (dev->needed_tailroom) + eth_skb_pad(skb); + + /* Transmit function may have to reallocate the original SKB, + * in which case it must have freed it. Only free it here on error. + */ + nskb = p->xmit(skb, dev); + if (!nskb) { + kfree_skb(skb); + return NETDEV_TX_OK; + } + + return dsa_enqueue_skb(nskb, dev); +} + +/* ethtool operations *******************************************************/ + +static void dsa_user_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + strscpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver)); + strscpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strscpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info)); +} + +static int dsa_user_get_regs_len(struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_regs_len) + return ds->ops->get_regs_len(ds, dp->index); + + return -EOPNOTSUPP; +} + +static void +dsa_user_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_regs) + ds->ops->get_regs(ds, dp->index, regs, _p); +} + +static int dsa_user_nway_reset(struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + return phylink_ethtool_nway_reset(dp->pl); +} + +static int dsa_user_get_eeprom_len(struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->cd && ds->cd->eeprom_len) + return ds->cd->eeprom_len; + + if (ds->ops->get_eeprom_len) + return ds->ops->get_eeprom_len(ds); + + return 0; +} + +static int dsa_user_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_eeprom) + return ds->ops->get_eeprom(ds, eeprom, data); + + return -EOPNOTSUPP; +} + +static int dsa_user_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->set_eeprom) + return ds->ops->set_eeprom(ds, eeprom, data); + + return -EOPNOTSUPP; +} + +static void dsa_user_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (stringset == ETH_SS_STATS) { + int len = ETH_GSTRING_LEN; + + strscpy_pad(data, "tx_packets", len); + strscpy_pad(data + len, "tx_bytes", len); + strscpy_pad(data + 2 * len, "rx_packets", len); + strscpy_pad(data + 3 * len, "rx_bytes", len); + if (ds->ops->get_strings) + ds->ops->get_strings(ds, dp->index, stringset, + data + 4 * len); + } else if (stringset == ETH_SS_TEST) { + net_selftest_get_strings(data); + } + +} + +static void dsa_user_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + struct pcpu_sw_netstats *s; + unsigned int start; + int i; + + for_each_possible_cpu(i) { + u64 tx_packets, tx_bytes, rx_packets, rx_bytes; + + s = per_cpu_ptr(dev->tstats, i); + do { + start = u64_stats_fetch_begin(&s->syncp); + tx_packets = u64_stats_read(&s->tx_packets); + tx_bytes = u64_stats_read(&s->tx_bytes); + rx_packets = u64_stats_read(&s->rx_packets); + rx_bytes = u64_stats_read(&s->rx_bytes); + } while (u64_stats_fetch_retry(&s->syncp, start)); + data[0] += tx_packets; + data[1] += tx_bytes; + data[2] += rx_packets; + data[3] += rx_bytes; + } + if (ds->ops->get_ethtool_stats) + ds->ops->get_ethtool_stats(ds, dp->index, data + 4); +} + +static int dsa_user_get_sset_count(struct net_device *dev, int sset) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (sset == ETH_SS_STATS) { + int count = 0; + + if (ds->ops->get_sset_count) { + count = ds->ops->get_sset_count(ds, dp->index, sset); + if (count < 0) + return count; + } + + return count + 4; + } else if (sset == ETH_SS_TEST) { + return net_selftest_get_count(); + } + + return -EOPNOTSUPP; +} + +static void dsa_user_get_eth_phy_stats(struct net_device *dev, + struct ethtool_eth_phy_stats *phy_stats) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_eth_phy_stats) + ds->ops->get_eth_phy_stats(ds, dp->index, phy_stats); +} + +static void dsa_user_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_eth_mac_stats) + ds->ops->get_eth_mac_stats(ds, dp->index, mac_stats); +} + +static void +dsa_user_get_eth_ctrl_stats(struct net_device *dev, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_eth_ctrl_stats) + ds->ops->get_eth_ctrl_stats(ds, dp->index, ctrl_stats); +} + +static void +dsa_user_get_rmon_stats(struct net_device *dev, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_rmon_stats) + ds->ops->get_rmon_stats(ds, dp->index, rmon_stats, ranges); +} + +static void dsa_user_net_selftest(struct net_device *ndev, + struct ethtool_test *etest, u64 *buf) +{ + struct dsa_port *dp = dsa_user_to_port(ndev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->self_test) { + ds->ops->self_test(ds, dp->index, etest, buf); + return; + } + + net_selftest(ndev, etest, buf); +} + +static int dsa_user_get_mm(struct net_device *dev, + struct ethtool_mm_state *state) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->get_mm) + return -EOPNOTSUPP; + + return ds->ops->get_mm(ds, dp->index, state); +} + +static int dsa_user_set_mm(struct net_device *dev, struct ethtool_mm_cfg *cfg, + struct netlink_ext_ack *extack) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->set_mm) + return -EOPNOTSUPP; + + return ds->ops->set_mm(ds, dp->index, cfg, extack); +} + +static void dsa_user_get_mm_stats(struct net_device *dev, + struct ethtool_mm_stats *stats) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_mm_stats) + ds->ops->get_mm_stats(ds, dp->index, stats); +} + +static void dsa_user_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + phylink_ethtool_get_wol(dp->pl, w); + + if (ds->ops->get_wol) + ds->ops->get_wol(ds, dp->index, w); +} + +static int dsa_user_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int ret = -EOPNOTSUPP; + + phylink_ethtool_set_wol(dp->pl, w); + + if (ds->ops->set_wol) + ret = ds->ops->set_wol(ds, dp->index, w); + + return ret; +} + +static int dsa_user_set_eee(struct net_device *dev, struct ethtool_eee *e) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int ret; + + /* Port's PHY and MAC both need to be EEE capable */ + if (!dev->phydev || !dp->pl) + return -ENODEV; + + if (!ds->ops->set_mac_eee) + return -EOPNOTSUPP; + + ret = ds->ops->set_mac_eee(ds, dp->index, e); + if (ret) + return ret; + + return phylink_ethtool_set_eee(dp->pl, e); +} + +static int dsa_user_get_eee(struct net_device *dev, struct ethtool_eee *e) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int ret; + + /* Port's PHY and MAC both need to be EEE capable */ + if (!dev->phydev || !dp->pl) + return -ENODEV; + + if (!ds->ops->get_mac_eee) + return -EOPNOTSUPP; + + ret = ds->ops->get_mac_eee(ds, dp->index, e); + if (ret) + return ret; + + return phylink_ethtool_get_eee(dp->pl, e); +} + +static int dsa_user_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + return phylink_ethtool_ksettings_get(dp->pl, cmd); +} + +static int dsa_user_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + return phylink_ethtool_ksettings_set(dp->pl, cmd); +} + +static void dsa_user_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_pause_stats) + ds->ops->get_pause_stats(ds, dp->index, pause_stats); +} + +static void dsa_user_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + phylink_ethtool_get_pauseparam(dp->pl, pause); +} + +static int dsa_user_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + return phylink_ethtool_set_pauseparam(dp->pl, pause); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static int dsa_user_netpoll_setup(struct net_device *dev, + struct netpoll_info *ni) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_user_priv *p = netdev_priv(dev); + struct netpoll *netpoll; + int err = 0; + + netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); + if (!netpoll) + return -ENOMEM; + + err = __netpoll_setup(netpoll, conduit); + if (err) { + kfree(netpoll); + goto out; + } + + p->netpoll = netpoll; +out: + return err; +} + +static void dsa_user_netpoll_cleanup(struct net_device *dev) +{ + struct dsa_user_priv *p = netdev_priv(dev); + struct netpoll *netpoll = p->netpoll; + + if (!netpoll) + return; + + p->netpoll = NULL; + + __netpoll_free(netpoll); +} + +static void dsa_user_poll_controller(struct net_device *dev) +{ +} +#endif + +static struct dsa_mall_tc_entry * +dsa_user_mall_tc_entry_find(struct net_device *dev, unsigned long cookie) +{ + struct dsa_user_priv *p = netdev_priv(dev); + struct dsa_mall_tc_entry *mall_tc_entry; + + list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) + if (mall_tc_entry->cookie == cookie) + return mall_tc_entry; + + return NULL; +} + +static int +dsa_user_add_cls_matchall_mirred(struct net_device *dev, + struct tc_cls_matchall_offload *cls, + bool ingress) +{ + struct netlink_ext_ack *extack = cls->common.extack; + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_user_priv *p = netdev_priv(dev); + struct dsa_mall_mirror_tc_entry *mirror; + struct dsa_mall_tc_entry *mall_tc_entry; + struct dsa_switch *ds = dp->ds; + struct flow_action_entry *act; + struct dsa_port *to_dp; + int err; + + if (!ds->ops->port_mirror_add) + return -EOPNOTSUPP; + + if (!flow_action_basic_hw_stats_check(&cls->rule->action, + cls->common.extack)) + return -EOPNOTSUPP; + + act = &cls->rule->action.entries[0]; + + if (!act->dev) + return -EINVAL; + + if (!dsa_user_dev_check(act->dev)) + return -EOPNOTSUPP; + + mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); + if (!mall_tc_entry) + return -ENOMEM; + + mall_tc_entry->cookie = cls->cookie; + mall_tc_entry->type = DSA_PORT_MALL_MIRROR; + mirror = &mall_tc_entry->mirror; + + to_dp = dsa_user_to_port(act->dev); + + mirror->to_local_port = to_dp->index; + mirror->ingress = ingress; + + err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress, extack); + if (err) { + kfree(mall_tc_entry); + return err; + } + + list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); + + return err; +} + +static int +dsa_user_add_cls_matchall_police(struct net_device *dev, + struct tc_cls_matchall_offload *cls, + bool ingress) +{ + struct netlink_ext_ack *extack = cls->common.extack; + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_user_priv *p = netdev_priv(dev); + struct dsa_mall_policer_tc_entry *policer; + struct dsa_mall_tc_entry *mall_tc_entry; + struct dsa_switch *ds = dp->ds; + struct flow_action_entry *act; + int err; + + if (!ds->ops->port_policer_add) { + NL_SET_ERR_MSG_MOD(extack, + "Policing offload not implemented"); + return -EOPNOTSUPP; + } + + if (!ingress) { + NL_SET_ERR_MSG_MOD(extack, + "Only supported on ingress qdisc"); + return -EOPNOTSUPP; + } + + if (!flow_action_basic_hw_stats_check(&cls->rule->action, + cls->common.extack)) + return -EOPNOTSUPP; + + list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) { + if (mall_tc_entry->type == DSA_PORT_MALL_POLICER) { + NL_SET_ERR_MSG_MOD(extack, + "Only one port policer allowed"); + return -EEXIST; + } + } + + act = &cls->rule->action.entries[0]; + + mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); + if (!mall_tc_entry) + return -ENOMEM; + + mall_tc_entry->cookie = cls->cookie; + mall_tc_entry->type = DSA_PORT_MALL_POLICER; + policer = &mall_tc_entry->policer; + policer->rate_bytes_per_sec = act->police.rate_bytes_ps; + policer->burst = act->police.burst; + + err = ds->ops->port_policer_add(ds, dp->index, policer); + if (err) { + kfree(mall_tc_entry); + return err; + } + + list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); + + return err; +} + +static int dsa_user_add_cls_matchall(struct net_device *dev, + struct tc_cls_matchall_offload *cls, + bool ingress) +{ + int err = -EOPNOTSUPP; + + if (cls->common.protocol == htons(ETH_P_ALL) && + flow_offload_has_one_action(&cls->rule->action) && + cls->rule->action.entries[0].id == FLOW_ACTION_MIRRED) + err = dsa_user_add_cls_matchall_mirred(dev, cls, ingress); + else if (flow_offload_has_one_action(&cls->rule->action) && + cls->rule->action.entries[0].id == FLOW_ACTION_POLICE) + err = dsa_user_add_cls_matchall_police(dev, cls, ingress); + + return err; +} + +static void dsa_user_del_cls_matchall(struct net_device *dev, + struct tc_cls_matchall_offload *cls) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_mall_tc_entry *mall_tc_entry; + struct dsa_switch *ds = dp->ds; + + mall_tc_entry = dsa_user_mall_tc_entry_find(dev, cls->cookie); + if (!mall_tc_entry) + return; + + list_del(&mall_tc_entry->list); + + switch (mall_tc_entry->type) { + case DSA_PORT_MALL_MIRROR: + if (ds->ops->port_mirror_del) + ds->ops->port_mirror_del(ds, dp->index, + &mall_tc_entry->mirror); + break; + case DSA_PORT_MALL_POLICER: + if (ds->ops->port_policer_del) + ds->ops->port_policer_del(ds, dp->index); + break; + default: + WARN_ON(1); + } + + kfree(mall_tc_entry); +} + +static int dsa_user_setup_tc_cls_matchall(struct net_device *dev, + struct tc_cls_matchall_offload *cls, + bool ingress) +{ + if (cls->common.chain_index) + return -EOPNOTSUPP; + + switch (cls->command) { + case TC_CLSMATCHALL_REPLACE: + return dsa_user_add_cls_matchall(dev, cls, ingress); + case TC_CLSMATCHALL_DESTROY: + dsa_user_del_cls_matchall(dev, cls); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int dsa_user_add_cls_flower(struct net_device *dev, + struct flow_cls_offload *cls, + bool ingress) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int port = dp->index; + + if (!ds->ops->cls_flower_add) + return -EOPNOTSUPP; + + return ds->ops->cls_flower_add(ds, port, cls, ingress); +} + +static int dsa_user_del_cls_flower(struct net_device *dev, + struct flow_cls_offload *cls, + bool ingress) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int port = dp->index; + + if (!ds->ops->cls_flower_del) + return -EOPNOTSUPP; + + return ds->ops->cls_flower_del(ds, port, cls, ingress); +} + +static int dsa_user_stats_cls_flower(struct net_device *dev, + struct flow_cls_offload *cls, + bool ingress) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int port = dp->index; + + if (!ds->ops->cls_flower_stats) + return -EOPNOTSUPP; + + return ds->ops->cls_flower_stats(ds, port, cls, ingress); +} + +static int dsa_user_setup_tc_cls_flower(struct net_device *dev, + struct flow_cls_offload *cls, + bool ingress) +{ + switch (cls->command) { + case FLOW_CLS_REPLACE: + return dsa_user_add_cls_flower(dev, cls, ingress); + case FLOW_CLS_DESTROY: + return dsa_user_del_cls_flower(dev, cls, ingress); + case FLOW_CLS_STATS: + return dsa_user_stats_cls_flower(dev, cls, ingress); + default: + return -EOPNOTSUPP; + } +} + +static int dsa_user_setup_tc_block_cb(enum tc_setup_type type, void *type_data, + void *cb_priv, bool ingress) +{ + struct net_device *dev = cb_priv; + + if (!tc_can_offload(dev)) + return -EOPNOTSUPP; + + switch (type) { + case TC_SETUP_CLSMATCHALL: + return dsa_user_setup_tc_cls_matchall(dev, type_data, ingress); + case TC_SETUP_CLSFLOWER: + return dsa_user_setup_tc_cls_flower(dev, type_data, ingress); + default: + return -EOPNOTSUPP; + } +} + +static int dsa_user_setup_tc_block_cb_ig(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + return dsa_user_setup_tc_block_cb(type, type_data, cb_priv, true); +} + +static int dsa_user_setup_tc_block_cb_eg(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + return dsa_user_setup_tc_block_cb(type, type_data, cb_priv, false); +} + +static LIST_HEAD(dsa_user_block_cb_list); + +static int dsa_user_setup_tc_block(struct net_device *dev, + struct flow_block_offload *f) +{ + struct flow_block_cb *block_cb; + flow_setup_cb_t *cb; + + if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) + cb = dsa_user_setup_tc_block_cb_ig; + else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) + cb = dsa_user_setup_tc_block_cb_eg; + else + return -EOPNOTSUPP; + + f->driver_block_list = &dsa_user_block_cb_list; + + switch (f->command) { + case FLOW_BLOCK_BIND: + if (flow_block_cb_is_busy(cb, dev, &dsa_user_block_cb_list)) + return -EBUSY; + + block_cb = flow_block_cb_alloc(cb, dev, dev, NULL); + if (IS_ERR(block_cb)) + return PTR_ERR(block_cb); + + flow_block_cb_add(block_cb, f); + list_add_tail(&block_cb->driver_list, &dsa_user_block_cb_list); + return 0; + case FLOW_BLOCK_UNBIND: + block_cb = flow_block_cb_lookup(f->block, cb, dev); + if (!block_cb) + return -ENOENT; + + flow_block_cb_remove(block_cb, f); + list_del(&block_cb->driver_list); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int dsa_user_setup_ft_block(struct dsa_switch *ds, int port, + void *type_data) +{ + struct net_device *conduit = dsa_port_to_conduit(dsa_to_port(ds, port)); + + if (!conduit->netdev_ops->ndo_setup_tc) + return -EOPNOTSUPP; + + return conduit->netdev_ops->ndo_setup_tc(conduit, TC_SETUP_FT, type_data); +} + +static int dsa_user_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + switch (type) { + case TC_SETUP_BLOCK: + return dsa_user_setup_tc_block(dev, type_data); + case TC_SETUP_FT: + return dsa_user_setup_ft_block(ds, dp->index, type_data); + default: + break; + } + + if (!ds->ops->port_setup_tc) + return -EOPNOTSUPP; + + return ds->ops->port_setup_tc(ds, dp->index, type, type_data); +} + +static int dsa_user_get_rxnfc(struct net_device *dev, + struct ethtool_rxnfc *nfc, u32 *rule_locs) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->get_rxnfc) + return -EOPNOTSUPP; + + return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs); +} + +static int dsa_user_set_rxnfc(struct net_device *dev, + struct ethtool_rxnfc *nfc) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->set_rxnfc) + return -EOPNOTSUPP; + + return ds->ops->set_rxnfc(ds, dp->index, nfc); +} + +static int dsa_user_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *ts) +{ + struct dsa_user_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->dp->ds; + + if (!ds->ops->get_ts_info) + return -EOPNOTSUPP; + + return ds->ops->get_ts_info(ds, p->dp->index, ts); +} + +static int dsa_user_vlan_rx_add_vid(struct net_device *dev, __be16 proto, + u16 vid) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_vlan vlan = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, + .vid = vid, + /* This API only allows programming tagged, non-PVID VIDs */ + .flags = 0, + }; + struct netlink_ext_ack extack = {0}; + struct dsa_switch *ds = dp->ds; + struct netdev_hw_addr *ha; + struct dsa_vlan *v; + int ret; + + /* User port... */ + ret = dsa_port_vlan_add(dp, &vlan, &extack); + if (ret) { + if (extack._msg) + netdev_err(dev, "%s\n", extack._msg); + return ret; + } + + /* And CPU port... */ + ret = dsa_port_host_vlan_add(dp, &vlan, &extack); + if (ret) { + if (extack._msg) + netdev_err(dev, "CPU port %d: %s\n", dp->cpu_dp->index, + extack._msg); + return ret; + } + + if (!dsa_switch_supports_uc_filtering(ds) && + !dsa_switch_supports_mc_filtering(ds)) + return 0; + + v = kzalloc(sizeof(*v), GFP_KERNEL); + if (!v) { + ret = -ENOMEM; + goto rollback; + } + + netif_addr_lock_bh(dev); + + v->vid = vid; + list_add_tail(&v->list, &dp->user_vlans); + + if (dsa_switch_supports_mc_filtering(ds)) { + netdev_for_each_synced_mc_addr(ha, dev) { + dsa_user_schedule_standalone_work(dev, DSA_MC_ADD, + ha->addr, vid); + } + } + + if (dsa_switch_supports_uc_filtering(ds)) { + netdev_for_each_synced_uc_addr(ha, dev) { + dsa_user_schedule_standalone_work(dev, DSA_UC_ADD, + ha->addr, vid); + } + } + + netif_addr_unlock_bh(dev); + + dsa_flush_workqueue(); + + return 0; + +rollback: + dsa_port_host_vlan_del(dp, &vlan); + dsa_port_vlan_del(dp, &vlan); + + return ret; +} + +static int dsa_user_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, + u16 vid) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct switchdev_obj_port_vlan vlan = { + .vid = vid, + /* This API only allows programming tagged, non-PVID VIDs */ + .flags = 0, + }; + struct dsa_switch *ds = dp->ds; + struct netdev_hw_addr *ha; + struct dsa_vlan *v; + int err; + + err = dsa_port_vlan_del(dp, &vlan); + if (err) + return err; + + err = dsa_port_host_vlan_del(dp, &vlan); + if (err) + return err; + + if (!dsa_switch_supports_uc_filtering(ds) && + !dsa_switch_supports_mc_filtering(ds)) + return 0; + + netif_addr_lock_bh(dev); + + v = dsa_vlan_find(&dp->user_vlans, &vlan); + if (!v) { + netif_addr_unlock_bh(dev); + return -ENOENT; + } + + list_del(&v->list); + kfree(v); + + if (dsa_switch_supports_mc_filtering(ds)) { + netdev_for_each_synced_mc_addr(ha, dev) { + dsa_user_schedule_standalone_work(dev, DSA_MC_DEL, + ha->addr, vid); + } + } + + if (dsa_switch_supports_uc_filtering(ds)) { + netdev_for_each_synced_uc_addr(ha, dev) { + dsa_user_schedule_standalone_work(dev, DSA_UC_DEL, + ha->addr, vid); + } + } + + netif_addr_unlock_bh(dev); + + dsa_flush_workqueue(); + + return 0; +} + +static int dsa_user_restore_vlan(struct net_device *vdev, int vid, void *arg) +{ + __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); + + return dsa_user_vlan_rx_add_vid(arg, proto, vid); +} + +static int dsa_user_clear_vlan(struct net_device *vdev, int vid, void *arg) +{ + __be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q); + + return dsa_user_vlan_rx_kill_vid(arg, proto, vid); +} + +/* Keep the VLAN RX filtering list in sync with the hardware only if VLAN + * filtering is enabled. The baseline is that only ports that offload a + * VLAN-aware bridge are VLAN-aware, and standalone ports are VLAN-unaware, + * but there are exceptions for quirky hardware. + * + * If ds->vlan_filtering_is_global = true, then standalone ports which share + * the same switch with other ports that offload a VLAN-aware bridge are also + * inevitably VLAN-aware. + * + * To summarize, a DSA switch port offloads: + * + * - If standalone (this includes software bridge, software LAG): + * - if ds->needs_standalone_vlan_filtering = true, OR if + * (ds->vlan_filtering_is_global = true AND there are bridges spanning + * this switch chip which have vlan_filtering=1) + * - the 8021q upper VLANs + * - else (standalone VLAN filtering is not needed, VLAN filtering is not + * global, or it is, but no port is under a VLAN-aware bridge): + * - no VLAN (any 8021q upper is a software VLAN) + * + * - If under a vlan_filtering=0 bridge which it offload: + * - if ds->configure_vlan_while_not_filtering = true (default): + * - the bridge VLANs. These VLANs are committed to hardware but inactive. + * - else (deprecated): + * - no VLAN. The bridge VLANs are not restored when VLAN awareness is + * enabled, so this behavior is broken and discouraged. + * + * - If under a vlan_filtering=1 bridge which it offload: + * - the bridge VLANs + * - the 8021q upper VLANs + */ +int dsa_user_manage_vlan_filtering(struct net_device *user, + bool vlan_filtering) +{ + int err; + + if (vlan_filtering) { + user->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + + err = vlan_for_each(user, dsa_user_restore_vlan, user); + if (err) { + vlan_for_each(user, dsa_user_clear_vlan, user); + user->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; + return err; + } + } else { + err = vlan_for_each(user, dsa_user_clear_vlan, user); + if (err) + return err; + + user->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; + } + + return 0; +} + +struct dsa_hw_port { + struct list_head list; + struct net_device *dev; + int old_mtu; +}; + +static int dsa_hw_port_list_set_mtu(struct list_head *hw_port_list, int mtu) +{ + const struct dsa_hw_port *p; + int err; + + list_for_each_entry(p, hw_port_list, list) { + if (p->dev->mtu == mtu) + continue; + + err = dev_set_mtu(p->dev, mtu); + if (err) + goto rollback; + } + + return 0; + +rollback: + list_for_each_entry_continue_reverse(p, hw_port_list, list) { + if (p->dev->mtu == p->old_mtu) + continue; + + if (dev_set_mtu(p->dev, p->old_mtu)) + netdev_err(p->dev, "Failed to restore MTU\n"); + } + + return err; +} + +static void dsa_hw_port_list_free(struct list_head *hw_port_list) +{ + struct dsa_hw_port *p, *n; + + list_for_each_entry_safe(p, n, hw_port_list, list) + kfree(p); +} + +/* Make the hardware datapath to/from @dev limited to a common MTU */ +static void dsa_bridge_mtu_normalization(struct dsa_port *dp) +{ + struct list_head hw_port_list; + struct dsa_switch_tree *dst; + int min_mtu = ETH_MAX_MTU; + struct dsa_port *other_dp; + int err; + + if (!dp->ds->mtu_enforcement_ingress) + return; + + if (!dp->bridge) + return; + + INIT_LIST_HEAD(&hw_port_list); + + /* Populate the list of ports that are part of the same bridge + * as the newly added/modified port + */ + list_for_each_entry(dst, &dsa_tree_list, list) { + list_for_each_entry(other_dp, &dst->ports, list) { + struct dsa_hw_port *hw_port; + struct net_device *user; + + if (other_dp->type != DSA_PORT_TYPE_USER) + continue; + + if (!dsa_port_bridge_same(dp, other_dp)) + continue; + + if (!other_dp->ds->mtu_enforcement_ingress) + continue; + + user = other_dp->user; + + if (min_mtu > user->mtu) + min_mtu = user->mtu; + + hw_port = kzalloc(sizeof(*hw_port), GFP_KERNEL); + if (!hw_port) + goto out; + + hw_port->dev = user; + hw_port->old_mtu = user->mtu; + + list_add(&hw_port->list, &hw_port_list); + } + } + + /* Attempt to configure the entire hardware bridge to the newly added + * interface's MTU first, regardless of whether the intention of the + * user was to raise or lower it. + */ + err = dsa_hw_port_list_set_mtu(&hw_port_list, dp->user->mtu); + if (!err) + goto out; + + /* Clearly that didn't work out so well, so just set the minimum MTU on + * all hardware bridge ports now. If this fails too, then all ports will + * still have their old MTU rolled back anyway. + */ + dsa_hw_port_list_set_mtu(&hw_port_list, min_mtu); + +out: + dsa_hw_port_list_free(&hw_port_list); +} + +int dsa_user_change_mtu(struct net_device *dev, int new_mtu) +{ + struct net_device *conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_port *cpu_dp = dp->cpu_dp; + struct dsa_switch *ds = dp->ds; + struct dsa_port *other_dp; + int largest_mtu = 0; + int new_conduit_mtu; + int old_conduit_mtu; + int mtu_limit; + int overhead; + int cpu_mtu; + int err; + + if (!ds->ops->port_change_mtu) + return -EOPNOTSUPP; + + dsa_tree_for_each_user_port(other_dp, ds->dst) { + int user_mtu; + + /* During probe, this function will be called for each user + * device, while not all of them have been allocated. That's + * ok, it doesn't change what the maximum is, so ignore it. + */ + if (!other_dp->user) + continue; + + /* Pretend that we already applied the setting, which we + * actually haven't (still haven't done all integrity checks) + */ + if (dp == other_dp) + user_mtu = new_mtu; + else + user_mtu = other_dp->user->mtu; + + if (largest_mtu < user_mtu) + largest_mtu = user_mtu; + } + + overhead = dsa_tag_protocol_overhead(cpu_dp->tag_ops); + mtu_limit = min_t(int, conduit->max_mtu, dev->max_mtu + overhead); + old_conduit_mtu = conduit->mtu; + new_conduit_mtu = largest_mtu + overhead; + if (new_conduit_mtu > mtu_limit) + return -ERANGE; + + /* If the conduit MTU isn't over limit, there's no need to check the CPU + * MTU, since that surely isn't either. + */ + cpu_mtu = largest_mtu; + + /* Start applying stuff */ + if (new_conduit_mtu != old_conduit_mtu) { + err = dev_set_mtu(conduit, new_conduit_mtu); + if (err < 0) + goto out_conduit_failed; + + /* We only need to propagate the MTU of the CPU port to + * upstream switches, so emit a notifier which updates them. + */ + err = dsa_port_mtu_change(cpu_dp, cpu_mtu); + if (err) + goto out_cpu_failed; + } + + err = ds->ops->port_change_mtu(ds, dp->index, new_mtu); + if (err) + goto out_port_failed; + + dev->mtu = new_mtu; + + dsa_bridge_mtu_normalization(dp); + + return 0; + +out_port_failed: + if (new_conduit_mtu != old_conduit_mtu) + dsa_port_mtu_change(cpu_dp, old_conduit_mtu - overhead); +out_cpu_failed: + if (new_conduit_mtu != old_conduit_mtu) + dev_set_mtu(conduit, old_conduit_mtu); +out_conduit_failed: + return err; +} + +static int __maybe_unused +dsa_user_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + unsigned long mask, new_prio; + int err, port = dp->index; + + if (!ds->ops->port_set_default_prio) + return -EOPNOTSUPP; + + err = dcb_ieee_setapp(dev, app); + if (err) + return err; + + mask = dcb_ieee_getapp_mask(dev, app); + new_prio = __fls(mask); + + err = ds->ops->port_set_default_prio(ds, port, new_prio); + if (err) { + dcb_ieee_delapp(dev, app); + return err; + } + + return 0; +} + +static int __maybe_unused +dsa_user_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + unsigned long mask, new_prio; + int err, port = dp->index; + u8 dscp = app->protocol; + + if (!ds->ops->port_add_dscp_prio) + return -EOPNOTSUPP; + + if (dscp >= 64) { + netdev_err(dev, "DSCP APP entry with protocol value %u is invalid\n", + dscp); + return -EINVAL; + } + + err = dcb_ieee_setapp(dev, app); + if (err) + return err; + + mask = dcb_ieee_getapp_mask(dev, app); + new_prio = __fls(mask); + + err = ds->ops->port_add_dscp_prio(ds, port, dscp, new_prio); + if (err) { + dcb_ieee_delapp(dev, app); + return err; + } + + return 0; +} + +static int __maybe_unused dsa_user_dcbnl_ieee_setapp(struct net_device *dev, + struct dcb_app *app) +{ + switch (app->selector) { + case IEEE_8021QAZ_APP_SEL_ETHERTYPE: + switch (app->protocol) { + case 0: + return dsa_user_dcbnl_set_default_prio(dev, app); + default: + return -EOPNOTSUPP; + } + break; + case IEEE_8021QAZ_APP_SEL_DSCP: + return dsa_user_dcbnl_add_dscp_prio(dev, app); + default: + return -EOPNOTSUPP; + } +} + +static int __maybe_unused +dsa_user_dcbnl_del_default_prio(struct net_device *dev, struct dcb_app *app) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + unsigned long mask, new_prio; + int err, port = dp->index; + + if (!ds->ops->port_set_default_prio) + return -EOPNOTSUPP; + + err = dcb_ieee_delapp(dev, app); + if (err) + return err; + + mask = dcb_ieee_getapp_mask(dev, app); + new_prio = mask ? __fls(mask) : 0; + + err = ds->ops->port_set_default_prio(ds, port, new_prio); + if (err) { + dcb_ieee_setapp(dev, app); + return err; + } + + return 0; +} + +static int __maybe_unused +dsa_user_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int err, port = dp->index; + u8 dscp = app->protocol; + + if (!ds->ops->port_del_dscp_prio) + return -EOPNOTSUPP; + + err = dcb_ieee_delapp(dev, app); + if (err) + return err; + + err = ds->ops->port_del_dscp_prio(ds, port, dscp, app->priority); + if (err) { + dcb_ieee_setapp(dev, app); + return err; + } + + return 0; +} + +static int __maybe_unused dsa_user_dcbnl_ieee_delapp(struct net_device *dev, + struct dcb_app *app) +{ + switch (app->selector) { + case IEEE_8021QAZ_APP_SEL_ETHERTYPE: + switch (app->protocol) { + case 0: + return dsa_user_dcbnl_del_default_prio(dev, app); + default: + return -EOPNOTSUPP; + } + break; + case IEEE_8021QAZ_APP_SEL_DSCP: + return dsa_user_dcbnl_del_dscp_prio(dev, app); + default: + return -EOPNOTSUPP; + } +} + +/* Pre-populate the DCB application priority table with the priorities + * configured during switch setup, which we read from hardware here. + */ +static int dsa_user_dcbnl_init(struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + int port = dp->index; + int err; + + if (ds->ops->port_get_default_prio) { + int prio = ds->ops->port_get_default_prio(ds, port); + struct dcb_app app = { + .selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE, + .protocol = 0, + .priority = prio, + }; + + if (prio < 0) + return prio; + + err = dcb_ieee_setapp(dev, &app); + if (err) + return err; + } + + if (ds->ops->port_get_dscp_prio) { + int protocol; + + for (protocol = 0; protocol < 64; protocol++) { + struct dcb_app app = { + .selector = IEEE_8021QAZ_APP_SEL_DSCP, + .protocol = protocol, + }; + int prio; + + prio = ds->ops->port_get_dscp_prio(ds, port, protocol); + if (prio == -EOPNOTSUPP) + continue; + if (prio < 0) + return prio; + + app.priority = prio; + + err = dcb_ieee_setapp(dev, &app); + if (err) + return err; + } + } + + return 0; +} + +static const struct ethtool_ops dsa_user_ethtool_ops = { + .get_drvinfo = dsa_user_get_drvinfo, + .get_regs_len = dsa_user_get_regs_len, + .get_regs = dsa_user_get_regs, + .nway_reset = dsa_user_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = dsa_user_get_eeprom_len, + .get_eeprom = dsa_user_get_eeprom, + .set_eeprom = dsa_user_set_eeprom, + .get_strings = dsa_user_get_strings, + .get_ethtool_stats = dsa_user_get_ethtool_stats, + .get_sset_count = dsa_user_get_sset_count, + .get_eth_phy_stats = dsa_user_get_eth_phy_stats, + .get_eth_mac_stats = dsa_user_get_eth_mac_stats, + .get_eth_ctrl_stats = dsa_user_get_eth_ctrl_stats, + .get_rmon_stats = dsa_user_get_rmon_stats, + .set_wol = dsa_user_set_wol, + .get_wol = dsa_user_get_wol, + .set_eee = dsa_user_set_eee, + .get_eee = dsa_user_get_eee, + .get_link_ksettings = dsa_user_get_link_ksettings, + .set_link_ksettings = dsa_user_set_link_ksettings, + .get_pause_stats = dsa_user_get_pause_stats, + .get_pauseparam = dsa_user_get_pauseparam, + .set_pauseparam = dsa_user_set_pauseparam, + .get_rxnfc = dsa_user_get_rxnfc, + .set_rxnfc = dsa_user_set_rxnfc, + .get_ts_info = dsa_user_get_ts_info, + .self_test = dsa_user_net_selftest, + .get_mm = dsa_user_get_mm, + .set_mm = dsa_user_set_mm, + .get_mm_stats = dsa_user_get_mm_stats, +}; + +static const struct dcbnl_rtnl_ops __maybe_unused dsa_user_dcbnl_ops = { + .ieee_setapp = dsa_user_dcbnl_ieee_setapp, + .ieee_delapp = dsa_user_dcbnl_ieee_delapp, +}; + +static void dsa_user_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *s) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + + if (ds->ops->get_stats64) + ds->ops->get_stats64(ds, dp->index, s); + else + dev_get_tstats64(dev, s); +} + +static int dsa_user_fill_forward_path(struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + struct dsa_port *dp = dsa_user_to_port(ctx->dev); + struct net_device *conduit = dsa_port_to_conduit(dp); + struct dsa_port *cpu_dp = dp->cpu_dp; + + path->dev = ctx->dev; + path->type = DEV_PATH_DSA; + path->dsa.proto = cpu_dp->tag_ops->proto; + path->dsa.port = dp->index; + ctx->dev = conduit; + + return 0; +} + +static const struct net_device_ops dsa_user_netdev_ops = { + .ndo_open = dsa_user_open, + .ndo_stop = dsa_user_close, + .ndo_start_xmit = dsa_user_xmit, + .ndo_change_rx_flags = dsa_user_change_rx_flags, + .ndo_set_rx_mode = dsa_user_set_rx_mode, + .ndo_set_mac_address = dsa_user_set_mac_address, + .ndo_fdb_dump = dsa_user_fdb_dump, + .ndo_eth_ioctl = dsa_user_ioctl, + .ndo_get_iflink = dsa_user_get_iflink, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_netpoll_setup = dsa_user_netpoll_setup, + .ndo_netpoll_cleanup = dsa_user_netpoll_cleanup, + .ndo_poll_controller = dsa_user_poll_controller, +#endif + .ndo_setup_tc = dsa_user_setup_tc, + .ndo_get_stats64 = dsa_user_get_stats64, + .ndo_vlan_rx_add_vid = dsa_user_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = dsa_user_vlan_rx_kill_vid, + .ndo_change_mtu = dsa_user_change_mtu, + .ndo_fill_forward_path = dsa_user_fill_forward_path, +}; + +static struct device_type dsa_type = { + .name = "dsa", +}; + +void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up) +{ + const struct dsa_port *dp = dsa_to_port(ds, port); + + if (dp->pl) + phylink_mac_change(dp->pl, up); +} +EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change); + +static void dsa_user_phylink_fixed_state(struct phylink_config *config, + struct phylink_link_state *state) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + /* No need to check that this operation is valid, the callback would + * not be called if it was not. + */ + ds->ops->phylink_fixed_state(ds, dp->index, state); +} + +/* user device setup *******************************************************/ +static int dsa_user_phy_connect(struct net_device *user_dev, int addr, + u32 flags) +{ + struct dsa_port *dp = dsa_user_to_port(user_dev); + struct dsa_switch *ds = dp->ds; + + user_dev->phydev = mdiobus_get_phy(ds->user_mii_bus, addr); + if (!user_dev->phydev) { + netdev_err(user_dev, "no phy at %d\n", addr); + return -ENODEV; + } + + user_dev->phydev->dev_flags |= flags; + + return phylink_connect_phy(dp->pl, user_dev->phydev); +} + +static int dsa_user_phy_setup(struct net_device *user_dev) +{ + struct dsa_port *dp = dsa_user_to_port(user_dev); + struct device_node *port_dn = dp->dn; + struct dsa_switch *ds = dp->ds; + u32 phy_flags = 0; + int ret; + + dp->pl_config.dev = &user_dev->dev; + dp->pl_config.type = PHYLINK_NETDEV; + + /* The get_fixed_state callback takes precedence over polling the + * link GPIO in PHYLINK (see phylink_get_fixed_state). Only set + * this if the switch provides such a callback. + */ + if (ds->ops->phylink_fixed_state) { + dp->pl_config.get_fixed_state = dsa_user_phylink_fixed_state; + dp->pl_config.poll_fixed_state = true; + } + + ret = dsa_port_phylink_create(dp); + if (ret) + return ret; + + if (ds->ops->get_phy_flags) + phy_flags = ds->ops->get_phy_flags(ds, dp->index); + + ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); + if (ret == -ENODEV && ds->user_mii_bus) { + /* We could not connect to a designated PHY or SFP, so try to + * use the switch internal MDIO bus instead + */ + ret = dsa_user_phy_connect(user_dev, dp->index, phy_flags); + } + if (ret) { + netdev_err(user_dev, "failed to connect to PHY: %pe\n", + ERR_PTR(ret)); + dsa_port_phylink_destroy(dp); + } + + return ret; +} + +void dsa_user_setup_tagger(struct net_device *user) +{ + struct dsa_port *dp = dsa_user_to_port(user); + struct net_device *conduit = dsa_port_to_conduit(dp); + struct dsa_user_priv *p = netdev_priv(user); + const struct dsa_port *cpu_dp = dp->cpu_dp; + const struct dsa_switch *ds = dp->ds; + + user->needed_headroom = cpu_dp->tag_ops->needed_headroom; + user->needed_tailroom = cpu_dp->tag_ops->needed_tailroom; + /* Try to save one extra realloc later in the TX path (in the conduit) + * by also inheriting the conduit's needed headroom and tailroom. + * The 8021q driver also does this. + */ + user->needed_headroom += conduit->needed_headroom; + user->needed_tailroom += conduit->needed_tailroom; + + p->xmit = cpu_dp->tag_ops->xmit; + + user->features = conduit->vlan_features | NETIF_F_HW_TC; + user->hw_features |= NETIF_F_HW_TC; + user->features |= NETIF_F_LLTX; + if (user->needed_tailroom) + user->features &= ~(NETIF_F_SG | NETIF_F_FRAGLIST); + if (ds->needs_standalone_vlan_filtering) + user->features |= NETIF_F_HW_VLAN_CTAG_FILTER; +} + +int dsa_user_suspend(struct net_device *user_dev) +{ + struct dsa_port *dp = dsa_user_to_port(user_dev); + + if (!netif_running(user_dev)) + return 0; + + netif_device_detach(user_dev); + + rtnl_lock(); + phylink_stop(dp->pl); + rtnl_unlock(); + + return 0; +} + +int dsa_user_resume(struct net_device *user_dev) +{ + struct dsa_port *dp = dsa_user_to_port(user_dev); + + if (!netif_running(user_dev)) + return 0; + + netif_device_attach(user_dev); + + rtnl_lock(); + phylink_start(dp->pl); + rtnl_unlock(); + + return 0; +} + +int dsa_user_create(struct dsa_port *port) +{ + struct net_device *conduit = dsa_port_to_conduit(port); + struct dsa_switch *ds = port->ds; + struct net_device *user_dev; + struct dsa_user_priv *p; + const char *name; + int assign_type; + int ret; + + if (!ds->num_tx_queues) + ds->num_tx_queues = 1; + + if (port->name) { + name = port->name; + assign_type = NET_NAME_PREDICTABLE; + } else { + name = "eth%d"; + assign_type = NET_NAME_ENUM; + } + + user_dev = alloc_netdev_mqs(sizeof(struct dsa_user_priv), name, + assign_type, ether_setup, + ds->num_tx_queues, 1); + if (user_dev == NULL) + return -ENOMEM; + + user_dev->rtnl_link_ops = &dsa_link_ops; + user_dev->ethtool_ops = &dsa_user_ethtool_ops; +#if IS_ENABLED(CONFIG_DCB) + user_dev->dcbnl_ops = &dsa_user_dcbnl_ops; +#endif + if (!is_zero_ether_addr(port->mac)) + eth_hw_addr_set(user_dev, port->mac); + else + eth_hw_addr_inherit(user_dev, conduit); + user_dev->priv_flags |= IFF_NO_QUEUE; + if (dsa_switch_supports_uc_filtering(ds)) + user_dev->priv_flags |= IFF_UNICAST_FLT; + user_dev->netdev_ops = &dsa_user_netdev_ops; + if (ds->ops->port_max_mtu) + user_dev->max_mtu = ds->ops->port_max_mtu(ds, port->index); + SET_NETDEV_DEVTYPE(user_dev, &dsa_type); + + SET_NETDEV_DEV(user_dev, port->ds->dev); + SET_NETDEV_DEVLINK_PORT(user_dev, &port->devlink_port); + user_dev->dev.of_node = port->dn; + user_dev->vlan_features = conduit->vlan_features; + + p = netdev_priv(user_dev); + user_dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!user_dev->tstats) { + free_netdev(user_dev); + return -ENOMEM; + } + + ret = gro_cells_init(&p->gcells, user_dev); + if (ret) + goto out_free; + + p->dp = port; + INIT_LIST_HEAD(&p->mall_tc_list); + port->user = user_dev; + dsa_user_setup_tagger(user_dev); + + netif_carrier_off(user_dev); + + ret = dsa_user_phy_setup(user_dev); + if (ret) { + netdev_err(user_dev, + "error %d setting up PHY for tree %d, switch %d, port %d\n", + ret, ds->dst->index, ds->index, port->index); + goto out_gcells; + } + + rtnl_lock(); + + ret = dsa_user_change_mtu(user_dev, ETH_DATA_LEN); + if (ret && ret != -EOPNOTSUPP) + dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", + ret, ETH_DATA_LEN, port->index); + + ret = register_netdevice(user_dev); + if (ret) { + netdev_err(conduit, "error %d registering interface %s\n", + ret, user_dev->name); + rtnl_unlock(); + goto out_phy; + } + + if (IS_ENABLED(CONFIG_DCB)) { + ret = dsa_user_dcbnl_init(user_dev); + if (ret) { + netdev_err(user_dev, + "failed to initialize DCB: %pe\n", + ERR_PTR(ret)); + rtnl_unlock(); + goto out_unregister; + } + } + + ret = netdev_upper_dev_link(conduit, user_dev, NULL); + + rtnl_unlock(); + + if (ret) + goto out_unregister; + + return 0; + +out_unregister: + unregister_netdev(user_dev); +out_phy: + rtnl_lock(); + phylink_disconnect_phy(p->dp->pl); + rtnl_unlock(); + dsa_port_phylink_destroy(p->dp); +out_gcells: + gro_cells_destroy(&p->gcells); +out_free: + free_percpu(user_dev->tstats); + free_netdev(user_dev); + port->user = NULL; + return ret; +} + +void dsa_user_destroy(struct net_device *user_dev) +{ + struct net_device *conduit = dsa_user_to_conduit(user_dev); + struct dsa_port *dp = dsa_user_to_port(user_dev); + struct dsa_user_priv *p = netdev_priv(user_dev); + + netif_carrier_off(user_dev); + rtnl_lock(); + netdev_upper_dev_unlink(conduit, user_dev); + unregister_netdevice(user_dev); + phylink_disconnect_phy(dp->pl); + rtnl_unlock(); + + dsa_port_phylink_destroy(dp); + gro_cells_destroy(&p->gcells); + free_percpu(user_dev->tstats); + free_netdev(user_dev); +} + +int dsa_user_change_conduit(struct net_device *dev, struct net_device *conduit, + struct netlink_ext_ack *extack) +{ + struct net_device *old_conduit = dsa_user_to_conduit(dev); + struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch *ds = dp->ds; + struct net_device *upper; + struct list_head *iter; + int err; + + if (conduit == old_conduit) + return 0; + + if (!ds->ops->port_change_conduit) { + NL_SET_ERR_MSG_MOD(extack, + "Driver does not support changing DSA conduit"); + return -EOPNOTSUPP; + } + + if (!netdev_uses_dsa(conduit)) { + NL_SET_ERR_MSG_MOD(extack, + "Interface not eligible as DSA conduit"); + return -EOPNOTSUPP; + } + + netdev_for_each_upper_dev_rcu(conduit, upper, iter) { + if (dsa_user_dev_check(upper)) + continue; + if (netif_is_bridge_master(upper)) + continue; + NL_SET_ERR_MSG_MOD(extack, "Cannot join conduit with unknown uppers"); + return -EOPNOTSUPP; + } + + /* Since we allow live-changing the DSA conduit, plus we auto-open the + * DSA conduit when the user port opens => we need to ensure that the + * new DSA conduit is open too. + */ + if (dev->flags & IFF_UP) { + err = dev_open(conduit, extack); + if (err) + return err; + } + + netdev_upper_dev_unlink(old_conduit, dev); + + err = netdev_upper_dev_link(conduit, dev, extack); + if (err) + goto out_revert_old_conduit_unlink; + + err = dsa_port_change_conduit(dp, conduit, extack); + if (err) + goto out_revert_conduit_link; + + /* Update the MTU of the new CPU port through cross-chip notifiers */ + err = dsa_user_change_mtu(dev, dev->mtu); + if (err && err != -EOPNOTSUPP) { + netdev_warn(dev, + "nonfatal error updating MTU with new conduit: %pe\n", + ERR_PTR(err)); + } + + /* If the port doesn't have its own MAC address and relies on the DSA + * conduit's one, inherit it again from the new DSA conduit. + */ + if (is_zero_ether_addr(dp->mac)) + eth_hw_addr_inherit(dev, conduit); + + return 0; + +out_revert_conduit_link: + netdev_upper_dev_unlink(conduit, dev); +out_revert_old_conduit_unlink: + netdev_upper_dev_link(old_conduit, dev, NULL); + return err; +} + +bool dsa_user_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &dsa_user_netdev_ops; +} +EXPORT_SYMBOL_GPL(dsa_user_dev_check); + +static int dsa_user_changeupper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct netlink_ext_ack *extack; + int err = NOTIFY_DONE; + + if (!dsa_user_dev_check(dev)) + return err; + + extack = netdev_notifier_info_to_extack(&info->info); + + if (netif_is_bridge_master(info->upper_dev)) { + if (info->linking) { + err = dsa_port_bridge_join(dp, info->upper_dev, extack); + if (!err) + dsa_bridge_mtu_normalization(dp); + if (err == -EOPNOTSUPP) { + NL_SET_ERR_MSG_WEAK_MOD(extack, + "Offloading not supported"); + err = 0; + } + err = notifier_from_errno(err); + } else { + dsa_port_bridge_leave(dp, info->upper_dev); + err = NOTIFY_OK; + } + } else if (netif_is_lag_master(info->upper_dev)) { + if (info->linking) { + err = dsa_port_lag_join(dp, info->upper_dev, + info->upper_info, extack); + if (err == -EOPNOTSUPP) { + NL_SET_ERR_MSG_WEAK_MOD(extack, + "Offloading not supported"); + err = 0; + } + err = notifier_from_errno(err); + } else { + dsa_port_lag_leave(dp, info->upper_dev); + err = NOTIFY_OK; + } + } else if (is_hsr_master(info->upper_dev)) { + if (info->linking) { + err = dsa_port_hsr_join(dp, info->upper_dev, extack); + if (err == -EOPNOTSUPP) { + NL_SET_ERR_MSG_WEAK_MOD(extack, + "Offloading not supported"); + err = 0; + } + err = notifier_from_errno(err); + } else { + dsa_port_hsr_leave(dp, info->upper_dev); + err = NOTIFY_OK; + } + } + + return err; +} + +static int dsa_user_prechangeupper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + if (!dsa_user_dev_check(dev)) + return NOTIFY_DONE; + + if (netif_is_bridge_master(info->upper_dev) && !info->linking) + dsa_port_pre_bridge_leave(dp, info->upper_dev); + else if (netif_is_lag_master(info->upper_dev) && !info->linking) + dsa_port_pre_lag_leave(dp, info->upper_dev); + /* dsa_port_pre_hsr_leave is not yet necessary since hsr devices cannot + * meaningfully placed under a bridge yet + */ + + return NOTIFY_DONE; +} + +static int +dsa_user_lag_changeupper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct net_device *lower; + struct list_head *iter; + int err = NOTIFY_DONE; + struct dsa_port *dp; + + if (!netif_is_lag_master(dev)) + return err; + + netdev_for_each_lower_dev(dev, lower, iter) { + if (!dsa_user_dev_check(lower)) + continue; + + dp = dsa_user_to_port(lower); + if (!dp->lag) + /* Software LAG */ + continue; + + err = dsa_user_changeupper(lower, info); + if (notifier_to_errno(err)) + break; + } + + return err; +} + +/* Same as dsa_user_lag_changeupper() except that it calls + * dsa_user_prechangeupper() + */ +static int +dsa_user_lag_prechangeupper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct net_device *lower; + struct list_head *iter; + int err = NOTIFY_DONE; + struct dsa_port *dp; + + if (!netif_is_lag_master(dev)) + return err; + + netdev_for_each_lower_dev(dev, lower, iter) { + if (!dsa_user_dev_check(lower)) + continue; + + dp = dsa_user_to_port(lower); + if (!dp->lag) + /* Software LAG */ + continue; + + err = dsa_user_prechangeupper(lower, info); + if (notifier_to_errno(err)) + break; + } + + return err; +} + +static int +dsa_prevent_bridging_8021q_upper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct netlink_ext_ack *ext_ack; + struct net_device *user, *br; + struct dsa_port *dp; + + ext_ack = netdev_notifier_info_to_extack(&info->info); + + if (!is_vlan_dev(dev)) + return NOTIFY_DONE; + + user = vlan_dev_real_dev(dev); + if (!dsa_user_dev_check(user)) + return NOTIFY_DONE; + + dp = dsa_user_to_port(user); + br = dsa_port_bridge_dev_get(dp); + if (!br) + return NOTIFY_DONE; + + /* Deny enslaving a VLAN device into a VLAN-aware bridge */ + if (br_vlan_enabled(br) && + netif_is_bridge_master(info->upper_dev) && info->linking) { + NL_SET_ERR_MSG_MOD(ext_ack, + "Cannot make VLAN device join VLAN-aware bridge"); + return notifier_from_errno(-EINVAL); + } + + return NOTIFY_DONE; +} + +static int +dsa_user_check_8021q_upper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + struct net_device *br = dsa_port_bridge_dev_get(dp); + struct bridge_vlan_info br_info; + struct netlink_ext_ack *extack; + int err = NOTIFY_DONE; + u16 vid; + + if (!br || !br_vlan_enabled(br)) + return NOTIFY_DONE; + + extack = netdev_notifier_info_to_extack(&info->info); + vid = vlan_dev_vlan_id(info->upper_dev); + + /* br_vlan_get_info() returns -EINVAL or -ENOENT if the + * device, respectively the VID is not found, returning + * 0 means success, which is a failure for us here. + */ + err = br_vlan_get_info(br, vid, &br_info); + if (err == 0) { + NL_SET_ERR_MSG_MOD(extack, + "This VLAN is already configured by the bridge"); + return notifier_from_errno(-EBUSY); + } + + return NOTIFY_DONE; +} + +static int +dsa_user_prechangeupper_sanity_check(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct dsa_switch *ds; + struct dsa_port *dp; + int err; + + if (!dsa_user_dev_check(dev)) + return dsa_prevent_bridging_8021q_upper(dev, info); + + dp = dsa_user_to_port(dev); + ds = dp->ds; + + if (ds->ops->port_prechangeupper) { + err = ds->ops->port_prechangeupper(ds, dp->index, info); + if (err) + return notifier_from_errno(err); + } + + if (is_vlan_dev(info->upper_dev)) + return dsa_user_check_8021q_upper(dev, info); + + return NOTIFY_DONE; +} + +/* To be eligible as a DSA conduit, a LAG must have all lower interfaces be + * eligible DSA conduits. Additionally, all LAG slaves must be DSA conduits of + * switches in the same switch tree. + */ +static int dsa_lag_conduit_validate(struct net_device *lag_dev, + struct netlink_ext_ack *extack) +{ + struct net_device *lower1, *lower2; + struct list_head *iter1, *iter2; + + netdev_for_each_lower_dev(lag_dev, lower1, iter1) { + netdev_for_each_lower_dev(lag_dev, lower2, iter2) { + if (!netdev_uses_dsa(lower1) || + !netdev_uses_dsa(lower2)) { + NL_SET_ERR_MSG_MOD(extack, + "All LAG ports must be eligible as DSA conduits"); + return notifier_from_errno(-EINVAL); + } + + if (lower1 == lower2) + continue; + + if (!dsa_port_tree_same(lower1->dsa_ptr, + lower2->dsa_ptr)) { + NL_SET_ERR_MSG_MOD(extack, + "LAG contains DSA conduits of disjoint switch trees"); + return notifier_from_errno(-EINVAL); + } + } + } + + return NOTIFY_DONE; +} + +static int +dsa_conduit_prechangeupper_sanity_check(struct net_device *conduit, + struct netdev_notifier_changeupper_info *info) +{ + struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); + + if (!netdev_uses_dsa(conduit)) + return NOTIFY_DONE; + + if (!info->linking) + return NOTIFY_DONE; + + /* Allow DSA switch uppers */ + if (dsa_user_dev_check(info->upper_dev)) + return NOTIFY_DONE; + + /* Allow bridge uppers of DSA conduits, subject to further + * restrictions in dsa_bridge_prechangelower_sanity_check() + */ + if (netif_is_bridge_master(info->upper_dev)) + return NOTIFY_DONE; + + /* Allow LAG uppers, subject to further restrictions in + * dsa_lag_conduit_prechangelower_sanity_check() + */ + if (netif_is_lag_master(info->upper_dev)) + return dsa_lag_conduit_validate(info->upper_dev, extack); + + NL_SET_ERR_MSG_MOD(extack, + "DSA conduit cannot join unknown upper interfaces"); + return notifier_from_errno(-EBUSY); +} + +static int +dsa_lag_conduit_prechangelower_sanity_check(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(&info->info); + struct net_device *lag_dev = info->upper_dev; + struct net_device *lower; + struct list_head *iter; + + if (!netdev_uses_dsa(lag_dev) || !netif_is_lag_master(lag_dev)) + return NOTIFY_DONE; + + if (!info->linking) + return NOTIFY_DONE; + + if (!netdev_uses_dsa(dev)) { + NL_SET_ERR_MSG(extack, + "Only DSA conduits can join a LAG DSA conduit"); + return notifier_from_errno(-EINVAL); + } + + netdev_for_each_lower_dev(lag_dev, lower, iter) { + if (!dsa_port_tree_same(dev->dsa_ptr, lower->dsa_ptr)) { + NL_SET_ERR_MSG(extack, + "Interface is DSA conduit for a different switch tree than this LAG"); + return notifier_from_errno(-EINVAL); + } + + break; + } + + return NOTIFY_DONE; +} + +/* Don't allow bridging of DSA conduits, since the bridge layer rx_handler + * prevents the DSA fake ethertype handler to be invoked, so we don't get the + * chance to strip off and parse the DSA switch tag protocol header (the bridge + * layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these + * frames). + * The only case where that would not be an issue is when bridging can already + * be offloaded, such as when the DSA conduit is itself a DSA or plain switchdev + * port, and is bridged only with other ports from the same hardware device. + */ +static int +dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower, + struct netdev_notifier_changeupper_info *info) +{ + struct net_device *br = info->upper_dev; + struct netlink_ext_ack *extack; + struct net_device *lower; + struct list_head *iter; + + if (!netif_is_bridge_master(br)) + return NOTIFY_DONE; + + if (!info->linking) + return NOTIFY_DONE; + + extack = netdev_notifier_info_to_extack(&info->info); + + netdev_for_each_lower_dev(br, lower, iter) { + if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower)) + continue; + + if (!netdev_port_same_parent_id(lower, new_lower)) { + NL_SET_ERR_MSG(extack, + "Cannot do software bridging with a DSA conduit"); + return notifier_from_errno(-EINVAL); + } + } + + return NOTIFY_DONE; +} + +static void dsa_tree_migrate_ports_from_lag_conduit(struct dsa_switch_tree *dst, + struct net_device *lag_dev) +{ + struct net_device *new_conduit = dsa_tree_find_first_conduit(dst); + struct dsa_port *dp; + int err; + + dsa_tree_for_each_user_port(dp, dst) { + if (dsa_port_to_conduit(dp) != lag_dev) + continue; + + err = dsa_user_change_conduit(dp->user, new_conduit, NULL); + if (err) { + netdev_err(dp->user, + "failed to restore conduit to %s: %pe\n", + new_conduit->name, ERR_PTR(err)); + } + } +} + +static int dsa_conduit_lag_join(struct net_device *conduit, + struct net_device *lag_dev, + struct netdev_lag_upper_info *uinfo, + struct netlink_ext_ack *extack) +{ + struct dsa_port *cpu_dp = conduit->dsa_ptr; + struct dsa_switch_tree *dst = cpu_dp->dst; + struct dsa_port *dp; + int err; + + err = dsa_conduit_lag_setup(lag_dev, cpu_dp, uinfo, extack); + if (err) + return err; + + dsa_tree_for_each_user_port(dp, dst) { + if (dsa_port_to_conduit(dp) != conduit) + continue; + + err = dsa_user_change_conduit(dp->user, lag_dev, extack); + if (err) + goto restore; + } + + return 0; + +restore: + dsa_tree_for_each_user_port_continue_reverse(dp, dst) { + if (dsa_port_to_conduit(dp) != lag_dev) + continue; + + err = dsa_user_change_conduit(dp->user, conduit, NULL); + if (err) { + netdev_err(dp->user, + "failed to restore conduit to %s: %pe\n", + conduit->name, ERR_PTR(err)); + } + } + + dsa_conduit_lag_teardown(lag_dev, conduit->dsa_ptr); + + return err; +} + +static void dsa_conduit_lag_leave(struct net_device *conduit, + struct net_device *lag_dev) +{ + struct dsa_port *dp, *cpu_dp = lag_dev->dsa_ptr; + struct dsa_switch_tree *dst = cpu_dp->dst; + struct dsa_port *new_cpu_dp = NULL; + struct net_device *lower; + struct list_head *iter; + + netdev_for_each_lower_dev(lag_dev, lower, iter) { + if (netdev_uses_dsa(lower)) { + new_cpu_dp = lower->dsa_ptr; + break; + } + } + + if (new_cpu_dp) { + /* Update the CPU port of the user ports still under the LAG + * so that dsa_port_to_conduit() continues to work properly + */ + dsa_tree_for_each_user_port(dp, dst) + if (dsa_port_to_conduit(dp) == lag_dev) + dp->cpu_dp = new_cpu_dp; + + /* Update the index of the virtual CPU port to match the lowest + * physical CPU port + */ + lag_dev->dsa_ptr = new_cpu_dp; + wmb(); + } else { + /* If the LAG DSA conduit has no ports left, migrate back all + * user ports to the first physical CPU port + */ + dsa_tree_migrate_ports_from_lag_conduit(dst, lag_dev); + } + + /* This DSA conduit has left its LAG in any case, so let + * the CPU port leave the hardware LAG as well + */ + dsa_conduit_lag_teardown(lag_dev, conduit->dsa_ptr); +} + +static int dsa_conduit_changeupper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct netlink_ext_ack *extack; + int err = NOTIFY_DONE; + + if (!netdev_uses_dsa(dev)) + return err; + + extack = netdev_notifier_info_to_extack(&info->info); + + if (netif_is_lag_master(info->upper_dev)) { + if (info->linking) { + err = dsa_conduit_lag_join(dev, info->upper_dev, + info->upper_info, extack); + err = notifier_from_errno(err); + } else { + dsa_conduit_lag_leave(dev, info->upper_dev); + err = NOTIFY_OK; + } + } + + return err; +} + +static int dsa_user_netdevice_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + + switch (event) { + case NETDEV_PRECHANGEUPPER: { + struct netdev_notifier_changeupper_info *info = ptr; + int err; + + err = dsa_user_prechangeupper_sanity_check(dev, info); + if (notifier_to_errno(err)) + return err; + + err = dsa_conduit_prechangeupper_sanity_check(dev, info); + if (notifier_to_errno(err)) + return err; + + err = dsa_lag_conduit_prechangelower_sanity_check(dev, info); + if (notifier_to_errno(err)) + return err; + + err = dsa_bridge_prechangelower_sanity_check(dev, info); + if (notifier_to_errno(err)) + return err; + + err = dsa_user_prechangeupper(dev, ptr); + if (notifier_to_errno(err)) + return err; + + err = dsa_user_lag_prechangeupper(dev, ptr); + if (notifier_to_errno(err)) + return err; + + break; + } + case NETDEV_CHANGEUPPER: { + int err; + + err = dsa_user_changeupper(dev, ptr); + if (notifier_to_errno(err)) + return err; + + err = dsa_user_lag_changeupper(dev, ptr); + if (notifier_to_errno(err)) + return err; + + err = dsa_conduit_changeupper(dev, ptr); + if (notifier_to_errno(err)) + return err; + + break; + } + case NETDEV_CHANGELOWERSTATE: { + struct netdev_notifier_changelowerstate_info *info = ptr; + struct dsa_port *dp; + int err = 0; + + if (dsa_user_dev_check(dev)) { + dp = dsa_user_to_port(dev); + + err = dsa_port_lag_change(dp, info->lower_state_info); + } + + /* Mirror LAG port events on DSA conduits that are in + * a LAG towards their respective switch CPU ports + */ + if (netdev_uses_dsa(dev)) { + dp = dev->dsa_ptr; + + err = dsa_port_lag_change(dp, info->lower_state_info); + } + + return notifier_from_errno(err); + } + case NETDEV_CHANGE: + case NETDEV_UP: { + /* Track state of conduit port. + * DSA driver may require the conduit port (and indirectly + * the tagger) to be available for some special operation. + */ + if (netdev_uses_dsa(dev)) { + struct dsa_port *cpu_dp = dev->dsa_ptr; + struct dsa_switch_tree *dst = cpu_dp->ds->dst; + + /* Track when the conduit port is UP */ + dsa_tree_conduit_oper_state_change(dst, dev, + netif_oper_up(dev)); + + /* Track when the conduit port is ready and can accept + * packet. + * NETDEV_UP event is not enough to flag a port as ready. + * We also have to wait for linkwatch_do_dev to dev_activate + * and emit a NETDEV_CHANGE event. + * We check if a conduit port is ready by checking if the dev + * have a qdisc assigned and is not noop. + */ + dsa_tree_conduit_admin_state_change(dst, dev, + !qdisc_tx_is_noop(dev)); + + return NOTIFY_OK; + } + + return NOTIFY_DONE; + } + case NETDEV_GOING_DOWN: { + struct dsa_port *dp, *cpu_dp; + struct dsa_switch_tree *dst; + LIST_HEAD(close_list); + + if (!netdev_uses_dsa(dev)) + return NOTIFY_DONE; + + cpu_dp = dev->dsa_ptr; + dst = cpu_dp->ds->dst; + + dsa_tree_conduit_admin_state_change(dst, dev, false); + + list_for_each_entry(dp, &dst->ports, list) { + if (!dsa_port_is_user(dp)) + continue; + + if (dp->cpu_dp != cpu_dp) + continue; + + list_add(&dp->user->close_list, &close_list); + } + + dev_close_many(&close_list, true); + + return NOTIFY_OK; + } + default: + break; + } + + return NOTIFY_DONE; +} + +static void +dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) +{ + struct switchdev_notifier_fdb_info info = {}; + + info.addr = switchdev_work->addr; + info.vid = switchdev_work->vid; + info.offloaded = true; + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + switchdev_work->orig_dev, &info.info, NULL); +} + +static void dsa_user_switchdev_event_work(struct work_struct *work) +{ + struct dsa_switchdev_event_work *switchdev_work = + container_of(work, struct dsa_switchdev_event_work, work); + const unsigned char *addr = switchdev_work->addr; + struct net_device *dev = switchdev_work->dev; + u16 vid = switchdev_work->vid; + struct dsa_switch *ds; + struct dsa_port *dp; + int err; + + dp = dsa_user_to_port(dev); + ds = dp->ds; + + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + if (switchdev_work->host_addr) + err = dsa_port_bridge_host_fdb_add(dp, addr, vid); + else if (dp->lag) + err = dsa_port_lag_fdb_add(dp, addr, vid); + else + err = dsa_port_fdb_add(dp, addr, vid); + if (err) { + dev_err(ds->dev, + "port %d failed to add %pM vid %d to fdb: %d\n", + dp->index, addr, vid, err); + break; + } + dsa_fdb_offload_notify(switchdev_work); + break; + + case SWITCHDEV_FDB_DEL_TO_DEVICE: + if (switchdev_work->host_addr) + err = dsa_port_bridge_host_fdb_del(dp, addr, vid); + else if (dp->lag) + err = dsa_port_lag_fdb_del(dp, addr, vid); + else + err = dsa_port_fdb_del(dp, addr, vid); + if (err) { + dev_err(ds->dev, + "port %d failed to delete %pM vid %d from fdb: %d\n", + dp->index, addr, vid, err); + } + + break; + } + + kfree(switchdev_work); +} + +static bool dsa_foreign_dev_check(const struct net_device *dev, + const struct net_device *foreign_dev) +{ + const struct dsa_port *dp = dsa_user_to_port(dev); + struct dsa_switch_tree *dst = dp->ds->dst; + + if (netif_is_bridge_master(foreign_dev)) + return !dsa_tree_offloads_bridge_dev(dst, foreign_dev); + + if (netif_is_bridge_port(foreign_dev)) + return !dsa_tree_offloads_bridge_port(dst, foreign_dev); + + /* Everything else is foreign */ + return true; +} + +static int dsa_user_fdb_event(struct net_device *dev, + struct net_device *orig_dev, + unsigned long event, const void *ctx, + const struct switchdev_notifier_fdb_info *fdb_info) +{ + struct dsa_switchdev_event_work *switchdev_work; + struct dsa_port *dp = dsa_user_to_port(dev); + bool host_addr = fdb_info->is_local; + struct dsa_switch *ds = dp->ds; + + if (ctx && ctx != dp) + return 0; + + if (!dp->bridge) + return 0; + + if (switchdev_fdb_is_dynamically_learned(fdb_info)) { + if (dsa_port_offloads_bridge_port(dp, orig_dev)) + return 0; + + /* FDB entries learned by the software bridge or by foreign + * bridge ports should be installed as host addresses only if + * the driver requests assisted learning. + */ + if (!ds->assisted_learning_on_cpu_port) + return 0; + } + + /* Also treat FDB entries on foreign interfaces bridged with us as host + * addresses. + */ + if (dsa_foreign_dev_check(dev, orig_dev)) + host_addr = true; + + /* Check early that we're not doing work in vain. + * Host addresses on LAG ports still require regular FDB ops, + * since the CPU port isn't in a LAG. + */ + if (dp->lag && !host_addr) { + if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del) + return -EOPNOTSUPP; + } else { + if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del) + return -EOPNOTSUPP; + } + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return -ENOMEM; + + netdev_dbg(dev, "%s FDB entry towards %s, addr %pM vid %d%s\n", + event == SWITCHDEV_FDB_ADD_TO_DEVICE ? "Adding" : "Deleting", + orig_dev->name, fdb_info->addr, fdb_info->vid, + host_addr ? " as host address" : ""); + + INIT_WORK(&switchdev_work->work, dsa_user_switchdev_event_work); + switchdev_work->event = event; + switchdev_work->dev = dev; + switchdev_work->orig_dev = orig_dev; + + ether_addr_copy(switchdev_work->addr, fdb_info->addr); + switchdev_work->vid = fdb_info->vid; + switchdev_work->host_addr = host_addr; + + dsa_schedule_work(&switchdev_work->work); + + return 0; +} + +/* Called under rcu_read_lock() */ +static int dsa_user_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + int err; + + switch (event) { + case SWITCHDEV_PORT_ATTR_SET: + err = switchdev_handle_port_attr_set(dev, ptr, + dsa_user_dev_check, + dsa_user_port_attr_set); + return notifier_from_errno(err); + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: + err = switchdev_handle_fdb_event_to_device(dev, event, ptr, + dsa_user_dev_check, + dsa_foreign_dev_check, + dsa_user_fdb_event); + return notifier_from_errno(err); + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static int dsa_user_switchdev_blocking_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + int err; + + switch (event) { + case SWITCHDEV_PORT_OBJ_ADD: + err = switchdev_handle_port_obj_add_foreign(dev, ptr, + dsa_user_dev_check, + dsa_foreign_dev_check, + dsa_user_port_obj_add); + return notifier_from_errno(err); + case SWITCHDEV_PORT_OBJ_DEL: + err = switchdev_handle_port_obj_del_foreign(dev, ptr, + dsa_user_dev_check, + dsa_foreign_dev_check, + dsa_user_port_obj_del); + return notifier_from_errno(err); + case SWITCHDEV_PORT_ATTR_SET: + err = switchdev_handle_port_attr_set(dev, ptr, + dsa_user_dev_check, + dsa_user_port_attr_set); + return notifier_from_errno(err); + } + + return NOTIFY_DONE; +} + +static struct notifier_block dsa_user_nb __read_mostly = { + .notifier_call = dsa_user_netdevice_event, +}; + +struct notifier_block dsa_user_switchdev_notifier = { + .notifier_call = dsa_user_switchdev_event, +}; + +struct notifier_block dsa_user_switchdev_blocking_notifier = { + .notifier_call = dsa_user_switchdev_blocking_event, +}; + +int dsa_user_register_notifier(void) +{ + struct notifier_block *nb; + int err; + + err = register_netdevice_notifier(&dsa_user_nb); + if (err) + return err; + + err = register_switchdev_notifier(&dsa_user_switchdev_notifier); + if (err) + goto err_switchdev_nb; + + nb = &dsa_user_switchdev_blocking_notifier; + err = register_switchdev_blocking_notifier(nb); + if (err) + goto err_switchdev_blocking_nb; + + return 0; + +err_switchdev_blocking_nb: + unregister_switchdev_notifier(&dsa_user_switchdev_notifier); +err_switchdev_nb: + unregister_netdevice_notifier(&dsa_user_nb); + return err; +} + +void dsa_user_unregister_notifier(void) +{ + struct notifier_block *nb; + int err; + + nb = &dsa_user_switchdev_blocking_notifier; + err = unregister_switchdev_blocking_notifier(nb); + if (err) + pr_err("DSA: failed to unregister switchdev blocking notifier (%d)\n", err); + + err = unregister_switchdev_notifier(&dsa_user_switchdev_notifier); + if (err) + pr_err("DSA: failed to unregister switchdev notifier (%d)\n", err); + + err = unregister_netdevice_notifier(&dsa_user_nb); + if (err) + pr_err("DSA: failed to unregister user notifier (%d)\n", err); +} diff --git a/net/dsa/user.h b/net/dsa/user.h new file mode 100644 index 000000000000..996069130bea --- /dev/null +++ b/net/dsa/user.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __DSA_USER_H +#define __DSA_USER_H + +#include +#include +#include +#include +#include +#include +#include + +struct net_device; +struct netlink_ext_ack; + +extern struct notifier_block dsa_user_switchdev_notifier; +extern struct notifier_block dsa_user_switchdev_blocking_notifier; + +struct dsa_user_priv { + /* Copy of CPU port xmit for faster access in user transmit hot path */ + struct sk_buff * (*xmit)(struct sk_buff *skb, + struct net_device *dev); + + struct gro_cells gcells; + + /* DSA port data, such as switch, port index, etc. */ + struct dsa_port *dp; + +#ifdef CONFIG_NET_POLL_CONTROLLER + struct netpoll *netpoll; +#endif + + /* TC context */ + struct list_head mall_tc_list; +}; + +void dsa_user_mii_bus_init(struct dsa_switch *ds); +int dsa_user_create(struct dsa_port *dp); +void dsa_user_destroy(struct net_device *user_dev); +int dsa_user_suspend(struct net_device *user_dev); +int dsa_user_resume(struct net_device *user_dev); +int dsa_user_register_notifier(void); +void dsa_user_unregister_notifier(void); +void dsa_user_sync_ha(struct net_device *dev); +void dsa_user_unsync_ha(struct net_device *dev); +void dsa_user_setup_tagger(struct net_device *user); +int dsa_user_change_mtu(struct net_device *dev, int new_mtu); +int dsa_user_change_conduit(struct net_device *dev, struct net_device *conduit, + struct netlink_ext_ack *extack); +int dsa_user_manage_vlan_filtering(struct net_device *dev, + bool vlan_filtering); + +static inline struct dsa_port *dsa_user_to_port(const struct net_device *dev) +{ + struct dsa_user_priv *p = netdev_priv(dev); + + return p->dp; +} + +static inline struct net_device * +dsa_user_to_conduit(const struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + + return dsa_port_to_conduit(dp); +} + +#endif -- cgit v1.2.3 From 87cd83714f30ef2f19f0390e98beb8d78e173f0f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 23 Oct 2023 11:17:29 -0700 Subject: net: dsa: Rename IFLA_DSA_MASTER to IFLA_DSA_CONDUIT This preserves the existing IFLA_DSA_MASTER which is part of the uAPI and creates an alias named IFLA_DSA_CONDUIT. Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Signed-off-by: Florian Fainelli Link: https://lore.kernel.org/r/20231023181729.1191071-3-florian.fainelli@broadcom.com Signed-off-by: Jakub Kicinski --- Documentation/networking/dsa/configuration.rst | 4 ++-- include/uapi/linux/if_link.h | 4 +++- net/dsa/netlink.c | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/dsa/configuration.rst b/Documentation/networking/dsa/configuration.rst index e6c9719874b0..6cc4ded3cc23 100644 --- a/Documentation/networking/dsa/configuration.rst +++ b/Documentation/networking/dsa/configuration.rst @@ -393,7 +393,7 @@ description which has an ``ethernet`` property. It is up to the user to configure the system for the switch to use other conduits. DSA uses the ``rtnl_link_ops`` mechanism (with a "dsa" ``kind``) to allow -changing the DSA conduit of a user port. The ``IFLA_DSA_MASTER`` u32 netlink +changing the DSA conduit of a user port. The ``IFLA_DSA_CONDUIT`` u32 netlink attribute contains the ifindex of the conduit device that handles each user device. The DSA conduit must be a valid candidate based on firmware node information, or a LAG interface which contains only slaves which are valid @@ -435,7 +435,7 @@ Using iproute2, the following manipulations are possible: dsa master bond0 Notice that in the case of CPU ports under a LAG, the use of the -``IFLA_DSA_MASTER`` netlink attribute is not strictly needed, but rather, DSA +``IFLA_DSA_CONDUIT`` netlink attribute is not strictly needed, but rather, DSA reacts to the ``IFLA_MASTER`` attribute change of its present conduit (``eth0``) and migrates all user ports to the new upper of ``eth0``, ``bond0``. Similarly, when ``bond0`` is destroyed using ``RTM_DELLINK``, DSA migrates the user ports diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 9f8a3da0f14f..f4191be137a4 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1394,7 +1394,9 @@ enum { enum { IFLA_DSA_UNSPEC, - IFLA_DSA_MASTER, + IFLA_DSA_CONDUIT, + /* Deprecated, use IFLA_DSA_CONDUIT instead */ + IFLA_DSA_MASTER = IFLA_DSA_CONDUIT, __IFLA_DSA_MAX, }; diff --git a/net/dsa/netlink.c b/net/dsa/netlink.c index f56f90a25b99..1332e56349e5 100644 --- a/net/dsa/netlink.c +++ b/net/dsa/netlink.c @@ -8,7 +8,7 @@ #include "user.h" static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = { - [IFLA_DSA_MASTER] = { .type = NLA_U32 }, + [IFLA_DSA_CONDUIT] = { .type = NLA_U32 }, }; static int dsa_changelink(struct net_device *dev, struct nlattr *tb[], @@ -20,8 +20,8 @@ static int dsa_changelink(struct net_device *dev, struct nlattr *tb[], if (!data) return 0; - if (data[IFLA_DSA_MASTER]) { - u32 ifindex = nla_get_u32(data[IFLA_DSA_MASTER]); + if (data[IFLA_DSA_CONDUIT]) { + u32 ifindex = nla_get_u32(data[IFLA_DSA_CONDUIT]); struct net_device *conduit; conduit = __dev_get_by_index(dev_net(dev), ifindex); @@ -38,7 +38,7 @@ static int dsa_changelink(struct net_device *dev, struct nlattr *tb[], static size_t dsa_get_size(const struct net_device *dev) { - return nla_total_size(sizeof(u32)) + /* IFLA_DSA_MASTER */ + return nla_total_size(sizeof(u32)) + /* IFLA_DSA_CONDUIT */ 0; } @@ -46,7 +46,7 @@ static int dsa_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct net_device *conduit = dsa_user_to_conduit(dev); - if (nla_put_u32(skb, IFLA_DSA_MASTER, conduit->ifindex)) + if (nla_put_u32(skb, IFLA_DSA_CONDUIT, conduit->ifindex)) return -EMSGSIZE; return 0; -- cgit v1.2.3 From 4e1799ae84fc9e1af5c965ee4f20c5b0f7a8d566 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 23 Oct 2023 11:33:36 +0200 Subject: dt-bindings: net: dsa: microchip: add wakeup-source property Add wakeup-source property to enable Wake on Lan functionality in the switch. Since PME wake pin is not always attached to the SoC, use wakeup-source instead of wakeup-gpios Signed-off-by: Oleksij Rempel Acked-by: Conor Dooley Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml index 41014f5c01c4..b3029c64d0d5 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml @@ -38,6 +38,8 @@ properties: Should be a gpio specifier for a reset line. maxItems: 1 + wakeup-source: true + microchip,synclko-125: $ref: /schemas/types.yaml#/definitions/flag description: -- cgit v1.2.3 From b5ef61718ad7c003687c759095fc4ae1419bf602 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Oct 2023 15:20:27 +0200 Subject: dt-bindings: net: dsa: Require ports or ethernet-ports Bindings using dsa.yaml#/$defs/ethernet-ports specify that a DSA switch node need to have a ports or ethernet-ports subnode, and that is actually required, so add requirements using oneOf. Suggested-by: Rob Herring Signed-off-by: Linus Walleij Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/dsa/dsa.yaml | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.yaml b/Documentation/devicetree/bindings/net/dsa/dsa.yaml index 6107189d276a..2abd036578d1 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.yaml +++ b/Documentation/devicetree/bindings/net/dsa/dsa.yaml @@ -46,4 +46,10 @@ $defs: $ref: dsa-port.yaml# unevaluatedProperties: false +oneOf: + - required: + - ports + - required: + - ethernet-ports + ... -- cgit v1.2.3 From ddae07ce9bb35a939318dfb22fa799f7cd6893ae Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Oct 2023 15:20:28 +0200 Subject: dt-bindings: net: mvusb: Fix up DSA example When adding a proper schema for the Marvell mx88e6xxx switch, the scripts start complaining about this embedded example: dtschema/dtc warnings/errors: net/marvell,mvusb.example.dtb: switch@0: ports: '#address-cells' is a required property from schema $id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# net/marvell,mvusb.example.dtb: switch@0: ports: '#size-cells' is a required property from schema $id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# Fix this up by extending the example with those properties in the ports node. While we are at it, rename "ports" to "ethernet-ports" and rename "switch" to "ethernet-switch" as this is recommended practice. Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Reviewed-by: Rob Herring Signed-off-by: Linus Walleij Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/marvell,mvusb.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml index 3a3325168048..ab838c1ffeed 100644 --- a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml +++ b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml @@ -50,11 +50,14 @@ examples: #address-cells = <1>; #size-cells = <0>; - switch@0 { + ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0x0>; - ports { + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + /* Port definitions */ }; -- cgit v1.2.3 From 0f35369b4efe30c2a7307d2a492e991032cfcfee Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Oct 2023 15:20:32 +0200 Subject: dt-bindings: marvell: Rewrite MV88E6xxx in schema This is an attempt to rewrite the Marvell MV88E6xxx switch bindings in YAML schema. The current text binding says: WARNING: This binding is currently unstable. Do not program it into a FLASH never to be changed again. Once this binding is stable, this warning will be removed. Well that never happened before we switched to YAML markup, we can't have it like this, what about fixing the mess? Reviewed-by: Andrew Lunn Reviewed-by: Rob Herring Signed-off-by: Linus Walleij Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../bindings/net/dsa/marvell,mv88e6xxx.yaml | 330 +++++++++++++++++++++ .../devicetree/bindings/net/dsa/marvell.txt | 109 ------- MAINTAINERS | 2 +- 3 files changed, 331 insertions(+), 110 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml delete mode 100644 Documentation/devicetree/bindings/net/dsa/marvell.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml new file mode 100644 index 000000000000..34d8561a2187 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml @@ -0,0 +1,330 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MV88E6xxx DSA switch family + +maintainers: + - Andrew Lunn + +description: + The Marvell MV88E6xxx switch series has been produced and sold + by Marvell since at least 2008. The switch has a few compatibles which + just indicate the base address of the switch, then operating systems + can investigate switch ID registers to find out which actual version + of the switch it is dealing with. + +properties: + compatible: + enum: + - marvell,mv88e6085 + - marvell,mv88e6190 + - marvell,mv88e6250 + description: | + marvell,mv88e6085: This switch uses base address 0x10. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6085" should be + specified. This includes the following list of MV88Exxxx switches: + 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, 6171, 6172, 6175, 6176, + 6185, 6240, 6320, 6321, 6341, 6350, 6351, 6352 + marvell,mv88e6190: This switch uses base address 0x00. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6190" should be + specified. This includes the following list of MV88Exxxx switches: + 6190, 6190X, 6191, 6290, 6361, 6390, 6390X + marvell,mv88e6250: This switch uses base address 0x08 or 0x18. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6250" should be + specified. This includes the following list of MV88Exxxx switches: + 6220, 6250 + + reg: + maxItems: 1 + + eeprom-length: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Set to the length of an EEPROM connected to the switch. Must be + set if the switch can not detect the presence and/or size of a connected + EEPROM, otherwise optional. + + reset-gpios: + description: + GPIO to be used to reset the whole device + maxItems: 1 + + interrupts: + description: The switch provides an external interrupt line, but it is + not always used by target systems. + maxItems: 1 + + interrupt-controller: + description: The switch has an internal interrupt controller used by + the different sub-blocks. + + '#interrupt-cells': + description: The internal interrupt controller only supports triggering + on active high level interrupts so the second cell must alway be set to + IRQ_TYPE_LEVEL_HIGH. + const: 2 + + mdio: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + description: Marvell MV88E6xxx switches have an varying combination of + internal and external MDIO buses, in some cases a combined bus that + can be used both internally and externally. This node is for the + primary bus, used internally and sometimes also externally. + + mdio-external: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + description: Marvell MV88E6xxx switches that have a separate external + MDIO bus use this port to access external components on the MDIO bus. + + properties: + compatible: + const: marvell,mv88e6xxx-mdio-external + + required: + - compatible + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + sw_phy0: ethernet-phy@0 { + reg = <0x0>; + }; + + sw_phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + sw_phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + sw_phy3: ethernet-phy@3 { + reg = <0x3>; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan4"; + phy-handle = <&sw_phy0>; + phy-mode = "internal"; + }; + + ethernet-port@1 { + reg = <1>; + label = "lan3"; + phy-handle = <&sw_phy1>; + phy-mode = "internal"; + }; + + ethernet-port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&sw_phy2>; + phy-mode = "internal"; + }; + + ethernet-port@3 { + reg = <3>; + label = "lan1"; + phy-handle = <&sw_phy3>; + phy-mode = "internal"; + }; + + ethernet-port@5 { + reg = <5>; + ethernet = <&fec>; + phy-mode = "rgmii-id"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + }; + - | + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@0 { + compatible = "marvell,mv88e6190"; + #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&switch_interrupt_pins>; + pinctrl-names = "default"; + reg = <0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch0phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + switch0phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + switch0phy3: ethernet-phy@3 { + reg = <0x3>; + }; + + switch0phy4: ethernet-phy@4 { + reg = <0x4>; + }; + + switch0phy5: ethernet-phy@5 { + reg = <0x5>; + }; + + switch0phy6: ethernet-phy@6 { + reg = <0x6>; + }; + + switch0phy7: ethernet-phy@7 { + reg = <0x7>; + }; + + switch0phy8: ethernet-phy@8 { + reg = <0x8>; + }; + }; + + mdio-external { + compatible = "marvell,mv88e6xxx-mdio-external"; + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@b { + reg = <0xb>; + compatible = "ethernet-phy-ieee802.3-c45"; + }; + + phy2: ethernet-phy@c { + reg = <0xc>; + compatible = "ethernet-phy-ieee802.3-c45"; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + ethernet = <ð0>; + phy-mode = "rgmii"; + reg = <0>; + + fixed-link { + full-duplex; + pause; + speed = <1000>; + }; + }; + + ethernet-port@1 { + label = "lan1"; + phy-handle = <&switch0phy1>; + reg = <1>; + }; + + ethernet-port@2 { + label = "lan2"; + phy-handle = <&switch0phy2>; + reg = <2>; + }; + + ethernet-port@3 { + label = "lan3"; + phy-handle = <&switch0phy3>; + reg = <3>; + }; + + ethernet-port@4 { + label = "lan4"; + phy-handle = <&switch0phy4>; + reg = <4>; + }; + + ethernet-port@5 { + label = "lan5"; + phy-handle = <&switch0phy5>; + reg = <5>; + }; + + ethernet-port@6 { + label = "lan6"; + phy-handle = <&switch0phy6>; + reg = <6>; + }; + + ethernet-port@7 { + label = "lan7"; + phy-handle = <&switch0phy7>; + reg = <7>; + }; + + ethernet-port@8 { + label = "lan8"; + phy-handle = <&switch0phy8>; + reg = <8>; + }; + + ethernet-port@9 { + /* 88X3310P external phy */ + label = "lan9"; + phy-handle = <&phy1>; + phy-mode = "xaui"; + reg = <9>; + }; + + ethernet-port@a { + /* 88X3310P external phy */ + label = "lan10"; + phy-handle = <&phy2>; + phy-mode = "xaui"; + reg = <0xa>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt deleted file mode 100644 index 6ec0c181b6db..000000000000 --- a/Documentation/devicetree/bindings/net/dsa/marvell.txt +++ /dev/null @@ -1,109 +0,0 @@ -Marvell DSA Switch Device Tree Bindings ---------------------------------------- - -WARNING: This binding is currently unstable. Do not program it into a -FLASH never to be changed again. Once this binding is stable, this -warning will be removed. - -If you need a stable binding, use the old dsa.txt binding. - -Marvell Switches are MDIO devices. The following properties should be -placed as a child node of an mdio device. - -The properties described here are those specific to Marvell devices. -Additional required and optional properties can be found in dsa.txt. - -The compatibility string is used only to find an identification register, -which is at a different MDIO base address in different switch families. -- "marvell,mv88e6085" : Switch has base address 0x10. Use with models: - 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, - 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, - 6341, 6350, 6351, 6352 -- "marvell,mv88e6190" : Switch has base address 0x00. Use with models: - 6190, 6190X, 6191, 6290, 6361, 6390, 6390X -- "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: - 6220, 6250 - -Required properties: -- compatible : Should be one of "marvell,mv88e6085", - "marvell,mv88e6190" or "marvell,mv88e6250" as - indicated above -- reg : Address on the MII bus for the switch. - -Optional properties: - -- reset-gpios : Should be a gpio specifier for a reset line -- interrupts : Interrupt from the switch -- interrupt-controller : Indicates the switch is itself an interrupt - controller. This is used for the PHY interrupts. -#interrupt-cells = <2> : Controller uses two cells, number and flag -- eeprom-length : Set to the length of an EEPROM connected to the - switch. Must be set if the switch can not detect - the presence and/or size of a connected EEPROM, - otherwise optional. -- mdio : Container of PHY and devices on the switches MDIO - bus. -- mdio? : Container of PHYs and devices on the external MDIO - bus. The node must contains a compatible string of - "marvell,mv88e6xxx-mdio-external" - -Example: - - mdio { - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&gpio0>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - - switch0: switch@0 { - compatible = "marvell,mv88e6085"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - }; - }; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&gpio0>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - - switch0: switch@0 { - compatible = "marvell,mv88e6190"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - - mdio1 { - compatible = "marvell,mv88e6xxx-mdio-external"; - #address-cells = <1>; - #size-cells = <0>; - switch1phy9: switch1phy0@9 { - reg = <9>; - }; - }; - }; - }; diff --git a/MAINTAINERS b/MAINTAINERS index b2f53d5cae06..cc0e1f848f27 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12626,7 +12626,7 @@ MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn L: netdev@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/net/dsa/marvell.txt +F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml F: Documentation/networking/devlink/mv88e6xxx.rst F: drivers/net/dsa/mv88e6xxx/ F: include/linux/dsa/mv88e6xxx.h -- cgit v1.2.3 From 53313ed25ba8935af30021a1603225a0fed8e402 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Oct 2023 15:20:33 +0200 Subject: dt-bindings: marvell: Add Marvell MV88E6060 DSA schema The Marvell MV88E6060 is one of the oldest DSA switches from Marvell, and it has DT bindings used in the wild. Let's define them properly. It is different enough from the rest of the MV88E6xxx switches that it deserves its own binding. Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Reviewed-by: Rob Herring Signed-off-by: Linus Walleij Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../bindings/net/dsa/marvell,mv88e6060.yaml | 88 ++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml new file mode 100644 index 000000000000..4f1adf00431a --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6060.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MV88E6060 DSA switch + +maintainers: + - Andrew Lunn + +description: + The Marvell MV88E6060 switch has been produced and sold by Marvell + since at least 2008. The switch has one pin ADDR4 that controls the + MDIO address of the switch to be 0x10 or 0x00, and on the MDIO bus + connected to the switch, the PHYs inside the switch appear as + independent devices on address 0x00-0x04 or 0x10-0x14, so in difference + from many other DSA switches this switch does not have an internal + MDIO bus for the PHY devices. + +properties: + compatible: + const: marvell,mv88e6060 + description: + The MV88E6060 is the oldest Marvell DSA switch product, and + as such a bit limited in features compared to later hardware. + + reg: + maxItems: 1 + + reset-gpios: + description: + GPIO to be used to reset the whole device + maxItems: 1 + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@16 { + compatible = "marvell,mv88e6060"; + reg = <16>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan1"; + }; + ethernet-port@1 { + reg = <1>; + label = "lan2"; + }; + ethernet-port@2 { + reg = <2>; + label = "lan3"; + }; + ethernet-port@3 { + reg = <3>; + label = "lan4"; + }; + ethernet-port@5 { + reg = <5>; + phy-mode = "rev-mii"; + ethernet = <ðc>; + fixed-link { + speed = <100>; + full-duplex; + }; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index cc0e1f848f27..b66dfd9e23b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12626,6 +12626,7 @@ MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml F: Documentation/networking/devlink/mv88e6xxx.rst F: drivers/net/dsa/mv88e6xxx/ -- cgit v1.2.3 From aad36cd32982d59470de6365f97f154c5af5d1d2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 25 Oct 2023 07:22:37 -0700 Subject: Revert "Merge branch 'mv88e6xxx-dsa-bindings'" This reverts the following commits: commit 53313ed25ba8 ("dt-bindings: marvell: Add Marvell MV88E6060 DSA schema") commit 0f35369b4efe ("dt-bindings: marvell: Rewrite MV88E6xxx in schema") commit 605a5f5d406d ("ARM64: dts: marvell: Fix some common switch mistakes") commit bfedd8423643 ("ARM: dts: nxp: Fix some common switch mistakes") commit 2b83557a588f ("ARM: dts: marvell: Fix some common switch mistakes") commit ddae07ce9bb3 ("dt-bindings: net: mvusb: Fix up DSA example") commit b5ef61718ad7 ("dt-bindings: net: dsa: Require ports or ethernet-ports") As repoted by Vladimir, it breaks boot on the Turris MOX board. Link: https://lore.kernel.org/all/20231025093632.fb2qdtunzaznd73z@skbuf/ Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/dsa/dsa.yaml | 6 - .../bindings/net/dsa/marvell,mv88e6060.yaml | 88 ------ .../bindings/net/dsa/marvell,mv88e6xxx.yaml | 330 --------------------- .../devicetree/bindings/net/dsa/marvell.txt | 109 +++++++ .../devicetree/bindings/net/marvell,mvusb.yaml | 7 +- MAINTAINERS | 3 +- arch/arm/boot/dts/marvell/armada-370-rd.dts | 24 +- .../dts/marvell/armada-381-netgear-gs110emx.dts | 44 +-- .../dts/marvell/armada-385-clearfog-gtr-l8.dts | 38 +-- .../dts/marvell/armada-385-clearfog-gtr-s4.dts | 22 +- arch/arm/boot/dts/marvell/armada-385-linksys.dtsi | 18 +- .../boot/dts/marvell/armada-385-turris-omnia.dts | 20 +- arch/arm/boot/dts/marvell/armada-388-clearfog.dts | 20 +- .../boot/dts/marvell/armada-xp-linksys-mamba.dts | 18 +- arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts | 14 +- arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts | 70 ++--- arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts | 18 +- arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts | 20 +- arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts | 18 +- .../dts/marvell/armada-3720-espressobin-ultra.dts | 14 +- .../boot/dts/marvell/armada-3720-espressobin.dtsi | 20 +- .../boot/dts/marvell/armada-3720-gl-mv1000.dts | 20 +- .../boot/dts/marvell/armada-3720-turris-mox.dts | 189 ++++++------ .../boot/dts/marvell/armada-7040-mochabin.dts | 24 +- .../dts/marvell/armada-8040-clearfog-gt-8k.dts | 22 +- arch/arm64/boot/dts/marvell/cn9130-crb.dtsi | 42 +-- 26 files changed, 457 insertions(+), 761 deletions(-) delete mode 100644 Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml delete mode 100644 Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml create mode 100644 Documentation/devicetree/bindings/net/dsa/marvell.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.yaml b/Documentation/devicetree/bindings/net/dsa/dsa.yaml index 2abd036578d1..6107189d276a 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.yaml +++ b/Documentation/devicetree/bindings/net/dsa/dsa.yaml @@ -46,10 +46,4 @@ $defs: $ref: dsa-port.yaml# unevaluatedProperties: false -oneOf: - - required: - - ports - - required: - - ethernet-ports - ... diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml deleted file mode 100644 index 4f1adf00431a..000000000000 --- a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6060.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Marvell MV88E6060 DSA switch - -maintainers: - - Andrew Lunn - -description: - The Marvell MV88E6060 switch has been produced and sold by Marvell - since at least 2008. The switch has one pin ADDR4 that controls the - MDIO address of the switch to be 0x10 or 0x00, and on the MDIO bus - connected to the switch, the PHYs inside the switch appear as - independent devices on address 0x00-0x04 or 0x10-0x14, so in difference - from many other DSA switches this switch does not have an internal - MDIO bus for the PHY devices. - -properties: - compatible: - const: marvell,mv88e6060 - description: - The MV88E6060 is the oldest Marvell DSA switch product, and - as such a bit limited in features compared to later hardware. - - reg: - maxItems: 1 - - reset-gpios: - description: - GPIO to be used to reset the whole device - maxItems: 1 - -allOf: - - $ref: dsa.yaml#/$defs/ethernet-ports - -required: - - compatible - - reg - -unevaluatedProperties: false - -examples: - - | - #include - #include - mdio { - #address-cells = <1>; - #size-cells = <0>; - - ethernet-switch@16 { - compatible = "marvell,mv88e6060"; - reg = <16>; - - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - ethernet-port@0 { - reg = <0>; - label = "lan1"; - }; - ethernet-port@1 { - reg = <1>; - label = "lan2"; - }; - ethernet-port@2 { - reg = <2>; - label = "lan3"; - }; - ethernet-port@3 { - reg = <3>; - label = "lan4"; - }; - ethernet-port@5 { - reg = <5>; - phy-mode = "rev-mii"; - ethernet = <ðc>; - fixed-link { - speed = <100>; - full-duplex; - }; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml deleted file mode 100644 index 34d8561a2187..000000000000 --- a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml +++ /dev/null @@ -1,330 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Marvell MV88E6xxx DSA switch family - -maintainers: - - Andrew Lunn - -description: - The Marvell MV88E6xxx switch series has been produced and sold - by Marvell since at least 2008. The switch has a few compatibles which - just indicate the base address of the switch, then operating systems - can investigate switch ID registers to find out which actual version - of the switch it is dealing with. - -properties: - compatible: - enum: - - marvell,mv88e6085 - - marvell,mv88e6190 - - marvell,mv88e6250 - description: | - marvell,mv88e6085: This switch uses base address 0x10. - This switch and its siblings will be autodetected from - ID registers found in the switch, so only "marvell,mv88e6085" should be - specified. This includes the following list of MV88Exxxx switches: - 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, 6171, 6172, 6175, 6176, - 6185, 6240, 6320, 6321, 6341, 6350, 6351, 6352 - marvell,mv88e6190: This switch uses base address 0x00. - This switch and its siblings will be autodetected from - ID registers found in the switch, so only "marvell,mv88e6190" should be - specified. This includes the following list of MV88Exxxx switches: - 6190, 6190X, 6191, 6290, 6361, 6390, 6390X - marvell,mv88e6250: This switch uses base address 0x08 or 0x18. - This switch and its siblings will be autodetected from - ID registers found in the switch, so only "marvell,mv88e6250" should be - specified. This includes the following list of MV88Exxxx switches: - 6220, 6250 - - reg: - maxItems: 1 - - eeprom-length: - $ref: /schemas/types.yaml#/definitions/uint32 - description: Set to the length of an EEPROM connected to the switch. Must be - set if the switch can not detect the presence and/or size of a connected - EEPROM, otherwise optional. - - reset-gpios: - description: - GPIO to be used to reset the whole device - maxItems: 1 - - interrupts: - description: The switch provides an external interrupt line, but it is - not always used by target systems. - maxItems: 1 - - interrupt-controller: - description: The switch has an internal interrupt controller used by - the different sub-blocks. - - '#interrupt-cells': - description: The internal interrupt controller only supports triggering - on active high level interrupts so the second cell must alway be set to - IRQ_TYPE_LEVEL_HIGH. - const: 2 - - mdio: - $ref: /schemas/net/mdio.yaml# - unevaluatedProperties: false - description: Marvell MV88E6xxx switches have an varying combination of - internal and external MDIO buses, in some cases a combined bus that - can be used both internally and externally. This node is for the - primary bus, used internally and sometimes also externally. - - mdio-external: - $ref: /schemas/net/mdio.yaml# - unevaluatedProperties: false - description: Marvell MV88E6xxx switches that have a separate external - MDIO bus use this port to access external components on the MDIO bus. - - properties: - compatible: - const: marvell,mv88e6xxx-mdio-external - - required: - - compatible - -allOf: - - $ref: dsa.yaml#/$defs/ethernet-ports - -required: - - compatible - - reg - -unevaluatedProperties: false - -examples: - - | - #include - mdio { - #address-cells = <1>; - #size-cells = <0>; - - ethernet-switch@0 { - compatible = "marvell,mv88e6085"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - sw_phy0: ethernet-phy@0 { - reg = <0x0>; - }; - - sw_phy1: ethernet-phy@1 { - reg = <0x1>; - }; - - sw_phy2: ethernet-phy@2 { - reg = <0x2>; - }; - - sw_phy3: ethernet-phy@3 { - reg = <0x3>; - }; - }; - - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - ethernet-port@0 { - reg = <0>; - label = "lan4"; - phy-handle = <&sw_phy0>; - phy-mode = "internal"; - }; - - ethernet-port@1 { - reg = <1>; - label = "lan3"; - phy-handle = <&sw_phy1>; - phy-mode = "internal"; - }; - - ethernet-port@2 { - reg = <2>; - label = "lan2"; - phy-handle = <&sw_phy2>; - phy-mode = "internal"; - }; - - ethernet-port@3 { - reg = <3>; - label = "lan1"; - phy-handle = <&sw_phy3>; - phy-mode = "internal"; - }; - - ethernet-port@5 { - reg = <5>; - ethernet = <&fec>; - phy-mode = "rgmii-id"; - - fixed-link { - speed = <1000>; - full-duplex; - }; - }; - }; - }; - }; - - | - #include - mdio { - #address-cells = <1>; - #size-cells = <0>; - - ethernet-switch@0 { - compatible = "marvell,mv88e6190"; - #interrupt-cells = <2>; - interrupt-controller; - interrupt-parent = <&gpio1>; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>; - pinctrl-0 = <&switch_interrupt_pins>; - pinctrl-names = "default"; - reg = <0>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - switch0phy1: ethernet-phy@1 { - reg = <0x1>; - }; - - switch0phy2: ethernet-phy@2 { - reg = <0x2>; - }; - - switch0phy3: ethernet-phy@3 { - reg = <0x3>; - }; - - switch0phy4: ethernet-phy@4 { - reg = <0x4>; - }; - - switch0phy5: ethernet-phy@5 { - reg = <0x5>; - }; - - switch0phy6: ethernet-phy@6 { - reg = <0x6>; - }; - - switch0phy7: ethernet-phy@7 { - reg = <0x7>; - }; - - switch0phy8: ethernet-phy@8 { - reg = <0x8>; - }; - }; - - mdio-external { - compatible = "marvell,mv88e6xxx-mdio-external"; - #address-cells = <1>; - #size-cells = <0>; - - phy1: ethernet-phy@b { - reg = <0xb>; - compatible = "ethernet-phy-ieee802.3-c45"; - }; - - phy2: ethernet-phy@c { - reg = <0xc>; - compatible = "ethernet-phy-ieee802.3-c45"; - }; - }; - - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - ethernet-port@0 { - ethernet = <ð0>; - phy-mode = "rgmii"; - reg = <0>; - - fixed-link { - full-duplex; - pause; - speed = <1000>; - }; - }; - - ethernet-port@1 { - label = "lan1"; - phy-handle = <&switch0phy1>; - reg = <1>; - }; - - ethernet-port@2 { - label = "lan2"; - phy-handle = <&switch0phy2>; - reg = <2>; - }; - - ethernet-port@3 { - label = "lan3"; - phy-handle = <&switch0phy3>; - reg = <3>; - }; - - ethernet-port@4 { - label = "lan4"; - phy-handle = <&switch0phy4>; - reg = <4>; - }; - - ethernet-port@5 { - label = "lan5"; - phy-handle = <&switch0phy5>; - reg = <5>; - }; - - ethernet-port@6 { - label = "lan6"; - phy-handle = <&switch0phy6>; - reg = <6>; - }; - - ethernet-port@7 { - label = "lan7"; - phy-handle = <&switch0phy7>; - reg = <7>; - }; - - ethernet-port@8 { - label = "lan8"; - phy-handle = <&switch0phy8>; - reg = <8>; - }; - - ethernet-port@9 { - /* 88X3310P external phy */ - label = "lan9"; - phy-handle = <&phy1>; - phy-mode = "xaui"; - reg = <9>; - }; - - ethernet-port@a { - /* 88X3310P external phy */ - label = "lan10"; - phy-handle = <&phy2>; - phy-mode = "xaui"; - reg = <0xa>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt new file mode 100644 index 000000000000..6ec0c181b6db --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell.txt @@ -0,0 +1,109 @@ +Marvell DSA Switch Device Tree Bindings +--------------------------------------- + +WARNING: This binding is currently unstable. Do not program it into a +FLASH never to be changed again. Once this binding is stable, this +warning will be removed. + +If you need a stable binding, use the old dsa.txt binding. + +Marvell Switches are MDIO devices. The following properties should be +placed as a child node of an mdio device. + +The properties described here are those specific to Marvell devices. +Additional required and optional properties can be found in dsa.txt. + +The compatibility string is used only to find an identification register, +which is at a different MDIO base address in different switch families. +- "marvell,mv88e6085" : Switch has base address 0x10. Use with models: + 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, + 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, + 6341, 6350, 6351, 6352 +- "marvell,mv88e6190" : Switch has base address 0x00. Use with models: + 6190, 6190X, 6191, 6290, 6361, 6390, 6390X +- "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: + 6220, 6250 + +Required properties: +- compatible : Should be one of "marvell,mv88e6085", + "marvell,mv88e6190" or "marvell,mv88e6250" as + indicated above +- reg : Address on the MII bus for the switch. + +Optional properties: + +- reset-gpios : Should be a gpio specifier for a reset line +- interrupts : Interrupt from the switch +- interrupt-controller : Indicates the switch is itself an interrupt + controller. This is used for the PHY interrupts. +#interrupt-cells = <2> : Controller uses two cells, number and flag +- eeprom-length : Set to the length of an EEPROM connected to the + switch. Must be set if the switch can not detect + the presence and/or size of a connected EEPROM, + otherwise optional. +- mdio : Container of PHY and devices on the switches MDIO + bus. +- mdio? : Container of PHYs and devices on the external MDIO + bus. The node must contains a compatible string of + "marvell,mv88e6xxx-mdio-external" + +Example: + + mdio { + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + switch0: switch@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + interrupt-parent = <&switch0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + switch0: switch@0 { + compatible = "marvell,mv88e6190"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + interrupt-parent = <&switch0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + mdio1 { + compatible = "marvell,mv88e6xxx-mdio-external"; + #address-cells = <1>; + #size-cells = <0>; + switch1phy9: switch1phy0@9 { + reg = <9>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml index ab838c1ffeed..3a3325168048 100644 --- a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml +++ b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml @@ -50,14 +50,11 @@ examples: #address-cells = <1>; #size-cells = <0>; - ethernet-switch@0 { + switch@0 { compatible = "marvell,mv88e6190"; reg = <0x0>; - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - + ports { /* Port definitions */ }; diff --git a/MAINTAINERS b/MAINTAINERS index b66dfd9e23b4..b2f53d5cae06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12626,8 +12626,7 @@ MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn L: netdev@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml -F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml +F: Documentation/devicetree/bindings/net/dsa/marvell.txt F: Documentation/networking/devlink/mv88e6xxx.rst F: drivers/net/dsa/mv88e6xxx/ F: include/linux/dsa/mv88e6xxx.h diff --git a/arch/arm/boot/dts/marvell/armada-370-rd.dts b/arch/arm/boot/dts/marvell/armada-370-rd.dts index 1b241da11e94..b459a670f615 100644 --- a/arch/arm/boot/dts/marvell/armada-370-rd.dts +++ b/arch/arm/boot/dts/marvell/armada-370-rd.dts @@ -149,37 +149,39 @@ }; }; - switch: ethernet-switch@10 { + switch: switch@10 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <0x10>; interrupt-controller; #interrupt-cells = <2>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; label = "lan0"; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan1"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan3"; }; - ethernet-port@5 { + port@5 { reg = <5>; ethernet = <ð1>; phy-mode = "rgmii-id"; @@ -194,25 +196,25 @@ #address-cells = <1>; #size-cells = <0>; - switchphy0: ethernet-phy@0 { + switchphy0: switchphy@0 { reg = <0>; interrupt-parent = <&switch>; interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; }; - switchphy1: ethernet-phy@1 { + switchphy1: switchphy@1 { reg = <1>; interrupt-parent = <&switch>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; }; - switchphy2: ethernet-phy@2 { + switchphy2: switchphy@2 { reg = <2>; interrupt-parent = <&switch>; interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; }; - switchphy3: ethernet-phy@3 { + switchphy3: switchphy@3 { reg = <3>; interrupt-parent = <&switch>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts b/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts index 5baf83e5253d..f4c4b213ef4e 100644 --- a/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts +++ b/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts @@ -77,49 +77,51 @@ pinctrl-0 = <&mdio_pins>; status = "okay"; - ethernet-switch@0 { + switch@0 { compatible = "marvell,mv88e6190"; + #address-cells = <1>; #interrupt-cells = <2>; interrupt-controller; interrupt-parent = <&gpio1>; interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&switch_interrupt_pins>; pinctrl-names = "default"; + #size-cells = <0>; reg = <0>; mdio { #address-cells = <1>; #size-cells = <0>; - switch0phy1: ethernet-phy@1 { + switch0phy1: switch0phy1@1 { reg = <0x1>; }; - switch0phy2: ethernet-phy@2 { + switch0phy2: switch0phy2@2 { reg = <0x2>; }; - switch0phy3: ethernet-phy@3 { + switch0phy3: switch0phy3@3 { reg = <0x3>; }; - switch0phy4: ethernet-phy@4 { + switch0phy4: switch0phy4@4 { reg = <0x4>; }; - switch0phy5: ethernet-phy@5 { + switch0phy5: switch0phy5@5 { reg = <0x5>; }; - switch0phy6: ethernet-phy@6 { + switch0phy6: switch0phy6@6 { reg = <0x6>; }; - switch0phy7: ethernet-phy@7 { + switch0phy7: switch0phy7@7 { reg = <0x7>; }; - switch0phy8: ethernet-phy@8 { + switch0phy8: switch0phy8@8 { reg = <0x8>; }; }; @@ -140,11 +142,11 @@ }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { ethernet = <ð0>; phy-mode = "rgmii"; reg = <0>; @@ -156,55 +158,55 @@ }; }; - ethernet-port@1 { + port@1 { label = "lan1"; phy-handle = <&switch0phy1>; reg = <1>; }; - ethernet-port@2 { + port@2 { label = "lan2"; phy-handle = <&switch0phy2>; reg = <2>; }; - ethernet-port@3 { + port@3 { label = "lan3"; phy-handle = <&switch0phy3>; reg = <3>; }; - ethernet-port@4 { + port@4 { label = "lan4"; phy-handle = <&switch0phy4>; reg = <4>; }; - ethernet-port@5 { + port@5 { label = "lan5"; phy-handle = <&switch0phy5>; reg = <5>; }; - ethernet-port@6 { + port@6 { label = "lan6"; phy-handle = <&switch0phy6>; reg = <6>; }; - ethernet-port@7 { + port@7 { label = "lan7"; phy-handle = <&switch0phy7>; reg = <7>; }; - ethernet-port@8 { + port@8 { label = "lan8"; phy-handle = <&switch0phy8>; reg = <8>; }; - ethernet-port@9 { + port@9 { /* 88X3310P external phy */ label = "lan9"; phy-handle = <&phy1>; @@ -212,7 +214,7 @@ reg = <9>; }; - ethernet-port@a { + port@a { /* 88X3310P external phy */ label = "lan10"; phy-handle = <&phy2>; diff --git a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts index 1707d1b01545..1990f7d0cc79 100644 --- a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts +++ b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts @@ -7,66 +7,66 @@ }; &mdio { - switch0: ethernet-switch@4 { + switch0: switch0@4 { compatible = "marvell,mv88e6190"; reg = <4>; pinctrl-names = "default"; pinctrl-0 = <&cf_gtr_switch_reset_pins>; reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan8"; phy-handle = <&switch0phy0>; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan7"; phy-handle = <&switch0phy1>; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan6"; phy-handle = <&switch0phy2>; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "lan5"; phy-handle = <&switch0phy3>; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "lan4"; phy-handle = <&switch0phy4>; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "lan3"; phy-handle = <&switch0phy5>; }; - ethernet-port@7 { + port@7 { reg = <7>; label = "lan2"; phy-handle = <&switch0phy6>; }; - ethernet-port@8 { + port@8 { reg = <8>; label = "lan1"; phy-handle = <&switch0phy7>; }; - ethernet-port@10 { + port@10 { reg = <10>; phy-mode = "2500base-x"; @@ -83,35 +83,35 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: ethernet-phy@1 { + switch0phy0: switch0phy0@1 { reg = <0x1>; }; - switch0phy1: ethernet-phy@2 { + switch0phy1: switch0phy1@2 { reg = <0x2>; }; - switch0phy2: ethernet-phy@3 { + switch0phy2: switch0phy2@3 { reg = <0x3>; }; - switch0phy3: ethernet-phy@4 { + switch0phy3: switch0phy3@4 { reg = <0x4>; }; - switch0phy4: ethernet-phy@5 { + switch0phy4: switch0phy4@5 { reg = <0x5>; }; - switch0phy5: ethernet-phy@6 { + switch0phy5: switch0phy5@6 { reg = <0x6>; }; - switch0phy6: ethernet-phy@7 { + switch0phy6: switch0phy6@7 { reg = <0x7>; }; - switch0phy7: ethernet-phy@8 { + switch0phy7: switch0phy7@8 { reg = <0x8>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts index a7678a784c18..b795ad573891 100644 --- a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts +++ b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts @@ -11,42 +11,42 @@ }; &mdio { - switch0: ethernet-switch@4 { + switch0: switch0@4 { compatible = "marvell,mv88e6085"; reg = <4>; pinctrl-names = "default"; pinctrl-0 = <&cf_gtr_switch_reset_pins>; reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan2"; phy-handle = <&switch0phy0>; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan1"; phy-handle = <&switch0phy1>; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan4"; phy-handle = <&switch0phy2>; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "lan3"; phy-handle = <&switch0phy3>; }; - ethernet-port@5 { + port@5 { reg = <5>; phy-mode = "2500base-x"; ethernet = <ð1>; @@ -63,19 +63,19 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: ethernet-phy@11 { + switch0phy0: switch0phy0@11 { reg = <0x11>; }; - switch0phy1: ethernet-phy@12 { + switch0phy1: switch0phy1@12 { reg = <0x12>; }; - switch0phy2: ethernet-phy@13 { + switch0phy2: switch0phy2@13 { reg = <0x13>; }; - switch0phy3: ethernet-phy@14 { + switch0phy3: switch0phy3@14 { reg = <0x14>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi b/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi index 4116ed60f709..fc8216fd9f60 100644 --- a/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi +++ b/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi @@ -158,40 +158,42 @@ &mdio { status = "okay"; - ethernet-switch@0 { + switch@0 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <0>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; label = "lan4"; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan3"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan1"; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "wan"; }; - ethernet-port@5 { + port@5 { reg = <5>; phy-mode = "sgmii"; ethernet = <ð2>; diff --git a/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts b/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts index 7b755bb4e4e7..2d8d319bec83 100644 --- a/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +++ b/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts @@ -435,10 +435,12 @@ }; /* Switch MV88E6176 at address 0x10 */ - ethernet-switch@10 { + switch@10 { pinctrl-names = "default"; pinctrl-0 = <&swint_pins>; compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; dsa,member = <0 0>; reg = <0x10>; @@ -446,36 +448,36 @@ interrupt-parent = <&gpio1>; interrupts = <13 IRQ_TYPE_LEVEL_LOW>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + ports@0 { reg = <0>; label = "lan0"; }; - ethernet-port@1 { + ports@1 { reg = <1>; label = "lan1"; }; - ethernet-port@2 { + ports@2 { reg = <2>; label = "lan2"; }; - ethernet-port@3 { + ports@3 { reg = <3>; label = "lan3"; }; - ethernet-port@4 { + ports@4 { reg = <4>; label = "lan4"; }; - ethernet-port@5 { + ports@5 { reg = <5>; ethernet = <ð1>; phy-mode = "rgmii-id"; @@ -486,7 +488,7 @@ }; }; - ethernet-port@6 { + ports@6 { reg = <6>; ethernet = <ð0>; phy-mode = "rgmii-id"; diff --git a/arch/arm/boot/dts/marvell/armada-388-clearfog.dts b/arch/arm/boot/dts/marvell/armada-388-clearfog.dts index 3290ccad2374..32c569df142f 100644 --- a/arch/arm/boot/dts/marvell/armada-388-clearfog.dts +++ b/arch/arm/boot/dts/marvell/armada-388-clearfog.dts @@ -92,42 +92,44 @@ &mdio { status = "okay"; - ethernet-switch@4 { + switch@4 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <4>; pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>; pinctrl-names = "default"; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; label = "lan5"; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan4"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan3"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan2"; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "lan1"; }; - ethernet-port@5 { + port@5 { reg = <5>; ethernet = <ð1>; phy-mode = "1000base-x"; @@ -138,7 +140,7 @@ }; }; - ethernet-port@6 { + port@6 { /* 88E1512 external phy */ reg = <6>; label = "lan6"; diff --git a/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts index ea859f7ea042..7a0614fd0c93 100644 --- a/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts +++ b/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts @@ -265,40 +265,42 @@ &mdio { status = "okay"; - ethernet-switch@0 { + switch@0 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <0>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; label = "lan4"; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan3"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan1"; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "internet"; }; - ethernet-port@5 { + port@5 { reg = <5>; phy-mode = "rgmii-id"; ethernet = <ð0>; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts index 7e72f860c3c5..1a19aec8957b 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts @@ -162,7 +162,7 @@ suppress-preamble; status = "okay"; - switch0: ethernet-switch@0 { + switch0: switch0@0 { compatible = "marvell,mv88e6085"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_switch>; @@ -173,26 +173,26 @@ interrupt-controller; #interrupt-cells = <2>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; label = "eth_cu_1000_1"; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "eth_cu_1000_2"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "eth_cu_1000_3"; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "eth_fc_1000_1"; phy-mode = "1000base-x"; @@ -200,7 +200,7 @@ sfp = <&sff>; }; - ethernet-port@6 { + port@6 { reg = <6>; phy-mode = "rmii"; ethernet = <&fec1>; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts index 77492eeea450..df1335492a19 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts @@ -47,17 +47,17 @@ #address-cells = <1>; #size-cells = <0>; - switch0: ethernet-switch@0 { + switch0: switch0@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 0>; eeprom-length = <65536>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -68,37 +68,37 @@ }; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "aib2main_1"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "aib2main_2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "eth_cu_1000_5"; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "eth_cu_1000_6"; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "eth_cu_1000_4"; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "eth_cu_1000_7"; }; - ethernet-port@7 { + port@7 { reg = <7>; label = "modem_pic"; @@ -108,7 +108,7 @@ }; }; - switch0port10: ethernet-port@10 { + switch0port10: port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; @@ -130,32 +130,32 @@ #address-cells = <1>; #size-cells = <0>; - switch1: ethernet-switch@0 { + switch1: switch1@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 1>; eeprom-length = <65536>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <1>; label = "eth_cu_1000_3"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "eth_cu_100_2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "eth_cu_100_3"; }; - switch1port9: ethernet-port@9 { + switch1port9: port@9 { reg = <9>; label = "dsa"; phy-mode = "xgmii"; @@ -168,7 +168,7 @@ }; }; - switch1port10: ethernet-port@10 { + switch1port10: port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; @@ -188,17 +188,17 @@ #address-cells = <1>; #size-cells = <0>; - switch2: ethernet-switch@0 { + switch2: switch2@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 2>; eeprom-length = <65536>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@2 { + port@2 { reg = <2>; label = "eth_fc_1000_2"; phy-mode = "1000base-x"; @@ -206,7 +206,7 @@ sfp = <&sff1>; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "eth_fc_1000_3"; phy-mode = "1000base-x"; @@ -214,7 +214,7 @@ sfp = <&sff2>; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "eth_fc_1000_4"; phy-mode = "1000base-x"; @@ -222,7 +222,7 @@ sfp = <&sff3>; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "eth_fc_1000_5"; phy-mode = "1000base-x"; @@ -230,7 +230,7 @@ sfp = <&sff4>; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "eth_fc_1000_6"; phy-mode = "1000base-x"; @@ -238,7 +238,7 @@ sfp = <&sff5>; }; - ethernet-port@7 { + port@7 { reg = <7>; label = "eth_fc_1000_7"; phy-mode = "1000base-x"; @@ -246,7 +246,7 @@ sfp = <&sff6>; }; - ethernet-port@9 { + port@9 { reg = <9>; label = "eth_fc_1000_1"; phy-mode = "1000base-x"; @@ -254,7 +254,7 @@ sfp = <&sff0>; }; - switch2port10: ethernet-port@10 { + switch2port10: port@10 { reg = <10>; label = "dsa"; phy-mode = "2500base-x"; @@ -276,17 +276,17 @@ #address-cells = <1>; #size-cells = <0>; - switch3: ethernet-switch@0 { + switch3: switch3@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 3>; eeprom-length = <65536>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@2 { + port@2 { reg = <2>; label = "eth_fc_1000_8"; phy-mode = "1000base-x"; @@ -294,7 +294,7 @@ sfp = <&sff7>; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "eth_fc_1000_9"; phy-mode = "1000base-x"; @@ -302,7 +302,7 @@ sfp = <&sff8>; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "eth_fc_1000_10"; phy-mode = "1000base-x"; @@ -310,7 +310,7 @@ sfp = <&sff9>; }; - switch3port9: ethernet-port@9 { + switch3port9: port@9 { reg = <9>; label = "dsa"; phy-mode = "2500base-x"; @@ -322,7 +322,7 @@ }; }; - switch3port10: ethernet-port@10 { + switch3port10: port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts index 2a490464660c..1461804ecaea 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts @@ -123,7 +123,7 @@ suppress-preamble; status = "okay"; - switch0: ethernet-switch@0 { + switch0: switch0@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -134,11 +134,11 @@ interrupt-controller; #interrupt-cells = <2>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -149,32 +149,32 @@ }; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "eth_cu_1000_1"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "eth_cu_1000_2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "eth_cu_1000_3"; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "eth_cu_1000_4"; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "eth_cu_1000_5"; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "eth_cu_1000_6"; }; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts index 078d8699e16d..463c2452b9b7 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts @@ -112,7 +112,7 @@ suppress-preamble; status = "okay"; - switch0: ethernet-switch@0 { + switch0: switch0@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -123,11 +123,11 @@ interrupt-controller; #interrupt-cells = <2>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -138,27 +138,27 @@ }; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "eth_cu_100_3"; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "eth_cu_1000_4"; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "eth_cu_1000_5"; }; - ethernet-port@8 { + port@8 { reg = <8>; label = "eth_cu_1000_1"; }; - ethernet-port@9 { + port@9 { reg = <9>; label = "eth_cu_1000_2"; phy-handle = <&phy9>; @@ -167,12 +167,12 @@ }; }; - mdio-external { + mdio1 { compatible = "marvell,mv88e6xxx-mdio-external"; #address-cells = <1>; #size-cells = <0>; - phy9: ethernet-phy@0 { + phy9: phy9@0 { compatible = "ethernet-phy-ieee802.3-c45"; pinctrl-0 = <&pinctrl_gpio_phy9>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts index 22c8f44390a9..f5ae0d5de315 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts @@ -137,7 +137,7 @@ suppress-preamble; status = "okay"; - switch0: ethernet-switch@0 { + switch0: switch0@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -148,11 +148,11 @@ interrupt-controller; #interrupt-cells = <2>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -163,32 +163,32 @@ }; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "eth_cu_1000_1"; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "eth_cu_1000_2"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "eth_cu_1000_3"; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "eth_cu_1000_4"; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "eth_cu_1000_5"; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "eth_cu_1000_6"; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts index 870bb380a40a..f9abef8dcc94 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts @@ -126,32 +126,32 @@ reset-gpios = <&gpiosb 23 GPIO_ACTIVE_LOW>; - ethernet-ports { - switch0port1: ethernet-port@1 { + ports { + switch0port1: port@1 { reg = <1>; label = "lan0"; phy-handle = <&switch0phy0>; }; - switch0port2: ethernet-port@2 { + switch0port2: port@2 { reg = <2>; label = "lan1"; phy-handle = <&switch0phy1>; }; - switch0port3: ethernet-port@3 { + switch0port3: port@3 { reg = <3>; label = "lan2"; phy-handle = <&switch0phy2>; }; - switch0port4: ethernet-port@4 { + switch0port4: port@4 { reg = <4>; label = "lan3"; phy-handle = <&switch0phy3>; }; - switch0port5: ethernet-port@5 { + switch0port5: port@5 { reg = <5>; label = "wan"; phy-handle = <&extphy>; @@ -160,7 +160,7 @@ }; mdio { - switch0phy3: ethernet-phy@14 { + switch0phy3: switch0phy3@14 { reg = <0x14>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi index fed2dcecb323..49cbdb55b4b3 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi @@ -145,17 +145,19 @@ }; &mdio { - switch0: ethernet-switch@1 { + switch0: switch0@1 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <1>; dsa,member = <0 0>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - switch0port0: ethernet-port@0 { + switch0port0: port@0 { reg = <0>; label = "cpu"; ethernet = <ð0>; @@ -166,19 +168,19 @@ }; }; - switch0port1: ethernet-port@1 { + switch0port1: port@1 { reg = <1>; label = "wan"; phy-handle = <&switch0phy0>; }; - switch0port2: ethernet-port@2 { + switch0port2: port@2 { reg = <2>; label = "lan0"; phy-handle = <&switch0phy1>; }; - switch0port3: ethernet-port@3 { + switch0port3: port@3 { reg = <3>; label = "lan1"; phy-handle = <&switch0phy2>; @@ -190,13 +192,13 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: ethernet-phy@11 { + switch0phy0: switch0phy0@11 { reg = <0x11>; }; - switch0phy1: ethernet-phy@12 { + switch0phy1: switch0phy1@12 { reg = <0x12>; }; - switch0phy2: ethernet-phy@13 { + switch0phy2: switch0phy2@13 { reg = <0x13>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts b/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts index 63fbc8352161..b1b45b4fa9d4 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts @@ -152,29 +152,31 @@ }; &mdio { - switch0: ethernet-switch@1 { + switch0: switch0@1 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <1>; dsa,member = <0 0>; - ports: ethernet-ports { + ports: ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@0 { + port@0 { reg = <0>; label = "cpu"; ethernet = <ð0>; }; - ethernet-port@1 { + port@1 { reg = <1>; label = "wan"; phy-handle = <&switch0phy0>; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan0"; phy-handle = <&switch0phy1>; @@ -183,7 +185,7 @@ nvmem-cell-names = "mac-address"; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan1"; phy-handle = <&switch0phy2>; @@ -197,13 +199,13 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: ethernet-phy@11 { + switch0phy0: switch0phy0@11 { reg = <0x11>; }; - switch0phy1: ethernet-phy@12 { + switch0phy1: switch0phy1@12 { reg = <0x12>; }; - switch0phy2: ethernet-phy@13 { + switch0phy2: switch0phy2@13 { reg = <0x13>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts index cdf1b8bdb230..9eab2bb22134 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts @@ -304,12 +304,7 @@ reg = <1>; }; - /* - * NOTE: switch nodes are enabled by U-Boot if modules are present - * DO NOT change this node name (switch0@10) even if it is not following - * conventions! Deployed U-Boot binaries are explicitly looking for - * this node in order to augment the device tree! - */ + /* switch nodes are enabled by U-Boot if modules are present */ switch0@10 { compatible = "marvell,mv88e6190"; reg = <0x10>; @@ -322,92 +317,92 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy1: ethernet-phy@1 { + switch0phy1: switch0phy1@1 { reg = <0x1>; }; - switch0phy2: ethernet-phy@2 { + switch0phy2: switch0phy2@2 { reg = <0x2>; }; - switch0phy3: ethernet-phy@3 { + switch0phy3: switch0phy3@3 { reg = <0x3>; }; - switch0phy4: ethernet-phy@4 { + switch0phy4: switch0phy4@4 { reg = <0x4>; }; - switch0phy5: ethernet-phy@5 { + switch0phy5: switch0phy5@5 { reg = <0x5>; }; - switch0phy6: ethernet-phy@6 { + switch0phy6: switch0phy6@6 { reg = <0x6>; }; - switch0phy7: ethernet-phy@7 { + switch0phy7: switch0phy7@7 { reg = <0x7>; }; - switch0phy8: ethernet-phy@8 { + switch0phy8: switch0phy8@8 { reg = <0x8>; }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <0x1>; label = "lan1"; phy-handle = <&switch0phy1>; }; - ethernet-port@2 { + port@2 { reg = <0x2>; label = "lan2"; phy-handle = <&switch0phy2>; }; - ethernet-port@3 { + port@3 { reg = <0x3>; label = "lan3"; phy-handle = <&switch0phy3>; }; - ethernet-port@4 { + port@4 { reg = <0x4>; label = "lan4"; phy-handle = <&switch0phy4>; }; - ethernet-port@5 { + port@5 { reg = <0x5>; label = "lan5"; phy-handle = <&switch0phy5>; }; - ethernet-port@6 { + port@6 { reg = <0x6>; label = "lan6"; phy-handle = <&switch0phy6>; }; - ethernet-port@7 { + port@7 { reg = <0x7>; label = "lan7"; phy-handle = <&switch0phy7>; }; - ethernet-port@8 { + port@8 { reg = <0x8>; label = "lan8"; phy-handle = <&switch0phy8>; }; - ethernet-port@9 { + port@9 { reg = <0x9>; label = "cpu"; ethernet = <ð1>; @@ -415,7 +410,7 @@ managed = "in-band-status"; }; - switch0port10: ethernet-port@a { + switch0port10: port@a { reg = <0xa>; label = "dsa"; phy-mode = "2500base-x"; @@ -435,7 +430,7 @@ }; }; - ethernet-switch@2 { + switch0@2 { compatible = "marvell,mv88e6085"; reg = <0x2>; dsa,member = <0 0>; @@ -447,52 +442,52 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy1_topaz: ethernet-phy@11 { + switch0phy1_topaz: switch0phy1@11 { reg = <0x11>; }; - switch0phy2_topaz: ethernet-phy@12 { + switch0phy2_topaz: switch0phy2@12 { reg = <0x12>; }; - switch0phy3_topaz: ethernet-phy@13 { + switch0phy3_topaz: switch0phy3@13 { reg = <0x13>; }; - switch0phy4_topaz: ethernet-phy@14 { + switch0phy4_topaz: switch0phy4@14 { reg = <0x14>; }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <0x1>; label = "lan1"; phy-handle = <&switch0phy1_topaz>; }; - ethernet-port@2 { + port@2 { reg = <0x2>; label = "lan2"; phy-handle = <&switch0phy2_topaz>; }; - ethernet-port@3 { + port@3 { reg = <0x3>; label = "lan3"; phy-handle = <&switch0phy3_topaz>; }; - ethernet-port@4 { + port@4 { reg = <0x4>; label = "lan4"; phy-handle = <&switch0phy4_topaz>; }; - ethernet-port@5 { + port@5 { reg = <0x5>; label = "cpu"; phy-mode = "2500base-x"; @@ -502,7 +497,7 @@ }; }; - ethernet-switch@11 { + switch1@11 { compatible = "marvell,mv88e6190"; reg = <0x11>; dsa,member = <0 1>; @@ -514,92 +509,92 @@ #address-cells = <1>; #size-cells = <0>; - switch1phy1: ethernet-phy@1 { + switch1phy1: switch1phy1@1 { reg = <0x1>; }; - switch1phy2: ethernet-phy@2 { + switch1phy2: switch1phy2@2 { reg = <0x2>; }; - switch1phy3: ethernet-phy@3 { + switch1phy3: switch1phy3@3 { reg = <0x3>; }; - switch1phy4: ethernet-phy@4 { + switch1phy4: switch1phy4@4 { reg = <0x4>; }; - switch1phy5: ethernet-phy@5 { + switch1phy5: switch1phy5@5 { reg = <0x5>; }; - switch1phy6: ethernet-phy@6 { + switch1phy6: switch1phy6@6 { reg = <0x6>; }; - switch1phy7: ethernet-phy@7 { + switch1phy7: switch1phy7@7 { reg = <0x7>; }; - switch1phy8: ethernet-phy@8 { + switch1phy8: switch1phy8@8 { reg = <0x8>; }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <0x1>; label = "lan9"; phy-handle = <&switch1phy1>; }; - ethernet-port@2 { + port@2 { reg = <0x2>; label = "lan10"; phy-handle = <&switch1phy2>; }; - ethernet-port@3 { + port@3 { reg = <0x3>; label = "lan11"; phy-handle = <&switch1phy3>; }; - ethernet-port@4 { + port@4 { reg = <0x4>; label = "lan12"; phy-handle = <&switch1phy4>; }; - ethernet-port@5 { + port@5 { reg = <0x5>; label = "lan13"; phy-handle = <&switch1phy5>; }; - ethernet-port@6 { + port@6 { reg = <0x6>; label = "lan14"; phy-handle = <&switch1phy6>; }; - ethernet-port@7 { + port@7 { reg = <0x7>; label = "lan15"; phy-handle = <&switch1phy7>; }; - ethernet-port@8 { + port@8 { reg = <0x8>; label = "lan16"; phy-handle = <&switch1phy8>; }; - switch1port9: ethernet-port@9 { + switch1port9: port@9 { reg = <0x9>; label = "dsa"; phy-mode = "2500base-x"; @@ -607,7 +602,7 @@ link = <&switch0port10>; }; - switch1port10: ethernet-port@a { + switch1port10: port@a { reg = <0xa>; label = "dsa"; phy-mode = "2500base-x"; @@ -627,7 +622,7 @@ }; }; - ethernet-switch@2 { + switch1@2 { compatible = "marvell,mv88e6085"; reg = <0x2>; dsa,member = <0 1>; @@ -639,52 +634,52 @@ #address-cells = <1>; #size-cells = <0>; - switch1phy1_topaz: ethernet-phy@11 { + switch1phy1_topaz: switch1phy1@11 { reg = <0x11>; }; - switch1phy2_topaz: ethernet-phy@12 { + switch1phy2_topaz: switch1phy2@12 { reg = <0x12>; }; - switch1phy3_topaz: ethernet-phy@13 { + switch1phy3_topaz: switch1phy3@13 { reg = <0x13>; }; - switch1phy4_topaz: ethernet-phy@14 { + switch1phy4_topaz: switch1phy4@14 { reg = <0x14>; }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <0x1>; label = "lan9"; phy-handle = <&switch1phy1_topaz>; }; - ethernet-port@2 { + port@2 { reg = <0x2>; label = "lan10"; phy-handle = <&switch1phy2_topaz>; }; - ethernet-port@3 { + port@3 { reg = <0x3>; label = "lan11"; phy-handle = <&switch1phy3_topaz>; }; - ethernet-port@4 { + port@4 { reg = <0x4>; label = "lan12"; phy-handle = <&switch1phy4_topaz>; }; - ethernet-port@5 { + port@5 { reg = <0x5>; label = "dsa"; phy-mode = "2500base-x"; @@ -694,7 +689,7 @@ }; }; - ethernet-switch@12 { + switch2@12 { compatible = "marvell,mv88e6190"; reg = <0x12>; dsa,member = <0 2>; @@ -706,92 +701,92 @@ #address-cells = <1>; #size-cells = <0>; - switch2phy1: ethernet-phy@1 { + switch2phy1: switch2phy1@1 { reg = <0x1>; }; - switch2phy2: ethernet-phy@2 { + switch2phy2: switch2phy2@2 { reg = <0x2>; }; - switch2phy3: ethernet-phy@3 { + switch2phy3: switch2phy3@3 { reg = <0x3>; }; - switch2phy4: ethernet-phy@4 { + switch2phy4: switch2phy4@4 { reg = <0x4>; }; - switch2phy5: ethernet-phy@5 { + switch2phy5: switch2phy5@5 { reg = <0x5>; }; - switch2phy6: ethernet-phy@6 { + switch2phy6: switch2phy6@6 { reg = <0x6>; }; - switch2phy7: ethernet-phy@7 { + switch2phy7: switch2phy7@7 { reg = <0x7>; }; - switch2phy8: ethernet-phy@8 { + switch2phy8: switch2phy8@8 { reg = <0x8>; }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <0x1>; label = "lan17"; phy-handle = <&switch2phy1>; }; - ethernet-port@2 { + port@2 { reg = <0x2>; label = "lan18"; phy-handle = <&switch2phy2>; }; - ethernet-port@3 { + port@3 { reg = <0x3>; label = "lan19"; phy-handle = <&switch2phy3>; }; - ethernet-port@4 { + port@4 { reg = <0x4>; label = "lan20"; phy-handle = <&switch2phy4>; }; - ethernet-port@5 { + port@5 { reg = <0x5>; label = "lan21"; phy-handle = <&switch2phy5>; }; - ethernet-port@6 { + port@6 { reg = <0x6>; label = "lan22"; phy-handle = <&switch2phy6>; }; - ethernet-port@7 { + port@7 { reg = <0x7>; label = "lan23"; phy-handle = <&switch2phy7>; }; - ethernet-port@8 { + port@8 { reg = <0x8>; label = "lan24"; phy-handle = <&switch2phy8>; }; - switch2port9: ethernet-port@9 { + switch2port9: port@9 { reg = <0x9>; label = "dsa"; phy-mode = "2500base-x"; @@ -810,7 +805,7 @@ }; }; - ethernet-switch@2 { + switch2@2 { compatible = "marvell,mv88e6085"; reg = <0x2>; dsa,member = <0 2>; @@ -822,52 +817,52 @@ #address-cells = <1>; #size-cells = <0>; - switch2phy1_topaz: ethernet-phy@11 { + switch2phy1_topaz: switch2phy1@11 { reg = <0x11>; }; - switch2phy2_topaz: ethernet-phy@12 { + switch2phy2_topaz: switch2phy2@12 { reg = <0x12>; }; - switch2phy3_topaz: ethernet-phy@13 { + switch2phy3_topaz: switch2phy3@13 { reg = <0x13>; }; - switch2phy4_topaz: ethernet-phy@14 { + switch2phy4_topaz: switch2phy4@14 { reg = <0x14>; }; }; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <0x1>; label = "lan17"; phy-handle = <&switch2phy1_topaz>; }; - ethernet-port@2 { + port@2 { reg = <0x2>; label = "lan18"; phy-handle = <&switch2phy2_topaz>; }; - ethernet-port@3 { + port@3 { reg = <0x3>; label = "lan19"; phy-handle = <&switch2phy3_topaz>; }; - ethernet-port@4 { + port@4 { reg = <0x4>; label = "lan20"; phy-handle = <&switch2phy4_topaz>; }; - ethernet-port@5 { + port@5 { reg = <0x5>; label = "dsa"; phy-mode = "2500base-x"; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts b/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts index 40b7ee7ead72..48202810bf78 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts @@ -301,8 +301,10 @@ }; /* 88E6141 Topaz switch */ - switch: ethernet-switch@3 { + switch: switch@3 { compatible = "marvell,mv88e6085"; + #address-cells = <1>; + #size-cells = <0>; reg = <3>; pinctrl-names = "default"; @@ -312,35 +314,35 @@ interrupt-parent = <&cp0_gpio1>; interrupts = <1 IRQ_TYPE_LEVEL_LOW>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - swport1: ethernet-port@1 { + swport1: port@1 { reg = <1>; label = "lan0"; phy-handle = <&swphy1>; }; - swport2: ethernet-port@2 { + swport2: port@2 { reg = <2>; label = "lan1"; phy-handle = <&swphy2>; }; - swport3: ethernet-port@3 { + swport3: port@3 { reg = <3>; label = "lan2"; phy-handle = <&swphy3>; }; - swport4: ethernet-port@4 { + swport4: port@4 { reg = <4>; label = "lan3"; phy-handle = <&swphy4>; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "cpu"; ethernet = <&cp0_eth1>; @@ -353,19 +355,19 @@ #address-cells = <1>; #size-cells = <0>; - swphy1: ethernet-phy@17 { + swphy1: swphy1@17 { reg = <17>; }; - swphy2: ethernet-phy@18 { + swphy2: swphy2@18 { reg = <18>; }; - swphy3: ethernet-phy@19 { + swphy3: swphy3@19 { reg = <19>; }; - swphy4: ethernet-phy@20 { + swphy4: swphy4@20 { reg = <20>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts b/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts index 67892f0d2863..4125202028c8 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts @@ -497,42 +497,42 @@ reset-deassert-us = <10000>; }; - switch0: ethernet-switch@4 { + switch0: switch0@4 { compatible = "marvell,mv88e6085"; reg = <4>; pinctrl-names = "default"; pinctrl-0 = <&cp1_switch_reset_pins>; reset-gpios = <&cp1_gpio1 24 GPIO_ACTIVE_LOW>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <1>; label = "lan2"; phy-handle = <&switch0phy0>; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "lan1"; phy-handle = <&switch0phy1>; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "lan4"; phy-handle = <&switch0phy2>; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "lan3"; phy-handle = <&switch0phy3>; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "cpu"; ethernet = <&cp1_eth2>; @@ -545,19 +545,19 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: ethernet-phy@11 { + switch0phy0: switch0phy0@11 { reg = <0x11>; }; - switch0phy1: ethernet-phy@12 { + switch0phy1: switch0phy1@12 { reg = <0x12>; }; - switch0phy2: ethernet-phy@13 { + switch0phy2: switch0phy2@13 { reg = <0x13>; }; - switch0phy3: ethernet-phy@14 { + switch0phy3: switch0phy3@14 { reg = <0x14>; }; }; diff --git a/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi b/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi index 7538ed56053b..32cfb3e2efc3 100644 --- a/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi +++ b/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi @@ -207,9 +207,11 @@ reg = <0>; }; - switch6: ethernet-switch@6 { + switch6: switch0@6 { /* Actual device is MV88E6393X */ compatible = "marvell,mv88e6190"; + #address-cells = <1>; + #size-cells = <0>; reg = <6>; interrupt-parent = <&cp0_gpio1>; interrupts = <28 IRQ_TYPE_LEVEL_LOW>; @@ -218,59 +220,59 @@ dsa,member = <0 0>; - ethernet-ports { + ports { #address-cells = <1>; #size-cells = <0>; - ethernet-port@1 { + port@1 { reg = <1>; label = "p1"; phy-handle = <&switch0phy1>; }; - ethernet-port@2 { + port@2 { reg = <2>; label = "p2"; phy-handle = <&switch0phy2>; }; - ethernet-port@3 { + port@3 { reg = <3>; label = "p3"; phy-handle = <&switch0phy3>; }; - ethernet-port@4 { + port@4 { reg = <4>; label = "p4"; phy-handle = <&switch0phy4>; }; - ethernet-port@5 { + port@5 { reg = <5>; label = "p5"; phy-handle = <&switch0phy5>; }; - ethernet-port@6 { + port@6 { reg = <6>; label = "p6"; phy-handle = <&switch0phy6>; }; - ethernet-port@7 { + port@7 { reg = <7>; label = "p7"; phy-handle = <&switch0phy7>; }; - ethernet-port@8 { + port@8 { reg = <8>; label = "p8"; phy-handle = <&switch0phy8>; }; - ethernet-port@9 { + port@9 { reg = <9>; label = "p9"; phy-mode = "10gbase-r"; @@ -278,7 +280,7 @@ managed = "in-band-status"; }; - ethernet-port@a { + port@a { reg = <10>; ethernet = <&cp0_eth0>; phy-mode = "10gbase-r"; @@ -291,35 +293,35 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy1: ethernet-phy@1 { + switch0phy1: switch0phy1@1 { reg = <0x1>; }; - switch0phy2: ethernet-phy@2 { + switch0phy2: switch0phy2@2 { reg = <0x2>; }; - switch0phy3: ethernet-phy@3 { + switch0phy3: switch0phy3@3 { reg = <0x3>; }; - switch0phy4: ethernet-phy@4 { + switch0phy4: switch0phy4@4 { reg = <0x4>; }; - switch0phy5: ethernet-phy@5 { + switch0phy5: switch0phy5@5 { reg = <0x5>; }; - switch0phy6: ethernet-phy@6 { + switch0phy6: switch0phy6@6 { reg = <0x6>; }; - switch0phy7: ethernet-phy@7 { + switch0phy7: switch0phy7@7 { reg = <0x7>; }; - switch0phy8: ethernet-phy@8 { + switch0phy8: switch0phy8@8 { reg = <0x8>; }; }; -- cgit v1.2.3 From d866ae9aaa4325f1097e8b7a50f202348ca89b87 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Mon, 23 Oct 2023 13:44:34 -0700 Subject: mptcp: add a new sysctl for make after break timeout The MPTCP protocol allows sockets with no alive subflows to stay in ESTABLISHED status for and user-defined timeout, to allow for later subflows creation. Currently such timeout is constant - TCP_TIMEWAIT_LEN. Let the user-space configure them via a newly added sysctl, to better cope with busy servers and simplify (make them faster) the relevant pktdrill tests. Note that the new know does not apply to orphaned MPTCP socket waiting for the data_fin handshake completion: they always wait TCP_TIMEWAIT_LEN. Reviewed-by: Mat Martineau Signed-off-by: Paolo Abeni Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20231023-send-net-next-20231023-2-v1-1-9dc60939d371@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/mptcp-sysctl.rst | 11 +++++++++++ net/mptcp/ctrl.c | 16 ++++++++++++++++ net/mptcp/protocol.c | 6 +++--- net/mptcp/protocol.h | 1 + 4 files changed, 31 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/mptcp-sysctl.rst b/Documentation/networking/mptcp-sysctl.rst index 15f1919d640c..69975ce25a02 100644 --- a/Documentation/networking/mptcp-sysctl.rst +++ b/Documentation/networking/mptcp-sysctl.rst @@ -25,6 +25,17 @@ add_addr_timeout - INTEGER (seconds) Default: 120 +close_timeout - INTEGER (seconds) + Set the make-after-break timeout: in absence of any close or + shutdown syscall, MPTCP sockets will maintain the status + unchanged for such time, after the last subflow removal, before + moving to TCP_CLOSE. + + The default value matches TCP_TIMEWAIT_LEN. This is a per-namespace + sysctl. + + Default: 60 + checksum_enabled - BOOLEAN Control whether DSS checksum can be enabled. diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index e72b518c5d02..13fe0748dde8 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -27,6 +27,7 @@ struct mptcp_pernet { #endif unsigned int add_addr_timeout; + unsigned int close_timeout; unsigned int stale_loss_cnt; u8 mptcp_enabled; u8 checksum_enabled; @@ -65,6 +66,13 @@ unsigned int mptcp_stale_loss_cnt(const struct net *net) return mptcp_get_pernet(net)->stale_loss_cnt; } +unsigned int mptcp_close_timeout(const struct sock *sk) +{ + if (sock_flag(sk, SOCK_DEAD)) + return TCP_TIMEWAIT_LEN; + return mptcp_get_pernet(sock_net(sk))->close_timeout; +} + int mptcp_get_pm_type(const struct net *net) { return mptcp_get_pernet(net)->pm_type; @@ -79,6 +87,7 @@ static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) { pernet->mptcp_enabled = 1; pernet->add_addr_timeout = TCP_RTO_MAX; + pernet->close_timeout = TCP_TIMEWAIT_LEN; pernet->checksum_enabled = 0; pernet->allow_join_initial_addr_port = 1; pernet->stale_loss_cnt = 4; @@ -141,6 +150,12 @@ static struct ctl_table mptcp_sysctl_table[] = { .mode = 0644, .proc_handler = proc_dostring, }, + { + .procname = "close_timeout", + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, {} }; @@ -163,6 +178,7 @@ static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) table[4].data = &pernet->stale_loss_cnt; table[5].data = &pernet->pm_type; table[6].data = &pernet->scheduler; + table[7].data = &pernet->close_timeout; hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table, ARRAY_SIZE(mptcp_sysctl_table)); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 886ab689a8ae..a21f8ed26343 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2391,8 +2391,8 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, if (msk->in_accept_queue && msk->first == ssk && (sock_flag(sk, SOCK_DEAD) || sock_flag(ssk, SOCK_DEAD))) { /* ensure later check in mptcp_worker() will dispose the msk */ - mptcp_set_close_tout(sk, tcp_jiffies32 - (TCP_TIMEWAIT_LEN + 1)); sock_set_flag(sk, SOCK_DEAD); + mptcp_set_close_tout(sk, tcp_jiffies32 - (mptcp_close_timeout(sk) + 1)); lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); mptcp_subflow_drop_ctx(ssk); goto out_release; @@ -2516,7 +2516,7 @@ static bool mptcp_close_tout_expired(const struct sock *sk) return false; return time_after32(tcp_jiffies32, - inet_csk(sk)->icsk_mtup.probe_timestamp + TCP_TIMEWAIT_LEN); + inet_csk(sk)->icsk_mtup.probe_timestamp + mptcp_close_timeout(sk)); } static void mptcp_check_fastclose(struct mptcp_sock *msk) @@ -2659,7 +2659,7 @@ void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout) return; close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies + - TCP_TIMEWAIT_LEN; + mptcp_close_timeout(sk); /* the close timeout takes precedence on the fail one, and here at least one of * them is active diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index c4c05afdc48c..40228b55e3e9 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -615,6 +615,7 @@ unsigned int mptcp_get_add_addr_timeout(const struct net *net); int mptcp_is_checksum_enabled(const struct net *net); int mptcp_allow_join_id0(const struct net *net); unsigned int mptcp_stale_loss_cnt(const struct net *net); +unsigned int mptcp_close_timeout(const struct sock *sk); int mptcp_get_pm_type(const struct net *net); const char *mptcp_get_scheduler(const struct net *net); void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow, -- cgit v1.2.3 From 433d6c8048cb297c3e25af237d6d006daa2195f9 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 24 Oct 2023 15:23:09 -0600 Subject: Documentation: networking: explain what happens if temp_valid_lft is too small Signed-off-by: Alex Henrie Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20231024212312.299370-4-alexhenrie24@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index e7ec9026e5db..6134ff4561e8 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2502,7 +2502,9 @@ use_tempaddr - INTEGER * -1 (for point-to-point devices and loopback devices) temp_valid_lft - INTEGER - valid lifetime (in seconds) for temporary addresses. + valid lifetime (in seconds) for temporary addresses. If less than the + minimum required lifetime (typically 5 seconds), temporary addresses + will not be created. Default: 172800 (2 days) -- cgit v1.2.3 From ec575f885e3eca6b003e007f4acfba9a0ec3c04a Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 24 Oct 2023 15:23:10 -0600 Subject: Documentation: networking: explain what happens if temp_prefered_lft is too small or too large Signed-off-by: Alex Henrie Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20231024212312.299370-5-alexhenrie24@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/networking/ip-sysctl.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 6134ff4561e8..4dfe0d9a57bb 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2509,7 +2509,11 @@ temp_valid_lft - INTEGER Default: 172800 (2 days) temp_prefered_lft - INTEGER - Preferred lifetime (in seconds) for temporary addresses. + Preferred lifetime (in seconds) for temporary addresses. If + temp_prefered_lft is less than the minimum required lifetime (typically + 5 seconds), the preferred lifetime is the minimum required. If + temp_prefered_lft is greater than temp_valid_lft, the preferred lifetime + is temp_valid_lft. Default: 86400 (1 day) -- cgit v1.2.3 From bc30bb88ff3153fba7693557d15733179adf7492 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 25 Oct 2023 09:22:53 -0700 Subject: netlink: specs: support conditional operations Page pool code is compiled conditionally, but the operations are part of the shared netlink family. We can handle this by reporting empty list of pools or -EOPNOTSUPP / -ENOSYS but the cleanest way seems to be removing the ops completely at compilation time. That way user can see that the page pool ops are not present using genetlink introspection. Same way they'd check if the kernel is "new enough" to support the ops. Extend the specs with the ability to specify the config condition under which op (and its policies, etc.) should be hidden. Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20231025162253.133159-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 5 +++++ Documentation/netlink/genetlink-legacy.yaml | 5 +++++ Documentation/netlink/genetlink.yaml | 5 +++++ tools/net/ynl/ynl-gen-c.py | 22 ++++++++++++++++++++++ 4 files changed, 37 insertions(+) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 7ef2496d57c8..9d13bbb7ae47 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -295,6 +295,11 @@ properties: type: array items: enum: [ strict, dump, dump-strict ] + config-cond: + description: | + Name of the kernel config option gating the presence of + the operation, without the 'CONFIG_' prefix. + type: string do: &subop-type description: Main command handler. type: object diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index cd5ebe39b52c..0daf40402a29 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -346,6 +346,11 @@ properties: type: array items: enum: [ strict, dump, dump-strict ] + config-cond: + description: | + Name of the kernel config option gating the presence of + the operation, without the 'CONFIG_' prefix. + type: string # Start genetlink-legacy fixed-header: *fixed-header # End genetlink-legacy diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index 501ed2e6c8ef..3283bf458ff1 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -264,6 +264,11 @@ properties: type: array items: enum: [ strict, dump, dump-strict ] + config-cond: + description: | + Name of the kernel config option gating the presence of + the operation, without the 'CONFIG_' prefix. + type: string do: &subop-type description: Main command handler. type: object diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 31fd96f14fc0..1c7474ad92dc 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1162,6 +1162,7 @@ class CodeWriter: self._block_end = False self._silent_block = False self._ind = 0 + self._ifdef_block = None if out_file is None: self._out = os.sys.stdout else: @@ -1202,6 +1203,8 @@ class CodeWriter: if self._silent_block: ind += 1 self._silent_block = line.endswith(')') and CodeWriter._is_cond(line) + if line[0] == '#': + ind = 0 if add_ind: ind += add_ind self._out.write('\t' * ind + line + '\n') @@ -1328,6 +1331,19 @@ class CodeWriter: line += '= ' + str(one[1]) + ',' self.p(line) + def ifdef_block(self, config): + config_option = None + if config: + config_option = 'CONFIG_' + c_upper(config) + if self._ifdef_block == config_option: + return + + if self._ifdef_block: + self.p('#endif /* ' + self._ifdef_block + ' */') + if config_option: + self.p('#ifdef ' + config_option) + self._ifdef_block = config_option + scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'} @@ -2006,10 +2022,13 @@ def print_req_policy_fwd(cw, struct, ri=None, terminate=True): def print_req_policy(cw, struct, ri=None): + if ri and ri.op: + cw.ifdef_block(ri.op.get('config-cond', None)) print_req_policy_fwd(cw, struct, ri=ri, terminate=False) for _, arg in struct.member_list(): arg.attr_policy(cw) cw.p("};") + cw.ifdef_block(None) cw.nl() @@ -2127,6 +2146,7 @@ def print_kernel_op_table(family, cw): if op.is_async: continue + cw.ifdef_block(op.get('config-cond', None)) cw.block_start() members = [('cmd', op.enum_name)] if 'dont-validate' in op: @@ -2157,6 +2177,7 @@ def print_kernel_op_table(family, cw): if op.is_async or op_mode not in op: continue + cw.ifdef_block(op.get('config-cond', None)) cw.block_start() members = [('cmd', op.enum_name)] if 'dont-validate' in op: @@ -2192,6 +2213,7 @@ def print_kernel_op_table(family, cw): members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in flags]))) cw.write_struct_init(members) cw.block_end(line=',') + cw.ifdef_block(None) cw.block_end(line=';') cw.nl() -- cgit v1.2.3 From 7fe0e38bb669aff739c95846b59b63925570d7ef Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 23 Oct 2023 20:22:15 +0100 Subject: Documentation/tcp: Add TCP-AO documentation It has Frequently Asked Questions (FAQ) on RFC 5925 - I found it very useful answering those before writing the actual code. It provides answers to common questions that arise on a quick read of the RFC, as well as how they were answered. There's also comparison to TCP-MD5 option, evaluation of per-socket vs in-kernel-DB approaches and description of uAPI provided. Hopefully, it will be as useful for reviewing the code as it was for writing. Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Dmitry Safonov Acked-by: David Ahern Signed-off-by: David S. Miller --- Documentation/networking/index.rst | 1 + Documentation/networking/tcp_ao.rst | 444 ++++++++++++++++++++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 Documentation/networking/tcp_ao.rst (limited to 'Documentation') diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 2ffc5ad10295..683eb42309cc 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -106,6 +106,7 @@ Contents: sysfs-tagging tc-actions-env-rules tc-queue-filters + tcp_ao tcp-thin team timestamping diff --git a/Documentation/networking/tcp_ao.rst b/Documentation/networking/tcp_ao.rst new file mode 100644 index 000000000000..cfa5bf1cc542 --- /dev/null +++ b/Documentation/networking/tcp_ao.rst @@ -0,0 +1,444 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======================================================== +TCP Authentication Option Linux implementation (RFC5925) +======================================================== + +TCP Authentication Option (TCP-AO) provides a TCP extension aimed at verifying +segments between trusted peers. It adds a new TCP header option with +a Message Authentication Code (MAC). MACs are produced from the content +of a TCP segment using a hashing function with a password known to both peers. +The intent of TCP-AO is to deprecate TCP-MD5 providing better security, +key rotation and support for variety of hashing algorithms. + +1. Introduction +=============== + +.. table:: Short and Limited Comparison of TCP-AO and TCP-MD5 + + +----------------------+------------------------+-----------------------+ + | | TCP-MD5 | TCP-AO | + +======================+========================+=======================+ + |Supported hashing |MD5 |Must support HMAC-SHA1 | + |algorithms |(cryptographically weak)|(chosen-prefix attacks)| + | | |and CMAC-AES-128 (only | + | | |side-channel attacks). | + | | |May support any hashing| + | | |algorithm. | + +----------------------+------------------------+-----------------------+ + |Length of MACs (bytes)|16 |Typically 12-16. | + | | |Other variants that fit| + | | |TCP header permitted. | + +----------------------+------------------------+-----------------------+ + |Number of keys per |1 |Many | + |TCP connection | | | + +----------------------+------------------------+-----------------------+ + |Possibility to change |Non-practical (both |Supported by protocol | + |an active key |peers have to change | | + | |them during MSL) | | + +----------------------+------------------------+-----------------------+ + |Protection against |No |Yes: ignoring them | + |ICMP 'hard errors' | |by default on | + | | |established connections| + +----------------------+------------------------+-----------------------+ + |Protection against |No |Yes: pseudo-header | + |traffic-crossing | |includes TCP ports. | + |attack | | | + +----------------------+------------------------+-----------------------+ + |Protection against |No |Sequence Number | + |replayed TCP segments | |Extension (SNE) and | + | | |Initial Sequence | + | | |Numbers (ISNs) | + +----------------------+------------------------+-----------------------+ + |Supports |Yes |No. ISNs+SNE are needed| + |Connectionless Resets | |to correctly sign RST. | + +----------------------+------------------------+-----------------------+ + |Standards |RFC 2385 |RFC 5925, RFC 5926 | + +----------------------+------------------------+-----------------------+ + + +1.1 Frequently Asked Questions (FAQ) with references to RFC 5925 +---------------------------------------------------------------- + +Q: Can either SendID or RecvID be non-unique for the same 4-tuple +(srcaddr, srcport, dstaddr, dstport)? + +A: No [3.1]:: + + >> The IDs of MKTs MUST NOT overlap where their TCP connection + identifiers overlap. + +Q: Can Master Key Tuple (MKT) for an active connection be removed? + +A: No, unless it's copied to Transport Control Block (TCB) [3.1]:: + + It is presumed that an MKT affecting a particular connection cannot + be destroyed during an active connection -- or, equivalently, that + its parameters are copied to an area local to the connection (i.e., + instantiated) and so changes would affect only new connections. + +Q: If an old MKT needs to be deleted, how should it be done in order +to not remove it for an active connection? (As it can be still in use +at any moment later) + +A: Not specified by RFC 5925, seems to be a problem for key management +to ensure that no one uses such MKT before trying to remove it. + +Q: Can an old MKT exist forever and be used by another peer? + +A: It can, it's a key management task to decide when to remove an old key [6.1]:: + + Deciding when to start using a key is a performance issue. Deciding + when to remove an MKT is a security issue. Invalid MKTs are expected + to be removed. TCP-AO provides no mechanism to coordinate their removal, + as we consider this a key management operation. + +also [6.1]:: + + The only way to avoid reuse of previously used MKTs is to remove the MKT + when it is no longer considered permitted. + +Linux TCP-AO will try its best to prevent you from removing a key that's +being used, considering it a key management failure. But sine keeping +an outdated key may become a security issue and as a peer may +unintentionally prevent the removal of an old key by always setting +it as RNextKeyID - a forced key removal mechanism is provided, where +userspace has to supply KeyID to use instead of the one that's being removed +and the kernel will atomically delete the old key, even if the peer is +still requesting it. There are no guarantees for force-delete as the peer +may yet not have the new key - the TCP connection may just break. +Alternatively, one may choose to shut down the socket. + +Q: What happens when a packet is received on a new connection with no known +MKT's RecvID? + +A: RFC 5925 specifies that by default it is accepted with a warning logged, but +the behaviour can be configured by the user [7.5.1.a]:: + + If the segment is a SYN, then this is the first segment of a new + connection. Find the matching MKT for this segment, using the segment's + socket pair and its TCP-AO KeyID, matched against the MKT's TCP connection + identifier and the MKT's RecvID. + + i. If there is no matching MKT, remove TCP-AO from the segment. + Proceed with further TCP handling of the segment. + NOTE: this presumes that connections that do not match any MKT + should be silently accepted, as noted in Section 7.3. + +[7.3]:: + + >> A TCP-AO implementation MUST allow for configuration of the behavior + of segments with TCP-AO but that do not match an MKT. The initial default + of this configuration SHOULD be to silently accept such connections. + If this is not the desired case, an MKT can be included to match such + connections, or the connection can indicate that TCP-AO is required. + Alternately, the configuration can be changed to discard segments with + the AO option not matching an MKT. + +[10.2.b]:: + + Connections not matching any MKT do not require TCP-AO. Further, incoming + segments with TCP-AO are not discarded solely because they include + the option, provided they do not match any MKT. + +Note that Linux TCP-AO implementation differs in this aspect. Currently, TCP-AO +segments with unknown key signatures are discarded with warnings logged. + +Q: Does the RFC imply centralized kernel key management in any way? +(i.e. that a key on all connections MUST be rotated at the same time?) + +A: Not specified. MKTs can be managed in userspace, the only relevant part to +key changes is [7.3]:: + + >> All TCP segments MUST be checked against the set of MKTs for matching + TCP connection identifiers. + +Q: What happens when RNextKeyID requested by a peer is unknown? Should +the connection be reset? + +A: It should not, no action needs to be performed [7.5.2.e]:: + + ii. If they differ, determine whether the RNextKeyID MKT is ready. + + 1. If the MKT corresponding to the segment’s socket pair and RNextKeyID + is not available, no action is required (RNextKeyID of a received + segment needs to match the MKT’s SendID). + +Q: How current_key is set and when does it change? It is a user-triggered +change, or is it by a request from the remote peer? Is it set by the user +explicitly, or by a matching rule? + +A: current_key is set by RNextKeyID [6.1]:: + + Rnext_key is changed only by manual user intervention or MKT management + protocol operation. It is not manipulated by TCP-AO. Current_key is updated + by TCP-AO when processing received TCP segments as discussed in the segment + processing description in Section 7.5. Note that the algorithm allows + the current_key to change to a new MKT, then change back to a previously + used MKT (known as "backing up"). This can occur during an MKT change when + segments are received out of order, and is considered a feature of TCP-AO, + because reordering does not result in drops. + +[7.5.2.e.ii]:: + + 2. If the matching MKT corresponding to the segment’s socket pair and + RNextKeyID is available: + + a. Set current_key to the RNextKeyID MKT. + +Q: If both peers have multiple MKTs matching the connection's socket pair +(with different KeyIDs), how should the sender/receiver pick KeyID to use? + +A: Some mechanism should pick the "desired" MKT [3.3]:: + + Multiple MKTs may match a single outgoing segment, e.g., when MKTs + are being changed. Those MKTs cannot have conflicting IDs (as noted + elsewhere), and some mechanism must determine which MKT to use for each + given outgoing segment. + + >> An outgoing TCP segment MUST match at most one desired MKT, indicated + by the segment’s socket pair. The segment MAY match multiple MKTs, provided + that exactly one MKT is indicated as desired. Other information in + the segment MAY be used to determine the desired MKT when multiple MKTs + match; such information MUST NOT include values in any TCP option fields. + +Q: Can TCP-MD5 connection migrate to TCP-AO (and vice-versa): + +A: No [1]:: + + TCP MD5-protected connections cannot be migrated to TCP-AO because TCP MD5 + does not support any changes to a connection’s security algorithm + once established. + +Q: If all MKTs are removed on a connection, can it become a non-TCP-AO signed +connection? + +A: [7.5.2] doesn't have the same choice as SYN packet handling in [7.5.1.i] +that would allow accepting segments without a sign (which would be insecure). +While switching to non-TCP-AO connection is not prohibited directly, it seems +what the RFC means. Also, there's a requirement for TCP-AO connections to +always have one current_key [3.3]:: + + TCP-AO requires that every protected TCP segment match exactly one MKT. + +[3.3]:: + + >> An incoming TCP segment including TCP-AO MUST match exactly one MKT, + indicated solely by the segment’s socket pair and its TCP-AO KeyID. + +[4.4]:: + + One or more MKTs. These are the MKTs that match this connection’s + socket pair. + +Q: Can a non-TCP-AO connection become a TCP-AO-enabled one? + +A: No: for already established non-TCP-AO connection it would be impossible +to switch using TCP-AO as the traffic key generation requires the initial +sequence numbers. Paraphrasing, starting using TCP-AO would require +re-establishing the TCP connection. + +2. In-kernel MKTs database vs database in userspace +=================================================== + +Linux TCP-AO support is implemented using ``setsockopt()s``, in a similar way +to TCP-MD5. It means that a userspace application that wants to use TCP-AO +should perform ``setsockopt()`` on a TCP socket when it wants to add, +remove or rotate MKTs. This approach moves the key management responsibility +to userspace as well as decisions on corner cases, i.e. what to do if +the peer doesn't respect RNextKeyID; moving more code to userspace, especially +responsible for the policy decisions. Besides, it's flexible and scales well +(with less locking needed than in the case of an in-kernel database). One also +should keep in mind that mainly intended users are BGP processes, not any +random applications, which means that compared to IPsec tunnels, +no transparency is really needed and modern BGP daemons already have +``setsockopt()s`` for TCP-MD5 support. + +.. table:: Considered pros and cons of the approaches + + +----------------------+------------------------+-----------------------+ + | | ``setsockopt()`` | in-kernel DB | + +======================+========================+=======================+ + | Extendability | ``setsockopt()`` | Netlink messages are | + | | commands should be | simple and extendable | + | | extendable syscalls | | + +----------------------+------------------------+-----------------------+ + | Required userspace | BGP or any application | could be transparent | + | changes | that wants TCP-AO needs| as tunnels, providing | + | | to perform | something like | + | | ``setsockopt()s`` | ``ip tcpao add key`` | + | | and do key management | (delete/show/rotate) | + +----------------------+------------------------+-----------------------+ + |MKTs removal or adding| harder for userspace | harder for kernel | + +----------------------+------------------------+-----------------------+ + | Dump-ability | ``getsockopt()`` | Netlink .dump() | + | | | callback | + +----------------------+------------------------+-----------------------+ + | Limits on kernel | equal | + | resources/memory | | + +----------------------+------------------------+-----------------------+ + | Scalability | contention on | contention on | + | | ``TCP_LISTEN`` sockets | the whole database | + +----------------------+------------------------+-----------------------+ + | Monitoring & warnings| ``TCP_DIAG`` | same Netlink socket | + +----------------------+------------------------+-----------------------+ + | Matching of MKTs | half-problem: only | hard | + | | listen sockets | | + +----------------------+------------------------+-----------------------+ + + +3. uAPI +======= + +Linux provides a set of ``setsockopt()s`` and ``getsockopt()s`` that let +userspace manage TCP-AO on a per-socket basis. In order to add/delete MKTs +``TCP_AO_ADD_KEY`` and ``TCP_AO_DEL_KEY`` TCP socket options must be used +It is not allowed to add a key on an established non-TCP-AO connection +as well as to remove the last key from TCP-AO connection. + +``setsockopt(TCP_AO_DEL_KEY)`` command may specify ``tcp_ao_del::current_key`` ++ ``tcp_ao_del::set_current`` and/or ``tcp_ao_del::rnext`` ++ ``tcp_ao_del::set_rnext`` which makes such delete "forced": it +provides userspace a way to delete a key that's being used and atomically set +another one instead. This is not intended for normal use and should be used +only when the peer ignores RNextKeyID and keeps requesting/using an old key. +It provides a way to force-delete a key that's not trusted but may break +the TCP-AO connection. + +The usual/normal key-rotation can be performed with ``setsockopt(TCP_AO_INFO)``. +It also provides a uAPI to change per-socket TCP-AO settings, such as +ignoring ICMPs, as well as clear per-socket TCP-AO packet counters. +The corresponding ``getsockopt(TCP_AO_INFO)`` can be used to get those +per-socket TCP-AO settings. + +Another useful command is ``getsockopt(TCP_AO_GET_KEYS)``. One can use it +to list all MKTs on a TCP socket or use a filter to get keys for a specific +peer and/or sndid/rcvid, VRF L3 interface or get current_key/rnext_key. + +To repair TCP-AO connections ``setsockopt(TCP_AO_REPAIR)`` is available, +provided that the user previously has checkpointed/dumped the socket with +``getsockopt(TCP_AO_REPAIR)``. + +A tip here for scaled TCP_LISTEN sockets, that may have some thousands TCP-AO +keys, is: use filters in ``getsockopt(TCP_AO_GET_KEYS)`` and asynchronous +delete with ``setsockopt(TCP_AO_DEL_KEY)``. + +Linux TCP-AO also provides a bunch of segment counters that can be helpful +with troubleshooting/debugging issues. Every MKT has good/bad counters +that reflect how many packets passed/failed verification. +Each TCP-AO socket has the following counters: +- for good segments (properly signed) +- for bad segments (failed TCP-AO verification) +- for segments with unknown keys +- for segments where an AO signature was expected, but wasn't found +- for the number of ignored ICMPs + +TCP-AO per-socket counters are also duplicated with per-netns counters, +exposed with SNMP. Those are ``TCPAOGood``, ``TCPAOBad``, ``TCPAOKeyNotFound``, +``TCPAORequired`` and ``TCPAODroppedIcmps``. + +RFC 5925 very permissively specifies how TCP port matching can be done for +MKTs:: + + TCP connection identifier. A TCP socket pair, i.e., a local IP + address, a remote IP address, a TCP local port, and a TCP remote port. + Values can be partially specified using ranges (e.g., 2-30), masks + (e.g., 0xF0), wildcards (e.g., "*"), or any other suitable indication. + +Currently Linux TCP-AO implementation doesn't provide any TCP port matching. +Probably, port ranges are the most flexible for uAPI, but so far +not implemented. + +4. ``setsockopt()`` vs ``accept()`` race +======================================== + +In contrast with TCP-MD5 established connection which has just one key, +TCP-AO connections may have many keys, which means that accepted connections +on a listen socket may have any amount of keys as well. As copying all those +keys on a first properly signed SYN would make the request socket bigger, that +would be undesirable. Currently, the implementation doesn't copy keys +to request sockets, but rather look them up on the "parent" listener socket. + +The result is that when userspace removes TCP-AO keys, that may break +not-yet-established connections on request sockets as well as not removing +keys from sockets that were already established, but not yet ``accept()``'ed, +hanging in the accept queue. + +The reverse is valid as well: if userspace adds a new key for a peer on +a listener socket, the established sockets in accept queue won't +have the new keys. + +At this moment, the resolution for the two races: +``setsockopt(TCP_AO_ADD_KEY)`` vs ``accept()`` +and ``setsockopt(TCP_AO_DEL_KEY)`` vs ``accept()`` is delegated to userspace. +This means that it's expected that userspace would check the MKTs on the socket +that was returned by ``accept()`` to verify that any key rotation that +happened on listen socket is reflected on the newly established connection. + +This is a similar "do-nothing" approach to TCP-MD5 from the kernel side and +may be changed later by introducing new flags to ``tcp_ao_add`` +and ``tcp_ao_del``. + +Note that this race is rare for it needs TCP-AO key rotation to happen +during the 3-way handshake for the new TCP connection. + +5. Interaction with TCP-MD5 +=========================== + +A TCP connection can not migrate between TCP-AO and TCP-MD5 options. The +established sockets that have either AO or MD5 keys are restricted for +adding keys of the other option. + +For listening sockets the picture is different: BGP server may want to receive +both TCP-AO and (deprecated) TCP-MD5 clients. As a result, both types of keys +may be added to TCP_CLOSED or TCP_LISTEN sockets. It's not allowed to add +different types of keys for the same peer. + +6. SNE Linux implementation +=========================== + +RFC 5925 [6.2] describes the algorithm of how to extend TCP sequence numbers +with SNE. In short: TCP has to track the previous sequence numbers and set +sne_flag when the current SEQ number rolls over. The flag is cleared when +both current and previous SEQ numbers cross 0x7fff, which is 32Kb. + +In times when sne_flag is set, the algorithm compares SEQ for each packet with +0x7fff and if it's higher than 32Kb, it assumes that the packet should be +verified with SNE before the increment. As a result, there's +this [0; 32Kb] window, when packets with (SNE - 1) can be accepted. + +Linux implementation simplifies this a bit: as the network stack already tracks +the first SEQ byte that ACK is wanted for (snd_una) and the next SEQ byte that +is wanted (rcv_nxt) - that's enough information for a rough estimation +on where in the 4GB SEQ number space both sender and receiver are. +When they roll over to zero, the corresponding SNE gets incremented. + +tcp_ao_compute_sne() is called for each TCP-AO segment. It compares SEQ numbers +from the segment with snd_una or rcv_nxt and fits the result into a 2GB window around them, +detecting SEQ numbers rolling over. That simplifies the code a lot and only +requires SNE numbers to be stored on every TCP-AO socket. + +The 2GB window at first glance seems much more permissive compared to +RFC 5926. But that is only used to pick the correct SNE before/after +a rollover. It allows more TCP segment replays, but yet all regular +TCP checks in tcp_sequence() are applied on the verified segment. +So, it trades a bit more permissive acceptance of replayed/retransmitted +segments for the simplicity of the algorithm and what seems better behaviour +for large TCP windows. + +7. Links +======== + +RFC 5925 The TCP Authentication Option + https://www.rfc-editor.org/rfc/pdfrfc/rfc5925.txt.pdf + +RFC 5926 Cryptographic Algorithms for the TCP Authentication Option (TCP-AO) + https://www.rfc-editor.org/rfc/pdfrfc/rfc5926.txt.pdf + +Draft "SHA-2 Algorithm for the TCP Authentication Option (TCP-AO)" + https://datatracker.ietf.org/doc/html/draft-nayak-tcp-sha2-03 + +RFC 2385 Protection of BGP Sessions via the TCP MD5 Signature Option + https://www.rfc-editor.org/rfc/pdfrfc/rfc2385.txt.pdf + +:Author: Dmitry Safonov -- cgit v1.2.3 From 6479c975b20a7fe6ecacec3a60dc6f838ecee9d6 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 27 Oct 2023 16:04:54 +0200 Subject: doc/netlink: Update schema to support cmd-cnt-name and cmd-max-name allow specifying cmd-cnt-name and cmd-max-name in netlink specs, in accordance with Documentation/userspace-api/netlink/c-code-gen.rst. Use cmd-cnt-name and attr-cnt-name in the mptcp yaml spec and in the corresponding uAPI headers, to preserve the #defines we had in the past and avoid adding new ones. v2: - squash modification in mptcp.yaml and MPTCP uAPI headers Suggested-by: Jakub Kicinski Signed-off-by: Davide Caratti Link: https://lore.kernel.org/r/12d4ed0116d8883cf4b533b856f3125a34e56749.1698415310.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 6 ++++++ Documentation/netlink/genetlink-legacy.yaml | 6 ++++++ Documentation/netlink/netlink-raw.yaml | 6 ++++++ Documentation/netlink/specs/mptcp.yaml | 2 ++ include/uapi/linux/mptcp.h | 4 ---- include/uapi/linux/mptcp_pm.h | 8 ++++---- 6 files changed, 24 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 9d13bbb7ae47..c58f7153fcf8 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -47,6 +47,12 @@ properties: max-by-define: description: Makes the number of attributes and commands be specified by a define, not an enum value. type: boolean + cmd-max-name: + description: Name of the define for the last operation in the list. + type: string + cmd-cnt-name: + description: The explicit name for constant holding the count of operations (last operation + 1). + type: string # End genetlink-c definitions: diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index 0daf40402a29..938703088306 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -47,6 +47,12 @@ properties: max-by-define: description: Makes the number of attributes and commands be specified by a define, not an enum value. type: boolean + cmd-max-name: + description: Name of the define for the last operation in the list. + type: string + cmd-cnt-name: + description: The explicit name for constant holding the count of operations (last operation + 1). + type: string # End genetlink-c # Start genetlink-legacy kernel-policy: diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index 48db31f1d059..775cce8c548a 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -47,6 +47,12 @@ properties: max-by-define: description: Makes the number of attributes and commands be specified by a define, not an enum value. type: boolean + cmd-max-name: + description: Name of the define for the last operation in the list. + type: string + cmd-cnt-name: + description: The explicit name for constant holding the count of operations (last operation + 1). + type: string # End genetlink-c # Start genetlink-legacy kernel-policy: diff --git a/Documentation/netlink/specs/mptcp.yaml b/Documentation/netlink/specs/mptcp.yaml index ec5c454a87ea..49f90cfb4698 100644 --- a/Documentation/netlink/specs/mptcp.yaml +++ b/Documentation/netlink/specs/mptcp.yaml @@ -8,6 +8,7 @@ c-family-name: mptcp-pm-name c-version-name: mptcp-pm-ver max-by-define: true kernel-policy: per-op +cmd-cnt-name: --mptcp-pm-cmd-after-last definitions: - @@ -167,6 +168,7 @@ attribute-sets: - name: attr name-prefix: mptcp-pm-attr- + attr-cnt-name: --mptcp-attr-after-last attributes: - name: unspec diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index 64ecc8a3f9f2..a6451561f3f8 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -28,10 +28,6 @@ #include -/* for backward compatibility */ -#define __MPTCP_PM_CMD_AFTER_LAST __MPTCP_PM_CMD_MAX -#define __MPTCP_ATTR_AFTER_LAST __MPTCP_ATTR_MAX - #define MPTCP_INFO_FLAG_FALLBACK _BITUL(0) #define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED _BITUL(1) diff --git a/include/uapi/linux/mptcp_pm.h b/include/uapi/linux/mptcp_pm.h index 0ad598fe940b..b5d11aece408 100644 --- a/include/uapi/linux/mptcp_pm.h +++ b/include/uapi/linux/mptcp_pm.h @@ -100,9 +100,9 @@ enum { MPTCP_PM_ATTR_LOC_ID, MPTCP_PM_ATTR_ADDR_REMOTE, - __MPTCP_PM_ATTR_MAX + __MPTCP_ATTR_AFTER_LAST }; -#define MPTCP_PM_ATTR_MAX (__MPTCP_PM_ATTR_MAX - 1) +#define MPTCP_PM_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) enum mptcp_event_attr { MPTCP_ATTR_UNSPEC, @@ -143,8 +143,8 @@ enum { MPTCP_PM_CMD_SUBFLOW_CREATE, MPTCP_PM_CMD_SUBFLOW_DESTROY, - __MPTCP_PM_CMD_MAX + __MPTCP_PM_CMD_AFTER_LAST }; -#define MPTCP_PM_CMD_MAX (__MPTCP_PM_CMD_MAX - 1) +#define MPTCP_PM_CMD_MAX (__MPTCP_PM_CMD_AFTER_LAST - 1) #endif /* _UAPI_LINUX_MPTCP_PM_H */ -- cgit v1.2.3