> Subject: [PATCH net-next v2 2/4] net: mana: Add support for net_shaper_ops > > 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 <er...@linux.microsoft.com> > Reviewed-by: Haiyang Zhang <haiya...@microsoft.com> > Reviewed-by: Shradha Gupta <shradhagu...@linux.microsoft.com> > Reviewed-by: Saurabh Singh Sengar <ssen...@linux.microsoft.com>
Reviewed-by: Long Li <lon...@microsoft.com> > --- > Changes in v2: > * No change. > --- > drivers/net/ethernet/microsoft/mana/mana_en.c | 155 ++++++++++++++++++ > include/net/mana/mana.h | 40 +++++ > 2 files changed, 195 insertions(+) > > diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c > b/drivers/net/ethernet/microsoft/mana/mana_en.c > index ca5e9c3d374b..7e8bc2c6a194 100644 > --- a/drivers/net/ethernet/microsoft/mana/mana_en.c > +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c > @@ -719,6 +719,78 @@ static int mana_change_mtu(struct net_device *ndev, > int new_mtu) > 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 @@ static int mana_cfg_vport_steering(struct > mana_port_context *apc, > 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, @@ -3013,6 > +3166,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: > diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index > 4176edf1be71..038b18340e51 100644 > --- a/include/net/mana/mana.h > +++ b/include/net/mana/mana.h > @@ -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; > -- > 2.34.1