]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: mana: Add support for net_shaper_ops
authorErni Sri Satya Vennela <ernis@linux.microsoft.com>
Tue, 17 Jun 2025 07:17:34 +0000 (00:17 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 19 Jun 2025 13:13:49 +0000 (15:13 +0200)
Introduce support for net_shaper_ops in the MANA driver,
enabling configuration of rate limiting on the MANA NIC.

To apply rate limiting, the driver issues a HWC command via
mana_set_bw_clamp() and updates the corresponding shaper object
in the net_shaper cache. If an error occurs during this process,
the driver restores the previous speed by querying the current link
configuration using mana_query_link_cfg().

The minimum supported bandwidth is 100 Mbps, and only values that are
exact multiples of 100 Mbps are allowed. Any other values are rejected.

To remove a shaper, the driver resets the bandwidth to the maximum
supported by the SKU using mana_set_bw_clamp() and clears the
associated cache entry. If an error occurs during this process,
the shaper details are retained.

On the hardware that does not support these APIs, the net-shaper
calls to set speed would fail.

Set the speed:
./tools/net/ynl/pyynl/cli.py \
 --spec Documentation/netlink/specs/net_shaper.yaml \
 --do set --json '{"ifindex":'$IFINDEX',
   "handle":{"scope": "netdev", "id":'$ID' },
   "bw-max": 200000000 }'

Get the shaper details:
./tools/net/ynl/pyynl/cli.py \
 --spec Documentation/netlink/specs/net_shaper.yaml \
 --do get --json '{"ifindex":'$IFINDEX',
      "handle":{"scope": "netdev", "id":'$ID' }}'

> {'bw-max': 200000000,
> 'handle': {'scope': 'netdev'},
> 'ifindex': $IFINDEX,
> 'metric': 'bps'}

Delete the shaper object:
./tools/net/ynl/pyynl/cli.py \
 --spec Documentation/netlink/specs/net_shaper.yaml \
 --do delete --json '{"ifindex":'$IFINDEX',
      "handle":{"scope": "netdev","id":'$ID' }}'

Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
Reviewed-by: Saurabh Singh Sengar <ssengar@linux.microsoft.com>
Reviewed-by: Long Li <longli@microsoft.com>
Link: https://patch.msgid.link/1750144656-2021-3-git-send-email-ernis@linux.microsoft.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/microsoft/mana/mana_en.c
include/net/mana/mana.h

index bcc33ea7aca3a90299a7bc192931e993abaf5356..547dff450b6ddd6d8dbb8775afa8d11b4127d143 100644 (file)
@@ -719,6 +719,78 @@ out:
        return err;
 }
 
+static int mana_shaper_set(struct net_shaper_binding *binding,
+                          const struct net_shaper *shaper,
+                          struct netlink_ext_ack *extack)
+{
+       struct mana_port_context *apc = netdev_priv(binding->netdev);
+       u32 old_speed, rate;
+       int err;
+
+       if (shaper->handle.scope != NET_SHAPER_SCOPE_NETDEV) {
+               NL_SET_ERR_MSG_MOD(extack, "net shaper scope should be netdev");
+               return -EINVAL;
+       }
+
+       if (apc->handle.id && shaper->handle.id != apc->handle.id) {
+               NL_SET_ERR_MSG_MOD(extack, "Cannot create multiple shapers");
+               return -EOPNOTSUPP;
+       }
+
+       if (!shaper->bw_max || (shaper->bw_max % 100000000)) {
+               NL_SET_ERR_MSG_MOD(extack, "Please use multiples of 100Mbps for bandwidth");
+               return -EINVAL;
+       }
+
+       rate = div_u64(shaper->bw_max, 1000); /* Convert bps to Kbps */
+       rate = div_u64(rate, 1000);           /* Convert Kbps to Mbps */
+
+       /* Get current speed */
+       err = mana_query_link_cfg(apc);
+       old_speed = (err) ? SPEED_UNKNOWN : apc->speed;
+
+       if (!err) {
+               err = mana_set_bw_clamp(apc, rate, TRI_STATE_TRUE);
+               apc->speed = (err) ? old_speed : rate;
+               apc->handle = (err) ? apc->handle : shaper->handle;
+       }
+
+       return err;
+}
+
+static int mana_shaper_del(struct net_shaper_binding *binding,
+                          const struct net_shaper_handle *handle,
+                          struct netlink_ext_ack *extack)
+{
+       struct mana_port_context *apc = netdev_priv(binding->netdev);
+       int err;
+
+       err = mana_set_bw_clamp(apc, 0, TRI_STATE_FALSE);
+
+       if (!err) {
+               /* Reset mana port context parameters */
+               apc->handle.id = 0;
+               apc->handle.scope = NET_SHAPER_SCOPE_UNSPEC;
+               apc->speed = 0;
+       }
+
+       return err;
+}
+
+static void mana_shaper_cap(struct net_shaper_binding *binding,
+                           enum net_shaper_scope scope,
+                           unsigned long *flags)
+{
+       *flags = BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MAX) |
+                BIT(NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS);
+}
+
+static const struct net_shaper_ops mana_shaper_ops = {
+       .set = mana_shaper_set,
+       .delete = mana_shaper_del,
+       .capabilities = mana_shaper_cap,
+};
+
 static const struct net_device_ops mana_devops = {
        .ndo_open               = mana_open,
        .ndo_stop               = mana_close,
@@ -729,6 +801,7 @@ static const struct net_device_ops mana_devops = {
        .ndo_bpf                = mana_bpf,
        .ndo_xdp_xmit           = mana_xdp_xmit,
        .ndo_change_mtu         = mana_change_mtu,
+       .net_shaper_ops         = &mana_shaper_ops,
 };
 
 static void mana_cleanup_port_context(struct mana_port_context *apc)
@@ -1162,6 +1235,86 @@ out:
        return err;
 }
 
+int mana_query_link_cfg(struct mana_port_context *apc)
+{
+       struct net_device *ndev = apc->ndev;
+       struct mana_query_link_config_resp resp = {};
+       struct mana_query_link_config_req req = {};
+       int err;
+
+       mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_LINK_CONFIG,
+                            sizeof(req), sizeof(resp));
+
+       req.vport = apc->port_handle;
+       req.hdr.resp.msg_version = GDMA_MESSAGE_V2;
+
+       err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+                               sizeof(resp));
+
+       if (err) {
+               netdev_err(ndev, "Failed to query link config: %d\n", err);
+               return err;
+       }
+
+       err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_LINK_CONFIG,
+                                  sizeof(resp));
+
+       if (err || resp.hdr.status) {
+               netdev_err(ndev, "Failed to query link config: %d, 0x%x\n", err,
+                          resp.hdr.status);
+               if (!err)
+                       err = -EOPNOTSUPP;
+               return err;
+       }
+
+       if (resp.qos_unconfigured) {
+               err = -EINVAL;
+               return err;
+       }
+       apc->speed = resp.link_speed_mbps;
+       return 0;
+}
+
+int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed,
+                     int enable_clamping)
+{
+       struct mana_set_bw_clamp_resp resp = {};
+       struct mana_set_bw_clamp_req req = {};
+       struct net_device *ndev = apc->ndev;
+       int err;
+
+       mana_gd_init_req_hdr(&req.hdr, MANA_SET_BW_CLAMP,
+                            sizeof(req), sizeof(resp));
+       req.vport = apc->port_handle;
+       req.link_speed_mbps = speed;
+       req.enable_clamping = enable_clamping;
+
+       err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+                               sizeof(resp));
+
+       if (err) {
+               netdev_err(ndev, "Failed to set bandwidth clamp for speed %u, err = %d",
+                          speed, err);
+               return err;
+       }
+
+       err = mana_verify_resp_hdr(&resp.hdr, MANA_SET_BW_CLAMP,
+                                  sizeof(resp));
+
+       if (err || resp.hdr.status) {
+               netdev_err(ndev, "Failed to set bandwidth clamp: %d, 0x%x\n", err,
+                          resp.hdr.status);
+               if (!err)
+                       err = -EOPNOTSUPP;
+               return err;
+       }
+
+       if (resp.qos_unconfigured)
+               netdev_info(ndev, "QoS is unconfigured\n");
+
+       return 0;
+}
+
 int mana_create_wq_obj(struct mana_port_context *apc,
                       mana_handle_t vport,
                       u32 wq_type, struct mana_obj_spec *wq_spec,
@@ -3011,6 +3164,8 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
                goto free_indir;
        }
 
+       debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, &apc->speed);
+
        return 0;
 
 free_indir:
index 4176edf1be719c7821bd28046bd6ff86ec70e991..038b18340e51334e0c38f3bfc214b3afe0422c54 100644 (file)
@@ -5,6 +5,7 @@
 #define _MANA_H
 
 #include <net/xdp.h>
+#include <net/net_shaper.h>
 
 #include "gdma.h"
 #include "hw_channel.h"
@@ -526,7 +527,12 @@ struct mana_port_context {
        struct mutex vport_mutex;
        int vport_use_count;
 
+       /* Net shaper handle*/
+       struct net_shaper_handle handle;
+
        u16 port_idx;
+       /* Currently configured speed (mbps) */
+       u32 speed;
 
        bool port_is_up;
        bool port_st_save; /* Saved port state */
@@ -562,6 +568,9 @@ struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
 void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog);
 int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf);
 void mana_query_gf_stats(struct mana_port_context *apc);
+int mana_query_link_cfg(struct mana_port_context *apc);
+int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed,
+                     int enable_clamping);
 void mana_query_phy_stats(struct mana_port_context *apc);
 int mana_pre_alloc_rxbufs(struct mana_port_context *apc, int mtu, int num_queues);
 void mana_pre_dealloc_rxbufs(struct mana_port_context *apc);
@@ -589,6 +598,8 @@ enum mana_command_code {
        MANA_FENCE_RQ           = 0x20006,
        MANA_CONFIG_VPORT_RX    = 0x20007,
        MANA_QUERY_VPORT_CONFIG = 0x20008,
+       MANA_QUERY_LINK_CONFIG  = 0x2000A,
+       MANA_SET_BW_CLAMP       = 0x2000B,
        MANA_QUERY_PHY_STAT     = 0x2000c,
 
        /* Privileged commands for the PF mode */
@@ -598,6 +609,35 @@ enum mana_command_code {
        MANA_DEREGISTER_HW_PORT = 0x28004,
 };
 
+/* Query Link Configuration*/
+struct mana_query_link_config_req {
+       struct gdma_req_hdr hdr;
+       mana_handle_t vport;
+}; /* HW DATA */
+
+struct mana_query_link_config_resp {
+       struct gdma_resp_hdr hdr;
+       u32 qos_speed_mbps;
+       u8 qos_unconfigured;
+       u8 reserved1[3];
+       u32 link_speed_mbps;
+       u8 reserved2[4];
+}; /* HW DATA */
+
+/* Set Bandwidth Clamp*/
+struct mana_set_bw_clamp_req {
+       struct gdma_req_hdr hdr;
+       mana_handle_t vport;
+       enum TRI_STATE enable_clamping;
+       u32 link_speed_mbps;
+}; /* HW DATA */
+
+struct mana_set_bw_clamp_resp {
+       struct gdma_resp_hdr hdr;
+       u8 qos_unconfigured;
+       u8 reserved[7];
+}; /* HW DATA */
+
 /* Query Device Configuration */
 struct mana_query_device_cfg_req {
        struct gdma_req_hdr hdr;