diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox')
67 files changed, 2524 insertions, 1272 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 70fd246840e2..7af75b63245f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2295,11 +2295,7 @@ int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, lockdep_is_held(&priv->mdev->state_lock)); if (xdp_prog && carry_xdp_prog) { - xdp_prog = bpf_prog_add(xdp_prog, tmp->rx_ring_num); - if (IS_ERR(xdp_prog)) { - mlx4_en_free_resources(tmp); - return PTR_ERR(xdp_prog); - } + bpf_prog_add(xdp_prog, tmp->rx_ring_num); for (i = 0; i < tmp->rx_ring_num; i++) rcu_assign_pointer(tmp->rx_ring[i]->xdp_prog, xdp_prog); @@ -2791,11 +2787,9 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) * program for a new one. */ if (priv->tx_ring_num[TX_XDP] == xdp_ring_num) { - if (prog) { - prog = bpf_prog_add(prog, priv->rx_ring_num - 1); - if (IS_ERR(prog)) - return PTR_ERR(prog); - } + if (prog) + bpf_prog_add(prog, priv->rx_ring_num - 1); + mutex_lock(&mdev->state_lock); for (i = 0; i < priv->rx_ring_num; i++) { old_prog = rcu_dereference_protected( @@ -2816,13 +2810,8 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) if (!tmp) return -ENOMEM; - if (prog) { - prog = bpf_prog_add(prog, priv->rx_ring_num - 1); - if (IS_ERR(prog)) { - err = PTR_ERR(prog); - goto out; - } - } + if (prog) + bpf_prog_add(prog, priv->rx_ring_num - 1); mutex_lock(&mdev->state_lock); memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); @@ -2871,7 +2860,6 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) unlock_out: mutex_unlock(&mdev->state_lock); -out: kfree(tmp); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index d44ac666e730..5716c3d2bb86 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3934,13 +3934,17 @@ static void mlx4_restart_one_down(struct pci_dev *pdev); static int mlx4_restart_one_up(struct pci_dev *pdev, bool reload, struct devlink *devlink); -static int mlx4_devlink_reload_down(struct devlink *devlink, +static int mlx4_devlink_reload_down(struct devlink *devlink, bool netns_change, struct netlink_ext_ack *extack) { struct mlx4_priv *priv = devlink_priv(devlink); struct mlx4_dev *dev = &priv->dev; struct mlx4_dev_persistent *persist = dev->persist; + if (netns_change) { + NL_SET_ERR_MSG_MOD(extack, "Namespace change is not supported"); + return -EOPNOTSUPP; + } if (persist->num_vfs) mlx4_warn(persist->dev, "Reload performed on PF, will cause reset on operating Virtual Functions\n"); mlx4_restart_one_down(persist->pdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 5708fcc079ca..a6f390fdb971 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -70,7 +70,7 @@ mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/t mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \ steering/dr_matcher.o steering/dr_rule.o \ - steering/dr_icm_pool.o steering/dr_crc32.o \ + steering/dr_icm_pool.o \ steering/dr_ste.o steering/dr_send.o \ steering/dr_cmd.o steering/dr_fw.o \ steering/dr_action.o steering/fs_dr.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index ea934cd02448..34cba97f7bf4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -866,7 +866,7 @@ static void cmd_work_handler(struct work_struct *work) if (!ent->page_queue) { alloc_ret = alloc_ent(cmd); if (alloc_ret < 0) { - mlx5_core_err(dev, "failed to allocate command entry\n"); + mlx5_core_err_rl(dev, "failed to allocate command entry\n"); if (ent->callback) { ent->callback(-EAGAIN, ent->context); mlx5_free_cmd_msg(dev, ent->out); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 381925c90d94..ac108f1e5bd6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -85,6 +85,22 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, return 0; } +static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, + struct netlink_ext_ack *extack) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + + return mlx5_unload_one(dev, false); +} + +static int mlx5_devlink_reload_up(struct devlink *devlink, + struct netlink_ext_ack *extack) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + + return mlx5_load_one(dev, false); +} + static const struct devlink_ops mlx5_devlink_ops = { #ifdef CONFIG_MLX5_ESWITCH .eswitch_mode_set = mlx5_devlink_eswitch_mode_set, @@ -96,6 +112,8 @@ static const struct devlink_ops mlx5_devlink_ops = { #endif .flash_update = mlx5_devlink_flash_update, .info_get = mlx5_devlink_info_get, + .reload_down = mlx5_devlink_reload_down, + .reload_up = mlx5_devlink_reload_up, }; struct devlink *mlx5_devlink_alloc(void) @@ -177,12 +195,29 @@ enum mlx5_devlink_param_id { MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, }; +static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id, + union devlink_param_value val, + struct netlink_ext_ack *extack) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + bool new_state = val.vbool; + + if (new_state && !MLX5_CAP_GEN(dev, roce)) { + NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE"); + return -EOPNOTSUPP; + } + + return 0; +} + static const struct devlink_param mlx5_devlink_params[] = { DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, "flow_steering_mode", DEVLINK_PARAM_TYPE_STRING, BIT(DEVLINK_PARAM_CMODE_RUNTIME), mlx5_devlink_fs_mode_get, mlx5_devlink_fs_mode_set, mlx5_devlink_fs_mode_validate), + DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), + NULL, NULL, mlx5_devlink_enable_roce_validate), }; static void mlx5_devlink_set_params_init_values(struct devlink *devlink) @@ -197,6 +232,11 @@ static void mlx5_devlink_set_params_init_values(struct devlink *devlink) devlink_param_driverinit_value_set(devlink, MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, value); + + value.vbool = MLX5_CAP_GEN(dev, roce); + devlink_param_driverinit_value_set(devlink, + DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, + value); } int mlx5_devlink_register(struct devlink *devlink, struct device *dev) @@ -213,6 +253,7 @@ int mlx5_devlink_register(struct devlink *devlink, struct device *dev) goto params_reg_err; mlx5_devlink_set_params_init_values(devlink); devlink_params_publish(devlink); + devlink_reload_enable(devlink); return 0; params_reg_err: @@ -222,6 +263,7 @@ params_reg_err: void mlx5_devlink_unregister(struct devlink *devlink) { + devlink_reload_disable(devlink); devlink_params_unregister(devlink, mlx5_devlink_params, ARRAY_SIZE(mlx5_devlink_params)); devlink_unregister(devlink); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c index 633b117eb13e..7b672ada63a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c @@ -175,7 +175,7 @@ static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer, * @port_buffer: <output> port receive buffer configuration * @change: <output> * - * Update buffer configuration based on pfc configuraiton and + * Update buffer configuration based on pfc configuration and * priority to buffer mapping. * Buffer's lossy bit is changed to: * lossless if there is at least one PFC enabled priority diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c index b860569d4247..6c72b592315b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c @@ -222,7 +222,8 @@ static int mlx5e_rx_reporter_recover_from_ctx(struct mlx5e_err_ctx *err_ctx) } static int mlx5e_rx_reporter_recover(struct devlink_health_reporter *reporter, - void *context) + void *context, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_err_ctx *err_ctx = context; @@ -301,7 +302,8 @@ static int mlx5e_rx_reporter_build_diagnose_output(struct mlx5e_rq *rq, } static int mlx5e_rx_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_params *params = &priv->channels.params; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c index bfed558637c2..b468549e96ff 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c @@ -135,7 +135,8 @@ static int mlx5e_tx_reporter_recover_from_ctx(struct mlx5e_err_ctx *err_ctx) } static int mlx5e_tx_reporter_recover(struct devlink_health_reporter *reporter, - void *context) + void *context, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_err_ctx *err_ctx = context; @@ -205,7 +206,8 @@ mlx5e_tx_reporter_build_diagnose_output(struct devlink_fmsg *fmsg, } static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_txqsq *generic_sq = priv->txq2sq[0]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c index 745ab6cd7c30..784b1e26f414 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -77,8 +77,8 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, struct neighbour **out_n, u8 *out_ttl) { + struct neighbour *n; struct rtable *rt; - struct neighbour *n = NULL; #if IS_ENABLED(CONFIG_INET) struct mlx5_core_dev *mdev = priv->mdev; @@ -138,10 +138,9 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, struct neighbour **out_n, u8 *out_ttl) { - struct neighbour *n = NULL; struct dst_entry *dst; + struct neighbour *n; -#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) int ret; ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst, @@ -157,9 +156,6 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, dst_release(dst); return ret; } -#else - return -EOPNOTSUPP; -#endif n = dst_neigh_lookup(dst, &fl6->daddr); dst_release(dst); @@ -212,8 +208,8 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); const struct ip_tunnel_key *tun_key = &e->tun_info->key; struct net_device *out_dev, *route_dev; - struct neighbour *n = NULL; struct flowi4 fl4 = {}; + struct neighbour *n; int ipv4_encap_size; char *encap_header; u8 nud_state, ttl; @@ -240,13 +236,13 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv4_encap_size, max_encap_size); err = -EOPNOTSUPP; - goto out; + goto release_neigh; } encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL); if (!encap_header) { err = -ENOMEM; - goto out; + goto release_neigh; } /* used by mlx5e_detach_encap to lookup a neigh hash table @@ -298,7 +294,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, /* the encap entry will be made valid on neigh update event * and not used before that. */ - goto out; + goto release_neigh; } e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, e->reformat_type, @@ -318,9 +314,8 @@ destroy_neigh_entry: mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); free_encap: kfree(encap_header); -out: - if (n) - neigh_release(n); +release_neigh: + neigh_release(n); return err; } @@ -331,9 +326,9 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); const struct ip_tunnel_key *tun_key = &e->tun_info->key; struct net_device *out_dev, *route_dev; - struct neighbour *n = NULL; struct flowi6 fl6 = {}; struct ipv6hdr *ip6h; + struct neighbour *n; int ipv6_encap_size; char *encap_header; u8 nud_state, ttl; @@ -359,13 +354,13 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv6_encap_size, max_encap_size); err = -EOPNOTSUPP; - goto out; + goto release_neigh; } encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL); if (!encap_header) { err = -ENOMEM; - goto out; + goto release_neigh; } /* used by mlx5e_detach_encap to lookup a neigh hash table @@ -416,7 +411,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, /* the encap entry will be made valid on neigh update event * and not used before that. */ - goto out; + goto release_neigh; } e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, @@ -437,9 +432,8 @@ destroy_neigh_entry: mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); free_encap: kfree(encap_header); -out: - if (n) - neigh_release(n); +release_neigh: + neigh_release(n); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h index c362b9225dc2..6f9a78c85ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h @@ -58,9 +58,16 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, struct net_device *mirred_dev, struct mlx5e_encap_entry *e); +#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, struct net_device *mirred_dev, struct mlx5e_encap_entry *e); +#else +static inline int +mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, + struct net_device *mirred_dev, + struct mlx5e_encap_entry *e) { return -EOPNOTSUPP; } +#endif bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv, struct net_device *netdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 2a56e66f58d8..09ed7f5f688b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -63,6 +63,7 @@ #include "en/xsk/rx.h" #include "en/xsk/tx.h" #include "en/hv_vhca_stats.h" +#include "lib/mlx5.h" bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev) @@ -408,12 +409,9 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->stats = &c->priv->channel_stats[c->ix].rq; INIT_WORK(&rq->recover_work, mlx5e_rq_err_cqe_work); - rq->xdp_prog = params->xdp_prog ? bpf_prog_inc(params->xdp_prog) : NULL; - if (IS_ERR(rq->xdp_prog)) { - err = PTR_ERR(rq->xdp_prog); - rq->xdp_prog = NULL; - goto err_rq_wq_destroy; - } + if (params->xdp_prog) + bpf_prog_inc(params->xdp_prog); + rq->xdp_prog = params->xdp_prog; rq_xdp_ix = rq->ix; if (xsk) @@ -4409,16 +4407,11 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog) /* no need for full reset when exchanging programs */ reset = (!priv->channels.params.xdp_prog || !prog); - if (was_opened && !reset) { + if (was_opened && !reset) /* num_channels is invariant here, so we can take the * batched reference right upfront. */ - prog = bpf_prog_add(prog, priv->channels.num); - if (IS_ERR(prog)) { - err = PTR_ERR(prog); - goto unlock; - } - } + bpf_prog_add(prog, priv->channels.num); if (was_opened && reset) { struct mlx5e_channels new_channels = {}; @@ -5430,6 +5423,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev) return NULL; } + dev_net_set(netdev, mlx5_core_net(mdev)); priv = netdev_priv(netdev); err = mlx5e_attach(mdev, priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index cd9bb7c7b341..f175cb24bb67 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -47,6 +47,7 @@ #include "en/tc_tun.h" #include "fs_core.h" #include "lib/port_tun.h" +#include "lib/mlx5.h" #define CREATE_TRACE_POINTS #include "diag/en_rep_tracepoint.h" @@ -1243,21 +1244,60 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data, } } -static LIST_HEAD(mlx5e_rep_block_cb_list); +static int mlx5e_rep_setup_ft_cb(enum tc_setup_type type, void *type_data, + void *cb_priv) +{ + struct flow_cls_offload *f = type_data; + struct flow_cls_offload cls_flower; + struct mlx5e_priv *priv = cb_priv; + struct mlx5_eswitch *esw; + unsigned long flags; + int err; + + flags = MLX5_TC_FLAG(INGRESS) | + MLX5_TC_FLAG(ESW_OFFLOAD) | + MLX5_TC_FLAG(FT_OFFLOAD); + esw = priv->mdev->priv.eswitch; + switch (type) { + case TC_SETUP_CLSFLOWER: + if (!mlx5_eswitch_prios_supported(esw) || f->common.chain_index) + return -EOPNOTSUPP; + + /* Re-use tc offload path by moving the ft flow to the + * reserved ft chain. + */ + memcpy(&cls_flower, f, sizeof(*f)); + cls_flower.common.chain_index = FDB_FT_CHAIN; + err = mlx5e_rep_setup_tc_cls_flower(priv, &cls_flower, flags); + memcpy(&f->stats, &cls_flower.stats, sizeof(f->stats)); + return err; + default: + return -EOPNOTSUPP; + } +} + +static LIST_HEAD(mlx5e_rep_block_tc_cb_list); +static LIST_HEAD(mlx5e_rep_block_ft_cb_list); static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { struct mlx5e_priv *priv = netdev_priv(dev); struct flow_block_offload *f = type_data; + f->unlocked_driver_cb = true; + switch (type) { case TC_SETUP_BLOCK: - f->unlocked_driver_cb = true; return flow_block_cb_setup_simple(type_data, - &mlx5e_rep_block_cb_list, + &mlx5e_rep_block_tc_cb_list, mlx5e_rep_setup_tc_cb, priv, priv, true); + case TC_SETUP_FT: + return flow_block_cb_setup_simple(type_data, + &mlx5e_rep_block_ft_cb_list, + mlx5e_rep_setup_ft_cb, + priv, priv, true); default: return -EOPNOTSUPP; } @@ -1877,6 +1917,7 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) return -EINVAL; } + dev_net_set(netdev, mlx5_core_net(dev)); rpriv->netdev = netdev; rep->rep_data[REP_ETH].priv = rpriv; INIT_LIST_HEAD(&rpriv->vport_sqs_list); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 82cffb3a9964..9e9960146e5b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -1386,6 +1386,9 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget) if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state))) return 0; + if (rq->page_pool) + page_pool_nid_changed(rq->page_pool, numa_mem_id()); + if (rq->cqd.left) { work_done += mlx5e_decompress_cqes_cont(rq, cqwq, 0, budget); if (rq->cqd.left || work_done >= budget) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index f90a9f8e0fc6..0d5d84b5fa23 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -74,6 +74,7 @@ enum { MLX5E_TC_FLOW_FLAG_INGRESS = MLX5E_TC_FLAG_INGRESS_BIT, MLX5E_TC_FLOW_FLAG_EGRESS = MLX5E_TC_FLAG_EGRESS_BIT, MLX5E_TC_FLOW_FLAG_ESWITCH = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT, + MLX5E_TC_FLOW_FLAG_FT = MLX5E_TC_FLAG_FT_OFFLOAD_BIT, MLX5E_TC_FLOW_FLAG_NIC = MLX5E_TC_FLAG_NIC_OFFLOAD_BIT, MLX5E_TC_FLOW_FLAG_OFFLOADED = MLX5E_TC_FLOW_BASE, MLX5E_TC_FLOW_FLAG_HAIRPIN = MLX5E_TC_FLOW_BASE + 1, @@ -276,6 +277,11 @@ static bool mlx5e_is_eswitch_flow(struct mlx5e_tc_flow *flow) return flow_flag_test(flow, ESWITCH); } +static bool mlx5e_is_ft_flow(struct mlx5e_tc_flow *flow) +{ + return flow_flag_test(flow, FT); +} + static bool mlx5e_is_offloaded_flow(struct mlx5e_tc_flow *flow) { return flow_flag_test(flow, OFFLOADED); @@ -1074,7 +1080,7 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw, memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; slow_attr->split_count = 0; - slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN; + slow_attr->dest_chain = FDB_TC_SLOW_PATH_CHAIN; rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr); if (!IS_ERR(rule)) @@ -1091,7 +1097,7 @@ mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw, memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; slow_attr->split_count = 0; - slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN; + slow_attr->dest_chain = FDB_TC_SLOW_PATH_CHAIN; mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr); flow_flag_clear(flow, SLOW); } @@ -1168,7 +1174,12 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, return -EOPNOTSUPP; } - if (attr->chain > max_chain) { + /* We check chain range only for tc flows. + * For ft flows, we checked attr->chain was originally 0 and set it to + * FDB_FT_CHAIN which is outside tc range. + * See mlx5e_rep_setup_ft_cb(). + */ + if (!mlx5e_is_ft_flow(flow) && attr->chain > max_chain) { NL_SET_ERR_MSG(extack, "Requested chain is out of supported range"); return -EOPNOTSUPP; } @@ -2241,13 +2252,14 @@ out_err: struct mlx5_fields { u8 field; - u8 size; + u8 field_bsize; + u32 field_mask; u32 offset; u32 match_offset; }; -#define OFFLOAD(fw_field, size, field, off, match_field) \ - {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, size, \ +#define OFFLOAD(fw_field, field_bsize, field_mask, field, off, match_field) \ + {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, field_bsize, field_mask, \ offsetof(struct pedit_headers, field) + (off), \ MLX5_BYTE_OFF(fte_match_set_lyr_2_4, match_field)} @@ -2265,18 +2277,18 @@ struct mlx5_fields { }) static bool cmp_val_mask(void *valp, void *maskp, void *matchvalp, - void *matchmaskp, int size) + void *matchmaskp, u8 bsize) { bool same = false; - switch (size) { - case sizeof(u8): + switch (bsize) { + case 8: same = SAME_VAL_MASK(u8, valp, maskp, matchvalp, matchmaskp); break; - case sizeof(u16): + case 16: same = SAME_VAL_MASK(u16, valp, maskp, matchvalp, matchmaskp); break; - case sizeof(u32): + case 32: same = SAME_VAL_MASK(u32, valp, maskp, matchvalp, matchmaskp); break; } @@ -2285,41 +2297,43 @@ static bool cmp_val_mask(void *valp, void *maskp, void *matchvalp, } static struct mlx5_fields fields[] = { - OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0, dmac_47_16), - OFFLOAD(DMAC_15_0, 2, eth.h_dest[4], 0, dmac_15_0), - OFFLOAD(SMAC_47_16, 4, eth.h_source[0], 0, smac_47_16), - OFFLOAD(SMAC_15_0, 2, eth.h_source[4], 0, smac_15_0), - OFFLOAD(ETHERTYPE, 2, eth.h_proto, 0, ethertype), - OFFLOAD(FIRST_VID, 2, vlan.h_vlan_TCI, 0, first_vid), - - OFFLOAD(IP_TTL, 1, ip4.ttl, 0, ttl_hoplimit), - OFFLOAD(SIPV4, 4, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4), - OFFLOAD(DIPV4, 4, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), - - OFFLOAD(SIPV6_127_96, 4, ip6.saddr.s6_addr32[0], 0, + OFFLOAD(DMAC_47_16, 32, U32_MAX, eth.h_dest[0], 0, dmac_47_16), + OFFLOAD(DMAC_15_0, 16, U16_MAX, eth.h_dest[4], 0, dmac_15_0), + OFFLOAD(SMAC_47_16, 32, U32_MAX, eth.h_source[0], 0, smac_47_16), + OFFLOAD(SMAC_15_0, 16, U16_MAX, eth.h_source[4], 0, smac_15_0), + OFFLOAD(ETHERTYPE, 16, U16_MAX, eth.h_proto, 0, ethertype), + OFFLOAD(FIRST_VID, 16, U16_MAX, vlan.h_vlan_TCI, 0, first_vid), + + OFFLOAD(IP_DSCP, 8, 0xfc, ip4.tos, 0, ip_dscp), + OFFLOAD(IP_TTL, 8, U8_MAX, ip4.ttl, 0, ttl_hoplimit), + OFFLOAD(SIPV4, 32, U32_MAX, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4), + OFFLOAD(DIPV4, 32, U32_MAX, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), + + OFFLOAD(SIPV6_127_96, 32, U32_MAX, ip6.saddr.s6_addr32[0], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[0]), - OFFLOAD(SIPV6_95_64, 4, ip6.saddr.s6_addr32[1], 0, + OFFLOAD(SIPV6_95_64, 32, U32_MAX, ip6.saddr.s6_addr32[1], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[4]), - OFFLOAD(SIPV6_63_32, 4, ip6.saddr.s6_addr32[2], 0, + OFFLOAD(SIPV6_63_32, 32, U32_MAX, ip6.saddr.s6_addr32[2], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[8]), - OFFLOAD(SIPV6_31_0, 4, ip6.saddr.s6_addr32[3], 0, + OFFLOAD(SIPV6_31_0, 32, U32_MAX, ip6.saddr.s6_addr32[3], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[12]), - OFFLOAD(DIPV6_127_96, 4, ip6.daddr.s6_addr32[0], 0, + OFFLOAD(DIPV6_127_96, 32, U32_MAX, ip6.daddr.s6_addr32[0], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[0]), - OFFLOAD(DIPV6_95_64, 4, ip6.daddr.s6_addr32[1], 0, + OFFLOAD(DIPV6_95_64, 32, U32_MAX, ip6.daddr.s6_addr32[1], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[4]), - OFFLOAD(DIPV6_63_32, 4, ip6.daddr.s6_addr32[2], 0, + OFFLOAD(DIPV6_63_32, 32, U32_MAX, ip6.daddr.s6_addr32[2], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[8]), - OFFLOAD(DIPV6_31_0, 4, ip6.daddr.s6_addr32[3], 0, + OFFLOAD(DIPV6_31_0, 32, U32_MAX, ip6.daddr.s6_addr32[3], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[12]), - OFFLOAD(IPV6_HOPLIMIT, 1, ip6.hop_limit, 0, ttl_hoplimit), + OFFLOAD(IPV6_HOPLIMIT, 8, U8_MAX, ip6.hop_limit, 0, ttl_hoplimit), - OFFLOAD(TCP_SPORT, 2, tcp.source, 0, tcp_sport), - OFFLOAD(TCP_DPORT, 2, tcp.dest, 0, tcp_dport), - OFFLOAD(TCP_FLAGS, 1, tcp.ack_seq, 5, tcp_flags), + OFFLOAD(TCP_SPORT, 16, U16_MAX, tcp.source, 0, tcp_sport), + OFFLOAD(TCP_DPORT, 16, U16_MAX, tcp.dest, 0, tcp_dport), + /* in linux iphdr tcp_flags is 8 bits long */ + OFFLOAD(TCP_FLAGS, 8, U8_MAX, tcp.ack_seq, 5, tcp_flags), - OFFLOAD(UDP_SPORT, 2, udp.source, 0, udp_sport), - OFFLOAD(UDP_DPORT, 2, udp.dest, 0, udp_dport), + OFFLOAD(UDP_SPORT, 16, U16_MAX, udp.source, 0, udp_sport), + OFFLOAD(UDP_DPORT, 16, U16_MAX, udp.dest, 0, udp_dport), }; /* On input attr->max_mod_hdr_actions tells how many HW actions can be parsed at @@ -2332,19 +2346,17 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, struct netlink_ext_ack *extack) { struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals; - void *headers_c = get_match_headers_criteria(*action_flags, - &parse_attr->spec); - void *headers_v = get_match_headers_value(*action_flags, - &parse_attr->spec); int i, action_size, nactions, max_actions, first, last, next_z; - void *s_masks_p, *a_masks_p, *vals_p; + void *headers_c, *headers_v, *action, *vals_p; + u32 *s_masks_p, *a_masks_p, s_mask, a_mask; struct mlx5_fields *f; - u8 cmd, field_bsize; - u32 s_mask, a_mask; unsigned long mask; __be32 mask_be32; __be16 mask_be16; - void *action; + u8 cmd; + + headers_c = get_match_headers_criteria(*action_flags, &parse_attr->spec); + headers_v = get_match_headers_value(*action_flags, &parse_attr->spec); set_masks = &hdrs[0].masks; add_masks = &hdrs[1].masks; @@ -2369,8 +2381,8 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, s_masks_p = (void *)set_masks + f->offset; a_masks_p = (void *)add_masks + f->offset; - memcpy(&s_mask, s_masks_p, f->size); - memcpy(&a_mask, a_masks_p, f->size); + s_mask = *s_masks_p & f->field_mask; + a_mask = *a_masks_p & f->field_mask; if (!s_mask && !a_mask) /* nothing to offload here */ continue; @@ -2399,38 +2411,34 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, vals_p = (void *)set_vals + f->offset; /* don't rewrite if we have a match on the same value */ if (cmp_val_mask(vals_p, s_masks_p, match_val, - match_mask, f->size)) + match_mask, f->field_bsize)) skip = true; /* clear to denote we consumed this field */ - memset(s_masks_p, 0, f->size); + *s_masks_p &= ~f->field_mask; } else { - u32 zero = 0; - cmd = MLX5_ACTION_TYPE_ADD; mask = a_mask; vals_p = (void *)add_vals + f->offset; /* add 0 is no change */ - if (!memcmp(vals_p, &zero, f->size)) + if ((*(u32 *)vals_p & f->field_mask) == 0) skip = true; /* clear to denote we consumed this field */ - memset(a_masks_p, 0, f->size); + *a_masks_p &= ~f->field_mask; } if (skip) continue; - field_bsize = f->size * BITS_PER_BYTE; - - if (field_bsize == 32) { + if (f->field_bsize == 32) { mask_be32 = *(__be32 *)&mask; mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32)); - } else if (field_bsize == 16) { + } else if (f->field_bsize == 16) { mask_be16 = *(__be16 *)&mask; mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16)); } - first = find_first_bit(&mask, field_bsize); - next_z = find_next_zero_bit(&mask, field_bsize, first); - last = find_last_bit(&mask, field_bsize); + first = find_first_bit(&mask, f->field_bsize); + next_z = find_next_zero_bit(&mask, f->field_bsize, first); + last = find_last_bit(&mask, f->field_bsize); if (first < next_z && next_z < last) { NL_SET_ERR_MSG_MOD(extack, "rewrite of few sub-fields isn't supported"); @@ -2443,16 +2451,22 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, MLX5_SET(set_action_in, action, field, f->field); if (cmd == MLX5_ACTION_TYPE_SET) { - MLX5_SET(set_action_in, action, offset, first); + int start; + + /* if field is bit sized it can start not from first bit */ + start = find_first_bit((unsigned long *)&f->field_mask, + f->field_bsize); + + MLX5_SET(set_action_in, action, offset, first - start); /* length is num of bits to be written, zero means length of 32 */ MLX5_SET(set_action_in, action, length, (last - first + 1)); } - if (field_bsize == 32) + if (f->field_bsize == 32) MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p) >> first); - else if (field_bsize == 16) + else if (f->field_bsize == 16) MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p) >> first); - else if (field_bsize == 8) + else if (f->field_bsize == 8) MLX5_SET(set_action_in, action, data, *(u8 *)vals_p >> first); action += action_size; @@ -3214,6 +3228,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr; struct mlx5e_rep_priv *rpriv = priv->ppriv; const struct ip_tunnel_info *info = NULL; + bool ft_flow = mlx5e_is_ft_flow(flow); const struct flow_action_entry *act; bool encap = false; u32 action = 0; @@ -3258,6 +3273,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, return -EINVAL; } + if (ft_flow && out_dev == priv->netdev) { + /* Ignore forward to self rules generated + * by adding both mlx5 devs to the flow table + * block on a normal nft offload setup. + */ + return -EOPNOTSUPP; + } + if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) { NL_SET_ERR_MSG_MOD(extack, "can't support more output ports, can't offload forwarding"); @@ -3382,6 +3405,10 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, u32 dest_chain = act->chain_index; u32 max_chain = mlx5_eswitch_get_chain_range(esw); + if (ft_flow) { + NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported"); + return -EOPNOTSUPP; + } if (dest_chain <= attr->chain) { NL_SET_ERR_MSG(extack, "Goto earlier chain isn't supported"); return -EOPNOTSUPP; @@ -3443,6 +3470,12 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; } + if (!(attr->action & + (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) { + NL_SET_ERR_MSG(extack, "Rule must have at least one forward/drop action"); + return -EOPNOTSUPP; + } + if (attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) { NL_SET_ERR_MSG_MOD(extack, "current firmware doesn't support split rule for port mirroring"); @@ -3466,6 +3499,8 @@ static void get_flags(int flags, unsigned long *flow_flags) __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_ESWITCH); if (flags & MLX5_TC_FLAG(NIC_OFFLOAD)) __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_NIC); + if (flags & MLX5_TC_FLAG(FT_OFFLOAD)) + __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_FT); *flow_flags = __flow_flags; } @@ -3841,7 +3876,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv, int err; rcu_read_lock(); - flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params); + flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params); if (!flow || !same_flow_direction(flow, flags)) { err = -EINVAL; goto errout; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h index 924c6ef86a14..262cdb7b69b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h @@ -44,7 +44,8 @@ enum { MLX5E_TC_FLAG_EGRESS_BIT, MLX5E_TC_FLAG_NIC_OFFLOAD_BIT, MLX5E_TC_FLAG_ESW_OFFLOAD_BIT, - MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT, + MLX5E_TC_FLAG_FT_OFFLOAD_BIT, + MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_FT_OFFLOAD_BIT, }; #define MLX5_TC_FLAG(flag) BIT(MLX5E_TC_FLAG_##flag##_BIT) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 67dc4f0921b6..66951ff975f4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -461,8 +461,14 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) if (unlikely(get_cqe_opcode(cqe) == MLX5_CQE_REQ_ERR)) { if (!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) { + struct mlx5e_tx_wqe_info *wi; + u16 ci; + + ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc); + wi = &sq->db.wqe_info[ci]; mlx5e_dump_error_cqe(sq, (struct mlx5_err_cqe *)cqe); + mlx5_wq_cyc_wqe_dump(&sq->wq, ci, wi->num_wqebbs); queue_work(cq->channel->priv->wq, &sq->recover_work); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 60fddf8afc99..2c965ad0d744 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -111,42 +111,32 @@ static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport, } /* E-Switch vport context HW commands */ -static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport, - void *in, int inlen) +int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, + void *in, int inlen) { u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0}; MLX5_SET(modify_esw_vport_context_in, in, opcode, MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT); MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport); - MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); + MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport); return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); } -int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, - void *in, int inlen) -{ - return modify_esw_vport_context_cmd(esw->dev, vport, in, inlen); -} - -static int query_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport, - void *out, int outlen) +int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, + void *out, int outlen) { u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; MLX5_SET(query_esw_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport); - MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); + MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport); return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen); } -int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, - void *out, int outlen) -{ - return query_esw_vport_context_cmd(esw->dev, vport, out, outlen); -} - static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport, u16 vlan, u8 qos, u8 set_flags) { @@ -179,7 +169,8 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport, MLX5_SET(modify_esw_vport_context_in, in, field_select.vport_cvlan_insert, 1); - return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in)); + return mlx5_eswitch_modify_esw_vport_context(dev, vport, true, + in, sizeof(in)); } /* E-Switch FDB */ @@ -452,6 +443,13 @@ static int esw_create_legacy_table(struct mlx5_eswitch *esw) return err; } +static void esw_destroy_legacy_table(struct mlx5_eswitch *esw) +{ + esw_cleanup_vepa_rules(esw); + esw_destroy_legacy_fdb_table(esw); + esw_destroy_legacy_vepa_table(esw); +} + #define MLX5_LEGACY_SRIOV_VPORT_EVENTS (MLX5_VPORT_UC_ADDR_CHANGE | \ MLX5_VPORT_MC_ADDR_CHANGE | \ MLX5_VPORT_PROMISC_CHANGE) @@ -464,15 +462,10 @@ static int esw_legacy_enable(struct mlx5_eswitch *esw) if (ret) return ret; - mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_LEGACY_SRIOV_VPORT_EVENTS); - return 0; -} - -static void esw_destroy_legacy_table(struct mlx5_eswitch *esw) -{ - esw_cleanup_vepa_rules(esw); - esw_destroy_legacy_fdb_table(esw); - esw_destroy_legacy_vepa_table(esw); + ret = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_LEGACY_SRIOV_VPORT_EVENTS); + if (ret) + esw_destroy_legacy_table(esw); + return ret; } static void esw_legacy_disable(struct mlx5_eswitch *esw) @@ -501,7 +494,7 @@ static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) /* Skip mlx5_mpfs_add_mac for eswitch_managers, * it is already done by its netdev in mlx5e_execute_l2_action */ - if (esw->manager_vport == vport) + if (mlx5_esw_is_manager_vport(esw, vport)) goto fdb_add; err = mlx5_mpfs_add_mac(esw->dev, mac); @@ -530,10 +523,10 @@ static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) u16 vport = vaddr->vport; int err = 0; - /* Skip mlx5_mpfs_del_mac for eswitch managerss, + /* Skip mlx5_mpfs_del_mac for eswitch managers, * it is already done by its netdev in mlx5e_execute_l2_action */ - if (!vaddr->mpfs || esw->manager_vport == vport) + if (!vaddr->mpfs || mlx5_esw_is_manager_vport(esw, vport)) goto fdb_del; err = mlx5_mpfs_del_mac(esw->dev, mac); @@ -1040,14 +1033,15 @@ out: void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) + if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) { mlx5_del_flow_rules(vport->egress.allowed_vlan); + vport->egress.allowed_vlan = NULL; + } - if (!IS_ERR_OR_NULL(vport->egress.drop_rule)) - mlx5_del_flow_rules(vport->egress.drop_rule); - - vport->egress.allowed_vlan = NULL; - vport->egress.drop_rule = NULL; + if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) { + mlx5_del_flow_rules(vport->egress.legacy.drop_rule); + vport->egress.legacy.drop_rule = NULL; + } } void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, @@ -1067,57 +1061,21 @@ void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, vport->egress.acl = NULL; } -int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int +esw_vport_create_legacy_ingress_acl_groups(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_core_dev *dev = esw->dev; - struct mlx5_flow_namespace *root_ns; - struct mlx5_flow_table *acl; struct mlx5_flow_group *g; void *match_criteria; u32 *flow_group_in; - /* The ingress acl table contains 4 groups - * (2 active rules at the same time - - * 1 allow rule from one of the first 3 groups. - * 1 drop rule from the last group): - * 1)Allow untagged traffic with smac=original mac. - * 2)Allow untagged traffic. - * 3)Allow traffic with smac=original mac. - * 4)Drop all other traffic. - */ - int table_size = 4; - int err = 0; - - if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) - return -EOPNOTSUPP; - - if (!IS_ERR_OR_NULL(vport->ingress.acl)) - return 0; - - esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", - vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size)); - - root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS, - mlx5_eswitch_vport_num_to_index(esw, vport->vport)); - if (!root_ns) { - esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n", vport->vport); - return -EOPNOTSUPP; - } + int err; flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; - acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); - if (IS_ERR(acl)) { - err = PTR_ERR(acl); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow Table, err(%d)\n", - vport->vport, err); - goto out; - } - vport->ingress.acl = acl; - match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); @@ -1127,14 +1085,14 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress untagged spoofchk flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create untagged spoofchk flow group, err(%d)\n", vport->vport, err); - goto out; + goto spoof_err; } - vport->ingress.allow_untagged_spoofchk_grp = g; + vport->ingress.legacy.allow_untagged_spoofchk_grp = g; memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); @@ -1142,14 +1100,14 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress untagged flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create untagged flow group, err(%d)\n", vport->vport, err); - goto out; + goto untagged_err; } - vport->ingress.allow_untagged_only_grp = g; + vport->ingress.legacy.allow_untagged_only_grp = g; memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); @@ -1158,108 +1116,178 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 2); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 2); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress spoofchk flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create spoofchk flow group, err(%d)\n", vport->vport, err); - goto out; + goto allow_spoof_err; } - vport->ingress.allow_spoofchk_only_grp = g; + vport->ingress.legacy.allow_spoofchk_only_grp = g; memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 3); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 3); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress drop flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create drop flow group, err(%d)\n", vport->vport, err); - goto out; + goto drop_err; } - vport->ingress.drop_grp = g; + vport->ingress.legacy.drop_grp = g; + kvfree(flow_group_in); + return 0; -out: - if (err) { - if (!IS_ERR_OR_NULL(vport->ingress.allow_spoofchk_only_grp)) - mlx5_destroy_flow_group( - vport->ingress.allow_spoofchk_only_grp); - if (!IS_ERR_OR_NULL(vport->ingress.allow_untagged_only_grp)) - mlx5_destroy_flow_group( - vport->ingress.allow_untagged_only_grp); - if (!IS_ERR_OR_NULL(vport->ingress.allow_untagged_spoofchk_grp)) - mlx5_destroy_flow_group( - vport->ingress.allow_untagged_spoofchk_grp); - if (!IS_ERR_OR_NULL(vport->ingress.acl)) - mlx5_destroy_flow_table(vport->ingress.acl); +drop_err: + if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_spoofchk_only_grp)) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp); + vport->ingress.legacy.allow_spoofchk_only_grp = NULL; } - +allow_spoof_err: + if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_only_grp)) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp); + vport->ingress.legacy.allow_untagged_only_grp = NULL; + } +untagged_err: + if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_spoofchk_grp)) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp); + vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL; + } +spoof_err: kvfree(flow_group_in); return err; } +int esw_vport_create_ingress_acl_table(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, int table_size) +{ + struct mlx5_core_dev *dev = esw->dev; + struct mlx5_flow_namespace *root_ns; + struct mlx5_flow_table *acl; + int vport_index; + int err; + + if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) + return -EOPNOTSUPP; + + esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", + vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size)); + + vport_index = mlx5_eswitch_vport_num_to_index(esw, vport->vport); + root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS, + vport_index); + if (!root_ns) { + esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n", + vport->vport); + return -EOPNOTSUPP; + } + + acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); + if (IS_ERR(acl)) { + err = PTR_ERR(acl); + esw_warn(dev, "vport[%d] ingress create flow Table, err(%d)\n", + vport->vport, err); + return err; + } + vport->ingress.acl = acl; + return 0; +} + +void esw_vport_destroy_ingress_acl_table(struct mlx5_vport *vport) +{ + if (!vport->ingress.acl) + return; + + mlx5_destroy_flow_table(vport->ingress.acl); + vport->ingress.acl = NULL; +} + void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - if (!IS_ERR_OR_NULL(vport->ingress.drop_rule)) - mlx5_del_flow_rules(vport->ingress.drop_rule); + if (vport->ingress.legacy.drop_rule) { + mlx5_del_flow_rules(vport->ingress.legacy.drop_rule); + vport->ingress.legacy.drop_rule = NULL; + } - if (!IS_ERR_OR_NULL(vport->ingress.allow_rule)) + if (vport->ingress.allow_rule) { mlx5_del_flow_rules(vport->ingress.allow_rule); - - vport->ingress.drop_rule = NULL; - vport->ingress.allow_rule = NULL; - - esw_vport_del_ingress_acl_modify_metadata(esw, vport); + vport->ingress.allow_rule = NULL; + } } -void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static void esw_vport_disable_legacy_ingress_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - if (IS_ERR_OR_NULL(vport->ingress.acl)) + if (!vport->ingress.acl) return; esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport); esw_vport_cleanup_ingress_rules(esw, vport); - mlx5_destroy_flow_group(vport->ingress.allow_spoofchk_only_grp); - mlx5_destroy_flow_group(vport->ingress.allow_untagged_only_grp); - mlx5_destroy_flow_group(vport->ingress.allow_untagged_spoofchk_grp); - mlx5_destroy_flow_group(vport->ingress.drop_grp); - mlx5_destroy_flow_table(vport->ingress.acl); - vport->ingress.acl = NULL; - vport->ingress.drop_grp = NULL; - vport->ingress.allow_spoofchk_only_grp = NULL; - vport->ingress.allow_untagged_only_grp = NULL; - vport->ingress.allow_untagged_spoofchk_grp = NULL; + if (vport->ingress.legacy.allow_spoofchk_only_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp); + vport->ingress.legacy.allow_spoofchk_only_grp = NULL; + } + if (vport->ingress.legacy.allow_untagged_only_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp); + vport->ingress.legacy.allow_untagged_only_grp = NULL; + } + if (vport->ingress.legacy.allow_untagged_spoofchk_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp); + vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL; + } + if (vport->ingress.legacy.drop_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.drop_grp); + vport->ingress.legacy.drop_grp = NULL; + } + esw_vport_destroy_ingress_acl_table(vport); } static int esw_vport_ingress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - struct mlx5_fc *counter = vport->ingress.drop_counter; + struct mlx5_fc *counter = vport->ingress.legacy.drop_counter; struct mlx5_flow_destination drop_ctr_dst = {0}; struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_spec *spec; + struct mlx5_flow_spec *spec = NULL; int dest_num = 0; int err = 0; u8 *smac_v; + /* The ingress acl table contains 4 groups + * (2 active rules at the same time - + * 1 allow rule from one of the first 3 groups. + * 1 drop rule from the last group): + * 1)Allow untagged traffic with smac=original mac. + * 2)Allow untagged traffic. + * 3)Allow traffic with smac=original mac. + * 4)Drop all other traffic. + */ + int table_size = 4; + esw_vport_cleanup_ingress_rules(esw, vport); if (!vport->info.vlan && !vport->info.qos && !vport->info.spoofchk) { - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_disable_legacy_ingress_acl(esw, vport); return 0; } - err = esw_vport_enable_ingress_acl(esw, vport); - if (err) { - mlx5_core_warn(esw->dev, - "failed to enable ingress acl (%d) on vport[%d]\n", - err, vport->vport); - return err; + if (!vport->ingress.acl) { + err = esw_vport_create_ingress_acl_table(esw, vport, table_size); + if (err) { + esw_warn(esw->dev, + "vport[%d] enable ingress acl err (%d)\n", + err, vport->vport); + return err; + } + + err = esw_vport_create_legacy_ingress_acl_groups(esw, vport); + if (err) + goto out; } esw_debug(esw->dev, @@ -1309,21 +1337,59 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, dst = &drop_ctr_dst; dest_num++; } - vport->ingress.drop_rule = + vport->ingress.legacy.drop_rule = mlx5_add_flow_rules(vport->ingress.acl, spec, &flow_act, dst, dest_num); - if (IS_ERR(vport->ingress.drop_rule)) { - err = PTR_ERR(vport->ingress.drop_rule); + if (IS_ERR(vport->ingress.legacy.drop_rule)) { + err = PTR_ERR(vport->ingress.legacy.drop_rule); esw_warn(esw->dev, "vport[%d] configure ingress drop rule, err(%d)\n", vport->vport, err); - vport->ingress.drop_rule = NULL; + vport->ingress.legacy.drop_rule = NULL; goto out; } + kvfree(spec); + return 0; out: - if (err) - esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_disable_legacy_ingress_acl(esw, vport); + kvfree(spec); + return err; +} + +int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, + u16 vlan_id, u32 flow_action) +{ + struct mlx5_flow_act flow_act = {}; + struct mlx5_flow_spec *spec; + int err = 0; + + if (vport->egress.allowed_vlan) + return -EEXIST; + + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id); + + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + flow_act.action = flow_action; + vport->egress.allowed_vlan = + mlx5_add_flow_rules(vport->egress.acl, spec, + &flow_act, NULL, 0); + if (IS_ERR(vport->egress.allowed_vlan)) { + err = PTR_ERR(vport->egress.allowed_vlan); + esw_warn(esw->dev, + "vport[%d] configure egress vlan rule failed, err(%d)\n", + vport->vport, err); + vport->egress.allowed_vlan = NULL; + } + kvfree(spec); return err; } @@ -1331,7 +1397,7 @@ out: static int esw_vport_egress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - struct mlx5_fc *counter = vport->egress.drop_counter; + struct mlx5_fc *counter = vport->egress.legacy.drop_counter; struct mlx5_flow_destination drop_ctr_dst = {0}; struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_act flow_act = {0}; @@ -1358,34 +1424,17 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); - spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) { - err = -ENOMEM; - goto out; - } - /* Allowed vlan rule */ - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); - MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vport->info.vlan); + err = mlx5_esw_create_vport_egress_acl_vlan(esw, vport, vport->info.vlan, + MLX5_FLOW_CONTEXT_ACTION_ALLOW); + if (err) + return err; - spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; - vport->egress.allowed_vlan = - mlx5_add_flow_rules(vport->egress.acl, spec, - &flow_act, NULL, 0); - if (IS_ERR(vport->egress.allowed_vlan)) { - err = PTR_ERR(vport->egress.allowed_vlan); - esw_warn(esw->dev, - "vport[%d] configure egress allowed vlan rule failed, err(%d)\n", - vport->vport, err); - vport->egress.allowed_vlan = NULL; + /* Drop others rule (star rule) */ + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) goto out; - } - /* Drop others rule (star rule) */ - memset(spec, 0, sizeof(*spec)); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; /* Attach egress drop flow counter */ @@ -1396,15 +1445,15 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, dst = &drop_ctr_dst; dest_num++; } - vport->egress.drop_rule = + vport->egress.legacy.drop_rule = mlx5_add_flow_rules(vport->egress.acl, spec, &flow_act, dst, dest_num); - if (IS_ERR(vport->egress.drop_rule)) { - err = PTR_ERR(vport->egress.drop_rule); + if (IS_ERR(vport->egress.legacy.drop_rule)) { + err = PTR_ERR(vport->egress.legacy.drop_rule); esw_warn(esw->dev, "vport[%d] configure egress drop rule failed, err(%d)\n", vport->vport, err); - vport->egress.drop_rule = NULL; + vport->egress.legacy.drop_rule = NULL; } out: kvfree(spec); @@ -1619,7 +1668,7 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw, u16 vport_num = vport->vport; int flags; - if (esw->manager_vport == vport_num) + if (mlx5_esw_is_manager_vport(esw, vport_num)) return; mlx5_modify_vport_admin_state(esw->dev, @@ -1639,66 +1688,112 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw, SET_VLAN_STRIP | SET_VLAN_INSERT : 0; modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, vport->info.qos, flags); - - /* Only legacy mode needs ACLs */ - if (esw->mode == MLX5_ESWITCH_LEGACY) { - esw_vport_ingress_config(esw, vport); - esw_vport_egress_config(esw, vport); - } } -static void esw_vport_create_drop_counters(struct mlx5_vport *vport) +static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - struct mlx5_core_dev *dev = vport->dev; + int ret; - if (MLX5_CAP_ESW_INGRESS_ACL(dev, flow_counter)) { - vport->ingress.drop_counter = mlx5_fc_create(dev, false); - if (IS_ERR(vport->ingress.drop_counter)) { - esw_warn(dev, + /* Only non manager vports need ACL in legacy mode */ + if (mlx5_esw_is_manager_vport(esw, vport->vport)) + return 0; + + if (!mlx5_esw_is_manager_vport(esw, vport->vport) && + MLX5_CAP_ESW_INGRESS_ACL(esw->dev, flow_counter)) { + vport->ingress.legacy.drop_counter = mlx5_fc_create(esw->dev, false); + if (IS_ERR(vport->ingress.legacy.drop_counter)) { + esw_warn(esw->dev, "vport[%d] configure ingress drop rule counter failed\n", vport->vport); - vport->ingress.drop_counter = NULL; + vport->ingress.legacy.drop_counter = NULL; } } - if (MLX5_CAP_ESW_EGRESS_ACL(dev, flow_counter)) { - vport->egress.drop_counter = mlx5_fc_create(dev, false); - if (IS_ERR(vport->egress.drop_counter)) { - esw_warn(dev, + ret = esw_vport_ingress_config(esw, vport); + if (ret) + goto ingress_err; + + if (!mlx5_esw_is_manager_vport(esw, vport->vport) && + MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) { + vport->egress.legacy.drop_counter = mlx5_fc_create(esw->dev, false); + if (IS_ERR(vport->egress.legacy.drop_counter)) { + esw_warn(esw->dev, "vport[%d] configure egress drop rule counter failed\n", vport->vport); - vport->egress.drop_counter = NULL; + vport->egress.legacy.drop_counter = NULL; } } + + ret = esw_vport_egress_config(esw, vport); + if (ret) + goto egress_err; + + return 0; + +egress_err: + esw_vport_disable_legacy_ingress_acl(esw, vport); + mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); + vport->egress.legacy.drop_counter = NULL; + +ingress_err: + mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter); + vport->ingress.legacy.drop_counter = NULL; + return ret; } -static void esw_vport_destroy_drop_counters(struct mlx5_vport *vport) +static int esw_vport_setup_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - struct mlx5_core_dev *dev = vport->dev; + if (esw->mode == MLX5_ESWITCH_LEGACY) + return esw_vport_create_legacy_acl_tables(esw, vport); + else + return esw_vport_create_offloads_acl_tables(esw, vport); +} + +static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) - if (vport->ingress.drop_counter) - mlx5_fc_destroy(dev, vport->ingress.drop_counter); - if (vport->egress.drop_counter) - mlx5_fc_destroy(dev, vport->egress.drop_counter); +{ + if (mlx5_esw_is_manager_vport(esw, vport->vport)) + return; + + esw_vport_disable_egress_acl(esw, vport); + mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); + vport->egress.legacy.drop_counter = NULL; + + esw_vport_disable_legacy_ingress_acl(esw, vport); + mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter); + vport->ingress.legacy.drop_counter = NULL; } -static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, - enum mlx5_eswitch_vport_event enabled_events) +static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + if (esw->mode == MLX5_ESWITCH_LEGACY) + esw_vport_destroy_legacy_acl_tables(esw, vport); + else + esw_vport_destroy_offloads_acl_tables(esw, vport); +} + +static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, + enum mlx5_eswitch_vport_event enabled_events) { u16 vport_num = vport->vport; + int ret; mutex_lock(&esw->state_lock); WARN_ON(vport->enabled); esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num); - /* Create steering drop counters for ingress and egress ACLs */ - if (vport_num && esw->mode == MLX5_ESWITCH_LEGACY) - esw_vport_create_drop_counters(vport); - /* Restore old vport configuration */ esw_apply_vport_conf(esw, vport); + ret = esw_vport_setup_acl(esw, vport); + if (ret) + goto done; + /* Attach vport to the eswitch rate limiter */ if (esw_vport_enable_qos(esw, vport, vport->info.max_rate, vport->qos.bw_share)) @@ -1711,7 +1806,7 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, /* Esw manager is trusted by default. Host PF (vport 0) is trusted as well * in smartNIC as it's a vport group manager. */ - if (esw->manager_vport == vport_num || + if (mlx5_esw_is_manager_vport(esw, vport_num) || (!vport_num && mlx5_core_is_ecpf(esw->dev))) vport->info.trusted = true; @@ -1719,7 +1814,9 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, esw->enabled_vports++; esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num); +done: mutex_unlock(&esw->state_lock); + return ret; } static void esw_disable_vport(struct mlx5_eswitch *esw, @@ -1727,18 +1824,16 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, { u16 vport_num = vport->vport; + mutex_lock(&esw->state_lock); if (!vport->enabled) - return; + goto done; esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num); /* Mark this vport as disabled to discard new events */ vport->enabled = false; - /* Wait for current already scheduled events to complete */ - flush_workqueue(esw->work_queue); /* Disable events from this vport */ arm_vport_context_events_cmd(esw->dev, vport->vport, 0); - mutex_lock(&esw->state_lock); /* We don't assume VFs will cleanup after themselves. * Calling vport change handler while vport is disabled will cleanup * the vport resources. @@ -1746,17 +1841,18 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, esw_vport_change_handle_locked(vport); vport->enabled_events = 0; esw_vport_disable_qos(esw, vport); - if (esw->manager_vport != vport_num && - esw->mode == MLX5_ESWITCH_LEGACY) { + + if (!mlx5_esw_is_manager_vport(esw, vport->vport) && + esw->mode == MLX5_ESWITCH_LEGACY) mlx5_modify_vport_admin_state(esw->dev, MLX5_VPORT_STATE_OP_MOD_ESW_VPORT, vport_num, 1, MLX5_VPORT_ADMIN_STATE_DOWN); - esw_vport_disable_egress_acl(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); - esw_vport_destroy_drop_counters(vport); - } + + esw_vport_cleanup_acl(esw, vport); esw->enabled_vports--; + +done: mutex_unlock(&esw->state_lock); } @@ -1770,12 +1866,8 @@ static int eswitch_vport_event(struct notifier_block *nb, vport_num = be16_to_cpu(eqe->data.vport_change.vport_num); vport = mlx5_eswitch_get_vport(esw, vport_num); - if (IS_ERR(vport)) - return NOTIFY_OK; - - if (vport->enabled) + if (!IS_ERR(vport)) queue_work(esw->work_queue, &vport->vport_change_handler); - return NOTIFY_OK; } @@ -1831,32 +1923,66 @@ static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw) flush_workqueue(esw->work_queue); } +static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw) +{ + struct mlx5_vport *vport; + int i; + + mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) + memset(&vport->info, 0, sizeof(vport->info)); +} + /* Public E-Switch API */ #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev)) /* mlx5_eswitch_enable_pf_vf_vports() enables vports of PF, ECPF and VFs * whichever are present on the eswitch. */ -void +int mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, enum mlx5_eswitch_vport_event enabled_events) { struct mlx5_vport *vport; + int num_vfs; + int ret; int i; /* Enable PF vport */ vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF); - esw_enable_vport(esw, vport, enabled_events); + ret = esw_enable_vport(esw, vport, enabled_events); + if (ret) + return ret; - /* Enable ECPF vports */ + /* Enable ECPF vport */ if (mlx5_ecpf_vport_exists(esw->dev)) { vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF); - esw_enable_vport(esw, vport, enabled_events); + ret = esw_enable_vport(esw, vport, enabled_events); + if (ret) + goto ecpf_err; } /* Enable VF vports */ - mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) - esw_enable_vport(esw, vport, enabled_events); + mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) { + ret = esw_enable_vport(esw, vport, enabled_events); + if (ret) + goto vf_err; + } + return 0; + +vf_err: + num_vfs = i - 1; + mlx5_esw_for_each_vf_vport_reverse(esw, i, vport, num_vfs) + esw_disable_vport(esw, vport); + + if (mlx5_ecpf_vport_exists(esw->dev)) { + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF); + esw_disable_vport(esw, vport); + } + +ecpf_err: + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF); + esw_disable_vport(esw, vport); + return ret; } /* mlx5_eswitch_disable_pf_vf_vports() disables vports of PF, ECPF and VFs @@ -1923,7 +2049,7 @@ abort: return err; } -void mlx5_eswitch_disable(struct mlx5_eswitch *esw) +void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf) { int old_mode; @@ -1952,6 +2078,8 @@ void mlx5_eswitch_disable(struct mlx5_eswitch *esw) mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB); mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH); } + if (clear_vf) + mlx5_eswitch_clear_vf_vports_info(esw); } int mlx5_eswitch_init(struct mlx5_core_dev *dev) @@ -2474,12 +2602,12 @@ static int mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev, if (!vport->enabled || esw->mode != MLX5_ESWITCH_LEGACY) return 0; - if (vport->egress.drop_counter) - mlx5_fc_query(dev, vport->egress.drop_counter, + if (vport->egress.legacy.drop_counter) + mlx5_fc_query(dev, vport->egress.legacy.drop_counter, &stats->rx_dropped, &bytes); - if (vport->ingress.drop_counter) - mlx5_fc_query(dev, vport->ingress.drop_counter, + if (vport->ingress.legacy.drop_counter) + mlx5_fc_query(dev, vport->ingress.legacy.drop_counter, &stats->tx_dropped, &bytes); if (!MLX5_CAP_GEN(dev, receive_discard_vport_down) && diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 6bd6f5895244..962888a7c3c9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -43,6 +43,16 @@ #include <linux/mlx5/fs.h> #include "lib/mpfs.h" +#define FDB_TC_MAX_CHAIN 3 +#define FDB_FT_CHAIN (FDB_TC_MAX_CHAIN + 1) +#define FDB_TC_SLOW_PATH_CHAIN (FDB_FT_CHAIN + 1) + +/* The index of the last real chain (FT) + 1 as chain zero is valid as well */ +#define FDB_NUM_CHAINS (FDB_FT_CHAIN + 1) + +#define FDB_TC_MAX_PRIO 16 +#define FDB_TC_LEVELS_PER_PRIO 2 + #ifdef CONFIG_MLX5_ESWITCH #define MLX5_MAX_UC_PER_VPORT(dev) \ @@ -59,21 +69,22 @@ #define mlx5_esw_has_fwd_fdb(dev) \ MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_to_table) -#define FDB_MAX_CHAIN 3 -#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) -#define FDB_MAX_PRIO 16 - struct vport_ingress { struct mlx5_flow_table *acl; - struct mlx5_flow_group *allow_untagged_spoofchk_grp; - struct mlx5_flow_group *allow_spoofchk_only_grp; - struct mlx5_flow_group *allow_untagged_only_grp; - struct mlx5_flow_group *drop_grp; - struct mlx5_modify_hdr *modify_metadata; - struct mlx5_flow_handle *modify_metadata_rule; - struct mlx5_flow_handle *allow_rule; - struct mlx5_flow_handle *drop_rule; - struct mlx5_fc *drop_counter; + struct mlx5_flow_handle *allow_rule; + struct { + struct mlx5_flow_group *allow_spoofchk_only_grp; + struct mlx5_flow_group *allow_untagged_spoofchk_grp; + struct mlx5_flow_group *allow_untagged_only_grp; + struct mlx5_flow_group *drop_grp; + struct mlx5_flow_handle *drop_rule; + struct mlx5_fc *drop_counter; + } legacy; + struct { + struct mlx5_flow_group *metadata_grp; + struct mlx5_modify_hdr *modify_metadata; + struct mlx5_flow_handle *modify_metadata_rule; + } offloads; }; struct vport_egress { @@ -81,8 +92,10 @@ struct vport_egress { struct mlx5_flow_group *allowed_vlans_grp; struct mlx5_flow_group *drop_grp; struct mlx5_flow_handle *allowed_vlan; - struct mlx5_flow_handle *drop_rule; - struct mlx5_fc *drop_counter; + struct { + struct mlx5_flow_handle *drop_rule; + struct mlx5_fc *drop_counter; + } legacy; }; struct mlx5_vport_drop_stats { @@ -139,7 +152,6 @@ enum offloads_fdb_flags { extern const unsigned int ESW_POOLS[4]; -#define PRIO_LEVELS 2 struct mlx5_eswitch_fdb { union { struct legacy_fdb { @@ -166,7 +178,7 @@ struct mlx5_eswitch_fdb { struct { struct mlx5_flow_table *fdb; u32 num_rules; - } fdb_prio[FDB_MAX_CHAIN + 1][FDB_MAX_PRIO + 1][PRIO_LEVELS]; + } fdb_prio[FDB_NUM_CHAINS][FDB_TC_MAX_PRIO + 1][FDB_TC_LEVELS_PER_PRIO]; /* Protects fdb_prio table */ struct mutex fdb_prio_lock; @@ -217,8 +229,8 @@ enum { struct mlx5_eswitch { struct mlx5_core_dev *dev; struct mlx5_nb nb; - /* legacy data structures */ struct mlx5_eswitch_fdb fdb_table; + /* legacy data structures */ struct hlist_head mc_table[MLX5_L2_ADDR_HASH_SIZE]; struct esw_mc_addr mc_promisc; /* end of legacy */ @@ -251,18 +263,16 @@ void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw); int esw_offloads_init_reps(struct mlx5_eswitch *esw); void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport); -int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport); +int esw_vport_create_ingress_acl_table(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, + int table_size); +void esw_vport_destroy_ingress_acl_table(struct mlx5_vport *vport); void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport); int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, struct mlx5_vport *vport); void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, struct mlx5_vport *vport); -void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport); -void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, - struct mlx5_vport *vport); int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps); @@ -270,7 +280,7 @@ int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, int mlx5_eswitch_init(struct mlx5_core_dev *dev); void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw); int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode); -void mlx5_eswitch_disable(struct mlx5_eswitch *esw); +void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf); int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, u16 vport, u8 mac[ETH_ALEN]); int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, @@ -292,9 +302,11 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, struct ifla_vf_stats *vf_stats); void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule); -int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, +int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, void *in, int inlen); -int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, +int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, void *out, int outlen); struct mlx5_flow_spec; @@ -421,6 +433,10 @@ int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw, int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, u16 vport, u16 vlan, u8 qos, u8 set_flags); +int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, + u16 vlan_id, u32 flow_action); + static inline bool mlx5_eswitch_vlan_actions_supported(struct mlx5_core_dev *dev, u8 vlan_depth) { @@ -459,6 +475,12 @@ static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev) MLX5_VPORT_ECPF : MLX5_VPORT_PF; } +static inline bool +mlx5_esw_is_manager_vport(const struct mlx5_eswitch *esw, u16 vport_num) +{ + return esw->manager_vport == vport_num; +} + static inline u16 mlx5_eswitch_first_host_vport_num(struct mlx5_core_dev *dev) { return mlx5_core_is_ecpf_esw_manager(dev) ? @@ -593,17 +615,24 @@ bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num); void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs); int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data); -void +int mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, enum mlx5_eswitch_vport_event enabled_events); void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw); +int +esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport); +void +esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport); + #else /* CONFIG_MLX5_ESWITCH */ /* eswitch API stubs */ static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {} static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode) { return 0; } -static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {} +static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf) {} static inline bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1) { return true; } static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; } static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev) @@ -613,10 +642,6 @@ static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev) static inline void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs) {} -#define FDB_MAX_CHAIN 1 -#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) -#define FDB_MAX_PRIO 1 - #endif /* CONFIG_MLX5_ESWITCH */ #endif /* __MLX5_ESWITCH_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 9004a07e457a..8ba59a21a163 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -75,7 +75,7 @@ bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw) u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw) { if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) - return FDB_MAX_CHAIN; + return FDB_TC_MAX_CHAIN; return 0; } @@ -83,7 +83,7 @@ u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw) u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw) { if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) - return FDB_MAX_PRIO; + return FDB_TC_MAX_PRIO; return 1; } @@ -599,7 +599,7 @@ static int esw_set_passing_vport_metadata(struct mlx5_eswitch *esw, bool enable) if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) return 0; - err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport, + err = mlx5_eswitch_query_esw_vport_context(esw->dev, 0, false, out, sizeof(out)); if (err) return err; @@ -618,7 +618,7 @@ static int esw_set_passing_vport_metadata(struct mlx5_eswitch *esw, bool enable) MLX5_SET(modify_esw_vport_context_in, in, field_select.fdb_to_vport_reg_c_id, 1); - return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport, + return mlx5_eswitch_modify_esw_vport_context(esw->dev, 0, false, in, sizeof(in)); } @@ -927,7 +927,7 @@ esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) int table_prio, l = 0; u32 flags = 0; - if (chain == FDB_SLOW_PATH_CHAIN) + if (chain == FDB_TC_SLOW_PATH_CHAIN) return esw->fdb_table.offloads.slow_fdb; mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); @@ -952,7 +952,7 @@ esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); - table_prio = (chain * FDB_MAX_PRIO) + prio - 1; + table_prio = prio - 1; /* create earlier levels for correct fs_core lookup when * connecting tables @@ -989,7 +989,7 @@ esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) { int l; - if (chain == FDB_SLOW_PATH_CHAIN) + if (chain == FDB_TC_SLOW_PATH_CHAIN) return; mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); @@ -1369,7 +1369,7 @@ static int esw_offloads_start(struct mlx5_eswitch *esw, return -EINVAL; } - mlx5_eswitch_disable(esw); + mlx5_eswitch_disable(esw, false); mlx5_eswitch_update_num_of_vfs(esw, esw->dev->priv.sriov.num_vfs); err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS); if (err) { @@ -1777,9 +1777,9 @@ static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw, flow_act.vlan[0].vid = 0; flow_act.vlan[0].prio = 0; - if (vport->ingress.modify_metadata_rule) { + if (vport->ingress.offloads.modify_metadata_rule) { flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; - flow_act.modify_hdr = vport->ingress.modify_metadata; + flow_act.modify_hdr = vport->ingress.offloads.modify_metadata; } vport->ingress.allow_rule = @@ -1815,11 +1815,11 @@ static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, MLX5_SET(set_action_in, action, data, mlx5_eswitch_get_vport_metadata_for_match(esw, vport->vport)); - vport->ingress.modify_metadata = + vport->ingress.offloads.modify_metadata = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS, 1, action); - if (IS_ERR(vport->ingress.modify_metadata)) { - err = PTR_ERR(vport->ingress.modify_metadata); + if (IS_ERR(vport->ingress.offloads.modify_metadata)) { + err = PTR_ERR(vport->ingress.offloads.modify_metadata); esw_warn(esw->dev, "failed to alloc modify header for vport %d ingress acl (%d)\n", vport->vport, err); @@ -1827,100 +1827,76 @@ static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, } flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_ALLOW; - flow_act.modify_hdr = vport->ingress.modify_metadata; - vport->ingress.modify_metadata_rule = mlx5_add_flow_rules(vport->ingress.acl, - &spec, &flow_act, NULL, 0); - if (IS_ERR(vport->ingress.modify_metadata_rule)) { - err = PTR_ERR(vport->ingress.modify_metadata_rule); + flow_act.modify_hdr = vport->ingress.offloads.modify_metadata; + vport->ingress.offloads.modify_metadata_rule = + mlx5_add_flow_rules(vport->ingress.acl, + &spec, &flow_act, NULL, 0); + if (IS_ERR(vport->ingress.offloads.modify_metadata_rule)) { + err = PTR_ERR(vport->ingress.offloads.modify_metadata_rule); esw_warn(esw->dev, "failed to add setting metadata rule for vport %d ingress acl, err(%d)\n", vport->vport, err); - vport->ingress.modify_metadata_rule = NULL; + vport->ingress.offloads.modify_metadata_rule = NULL; goto out; } out: if (err) - mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata); + mlx5_modify_header_dealloc(esw->dev, vport->ingress.offloads.modify_metadata); return err; } -void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - if (vport->ingress.modify_metadata_rule) { - mlx5_del_flow_rules(vport->ingress.modify_metadata_rule); - mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata); + if (vport->ingress.offloads.modify_metadata_rule) { + mlx5_del_flow_rules(vport->ingress.offloads.modify_metadata_rule); + mlx5_modify_header_dealloc(esw->dev, vport->ingress.offloads.modify_metadata); - vport->ingress.modify_metadata_rule = NULL; + vport->ingress.offloads.modify_metadata_rule = NULL; } } -static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int esw_vport_create_ingress_acl_group(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_spec *spec; - int err = 0; - - if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) - return 0; - - /* For prio tag mode, there is only 1 FTEs: - * 1) prio tag packets - pop the prio tag VLAN, allow - * Unmatched traffic is allowed by default - */ - - esw_vport_cleanup_egress_rules(esw, vport); - - err = esw_vport_enable_egress_acl(esw, vport); - if (err) { - mlx5_core_warn(esw->dev, - "failed to enable egress acl (%d) on vport[%d]\n", - err, vport->vport); - return err; - } - - esw_debug(esw->dev, - "vport[%d] configure prio tag egress rules\n", vport->vport); + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + struct mlx5_flow_group *g; + u32 *flow_group_in; + int ret = 0; - spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) { - err = -ENOMEM; - goto out_no_mem; - } + flow_group_in = kvzalloc(inlen, GFP_KERNEL); + if (!flow_group_in) + return -ENOMEM; - /* prio tag vlan rule - pop it so VF receives untagged packets */ - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); - MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, 0); + memset(flow_group_in, 0, inlen); + MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); + MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); - spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - flow_act.action = MLX5_FLOW_CONTEXT_ACTION_VLAN_POP | - MLX5_FLOW_CONTEXT_ACTION_ALLOW; - vport->egress.allowed_vlan = - mlx5_add_flow_rules(vport->egress.acl, spec, - &flow_act, NULL, 0); - if (IS_ERR(vport->egress.allowed_vlan)) { - err = PTR_ERR(vport->egress.allowed_vlan); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); + if (IS_ERR(g)) { + ret = PTR_ERR(g); esw_warn(esw->dev, - "vport[%d] configure egress pop prio tag vlan rule failed, err(%d)\n", - vport->vport, err); - vport->egress.allowed_vlan = NULL; - goto out; + "Failed to create vport[%d] ingress metadata group, err(%d)\n", + vport->vport, ret); + goto grp_err; } + vport->ingress.offloads.metadata_grp = g; +grp_err: + kvfree(flow_group_in); + return ret; +} -out: - kvfree(spec); -out_no_mem: - if (err) - esw_vport_cleanup_egress_rules(esw, vport); - return err; +static void esw_vport_destroy_ingress_acl_group(struct mlx5_vport *vport) +{ + if (vport->ingress.offloads.metadata_grp) { + mlx5_destroy_flow_group(vport->ingress.offloads.metadata_grp); + vport->ingress.offloads.metadata_grp = NULL; + } } -static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int esw_vport_ingress_config(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { int err; @@ -1929,8 +1905,7 @@ static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw, return 0; esw_vport_cleanup_ingress_rules(esw, vport); - - err = esw_vport_enable_ingress_acl(esw, vport); + err = esw_vport_create_ingress_acl_table(esw, vport, 1); if (err) { esw_warn(esw->dev, "failed to enable ingress acl (%d) on vport[%d]\n", @@ -1938,25 +1913,65 @@ static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw, return err; } + err = esw_vport_create_ingress_acl_group(esw, vport); + if (err) + goto group_err; + esw_debug(esw->dev, "vport[%d] configure ingress rules\n", vport->vport); if (mlx5_eswitch_vport_match_metadata_enabled(esw)) { err = esw_vport_add_ingress_acl_modify_metadata(esw, vport); if (err) - goto out; + goto metadata_err; } if (MLX5_CAP_GEN(esw->dev, prio_tag_required) && mlx5_eswitch_is_vf_vport(esw, vport->vport)) { err = esw_vport_ingress_prio_tag_config(esw, vport); if (err) - goto out; + goto prio_tag_err; } + return 0; -out: +prio_tag_err: + esw_vport_del_ingress_acl_modify_metadata(esw, vport); +metadata_err: + esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_destroy_ingress_acl_group(vport); +group_err: + esw_vport_destroy_ingress_acl_table(vport); + return err; +} + +static int esw_vport_egress_config(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + int err; + + if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) + return 0; + + esw_vport_cleanup_egress_rules(esw, vport); + + err = esw_vport_enable_egress_acl(esw, vport); + if (err) + return err; + + /* For prio tag mode, there is only 1 FTEs: + * 1) prio tag packets - pop the prio tag VLAN, allow + * Unmatched traffic is allowed by default + */ + esw_debug(esw->dev, + "vport[%d] configure prio tag egress rules\n", vport->vport); + + /* prio tag vlan rule - pop it so VF receives untagged packets */ + err = mlx5_esw_create_vport_egress_acl_vlan(esw, vport, 0, + MLX5_FLOW_CONTEXT_ACTION_VLAN_POP | + MLX5_FLOW_CONTEXT_ACTION_ALLOW); if (err) - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_disable_egress_acl(esw, vport); + return err; } @@ -1980,54 +1995,59 @@ esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw) return true; } -static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) +int +esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - struct mlx5_vport *vport; - int i, j; int err; - if (esw_check_vport_match_metadata_supported(esw)) - esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA; - - mlx5_esw_for_all_vports(esw, i, vport) { - err = esw_vport_ingress_common_config(esw, vport); - if (err) - goto err_ingress; + err = esw_vport_ingress_config(esw, vport); + if (err) + return err; - if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) { - err = esw_vport_egress_prio_tag_config(esw, vport); - if (err) - goto err_egress; + if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) { + err = esw_vport_egress_config(esw, vport); + if (err) { + esw_vport_del_ingress_acl_modify_metadata(esw, vport); + esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_destroy_ingress_acl_table(vport); } } + return err; +} - if (mlx5_eswitch_vport_match_metadata_enabled(esw)) - esw_info(esw->dev, "Use metadata reg_c as source vport to match\n"); +void +esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + esw_vport_disable_egress_acl(esw, vport); + esw_vport_del_ingress_acl_modify_metadata(esw, vport); + esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_destroy_ingress_acl_group(vport); + esw_vport_destroy_ingress_acl_table(vport); +} - return 0; +static int esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch *esw) +{ + struct mlx5_vport *vport; + int err; -err_egress: - esw_vport_disable_ingress_acl(esw, vport); -err_ingress: - for (j = MLX5_VPORT_PF; j < i; j++) { - vport = &esw->vports[j]; - esw_vport_disable_egress_acl(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); - } + if (esw_check_vport_match_metadata_supported(esw)) + esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA; + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK); + err = esw_vport_create_offloads_acl_tables(esw, vport); + if (err) + esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA; return err; } -static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw) +static void esw_destroy_uplink_offloads_acl_tables(struct mlx5_eswitch *esw) { struct mlx5_vport *vport; - int i; - - mlx5_esw_for_all_vports(esw, i, vport) { - esw_vport_disable_egress_acl(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); - } + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK); + esw_vport_destroy_offloads_acl_tables(esw, vport); esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA; } @@ -2045,7 +2065,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw) memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb)); mutex_init(&esw->fdb_table.offloads.fdb_prio_lock); - err = esw_create_offloads_acl_tables(esw); + err = esw_create_uplink_offloads_acl_tables(esw); if (err) return err; @@ -2070,7 +2090,7 @@ create_ft_err: esw_destroy_offloads_fdb_tables(esw); create_fdb_err: - esw_destroy_offloads_acl_tables(esw); + esw_destroy_uplink_offloads_acl_tables(esw); return err; } @@ -2080,7 +2100,7 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw) esw_destroy_vport_rx_group(esw); esw_destroy_offloads_table(esw); esw_destroy_offloads_fdb_tables(esw); - esw_destroy_offloads_acl_tables(esw); + esw_destroy_uplink_offloads_acl_tables(esw); } static void @@ -2169,7 +2189,9 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) if (err) goto err_vport_metadata; - mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_VPORT_UC_ADDR_CHANGE); + err = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_VPORT_UC_ADDR_CHANGE); + if (err) + goto err_vports; err = esw_offloads_load_all_reps(esw); if (err) @@ -2182,6 +2204,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) err_reps: mlx5_eswitch_disable_pf_vf_vports(esw); +err_vports: esw_set_passing_vport_metadata(esw, false); err_vport_metadata: esw_offloads_steering_cleanup(esw); @@ -2195,7 +2218,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw, { int err, err1; - mlx5_eswitch_disable(esw); + mlx5_eswitch_disable(esw, false); err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY); if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h index eb8b0fe0b4e1..11621d265d7e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -35,11 +35,11 @@ #include <linux/mlx5/driver.h> -enum mlx5_fpga_device_id { - MLX5_FPGA_DEVICE_UNKNOWN = 0, - MLX5_FPGA_DEVICE_KU040 = 1, - MLX5_FPGA_DEVICE_KU060 = 2, - MLX5_FPGA_DEVICE_KU060_2 = 3, +enum mlx5_fpga_id { + MLX5_FPGA_NEWTON = 0, + MLX5_FPGA_EDISON = 1, + MLX5_FPGA_MORSE = 2, + MLX5_FPGA_MORSEQ = 3, }; enum mlx5_fpga_image { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c index d046d1ec2a86..2ce4241459ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -81,19 +81,28 @@ static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image) } } -static const char *mlx5_fpga_device_name(u32 device) +static const char *mlx5_fpga_name(u32 fpga_id) { - switch (device) { - case MLX5_FPGA_DEVICE_KU040: - return "ku040"; - case MLX5_FPGA_DEVICE_KU060: - return "ku060"; - case MLX5_FPGA_DEVICE_KU060_2: - return "ku060_2"; - case MLX5_FPGA_DEVICE_UNKNOWN: - default: - return "unknown"; + static char ret[32]; + + switch (fpga_id) { + case MLX5_FPGA_NEWTON: + return "Newton"; + case MLX5_FPGA_EDISON: + return "Edison"; + case MLX5_FPGA_MORSE: + return "Morse"; + case MLX5_FPGA_MORSEQ: + return "MorseQ"; } + + snprintf(ret, sizeof(ret), "Unknown %d", fpga_id); + return ret; +} + +static int mlx5_is_fpga_lookaside(u32 fpga_id) +{ + return fpga_id != MLX5_FPGA_NEWTON && fpga_id != MLX5_FPGA_EDISON; } static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) @@ -110,8 +119,12 @@ static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) fdev->last_admin_image = query.admin_image; fdev->last_oper_image = query.oper_image; - mlx5_fpga_dbg(fdev, "Status %u; Admin image %u; Oper image %u\n", - query.status, query.admin_image, query.oper_image); + mlx5_fpga_info(fdev, "Status %u; Admin image %u; Oper image %u\n", + query.status, query.admin_image, query.oper_image); + + /* for FPGA lookaside projects FPGA load status is not important */ + if (mlx5_is_fpga_lookaside(MLX5_CAP_FPGA(fdev->mdev, fpga_id))) + return 0; if (query.status != MLX5_FPGA_STATUS_SUCCESS) { mlx5_fpga_err(fdev, "%s image failed to load; status %u\n", @@ -167,25 +180,30 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) struct mlx5_fpga_device *fdev = mdev->fpga; unsigned int max_num_qps; unsigned long flags; - u32 fpga_device_id; + u32 fpga_id; int err; if (!fdev) return 0; - err = mlx5_fpga_device_load_check(fdev); + err = mlx5_fpga_caps(fdev->mdev); if (err) goto out; - err = mlx5_fpga_caps(fdev->mdev); + err = mlx5_fpga_device_load_check(fdev); if (err) goto out; - fpga_device_id = MLX5_CAP_FPGA(fdev->mdev, fpga_device); - mlx5_fpga_info(fdev, "%s:%u; %s image, version %u; SBU %06x:%04x version %d\n", - mlx5_fpga_device_name(fpga_device_id), - fpga_device_id, + fpga_id = MLX5_CAP_FPGA(fdev->mdev, fpga_id); + mlx5_fpga_info(fdev, "FPGA card %s:%u\n", mlx5_fpga_name(fpga_id), fpga_id); + + /* No QPs if FPGA does not participate in net processing */ + if (mlx5_is_fpga_lookaside(fpga_id)) + goto out; + + mlx5_fpga_info(fdev, "%s(%d): image, version %u; SBU %06x:%04x version %d\n", mlx5_fpga_image_name(fdev->last_oper_image), + fdev->last_oper_image, MLX5_CAP_FPGA(fdev->mdev, image_version), MLX5_CAP_FPGA(fdev->mdev, ieee_vendor_id), MLX5_CAP_FPGA(fdev->mdev, sandbox_product_id), @@ -264,6 +282,9 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) if (!fdev) return; + if (mlx5_is_fpga_lookaside(MLX5_CAP_FPGA(fdev->mdev, fpga_id))) + return; + spin_lock_irqsave(&fdev->state_lock, flags); if (fdev->state != MLX5_FPGA_STATUS_SUCCESS) { spin_unlock_irqrestore(&fdev->state_lock, flags); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 791e14ac26f4..d60577484567 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -531,9 +531,16 @@ static void del_hw_fte(struct fs_node *node) } } +static void del_sw_fte_rcu(struct rcu_head *head) +{ + struct fs_fte *fte = container_of(head, struct fs_fte, rcu); + struct mlx5_flow_steering *steering = get_steering(&fte->node); + + kmem_cache_free(steering->ftes_cache, fte); +} + static void del_sw_fte(struct fs_node *node) { - struct mlx5_flow_steering *steering = get_steering(node); struct mlx5_flow_group *fg; struct fs_fte *fte; int err; @@ -546,7 +553,8 @@ static void del_sw_fte(struct fs_node *node) rhash_fte); WARN_ON(err); ida_simple_remove(&fg->fte_allocator, fte->index - fg->start_index); - kmem_cache_free(steering->ftes_cache, fte); + + call_rcu(&fte->rcu, del_sw_fte_rcu); } static void del_hw_flow_group(struct fs_node *node) @@ -1625,22 +1633,47 @@ static u64 matched_fgs_get_version(struct list_head *match_head) } static struct fs_fte * -lookup_fte_locked(struct mlx5_flow_group *g, - const u32 *match_value, - bool take_write) +lookup_fte_for_write_locked(struct mlx5_flow_group *g, const u32 *match_value) { struct fs_fte *fte_tmp; - if (take_write) - nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); - else - nested_down_read_ref_node(&g->node, FS_LOCK_PARENT); - fte_tmp = rhashtable_lookup_fast(&g->ftes_hash, match_value, - rhash_fte); + nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); + + fte_tmp = rhashtable_lookup_fast(&g->ftes_hash, match_value, rhash_fte); + if (!fte_tmp || !tree_get_node(&fte_tmp->node)) { + fte_tmp = NULL; + goto out; + } + + if (!fte_tmp->node.active) { + tree_put_node(&fte_tmp->node, false); + fte_tmp = NULL; + goto out; + } + nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD); + +out: + up_write_ref_node(&g->node, false); + return fte_tmp; +} + +static struct fs_fte * +lookup_fte_for_read_locked(struct mlx5_flow_group *g, const u32 *match_value) +{ + struct fs_fte *fte_tmp; + + if (!tree_get_node(&g->node)) + return NULL; + + rcu_read_lock(); + fte_tmp = rhashtable_lookup(&g->ftes_hash, match_value, rhash_fte); if (!fte_tmp || !tree_get_node(&fte_tmp->node)) { + rcu_read_unlock(); fte_tmp = NULL; goto out; } + rcu_read_unlock(); + if (!fte_tmp->node.active) { tree_put_node(&fte_tmp->node, false); fte_tmp = NULL; @@ -1648,14 +1681,21 @@ lookup_fte_locked(struct mlx5_flow_group *g, } nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD); + out: - if (take_write) - up_write_ref_node(&g->node, false); - else - up_read_ref_node(&g->node); + tree_put_node(&g->node, false); return fte_tmp; } +static struct fs_fte * +lookup_fte_locked(struct mlx5_flow_group *g, const u32 *match_value, bool write) +{ + if (write) + return lookup_fte_for_write_locked(g, match_value); + else + return lookup_fte_for_read_locked(g, match_value); +} + static struct mlx5_flow_handle * try_add_to_existing_fg(struct mlx5_flow_table *ft, struct list_head *match_head, @@ -1816,6 +1856,13 @@ search_again_locked: return rule; } + fte = alloc_fte(ft, spec, flow_act); + if (IS_ERR(fte)) { + up_write_ref_node(&ft->node, false); + err = PTR_ERR(fte); + goto err_alloc_fte; + } + nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); up_write_ref_node(&ft->node, false); @@ -1823,17 +1870,9 @@ search_again_locked: if (err) goto err_release_fg; - fte = alloc_fte(ft, spec, flow_act); - if (IS_ERR(fte)) { - err = PTR_ERR(fte); - goto err_release_fg; - } - err = insert_fte(g, fte); - if (err) { - kmem_cache_free(steering->ftes_cache, fte); + if (err) goto err_release_fg; - } nested_down_write_ref_node(&fte->node, FS_LOCK_CHILD); up_write_ref_node(&g->node, false); @@ -1845,6 +1884,8 @@ search_again_locked: err_release_fg: up_write_ref_node(&g->node, false); + kmem_cache_free(steering->ftes_cache, fte); +err_alloc_fte: tree_put_node(&g->node, false); return ERR_PTR(err); } @@ -2361,9 +2402,17 @@ static void set_prio_attrs_in_prio(struct fs_prio *prio, int acc_level) int acc_level_ns = acc_level; prio->start_level = acc_level; - fs_for_each_ns(ns, prio) + fs_for_each_ns(ns, prio) { /* This updates start_level and num_levels of ns's priority descendants */ acc_level_ns = set_prio_attrs_in_ns(ns, acc_level); + + /* If this a prio with chains, and we can jump from one chain + * (namepsace) to another, so we accumulate the levels + */ + if (prio->node.type == FS_TYPE_PRIO_CHAINS) + acc_level = acc_level_ns; + } + if (!prio->num_levels) prio->num_levels = acc_level_ns - prio->start_level; WARN_ON(prio->num_levels < acc_level_ns - prio->start_level); @@ -2552,58 +2601,109 @@ out_err: steering->rdma_rx_root_ns = NULL; return err; } -static int init_fdb_root_ns(struct mlx5_flow_steering *steering) + +/* FT and tc chains are stored in the same array so we can re-use the + * mlx5_get_fdb_sub_ns() and tc api for FT chains. + * When creating a new ns for each chain store it in the first available slot. + * Assume tc chains are created and stored first and only then the FT chain. + */ +static void store_fdb_sub_ns_prio_chain(struct mlx5_flow_steering *steering, + struct mlx5_flow_namespace *ns) +{ + int chain = 0; + + while (steering->fdb_sub_ns[chain]) + ++chain; + + steering->fdb_sub_ns[chain] = ns; +} + +static int create_fdb_sub_ns_prio_chain(struct mlx5_flow_steering *steering, + struct fs_prio *maj_prio) { struct mlx5_flow_namespace *ns; - struct fs_prio *maj_prio; struct fs_prio *min_prio; + int prio; + + ns = fs_create_namespace(maj_prio, MLX5_FLOW_TABLE_MISS_ACTION_DEF); + if (IS_ERR(ns)) + return PTR_ERR(ns); + + for (prio = 0; prio < FDB_TC_MAX_PRIO; prio++) { + min_prio = fs_create_prio(ns, prio, FDB_TC_LEVELS_PER_PRIO); + if (IS_ERR(min_prio)) + return PTR_ERR(min_prio); + } + + store_fdb_sub_ns_prio_chain(steering, ns); + + return 0; +} + +static int create_fdb_chains(struct mlx5_flow_steering *steering, + int fs_prio, + int chains) +{ + struct fs_prio *maj_prio; int levels; int chain; - int prio; int err; - steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB); - if (!steering->fdb_root_ns) - return -ENOMEM; + levels = FDB_TC_LEVELS_PER_PRIO * FDB_TC_MAX_PRIO * chains; + maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, + fs_prio, + levels); + if (IS_ERR(maj_prio)) + return PTR_ERR(maj_prio); + + for (chain = 0; chain < chains; chain++) { + err = create_fdb_sub_ns_prio_chain(steering, maj_prio); + if (err) + return err; + } + + return 0; +} + +static int create_fdb_fast_path(struct mlx5_flow_steering *steering) +{ + int err; - steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) * - (FDB_MAX_CHAIN + 1), GFP_KERNEL); + steering->fdb_sub_ns = kcalloc(FDB_NUM_CHAINS, + sizeof(*steering->fdb_sub_ns), + GFP_KERNEL); if (!steering->fdb_sub_ns) return -ENOMEM; + err = create_fdb_chains(steering, FDB_TC_OFFLOAD, FDB_TC_MAX_CHAIN + 1); + if (err) + return err; + + err = create_fdb_chains(steering, FDB_FT_OFFLOAD, 1); + if (err) + return err; + + return 0; +} + +static int init_fdb_root_ns(struct mlx5_flow_steering *steering) +{ + struct fs_prio *maj_prio; + int err; + + steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB); + if (!steering->fdb_root_ns) + return -ENOMEM; + maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_BYPASS_PATH, 1); if (IS_ERR(maj_prio)) { err = PTR_ERR(maj_prio); goto out_err; } - - levels = 2 * FDB_MAX_PRIO * (FDB_MAX_CHAIN + 1); - maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, - FDB_FAST_PATH, - levels); - if (IS_ERR(maj_prio)) { - err = PTR_ERR(maj_prio); + err = create_fdb_fast_path(steering); + if (err) goto out_err; - } - - for (chain = 0; chain <= FDB_MAX_CHAIN; chain++) { - ns = fs_create_namespace(maj_prio, MLX5_FLOW_TABLE_MISS_ACTION_DEF); - if (IS_ERR(ns)) { - err = PTR_ERR(ns); - goto out_err; - } - - for (prio = 0; prio < FDB_MAX_PRIO * (chain + 1); prio++) { - min_prio = fs_create_prio(ns, prio, 2); - if (IS_ERR(min_prio)) { - err = PTR_ERR(min_prio); - goto out_err; - } - } - - steering->fdb_sub_ns[chain] = ns; - } maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_SLOW_PATH, 1); if (IS_ERR(maj_prio)) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index c2621b911563..e8cd997f413e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -203,6 +203,7 @@ struct fs_fte { enum fs_fte_status status; struct mlx5_fc *counter; struct rhash_head hash; + struct rcu_head rcu; int modify_mask; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index c07f3154437c..d9f4e8c59c1f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -390,7 +390,8 @@ static void print_health_info(struct mlx5_core_dev *dev) static int mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); struct mlx5_core_health *health = &dev->priv.health; @@ -491,7 +492,8 @@ mlx5_fw_reporter_heath_buffer_data_put(struct mlx5_core_dev *dev, static int mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg, void *priv_ctx) + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); int err; @@ -545,23 +547,22 @@ static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = { static int mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter, - void *priv_ctx) + void *priv_ctx, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); return mlx5_health_try_recover(dev); } -#define MLX5_CR_DUMP_CHUNK_SIZE 256 static int mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg, void *priv_ctx) + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); u32 crdump_size = dev->priv.health.crdump_size; u32 *cr_data; - u32 data_size; - u32 offset; int err; if (!mlx5_core_is_pf(dev)) @@ -582,20 +583,7 @@ mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter, goto free_data; } - err = devlink_fmsg_arr_pair_nest_start(fmsg, "crdump_data"); - if (err) - goto free_data; - for (offset = 0; offset < crdump_size; offset += data_size) { - if (crdump_size - offset < MLX5_CR_DUMP_CHUNK_SIZE) - data_size = crdump_size - offset; - else - data_size = MLX5_CR_DUMP_CHUNK_SIZE; - err = devlink_fmsg_binary_put(fmsg, (char *)cr_data + offset, - data_size); - if (err) - goto free_data; - } - err = devlink_fmsg_arr_pair_nest_end(fmsg); + err = devlink_fmsg_binary_pair_put(fmsg, "crdump_data", cr_data, crdump_size); free_data: kvfree(cr_data); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c index c5ef2ff26465..fc0d9583475d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c @@ -145,34 +145,35 @@ static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker, { *port1 = 1; *port2 = 2; - if (!tracker->netdev_state[0].tx_enabled || - !tracker->netdev_state[0].link_up) { + if (!tracker->netdev_state[MLX5_LAG_P1].tx_enabled || + !tracker->netdev_state[MLX5_LAG_P1].link_up) { *port1 = 2; return; } - if (!tracker->netdev_state[1].tx_enabled || - !tracker->netdev_state[1].link_up) + if (!tracker->netdev_state[MLX5_LAG_P2].tx_enabled || + !tracker->netdev_state[MLX5_LAG_P2].link_up) *port2 = 1; } void mlx5_modify_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; u8 v2p_port1, v2p_port2; int err; mlx5_infer_tx_affinity_mapping(tracker, &v2p_port1, &v2p_port2); - if (v2p_port1 != ldev->v2p_map[0] || - v2p_port2 != ldev->v2p_map[1]) { - ldev->v2p_map[0] = v2p_port1; - ldev->v2p_map[1] = v2p_port2; + if (v2p_port1 != ldev->v2p_map[MLX5_LAG_P1] || + v2p_port2 != ldev->v2p_map[MLX5_LAG_P2]) { + ldev->v2p_map[MLX5_LAG_P1] = v2p_port1; + ldev->v2p_map[MLX5_LAG_P2] = v2p_port2; mlx5_core_info(dev0, "modify lag map port 1:%d port 2:%d", - ldev->v2p_map[0], ldev->v2p_map[1]); + ldev->v2p_map[MLX5_LAG_P1], + ldev->v2p_map[MLX5_LAG_P2]); err = mlx5_cmd_modify_lag(dev0, v2p_port1, v2p_port2); if (err) @@ -185,16 +186,17 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, static int mlx5_create_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; int err; - mlx5_infer_tx_affinity_mapping(tracker, &ldev->v2p_map[0], - &ldev->v2p_map[1]); + mlx5_infer_tx_affinity_mapping(tracker, &ldev->v2p_map[MLX5_LAG_P1], + &ldev->v2p_map[MLX5_LAG_P2]); mlx5_core_info(dev0, "lag map port 1:%d port 2:%d", - ldev->v2p_map[0], ldev->v2p_map[1]); + ldev->v2p_map[MLX5_LAG_P1], ldev->v2p_map[MLX5_LAG_P2]); - err = mlx5_cmd_create_lag(dev0, ldev->v2p_map[0], ldev->v2p_map[1]); + err = mlx5_cmd_create_lag(dev0, ldev->v2p_map[MLX5_LAG_P1], + ldev->v2p_map[MLX5_LAG_P2]); if (err) mlx5_core_err(dev0, "Failed to create LAG (%d)\n", @@ -207,7 +209,7 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, u8 flags) { bool roce_lag = !!(flags & MLX5_LAG_FLAG_ROCE); - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; int err; err = mlx5_create_lag(ldev, tracker); @@ -229,7 +231,7 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, static int mlx5_deactivate_lag(struct mlx5_lag *ldev) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; bool roce_lag = __mlx5_lag_is_roce(ldev); int err; @@ -252,14 +254,15 @@ static int mlx5_deactivate_lag(struct mlx5_lag *ldev) static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) { - if (!ldev->pf[0].dev || !ldev->pf[1].dev) + if (!ldev->pf[MLX5_LAG_P1].dev || !ldev->pf[MLX5_LAG_P2].dev) return false; #ifdef CONFIG_MLX5_ESWITCH - return mlx5_esw_lag_prereq(ldev->pf[0].dev, ldev->pf[1].dev); + return mlx5_esw_lag_prereq(ldev->pf[MLX5_LAG_P1].dev, + ldev->pf[MLX5_LAG_P2].dev); #else - return (!mlx5_sriov_is_enabled(ldev->pf[0].dev) && - !mlx5_sriov_is_enabled(ldev->pf[1].dev)); + return (!mlx5_sriov_is_enabled(ldev->pf[MLX5_LAG_P1].dev) && + !mlx5_sriov_is_enabled(ldev->pf[MLX5_LAG_P2].dev)); #endif } @@ -285,8 +288,8 @@ static void mlx5_lag_remove_ib_devices(struct mlx5_lag *ldev) static void mlx5_do_bond(struct mlx5_lag *ldev) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; - struct mlx5_core_dev *dev1 = ldev->pf[1].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; + struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; struct lag_tracker tracker; bool do_bond, roce_lag; int err; @@ -692,10 +695,11 @@ struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev) goto unlock; if (ldev->tracker.tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { - ndev = ldev->tracker.netdev_state[0].tx_enabled ? - ldev->pf[0].netdev : ldev->pf[1].netdev; + ndev = ldev->tracker.netdev_state[MLX5_LAG_P1].tx_enabled ? + ldev->pf[MLX5_LAG_P1].netdev : + ldev->pf[MLX5_LAG_P2].netdev; } else { - ndev = ldev->pf[0].netdev; + ndev = ldev->pf[MLX5_LAG_P1].netdev; } if (ndev) dev_hold(ndev); @@ -717,7 +721,8 @@ bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv) return true; ldev = mlx5_lag_dev_get(dev); - if (!ldev || !__mlx5_lag_is_roce(ldev) || ldev->pf[0].dev == dev) + if (!ldev || !__mlx5_lag_is_roce(ldev) || + ldev->pf[MLX5_LAG_P1].dev == dev) return true; /* If bonded, we do not add an IB device for PF1. */ @@ -746,11 +751,11 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev, ldev = mlx5_lag_dev_get(dev); if (ldev && __mlx5_lag_is_roce(ldev)) { num_ports = MLX5_MAX_PORTS; - mdev[0] = ldev->pf[0].dev; - mdev[1] = ldev->pf[1].dev; + mdev[MLX5_LAG_P1] = ldev->pf[MLX5_LAG_P1].dev; + mdev[MLX5_LAG_P2] = ldev->pf[MLX5_LAG_P2].dev; } else { num_ports = 1; - mdev[0] = dev; + mdev[MLX5_LAG_P1] = dev; } for (i = 0; i < num_ports; ++i) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag.h index 1dea0b1c9826..f1068aac6406 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.h @@ -8,6 +8,11 @@ #include "lag_mp.h" enum { + MLX5_LAG_P1, + MLX5_LAG_P2, +}; + +enum { MLX5_LAG_FLAG_ROCE = 1 << 0, MLX5_LAG_FLAG_SRIOV = 1 << 1, MLX5_LAG_FLAG_MULTIPATH = 1 << 2, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c index 5d20d615663e..b70afa310ad2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c @@ -11,10 +11,11 @@ static bool mlx5_lag_multipath_check_prereq(struct mlx5_lag *ldev) { - if (!ldev->pf[0].dev || !ldev->pf[1].dev) + if (!ldev->pf[MLX5_LAG_P1].dev || !ldev->pf[MLX5_LAG_P2].dev) return false; - return mlx5_esw_multipath_prereq(ldev->pf[0].dev, ldev->pf[1].dev); + return mlx5_esw_multipath_prereq(ldev->pf[MLX5_LAG_P1].dev, + ldev->pf[MLX5_LAG_P2].dev); } static bool __mlx5_lag_is_multipath(struct mlx5_lag *ldev) @@ -43,7 +44,8 @@ bool mlx5_lag_is_multipath(struct mlx5_core_dev *dev) * 2 - set affinity to port 2. * **/ -static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, int port) +static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, + enum mlx5_lag_port_affinity port) { struct lag_tracker tracker; @@ -51,37 +53,37 @@ static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, int port) return; switch (port) { - case 0: - tracker.netdev_state[0].tx_enabled = true; - tracker.netdev_state[1].tx_enabled = true; - tracker.netdev_state[0].link_up = true; - tracker.netdev_state[1].link_up = true; + case MLX5_LAG_NORMAL_AFFINITY: + tracker.netdev_state[MLX5_LAG_P1].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P2].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P1].link_up = true; + tracker.netdev_state[MLX5_LAG_P2].link_up = true; break; - case 1: - tracker.netdev_state[0].tx_enabled = true; - tracker.netdev_state[0].link_up = true; - tracker.netdev_state[1].tx_enabled = false; - tracker.netdev_state[1].link_up = false; + case MLX5_LAG_P1_AFFINITY: + tracker.netdev_state[MLX5_LAG_P1].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P1].link_up = true; + tracker.netdev_state[MLX5_LAG_P2].tx_enabled = false; + tracker.netdev_state[MLX5_LAG_P2].link_up = false; break; - case 2: - tracker.netdev_state[0].tx_enabled = false; - tracker.netdev_state[0].link_up = false; - tracker.netdev_state[1].tx_enabled = true; - tracker.netdev_state[1].link_up = true; + case MLX5_LAG_P2_AFFINITY: + tracker.netdev_state[MLX5_LAG_P1].tx_enabled = false; + tracker.netdev_state[MLX5_LAG_P1].link_up = false; + tracker.netdev_state[MLX5_LAG_P2].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P2].link_up = true; break; default: - mlx5_core_warn(ldev->pf[0].dev, "Invalid affinity port %d", - port); + mlx5_core_warn(ldev->pf[MLX5_LAG_P1].dev, + "Invalid affinity port %d", port); return; } - if (tracker.netdev_state[0].tx_enabled) - mlx5_notifier_call_chain(ldev->pf[0].dev->priv.events, + if (tracker.netdev_state[MLX5_LAG_P1].tx_enabled) + mlx5_notifier_call_chain(ldev->pf[MLX5_LAG_P1].dev->priv.events, MLX5_DEV_EVENT_PORT_AFFINITY, (void *)0); - if (tracker.netdev_state[1].tx_enabled) - mlx5_notifier_call_chain(ldev->pf[1].dev->priv.events, + if (tracker.netdev_state[MLX5_LAG_P2].tx_enabled) + mlx5_notifier_call_chain(ldev->pf[MLX5_LAG_P2].dev->priv.events, MLX5_DEV_EVENT_PORT_AFFINITY, (void *)0); @@ -141,11 +143,12 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, /* Verify next hops are ports of the same hca */ fib_nh0 = fib_info_nh(fi, 0); fib_nh1 = fib_info_nh(fi, 1); - if (!(fib_nh0->fib_nh_dev == ldev->pf[0].netdev && - fib_nh1->fib_nh_dev == ldev->pf[1].netdev) && - !(fib_nh0->fib_nh_dev == ldev->pf[1].netdev && - fib_nh1->fib_nh_dev == ldev->pf[0].netdev)) { - mlx5_core_warn(ldev->pf[0].dev, "Multipath offload require two ports of the same HCA\n"); + if (!(fib_nh0->fib_nh_dev == ldev->pf[MLX5_LAG_P1].netdev && + fib_nh1->fib_nh_dev == ldev->pf[MLX5_LAG_P2].netdev) && + !(fib_nh0->fib_nh_dev == ldev->pf[MLX5_LAG_P2].netdev && + fib_nh1->fib_nh_dev == ldev->pf[MLX5_LAG_P1].netdev)) { + mlx5_core_warn(ldev->pf[MLX5_LAG_P1].dev, + "Multipath offload require two ports of the same HCA\n"); return; } @@ -157,7 +160,7 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, mlx5_activate_lag(ldev, &tracker, MLX5_LAG_FLAG_MULTIPATH); } - mlx5_lag_set_port_affinity(ldev, 0); + mlx5_lag_set_port_affinity(ldev, MLX5_LAG_NORMAL_AFFINITY); mp->mfi = fi; } @@ -182,7 +185,7 @@ static void mlx5_lag_fib_nexthop_event(struct mlx5_lag *ldev, } } else if (event == FIB_EVENT_NH_ADD && fib_info_num_path(fi) == 2) { - mlx5_lag_set_port_affinity(ldev, 0); + mlx5_lag_set_port_affinity(ldev, MLX5_LAG_NORMAL_AFFINITY); } } @@ -248,9 +251,6 @@ static int mlx5_lag_fib_event(struct notifier_block *nb, struct net_device *fib_dev; struct fib_info *fi; - if (!net_eq(info->net, &init_net)) - return NOTIFY_DONE; - if (info->family != AF_INET) return NOTIFY_DONE; @@ -270,8 +270,8 @@ static int mlx5_lag_fib_event(struct notifier_block *nb, return notifier_from_errno(-EINVAL); } fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev; - if (fib_dev != ldev->pf[0].netdev && - fib_dev != ldev->pf[1].netdev) { + if (fib_dev != ldev->pf[MLX5_LAG_P1].netdev && + fib_dev != ldev->pf[MLX5_LAG_P2].netdev) { return NOTIFY_DONE; } fib_work = mlx5_lag_init_fib_work(ldev, event); @@ -311,8 +311,8 @@ int mlx5_lag_mp_init(struct mlx5_lag *ldev) return 0; mp->fib_nb.notifier_call = mlx5_lag_fib_event; - err = register_fib_notifier(&mp->fib_nb, - mlx5_lag_fib_event_flush); + err = register_fib_notifier(&init_net, &mp->fib_nb, + mlx5_lag_fib_event_flush, NULL); if (err) mp->fib_nb.notifier_call = NULL; @@ -326,6 +326,6 @@ void mlx5_lag_mp_cleanup(struct mlx5_lag *ldev) if (!mp->fib_nb.notifier_call) return; - unregister_fib_notifier(&mp->fib_nb); + unregister_fib_notifier(&init_net, &mp->fib_nb); mp->fib_nb.notifier_call = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h index 6d14b1100be9..79be89e9c7a4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h @@ -7,6 +7,12 @@ #include "lag.h" #include "mlx5_core.h" +enum mlx5_lag_port_affinity { + MLX5_LAG_NORMAL_AFFINITY, + MLX5_LAG_P1_AFFINITY, + MLX5_LAG_P2_AFFINITY, +}; + struct lag_mp { struct notifier_block fib_nb; struct fib_info *mfi; /* used in tracking fib events */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h index b99d469e4e64..249539247e2e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h @@ -84,4 +84,9 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, void *key, u32 sz_bytes, u32 *p_key_id); void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id); +static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev) +{ + return devlink_net(priv_to_devlink(dev)); +} + #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 50ab88d80033..584074bbf669 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1168,7 +1168,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev) mlx5_put_uars_page(dev, dev->priv.uar); } -static int mlx5_load_one(struct mlx5_core_dev *dev, bool boot) +int mlx5_load_one(struct mlx5_core_dev *dev, bool boot) { int err = 0; @@ -1226,10 +1226,8 @@ function_teardown: return err; } -static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) +int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) { - int err = 0; - if (cleanup) { mlx5_unregister_device(dev); mlx5_drain_health_wq(dev); @@ -1257,7 +1255,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) mlx5_function_teardown(dev, cleanup); out: mutex_unlock(&dev->intf_state_mutex); - return err; + return 0; } static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b100489dc85c..da67b28d6e23 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -243,4 +243,7 @@ enum { u8 mlx5_get_nic_state(struct mlx5_core_dev *dev); void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state); + +int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup); +int mlx5_load_one(struct mlx5_core_dev *dev, bool boot); #endif /* __MLX5_CORE_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 61fcfd8b39b4..03f037811f1d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -108,10 +108,10 @@ enable_vfs_hca: return 0; } -static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev) +static void +mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf) { struct mlx5_core_sriov *sriov = &dev->priv.sriov; - int num_vfs = pci_num_vf(dev->pdev); int err; int vf; @@ -127,7 +127,7 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev) } if (MLX5_ESWITCH_MANAGER(dev)) - mlx5_eswitch_disable(dev->priv.eswitch); + mlx5_eswitch_disable(dev->priv.eswitch, clear_vf); if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages)) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); @@ -147,7 +147,7 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs) err = pci_enable_sriov(pdev, num_vfs); if (err) { mlx5_core_warn(dev, "pci_enable_sriov failed : %d\n", err); - mlx5_device_disable_sriov(dev); + mlx5_device_disable_sriov(dev, num_vfs, true); } return err; } @@ -155,9 +155,10 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs) static void mlx5_sriov_disable(struct pci_dev *pdev) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); + int num_vfs = pci_num_vf(dev->pdev); pci_disable_sriov(pdev); - mlx5_device_disable_sriov(dev); + mlx5_device_disable_sriov(dev, num_vfs, true); } int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs) @@ -192,7 +193,7 @@ void mlx5_sriov_detach(struct mlx5_core_dev *dev) if (!mlx5_core_is_pf(dev)) return; - mlx5_device_disable_sriov(dev); + mlx5_device_disable_sriov(dev, pci_num_vf(dev->pdev), false); } static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c deleted file mode 100644 index 9e2eccbb1eb8..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -/* Copyright (c) 2011-2015 Stephan Brumme. All rights reserved. - * Slicing-by-16 contributed by Bulat Ziganshin - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the author be held liable for any damages arising from the - * of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. - * 2. If you use this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * 3. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * Taken from http://create.stephan-brumme.com/crc32/ and adapted. - */ - -#include "dr_types.h" - -#define DR_STE_CRC_POLY 0xEDB88320L - -static u32 dr_ste_crc_tab32[8][256]; - -static void dr_crc32_calc_lookup_entry(u32 (*tbl)[256], u8 i, u8 j) -{ - tbl[i][j] = (tbl[i - 1][j] >> 8) ^ tbl[0][tbl[i - 1][j] & 0xff]; -} - -void mlx5dr_crc32_init_table(void) -{ - u32 crc, i, j; - - for (i = 0; i < 256; i++) { - crc = i; - for (j = 0; j < 8; j++) { - if (crc & 0x00000001L) - crc = (crc >> 1) ^ DR_STE_CRC_POLY; - else - crc = crc >> 1; - } - dr_ste_crc_tab32[0][i] = crc; - } - - /* Init CRC lookup tables according to crc_slice_8 algorithm */ - for (i = 0; i < 256; i++) { - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 1, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 2, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 3, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 4, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 5, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 6, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 7, i); - } -} - -/* Compute CRC32 (Slicing-by-8 algorithm) */ -u32 mlx5dr_crc32_slice8_calc(const void *input_data, size_t length) -{ - const u32 *curr = (const u32 *)input_data; - const u8 *curr_char; - u32 crc = 0, one, two; - - if (!input_data) - return 0; - - /* Process eight bytes at once (Slicing-by-8) */ - while (length >= 8) { - one = *curr++ ^ crc; - two = *curr++; - - crc = dr_ste_crc_tab32[0][(two >> 24) & 0xff] - ^ dr_ste_crc_tab32[1][(two >> 16) & 0xff] - ^ dr_ste_crc_tab32[2][(two >> 8) & 0xff] - ^ dr_ste_crc_tab32[3][two & 0xff] - ^ dr_ste_crc_tab32[4][(one >> 24) & 0xff] - ^ dr_ste_crc_tab32[5][(one >> 16) & 0xff] - ^ dr_ste_crc_tab32[6][(one >> 8) & 0xff] - ^ dr_ste_crc_tab32[7][one & 0xff]; - - length -= 8; - } - - curr_char = (const u8 *)curr; - /* Remaining 1 to 7 bytes (standard algorithm) */ - while (length-- != 0) - crc = (crc >> 8) ^ dr_ste_crc_tab32[0][(crc & 0xff) - ^ *curr_char++]; - - return ((crc >> 24) & 0xff) | ((crc << 8) & 0xff0000) | - ((crc >> 8) & 0xff00) | ((crc << 24) & 0xff000000); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c index 5b24732b18c0..a9da961d4d2f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c @@ -326,9 +326,6 @@ mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type) goto uninit_resourses; } - /* Init CRC table for htbl CRC calculation */ - mlx5dr_crc32_init_table(); - return dmn; uninit_resourses: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c index 67dea7698fc9..c6dbd856df94 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c @@ -102,13 +102,52 @@ static bool dr_mask_is_gre_set(struct mlx5dr_match_misc *misc) DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), gre) || \ DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), udp)) -static bool dr_mask_is_flex_parser_tnl_set(struct mlx5dr_match_misc3 *misc3) +static bool +dr_mask_is_misc3_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3) { return (misc3->outer_vxlan_gpe_vni || misc3->outer_vxlan_gpe_next_protocol || misc3->outer_vxlan_gpe_flags); } +static bool +dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & + MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; +} + +static bool +dr_mask_is_flex_parser_tnl_vxlan_gpe_set(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_misc3_vxlan_gpe_set(&mask->misc3) && + dr_matcher_supp_flex_parser_vxlan_gpe(&dmn->info.caps); +} + +static bool dr_mask_is_misc_geneve_set(struct mlx5dr_match_misc *misc) +{ + return misc->geneve_vni || + misc->geneve_oam || + misc->geneve_protocol_type || + misc->geneve_opt_len; +} + +static bool +dr_matcher_supp_flex_parser_geneve(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & + MLX5_FLEX_PARSER_GENEVE_ENABLED; +} + +static bool +dr_mask_is_flex_parser_tnl_geneve_set(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_misc_geneve_set(&mask->misc) && + dr_matcher_supp_flex_parser_geneve(&dmn->info.caps); +} + static bool dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 *misc3) { return (misc3->icmpv6_type || misc3->icmpv6_code || @@ -137,24 +176,15 @@ static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc) return (misc->source_sqn || misc->source_port); } -static bool -dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_domain *dmn) -{ - return dmn->info.caps.flex_protocols & - MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; -} - int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, - bool ipv6) + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv) { - if (ipv6) { - nic_matcher->ste_builder = nic_matcher->ste_builder6; - nic_matcher->num_of_builders = nic_matcher->num_of_builders6; - } else { - nic_matcher->ste_builder = nic_matcher->ste_builder4; - nic_matcher->num_of_builders = nic_matcher->num_of_builders4; - } + nic_matcher->ste_builder = + nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; + nic_matcher->num_of_builders = + nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; if (!nic_matcher->num_of_builders) { mlx5dr_dbg(matcher->tbl->dmn, @@ -167,26 +197,19 @@ int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, - bool ipv6) + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv) { struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; struct mlx5dr_domain *dmn = matcher->tbl->dmn; struct mlx5dr_match_param mask = {}; struct mlx5dr_match_misc3 *misc3; struct mlx5dr_ste_build *sb; - u8 *num_of_builders; bool inner, rx; int idx = 0; int ret, i; - if (ipv6) { - sb = nic_matcher->ste_builder6; - num_of_builders = &nic_matcher->num_of_builders6; - } else { - sb = nic_matcher->ste_builder4; - num_of_builders = &nic_matcher->num_of_builders4; - } - + sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; rx = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX; /* Create a temporary mask to track and clear used mask fields */ @@ -249,7 +272,7 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer)) mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx); - if (ipv6) { + if (outer_ipv == DR_RULE_IPV6) { if (dr_mask_is_dst_addr_set(&mask.outer)) mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask, inner, rx); @@ -271,10 +294,14 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, inner, rx); } - if (dr_mask_is_flex_parser_tnl_set(&mask.misc3) && - dr_matcher_supp_flex_parser_vxlan_gpe(dmn)) - mlx5dr_ste_build_flex_parser_tnl(&sb[idx++], &mask, - inner, rx); + if (dr_mask_is_flex_parser_tnl_vxlan_gpe_set(&mask, dmn)) + mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(&sb[idx++], + &mask, + inner, rx); + else if (dr_mask_is_flex_parser_tnl_geneve_set(&mask, dmn)) + mlx5dr_ste_build_flex_parser_tnl_geneve(&sb[idx++], + &mask, + inner, rx); if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx); @@ -325,7 +352,7 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner)) mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx); - if (ipv6) { + if (inner_ipv == DR_RULE_IPV6) { if (dr_mask_is_dst_addr_set(&mask.inner)) mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask, inner, rx); @@ -373,7 +400,8 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, } } - *num_of_builders = idx; + nic_matcher->ste_builder = sb; + nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx; return 0; } @@ -524,24 +552,33 @@ static void dr_matcher_uninit(struct mlx5dr_matcher *matcher) } } -static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher) +static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) { struct mlx5dr_domain *dmn = matcher->tbl->dmn; - int ret, ret_v4, ret_v6; - ret_v4 = dr_matcher_set_ste_builders(matcher, nic_matcher, false); - ret_v6 = dr_matcher_set_ste_builders(matcher, nic_matcher, true); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6); - if (ret_v4 && ret_v6) { + if (!nic_matcher->ste_builder) { mlx5dr_dbg(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n"); return -EINVAL; } - if (!ret_v4) - nic_matcher->ste_builder = nic_matcher->ste_builder4; - else - nic_matcher->ste_builder = nic_matcher->ste_builder6; + return 0; +} + +static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + int ret; + + ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher); + if (ret) + return ret; nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, DR_CHUNK_SIZE_1, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c index bd1699e62142..32e94d2ee5e4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c @@ -969,12 +969,12 @@ static int dr_rule_destroy_rule(struct mlx5dr_rule *rule) return 0; } -static bool dr_rule_is_ipv6(struct mlx5dr_match_param *param) +static enum mlx5dr_ipv dr_rule_get_ipv(struct mlx5dr_match_spec *spec) { - return (param->outer.ip_version == 6 || - param->inner.ip_version == 6 || - param->outer.ethertype == ETH_P_IPV6 || - param->inner.ethertype == ETH_P_IPV6); + if (spec->ip_version == 6 || spec->ethertype == ETH_P_IPV6) + return DR_RULE_IPV6; + + return DR_RULE_IPV4; } static bool dr_rule_skip(enum mlx5dr_domain_type domain, @@ -1038,7 +1038,8 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule, ret = mlx5dr_matcher_select_builders(matcher, nic_matcher, - dr_rule_is_ipv6(param)); + dr_rule_get_ipv(¶m->outer), + dr_rule_get_ipv(¶m->inner)); if (ret) goto out_err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c index 3cbf74b44d1f..a5a266983dd3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c @@ -2,6 +2,7 @@ /* Copyright (c) 2019 Mellanox Technologies. */ #include <linux/types.h> +#include <linux/crc32.h> #include "dr_types.h" #define DR_STE_CRC_POLY 0xEDB88320L @@ -107,6 +108,13 @@ struct dr_hw_ste_format { u8 mask[DR_STE_SIZE_MASK]; }; +static u32 dr_ste_crc32_calc(const void *input_data, size_t length) +{ + u32 crc = crc32(0, input_data, length); + + return htonl(crc); +} + u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl) { struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; @@ -128,7 +136,7 @@ u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl) bit = bit >> 1; } - crc32 = mlx5dr_crc32_slice8_calc(masked, DR_STE_SIZE_TAG); + crc32 = dr_ste_crc32_calc(masked, DR_STE_SIZE_TAG); index = crc32 & (htbl->chunk->num_of_entries - 1); return index; @@ -2075,68 +2083,110 @@ void mlx5dr_ste_build_eth_l4_misc(struct mlx5dr_ste_build *sb, sb->ste_build_tag_func = &dr_ste_build_eth_l4_misc_tag; } -static void dr_ste_build_flex_parser_tnl_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) +static void +dr_ste_build_flex_parser_tnl_vxlan_gpe_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) { struct mlx5dr_match_misc3 *misc_3_mask = &value->misc3; - if (misc_3_mask->outer_vxlan_gpe_flags || - misc_3_mask->outer_vxlan_gpe_next_protocol) { - MLX5_SET(ste_flex_parser_tnl, bit_mask, - flex_parser_tunneling_header_63_32, - (misc_3_mask->outer_vxlan_gpe_flags << 24) | - (misc_3_mask->outer_vxlan_gpe_next_protocol)); - misc_3_mask->outer_vxlan_gpe_flags = 0; - misc_3_mask->outer_vxlan_gpe_next_protocol = 0; - } - - if (misc_3_mask->outer_vxlan_gpe_vni) { - MLX5_SET(ste_flex_parser_tnl, bit_mask, - flex_parser_tunneling_header_31_0, - misc_3_mask->outer_vxlan_gpe_vni << 8); - misc_3_mask->outer_vxlan_gpe_vni = 0; - } + DR_STE_SET_MASK_V(flex_parser_tnl_vxlan_gpe, bit_mask, + outer_vxlan_gpe_flags, + misc_3_mask, outer_vxlan_gpe_flags); + DR_STE_SET_MASK_V(flex_parser_tnl_vxlan_gpe, bit_mask, + outer_vxlan_gpe_next_protocol, + misc_3_mask, outer_vxlan_gpe_next_protocol); + DR_STE_SET_MASK_V(flex_parser_tnl_vxlan_gpe, bit_mask, + outer_vxlan_gpe_vni, + misc_3_mask, outer_vxlan_gpe_vni); } -static int dr_ste_build_flex_parser_tnl_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *hw_ste_p) +static int +dr_ste_build_flex_parser_tnl_vxlan_gpe_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *hw_ste_p) { struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; struct mlx5dr_match_misc3 *misc3 = &value->misc3; u8 *tag = hw_ste->tag; - if (misc3->outer_vxlan_gpe_flags || - misc3->outer_vxlan_gpe_next_protocol) { - MLX5_SET(ste_flex_parser_tnl, tag, - flex_parser_tunneling_header_63_32, - (misc3->outer_vxlan_gpe_flags << 24) | - (misc3->outer_vxlan_gpe_next_protocol)); - misc3->outer_vxlan_gpe_flags = 0; - misc3->outer_vxlan_gpe_next_protocol = 0; - } - - if (misc3->outer_vxlan_gpe_vni) { - MLX5_SET(ste_flex_parser_tnl, tag, - flex_parser_tunneling_header_31_0, - misc3->outer_vxlan_gpe_vni << 8); - misc3->outer_vxlan_gpe_vni = 0; - } + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_flags, misc3, + outer_vxlan_gpe_flags); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_next_protocol, misc3, + outer_vxlan_gpe_next_protocol); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_vni, misc3, + outer_vxlan_gpe_vni); return 0; } -void mlx5dr_ste_build_flex_parser_tnl(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) +void mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + dr_ste_build_flex_parser_tnl_vxlan_gpe_bit_mask(mask, inner, + sb->bit_mask); + + sb->rx = rx; + sb->inner = inner; + sb->lu_type = MLX5DR_STE_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_vxlan_gpe_tag; +} + +static void +dr_ste_build_flex_parser_tnl_geneve_bit_mask(struct mlx5dr_match_param *value, + u8 *bit_mask) { - dr_ste_build_flex_parser_tnl_bit_mask(mask, inner, sb->bit_mask); + struct mlx5dr_match_misc *misc_mask = &value->misc; + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_protocol_type, + misc_mask, geneve_protocol_type); + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_oam, + misc_mask, geneve_oam); + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_opt_len, + misc_mask, geneve_opt_len); + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_vni, + misc_mask, geneve_vni); +} + +static int +dr_ste_build_flex_parser_tnl_geneve_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *hw_ste_p) +{ + struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; + struct mlx5dr_match_misc *misc = &value->misc; + u8 *tag = hw_ste->tag; + + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_protocol_type, misc, geneve_protocol_type); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_oam, misc, geneve_oam); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_opt_len, misc, geneve_opt_len); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_vni, misc, geneve_vni); + + return 0; +} + +void mlx5dr_ste_build_flex_parser_tnl_geneve(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + dr_ste_build_flex_parser_tnl_geneve_bit_mask(mask, sb->bit_mask); sb->rx = rx; sb->inner = inner; sb->lu_type = MLX5DR_STE_LU_TYPE_FLEX_PARSER_TNL_HEADER; sb->byte_mask = dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_tag; + sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_geneve_tag; } static void dr_ste_build_register_0_bit_mask(struct mlx5dr_match_param *value, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h index 1cb3769d4e3c..290fe61c33d0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -106,6 +106,12 @@ enum mlx5dr_action_type { DR_ACTION_TYP_MAX, }; +enum mlx5dr_ipv { + DR_RULE_IPV4, + DR_RULE_IPV6, + DR_RULE_IPV_MAX, +}; + struct mlx5dr_icm_pool; struct mlx5dr_icm_chunk; struct mlx5dr_icm_bucket; @@ -319,9 +325,12 @@ int mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_build *sb, struct mlx5dr_match_param *mask, struct mlx5dr_cmd_caps *caps, bool inner, bool rx); -void mlx5dr_ste_build_flex_parser_tnl(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); +void mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_flex_parser_tnl_geneve(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_build *sb, struct mlx5dr_match_param *mask, bool inner, bool rx); @@ -679,11 +688,11 @@ struct mlx5dr_matcher_rx_tx { struct mlx5dr_ste_htbl *s_htbl; struct mlx5dr_ste_htbl *e_anchor; struct mlx5dr_ste_build *ste_builder; - struct mlx5dr_ste_build ste_builder4[DR_RULE_MAX_STES]; - struct mlx5dr_ste_build ste_builder6[DR_RULE_MAX_STES]; + struct mlx5dr_ste_build ste_builder_arr[DR_RULE_IPV_MAX] + [DR_RULE_IPV_MAX] + [DR_RULE_MAX_STES]; u8 num_of_builders; - u8 num_of_builders4; - u8 num_of_builders6; + u8 num_of_builders_arr[DR_RULE_IPV_MAX][DR_RULE_IPV_MAX]; u64 default_icm_addr; struct mlx5dr_table_rx_tx *nic_tbl; }; @@ -812,7 +821,8 @@ mlx5dr_matcher_supp_flex_parser_icmp_v6(struct mlx5dr_cmd_caps *caps) int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, - bool ipv6); + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv); static inline u32 mlx5dr_icm_pool_chunk_size_to_entries(enum mlx5dr_icm_chunk_size chunk_size) @@ -962,9 +972,6 @@ void mlx5dr_ste_copy_param(u8 match_criteria, struct mlx5dr_match_param *set_param, struct mlx5dr_match_parameters *mask); -void mlx5dr_crc32_init_table(void); -u32 mlx5dr_crc32_slice8_calc(const void *input_data, size_t length); - struct mlx5dr_qp { struct mlx5_core_dev *mdev; struct mlx5_wq_qp wq; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h index 596c927220d9..1722f4668269 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h @@ -548,6 +548,30 @@ struct mlx5_ifc_ste_flex_parser_tnl_bits { u8 reserved_at_40[0x40]; }; +struct mlx5_ifc_ste_flex_parser_tnl_vxlan_gpe_bits { + u8 outer_vxlan_gpe_flags[0x8]; + u8 reserved_at_8[0x10]; + u8 outer_vxlan_gpe_next_protocol[0x8]; + + u8 outer_vxlan_gpe_vni[0x18]; + u8 reserved_at_38[0x8]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_ste_flex_parser_tnl_geneve_bits { + u8 reserved_at_0[0x2]; + u8 geneve_opt_len[0x6]; + u8 geneve_oam[0x1]; + u8 reserved_at_9[0x7]; + u8 geneve_protocol_type[0x10]; + + u8 geneve_vni[0x18]; + u8 reserved_at_38[0x8]; + + u8 reserved_at_40[0x40]; +}; + struct mlx5_ifc_ste_general_purpose_bits { u8 general_purpose_lookup_field[0x20]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 30f7848a6f88..1faac31f74d0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -1064,26 +1064,13 @@ int mlx5_core_modify_hca_vport_context(struct mlx5_core_dev *dev, ctx = MLX5_ADDR_OF(modify_hca_vport_context_in, in, hca_vport_context); MLX5_SET(hca_vport_context, ctx, field_select, req->field_select); - MLX5_SET(hca_vport_context, ctx, sm_virt_aware, req->sm_virt_aware); - MLX5_SET(hca_vport_context, ctx, has_smi, req->has_smi); - MLX5_SET(hca_vport_context, ctx, has_raw, req->has_raw); - MLX5_SET(hca_vport_context, ctx, vport_state_policy, req->policy); - MLX5_SET(hca_vport_context, ctx, port_physical_state, req->phys_state); - MLX5_SET(hca_vport_context, ctx, vport_state, req->vport_state); - MLX5_SET64(hca_vport_context, ctx, port_guid, req->port_guid); - MLX5_SET64(hca_vport_context, ctx, node_guid, req->node_guid); - MLX5_SET(hca_vport_context, ctx, cap_mask1, req->cap_mask1); - MLX5_SET(hca_vport_context, ctx, cap_mask1_field_select, req->cap_mask1_perm); - MLX5_SET(hca_vport_context, ctx, cap_mask2, req->cap_mask2); - MLX5_SET(hca_vport_context, ctx, cap_mask2_field_select, req->cap_mask2_perm); - MLX5_SET(hca_vport_context, ctx, lid, req->lid); - MLX5_SET(hca_vport_context, ctx, init_type_reply, req->init_type_reply); - MLX5_SET(hca_vport_context, ctx, lmc, req->lmc); - MLX5_SET(hca_vport_context, ctx, subnet_timeout, req->subnet_timeout); - MLX5_SET(hca_vport_context, ctx, sm_lid, req->sm_lid); - MLX5_SET(hca_vport_context, ctx, sm_sl, req->sm_sl); - MLX5_SET(hca_vport_context, ctx, qkey_violation_counter, req->qkey_violation_counter); - MLX5_SET(hca_vport_context, ctx, pkey_violation_counter, req->pkey_violation_counter); + if (req->field_select & MLX5_HCA_VPORT_SEL_STATE_POLICY) + MLX5_SET(hca_vport_context, ctx, vport_state_policy, + req->policy); + if (req->field_select & MLX5_HCA_VPORT_SEL_PORT_GUID) + MLX5_SET64(hca_vport_context, ctx, port_guid, req->port_guid); + if (req->field_select & MLX5_HCA_VPORT_SEL_NODE_GUID) + MLX5_SET64(hca_vport_context, ctx, node_guid, req->node_guid); err = mlx5_cmd_exec(dev, in, in_sz, out, sizeof(out)); ex: kfree(in); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c index dd2315ce4441..f2a0e72285ba 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c @@ -34,26 +34,6 @@ #include "wq.h" #include "mlx5_core.h" -u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq) -{ - return (u32)wq->fbc.sz_m1 + 1; -} - -u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq) -{ - return wq->fbc.sz_m1 + 1; -} - -u8 mlx5_cqwq_get_log_stride_size(struct mlx5_cqwq *wq) -{ - return wq->fbc.log_stride; -} - -u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq) -{ - return (u32)wq->fbc.sz_m1 + 1; -} - static u32 wq_get_byte_sz(u8 log_sz, u8 log_stride) { return ((u32)1 << log_sz) << log_stride; @@ -96,6 +76,24 @@ err_db_free: return err; } +void mlx5_wq_cyc_wqe_dump(struct mlx5_wq_cyc *wq, u16 ix, u8 nstrides) +{ + size_t len; + void *wqe; + + if (!net_ratelimit()) + return; + + nstrides = max_t(u8, nstrides, 1); + + len = nstrides << wq->fbc.log_stride; + wqe = mlx5_wq_cyc_get_wqe(wq, ix); + + pr_info("WQE DUMP: WQ size %d WQ cur size %d, WQE index 0x%x, len: %ld\n", + mlx5_wq_cyc_get_size(wq), wq->cur_sz, ix, len); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, wqe, len, false); +} + int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *qpc, struct mlx5_wq_qp *wq, struct mlx5_wq_ctrl *wq_ctrl) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index 55791f71a778..d9a94bc223c0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -79,7 +79,7 @@ struct mlx5_wq_ll { int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *wqc, struct mlx5_wq_cyc *wq, struct mlx5_wq_ctrl *wq_ctrl); -u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq); +void mlx5_wq_cyc_wqe_dump(struct mlx5_wq_cyc *wq, u16 ix, u8 nstrides); int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *qpc, struct mlx5_wq_qp *wq, @@ -88,16 +88,18 @@ int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *cqc, struct mlx5_cqwq *wq, struct mlx5_wq_ctrl *wq_ctrl); -u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq); -u8 mlx5_cqwq_get_log_stride_size(struct mlx5_cqwq *wq); int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *wqc, struct mlx5_wq_ll *wq, struct mlx5_wq_ctrl *wq_ctrl); -u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq); void mlx5_wq_destroy(struct mlx5_wq_ctrl *wq_ctrl); +static inline u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq) +{ + return (u32)wq->fbc.sz_m1 + 1; +} + static inline int mlx5_wq_cyc_is_full(struct mlx5_wq_cyc *wq) { return wq->cur_sz == wq->sz; @@ -168,6 +170,16 @@ static inline int mlx5_wq_cyc_cc_bigger(u16 cc1, u16 cc2) return !equal && !smaller; } +static inline u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq) +{ + return wq->fbc.sz_m1 + 1; +} + +static inline u8 mlx5_cqwq_get_log_stride_size(struct mlx5_cqwq *wq) +{ + return wq->fbc.log_stride; +} + static inline u32 mlx5_cqwq_ctr2ix(struct mlx5_cqwq *wq, u32 ctr) { return ctr & wq->fbc.sz_m1; @@ -224,6 +236,11 @@ static inline struct mlx5_cqe64 *mlx5_cqwq_get_cqe(struct mlx5_cqwq *wq) return cqe; } +static inline u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq) +{ + return (u32)wq->fbc.sz_m1 + 1; +} + static inline int mlx5_wq_ll_is_full(struct mlx5_wq_ll *wq) { return wq->cur_sz == wq->fbc.sz_m1; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 0a0884d86d44..e9f791c43f20 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -71,6 +71,7 @@ struct mlxsw_core { struct list_head trans_list; spinlock_t trans_list_lock; /* protects trans_list writes */ bool use_emad; + bool enable_string_tlv; } emad; struct { u8 *mapping; /* lag_id+port_index to local_port mapping */ @@ -127,6 +128,16 @@ bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core) } EXPORT_SYMBOL(mlxsw_core_res_query_enabled); +bool +mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, + const struct mlxsw_fw_rev *req_rev) +{ + return rev->minor > req_rev->minor || + (rev->minor == req_rev->minor && + rev->subminor >= req_rev->subminor); +} +EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate); + struct mlxsw_rx_listener_item { struct list_head list; struct mlxsw_rx_listener rxl; @@ -239,6 +250,25 @@ MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8); */ MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64); +/* emad_string_tlv_type + * Type of the TLV. + * Must be set to 0x2 (string TLV). + */ +MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5); + +/* emad_string_tlv_len + * Length of the string TLV in u32. + */ +MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11); + +#define MLXSW_EMAD_STRING_TLV_STRING_LEN 128 + +/* emad_string_tlv_string + * String provided by the device's firmware in case of erroneous register access + */ +MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04, + MLXSW_EMAD_STRING_TLV_STRING_LEN); + /* emad_reg_tlv_type * Type of the TLV. * Must be set to 0x3 (register TLV). @@ -294,6 +324,12 @@ static void mlxsw_emad_pack_reg_tlv(char *reg_tlv, memcpy(reg_tlv + sizeof(u32), payload, reg->len); } +static void mlxsw_emad_pack_string_tlv(char *string_tlv) +{ + mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING); + mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN); +} + static void mlxsw_emad_pack_op_tlv(char *op_tlv, const struct mlxsw_reg_info *reg, enum mlxsw_core_reg_access_type type, @@ -335,7 +371,7 @@ static void mlxsw_emad_construct(struct sk_buff *skb, const struct mlxsw_reg_info *reg, char *payload, enum mlxsw_core_reg_access_type type, - u64 tid) + u64 tid, bool enable_string_tlv) { char *buf; @@ -345,26 +381,82 @@ static void mlxsw_emad_construct(struct sk_buff *skb, buf = skb_push(skb, reg->len + sizeof(u32)); mlxsw_emad_pack_reg_tlv(buf, reg, payload); + if (enable_string_tlv) { + buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32)); + mlxsw_emad_pack_string_tlv(buf); + } + buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32)); mlxsw_emad_pack_op_tlv(buf, reg, type, tid); mlxsw_emad_construct_eth_hdr(skb); } +struct mlxsw_emad_tlv_offsets { + u16 op_tlv; + u16 string_tlv; + u16 reg_tlv; +}; + +static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv) +{ + u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv); + + return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING; +} + +static void mlxsw_emad_tlv_parse(struct sk_buff *skb) +{ + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN; + offsets->string_tlv = 0; + offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN + + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); + + /* If string TLV is present, it must come after the operation TLV. */ + if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) { + offsets->string_tlv = offsets->reg_tlv; + offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32); + } +} + static char *mlxsw_emad_op_tlv(const struct sk_buff *skb) { - return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN)); + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + return ((char *) (skb->data + offsets->op_tlv)); +} + +static char *mlxsw_emad_string_tlv(const struct sk_buff *skb) +{ + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + if (!offsets->string_tlv) + return NULL; + + return ((char *) (skb->data + offsets->string_tlv)); } static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb) { - return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN + - MLXSW_EMAD_OP_TLV_LEN * sizeof(u32))); + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + return ((char *) (skb->data + offsets->reg_tlv)); } -static char *mlxsw_emad_reg_payload(const char *op_tlv) +static char *mlxsw_emad_reg_payload(const char *reg_tlv) { - return ((char *) (op_tlv + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32))); + return ((char *) (reg_tlv + sizeof(u32))); +} + +static char *mlxsw_emad_reg_payload_cmd(const char *mbox) +{ + return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32))); } static u64 mlxsw_emad_get_tid(const struct sk_buff *skb) @@ -430,10 +522,31 @@ struct mlxsw_reg_trans { const struct mlxsw_reg_info *reg; enum mlxsw_core_reg_access_type type; int err; + char *emad_err_string; enum mlxsw_emad_op_tlv_status emad_status; struct rcu_head rcu; }; +static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb, + struct mlxsw_reg_trans *trans) +{ + char *string_tlv; + char *string; + + string_tlv = mlxsw_emad_string_tlv(skb); + if (!string_tlv) + return; + + trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN, + GFP_ATOMIC); + if (!trans->emad_err_string) + return; + + string = mlxsw_emad_string_tlv_string_data(string_tlv); + strlcpy(trans->emad_err_string, string, + MLXSW_EMAD_STRING_TLV_STRING_LEN); +} + #define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000 #define MLXSW_EMAD_TIMEOUT_MS 200 @@ -525,12 +638,14 @@ static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core, mlxsw_emad_transmit_retry(mlxsw_core, trans); } else { if (err == 0) { - char *op_tlv = mlxsw_emad_op_tlv(skb); + char *reg_tlv = mlxsw_emad_reg_tlv(skb); if (trans->cb) trans->cb(mlxsw_core, - mlxsw_emad_reg_payload(op_tlv), + mlxsw_emad_reg_payload(reg_tlv), trans->reg->len, trans->cb_priv); + } else { + mlxsw_emad_process_string_tlv(skb, trans); } mlxsw_emad_trans_finish(trans, err); } @@ -546,6 +661,8 @@ static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port, trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0, skb->data, skb->len); + mlxsw_emad_tlv_parse(skb); + if (!mlxsw_emad_is_resp(skb)) goto free_skb; @@ -621,7 +738,7 @@ static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core) } static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, - u16 reg_len) + u16 reg_len, bool enable_string_tlv) { struct sk_buff *skb; u16 emad_len; @@ -629,6 +746,8 @@ static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN + (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) * sizeof(u32) + mlxsw_core->driver->txhdr_len); + if (enable_string_tlv) + emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32); if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN) return NULL; @@ -650,6 +769,7 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv, u64 tid) { + bool enable_string_tlv; struct sk_buff *skb; int err; @@ -657,7 +777,12 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, tid, reg->id, mlxsw_reg_id_str(reg->id), mlxsw_core_reg_access_type_str(type)); - skb = mlxsw_emad_alloc(mlxsw_core, reg->len); + /* Since this can be changed during emad_reg_access, read it once and + * use the value all the way. + */ + enable_string_tlv = mlxsw_core->emad.enable_string_tlv; + + skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv); if (!skb) return -ENOMEM; @@ -674,7 +799,8 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, trans->reg = reg; trans->type = type; - mlxsw_emad_construct(skb, reg, payload, type, trans->tid); + mlxsw_emad_construct(skb, reg, payload, type, trans->tid, + enable_string_tlv); mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info); spin_lock_bh(&mlxsw_core->emad.trans_list_lock); @@ -985,6 +1111,7 @@ mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, static int mlxsw_devlink_core_bus_device_reload_down(struct devlink *devlink, + bool netns_change, struct netlink_ext_ack *extack) { struct mlxsw_core *mlxsw_core = devlink_priv(devlink); @@ -1005,7 +1132,7 @@ mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink, return mlxsw_core_bus_device_register(mlxsw_core->bus_info, mlxsw_core->bus, mlxsw_core->bus_priv, true, - devlink); + devlink, extack); } static int mlxsw_devlink_flash_update(struct devlink *devlink, @@ -1098,7 +1225,8 @@ static int __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, const struct mlxsw_bus *mlxsw_bus, void *bus_priv, bool reload, - struct devlink *devlink) + struct devlink *devlink, + struct netlink_ext_ack *extack) { const char *device_kind = mlxsw_bus_info->device_kind; struct mlxsw_core *mlxsw_core; @@ -1172,7 +1300,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, } if (mlxsw_driver->init) { - err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); + err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack); if (err) goto err_driver_init; } @@ -1226,14 +1354,16 @@ err_devlink_alloc: int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, const struct mlxsw_bus *mlxsw_bus, void *bus_priv, bool reload, - struct devlink *devlink) + struct devlink *devlink, + struct netlink_ext_ack *extack) { bool called_again = false; int err; again: err = __mlxsw_core_bus_device_register(mlxsw_bus_info, mlxsw_bus, - bus_priv, reload, devlink); + bus_priv, reload, + devlink, extack); /* -EAGAIN is returned in case the FW was updated. FW needs * a reset, so lets try to call __mlxsw_core_bus_device_register() * again. @@ -1381,12 +1511,16 @@ static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port, struct mlxsw_event_listener_item *event_listener_item = priv; struct mlxsw_reg_info reg; char *payload; - char *op_tlv = mlxsw_emad_op_tlv(skb); - char *reg_tlv = mlxsw_emad_reg_tlv(skb); + char *reg_tlv; + char *op_tlv; + + mlxsw_emad_tlv_parse(skb); + op_tlv = mlxsw_emad_op_tlv(skb); + reg_tlv = mlxsw_emad_reg_tlv(skb); reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv); reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32); - payload = mlxsw_emad_reg_payload(op_tlv); + payload = mlxsw_emad_reg_payload(reg_tlv); event_listener_item->el.func(®, payload, event_listener_item->priv); dev_kfree_skb(skb); } @@ -1604,8 +1738,11 @@ int mlxsw_reg_trans_write(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_reg_trans_write); +#define MLXSW_REG_TRANS_ERR_STRING_SIZE 256 + static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans) { + char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE]; struct mlxsw_core *mlxsw_core = trans->core; int err; @@ -1623,9 +1760,17 @@ static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans) mlxsw_core_reg_access_type_str(trans->type), trans->emad_status, mlxsw_emad_op_tlv_status_str(trans->emad_status)); + + snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE, + "(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid, + trans->reg->id, mlxsw_reg_id_str(trans->reg->id), + mlxsw_emad_op_tlv_status_str(trans->emad_status), + trans->emad_err_string ? trans->emad_err_string : ""); + trace_devlink_hwerr(priv_to_devlink(mlxsw_core), - trans->emad_status, - mlxsw_emad_op_tlv_status_str(trans->emad_status)); + trans->emad_status, err_string); + + kfree(trans->emad_err_string); } list_del(&trans->bulk_list); @@ -1699,7 +1844,7 @@ retry: } if (!err) - memcpy(payload, mlxsw_emad_reg_payload(out_mbox), + memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox), reg->len); mlxsw_cmd_mbox_free(out_mbox); @@ -2008,6 +2153,35 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get); +int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module) +{ + enum mlxsw_reg_pmtm_module_type module_type; + char pmtm_pl[MLXSW_REG_PMTM_LEN]; + int err; + + mlxsw_reg_pmtm_pack(pmtm_pl, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl); + if (err) + return err; + mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type); + + /* Here we need to get the module width according to the module type. */ + + switch (module_type) { + case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP: + return 4; + case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X: + return 2; + case MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X: + return 1; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL(mlxsw_core_module_max_width); + static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core, const char *buf, size_t size) { @@ -2167,6 +2341,12 @@ u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core) } EXPORT_SYMBOL(mlxsw_core_read_frc_l); +void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core) +{ + mlxsw_core->emad.enable_string_tlv = true; +} +EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable); + static int __init mlxsw_core_module_init(void) { int err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 5d7d2ab6d155..543476a2e503 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/skbuff.h> #include <linux/workqueue.h> +#include <linux/net_namespace.h> #include <net/devlink.h> #include "trap.h" @@ -23,6 +24,7 @@ struct mlxsw_core_port; struct mlxsw_driver; struct mlxsw_bus; struct mlxsw_bus_info; +struct mlxsw_fw_rev; unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); @@ -30,13 +32,18 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core); +bool +mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, + const struct mlxsw_fw_rev *req_rev); + int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, const struct mlxsw_bus *mlxsw_bus, void *bus_priv, bool reload, - struct devlink *devlink); + struct devlink *devlink, + struct netlink_ext_ack *extack); void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, bool reload); struct mlxsw_tx_info { @@ -193,6 +200,7 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, struct devlink_port * mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, u8 local_port); +int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module); int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay); bool mlxsw_core_schedule_work(struct work_struct *work); @@ -252,7 +260,8 @@ struct mlxsw_driver { const char *kind; size_t priv_size; int (*init)(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info); + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack); void (*fini)(struct mlxsw_core *mlxsw_core); int (*basic_trap_groups_set)(struct mlxsw_core *mlxsw_core); int (*port_type_set)(struct mlxsw_core *mlxsw_core, u8 local_port, @@ -338,6 +347,8 @@ void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core); u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core); u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core); +void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core); + bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core, enum mlxsw_res_id res_id); @@ -350,6 +361,11 @@ u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, #define MLXSW_CORE_RES_GET(mlxsw_core, short_res_id) \ mlxsw_core_res_get(mlxsw_core, MLXSW_RES_ID_##short_res_id) +static inline struct net *mlxsw_core_net(struct mlxsw_core *mlxsw_core) +{ + return devlink_net(priv_to_devlink(mlxsw_core)); +} + #define MLXSW_BUS_F_TXRX BIT(0) #define MLXSW_BUS_F_RESET BIT(1) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c index d2c7ce67c300..08215fed193d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c @@ -50,6 +50,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; char mcia_pl[MLXSW_REG_MCIA_LEN]; u16 i2c_addr; + u8 page = 0; int status; int err; @@ -62,11 +63,21 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { - i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; - offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; + page = MLXSW_REG_MCIA_PAGE_GET(offset); + offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; + /* When reading upper pages 1, 2 and 3 the offset starts at + * 128. Please refer to "QSFP+ Memory Map" figure in SFF-8436 + * specification for graphical depiction. + * MCIA register accepts buffer size <= 48. Page of size 128 + * should be read by chunks of size 48, 48, 32. Align the size + * of the last chunk to avoid reading after the end of the + * page. + */ + if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) + size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; } - mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr); + mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); if (err) @@ -168,7 +179,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, switch (module_id) { case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: @@ -176,10 +187,10 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, module_rev_id >= MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; } else { modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; } break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c index 5b00726c4346..9bf8da5f6daf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c @@ -41,7 +41,7 @@ struct mlxsw_hwmon { struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; unsigned int attrs_count; u8 sensor_count; - u8 module_sensor_count; + u8 module_sensor_max; }; static ssize_t mlxsw_hwmon_temp_show(struct device *dev, @@ -56,7 +56,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, int err; index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); + mlxsw_hwmon->module_sensor_max); mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); if (err) { @@ -79,7 +79,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, int err; index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); + mlxsw_hwmon->module_sensor_max); mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); if (err) { @@ -109,7 +109,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, return -EINVAL; index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); + mlxsw_hwmon->module_sensor_max); mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true); err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); if (err) { @@ -336,7 +336,7 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev, container_of(attr, struct mlxsw_hwmon_attr, dev_attr); struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; int index = mlwsw_hwmon_attr->type_index - - mlxsw_hwmon->module_sensor_count + 1; + mlxsw_hwmon->module_sensor_max + 1; return sprintf(buf, "gearbox %03u\n", index); } @@ -528,51 +528,45 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) { - unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); - char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; - int i, index; - u8 width; - int err; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + u8 module_sensor_max; + int i, err; if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) return 0; + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, + &module_sensor_max); + /* Add extra attributes for module temperature. Sensor index is * assigned to sensor_count value, while all indexed before * sensor_count are already utilized by the sensors connected through * mtmp register by mlxsw_hwmon_temp_init(). */ - index = mlxsw_hwmon->sensor_count; - for (i = 1; i < module_count; i++) { - mlxsw_reg_pmlp_pack(pmlp_pl, i); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp), - pmlp_pl); - if (err) { - dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n", - i); - return err; - } - width = mlxsw_reg_pmlp_width_get(pmlp_pl); - if (!width) - continue; + mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count + + module_sensor_max; + for (i = mlxsw_hwmon->sensor_count; + i < mlxsw_hwmon->module_sensor_max; i++) { mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, - index); + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, - index, index); + i, i); mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, - index, index); + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, + i); mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, - index, index); + i, i); mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, - index, index); - index++; + i, i); } - mlxsw_hwmon->module_sensor_count = index; return 0; } @@ -590,14 +584,14 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) if (err) return err; - mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL); + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL); if (!gbox_num) return 0; - index = mlxsw_hwmon->module_sensor_count; - max_index = mlxsw_hwmon->module_sensor_count + gbox_num; + index = mlxsw_hwmon->module_sensor_max; + max_index = mlxsw_hwmon->module_sensor_max + gbox_num; while (index < max_index) { - sensor_index = index % mlxsw_hwmon->module_sensor_count + + sensor_index = index % mlxsw_hwmon->module_sensor_max + MLXSW_REG_MTMP_GBOX_INDEX_MIN; mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); err = mlxsw_reg_write(mlxsw_hwmon->core, diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c index 35a1dc89c28a..c721b171bd8d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c @@ -112,6 +112,7 @@ struct mlxsw_thermal { struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; enum thermal_device_mode mode; struct mlxsw_thermal_module *tz_module_arr; + u8 tz_module_num; struct mlxsw_thermal_module *tz_gearbox_arr; u8 tz_gearbox_num; unsigned int tz_highest_score; @@ -775,23 +776,10 @@ static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) static int mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, - struct mlxsw_thermal *thermal, u8 local_port) + struct mlxsw_thermal *thermal, u8 module) { struct mlxsw_thermal_module *module_tz; - char pmlp_pl[MLXSW_REG_PMLP_LEN]; - u8 width, module; - int err; - - mlxsw_reg_pmlp_pack(pmlp_pl, local_port); - err = mlxsw_reg_query(core, MLXSW_REG(pmlp), pmlp_pl); - if (err) - return err; - width = mlxsw_reg_pmlp_width_get(pmlp_pl); - if (!width) - return 0; - - module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); module_tz = &thermal->tz_module_arr[module]; /* Skip if parent is already set (case of port split). */ if (module_tz->parent) @@ -819,26 +807,34 @@ static int mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, struct mlxsw_thermal *thermal) { - unsigned int module_count = mlxsw_core_max_ports(core); struct mlxsw_thermal_module *module_tz; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; int i, err; if (!mlxsw_core_res_query_enabled(core)) return 0; - thermal->tz_module_arr = kcalloc(module_count, + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, + &thermal->tz_module_num); + + thermal->tz_module_arr = kcalloc(thermal->tz_module_num, sizeof(*thermal->tz_module_arr), GFP_KERNEL); if (!thermal->tz_module_arr) return -ENOMEM; - for (i = 1; i < module_count; i++) { + for (i = 0; i < thermal->tz_module_num; i++) { err = mlxsw_thermal_module_init(dev, core, thermal, i); if (err) goto err_unreg_tz_module_arr; } - for (i = 0; i < module_count - 1; i++) { + for (i = 0; i < thermal->tz_module_num; i++) { module_tz = &thermal->tz_module_arr[i]; if (!module_tz->parent) continue; @@ -850,7 +846,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, return 0; err_unreg_tz_module_arr: - for (i = module_count - 1; i >= 0; i--) + for (i = thermal->tz_module_num - 1; i >= 0; i--) mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); kfree(thermal->tz_module_arr); return err; @@ -859,13 +855,12 @@ err_unreg_tz_module_arr: static void mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) { - unsigned int module_count = mlxsw_core_max_ports(thermal->core); int i; if (!mlxsw_core_res_query_enabled(thermal->core)) return; - for (i = module_count - 1; i >= 0; i--) + for (i = thermal->tz_module_num - 1; i >= 0; i--) mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); kfree(thermal->tz_module_arr); } @@ -913,7 +908,8 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, if (err) return err; - mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL); + mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL, + NULL); if (!thermal->tz_gearbox_num) return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/emad.h b/drivers/net/ethernet/mellanox/mlxsw/emad.h index a33b896f4bb8..acfbbec52424 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/emad.h +++ b/drivers/net/ethernet/mellanox/mlxsw/emad.h @@ -19,10 +19,8 @@ enum { MLXSW_EMAD_TLV_TYPE_END, MLXSW_EMAD_TLV_TYPE_OP, - MLXSW_EMAD_TLV_TYPE_DR, + MLXSW_EMAD_TLV_TYPE_STRING, MLXSW_EMAD_TLV_TYPE_REG, - MLXSW_EMAD_TLV_TYPE_USERDATA, - MLXSW_EMAD_TLV_TYPE_OOBETH, }; /* OP TLV */ @@ -89,6 +87,9 @@ enum { MLXSW_EMAD_OP_TLV_METHOD_EVENT = 5, }; +/* STRING TLV */ +#define MLXSW_EMAD_STRING_TLV_LEN 33 /* Length in u32 */ + /* END TLV */ #define MLXSW_EMAD_END_TLV_LEN 1 /* Length in u32 */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c index 95f408d0e103..34566eb62c47 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c +++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c @@ -640,7 +640,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client, err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, &mlxsw_i2c_bus, mlxsw_i2c, false, - NULL); + NULL, NULL); if (err) { dev_err(&client->dev, "Fail to register core bus\n"); return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index 471b0ca6d69a..2b543911ae00 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -16,6 +16,14 @@ static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; +#define MLXSW_M_FWREV_MINOR 2000 +#define MLXSW_M_FWREV_SUBMINOR 1886 + +static const struct mlxsw_fw_rev mlxsw_m_fw_rev = { + .minor = MLXSW_M_FWREV_MINOR, + .subminor = MLXSW_M_FWREV_SUBMINOR, +}; + struct mlxsw_m_port; struct mlxsw_m { @@ -172,6 +180,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) } SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev); + dev_net_set(dev, mlxsw_core_net(mlxsw_m->core)); mlxsw_m_port = netdev_priv(dev); mlxsw_m_port->dev = dev; mlxsw_m_port->mlxsw_m = mlxsw_m; @@ -325,8 +334,27 @@ static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) kfree(mlxsw_m->ports); } +static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) +{ + const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev; + + /* Validate driver and FW are compatible. + * Do not check major version, since it defines chip type, while + * driver is supposed to support any type. + */ + if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev)) + return 0; + + dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", + rev->major, rev->minor, rev->subminor, rev->major, + mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor); + + return -EINVAL; +} + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); int err; @@ -334,6 +362,10 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, mlxsw_m->core = mlxsw_core; mlxsw_m->bus_info = mlxsw_bus_info; + err = mlxsw_m_fw_rev_validate(mlxsw_m); + if (err) + return err; + err = mlxsw_m_base_mac_get(mlxsw_m); if (err) { dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n"); diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 615455a21567..914c33e46fb4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -284,15 +284,18 @@ static dma_addr_t __mlxsw_pci_queue_page_get(struct mlxsw_pci_queue *q, static int mlxsw_pci_sdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, struct mlxsw_pci_queue *q) { + int tclass; int i; int err; q->producer_counter = 0; q->consumer_counter = 0; + tclass = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_PCI_SDQ_EMAD_TC : + MLXSW_PCI_SDQ_CTL_TC; /* Set CQ of same number of this SDQ. */ mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num); - mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, 3); + mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, tclass); mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); @@ -963,6 +966,7 @@ static int mlxsw_pci_aqs_init(struct mlxsw_pci *mlxsw_pci, char *mbox) eq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_eq_sz_get(mbox); if (num_sdqs + num_rdqs > num_cqs || + num_sdqs < MLXSW_PCI_SDQS_MIN || num_cqs > MLXSW_PCI_CQS_MAX || num_eqs != MLXSW_PCI_EQS_COUNT) { dev_err(&pdev->dev, "Unsupported number of queues\n"); return -EINVAL; @@ -1520,7 +1524,15 @@ static struct mlxsw_pci_queue * mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, const struct mlxsw_tx_info *tx_info) { - u8 sdqn = tx_info->local_port % mlxsw_pci_sdq_count(mlxsw_pci); + u8 ctl_sdq_count = mlxsw_pci_sdq_count(mlxsw_pci) - 1; + u8 sdqn; + + if (tx_info->is_emad) { + sdqn = MLXSW_PCI_SDQ_EMAD_INDEX; + } else { + BUILD_BUG_ON(MLXSW_PCI_SDQ_EMAD_INDEX != 0); + sdqn = 1 + (tx_info->local_port % ctl_sdq_count); + } return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); } @@ -1790,7 +1802,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, &mlxsw_pci_bus, mlxsw_pci, false, - NULL); + NULL, NULL); if (err) { dev_err(&pdev->dev, "cannot register bus device\n"); goto err_bus_device_register; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index e57e42e2d2b2..e0d7d2d9a0c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -27,7 +27,7 @@ #define MLXSW_PCI_SW_RESET 0xF0010 #define MLXSW_PCI_SW_RESET_RST_BIT BIT(0) -#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 20000 +#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 900000 #define MLXSW_PCI_SW_RESET_WAIT_MSECS 100 #define MLXSW_PCI_FW_READY 0xA1844 #define MLXSW_PCI_FW_READY_MASK 0xFFFF @@ -51,6 +51,11 @@ #define MLXSW_PCI_EQ_ASYNC_NUM 0 #define MLXSW_PCI_EQ_COMP_NUM 1 +#define MLXSW_PCI_SDQS_MIN 2 /* EMAD and control traffic */ +#define MLXSW_PCI_SDQ_EMAD_INDEX 0 +#define MLXSW_PCI_SDQ_EMAD_TC 0 +#define MLXSW_PCI_SDQ_CTL_TC 3 + #define MLXSW_PCI_AQ_PAGES 8 #define MLXSW_PCI_AQ_SIZE (MLXSW_PCI_PAGE_SIZE * MLXSW_PCI_AQ_PAGES) #define MLXSW_PCI_WQE_SIZE 32 /* 32 bytes per element */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h index a33eeef0b00c..741fd2989d12 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/port.h +++ b/drivers/net/ethernet/mellanox/mlxsw/port.h @@ -24,8 +24,6 @@ #define MLXSW_PORT_DONT_CARE 0xFF -#define MLXSW_PORT_MODULE_MAX_WIDTH 4 - enum mlxsw_port_admin_status { MLXSW_PORT_ADMIN_STATUS_UP = 1, MLXSW_PORT_ADMIN_STATUS_DOWN = 2, diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 5494cf93f34c..5294a1622643 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -3969,6 +3969,7 @@ MLXSW_ITEM32(reg, pmlp, local_port, 0x00, 16, 8); * 1 - Lane 0 is used. * 2 - Lanes 0 and 1 are used. * 4 - Lanes 0, 1, 2 and 3 are used. + * 8 - Lanes 0-7 are used. * Access: RW */ MLXSW_ITEM32(reg, pmlp, width, 0x00, 0, 8); @@ -3983,14 +3984,14 @@ MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0x00, false); * Tx Lane. When rxtx field is cleared, this field is used for Rx as well. * Access: RW */ -MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 0x00, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 4, 0x04, 0x00, false); /* reg_pmlp_rx_lane * Rx Lane. When rxtx field is cleared, this field is ignored and Rx lane is * equal to Tx lane. * Access: RW */ -MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 0x00, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 4, 0x04, 0x00, false); static inline void mlxsw_reg_pmlp_pack(char *payload, u8 local_port) { @@ -4111,6 +4112,7 @@ MLXSW_ITEM32(reg, ptys, an_status, 0x04, 28, 4); #define MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4 BIT(9) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2 BIT(10) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4 BIT(12) +#define MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8 BIT(15) /* reg_ptys_ext_eth_proto_cap * Extended Ethernet port supported speeds and protocols. @@ -5373,6 +5375,55 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port, MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0); } +/* PMTM - Port Module Type Mapping Register + * ---------------------------------------- + * The PMTM allows query or configuration of module types. + */ +#define MLXSW_REG_PMTM_ID 0x5067 +#define MLXSW_REG_PMTM_LEN 0x10 + +MLXSW_REG_DEFINE(pmtm, MLXSW_REG_PMTM_ID, MLXSW_REG_PMTM_LEN); + +/* reg_pmtm_module + * Module number. + * Access: Index + */ +MLXSW_ITEM32(reg, pmtm, module, 0x00, 16, 8); + +enum mlxsw_reg_pmtm_module_type { + /* Backplane with 4 lanes */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_4X, + /* QSFP */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP, + /* SFP */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP, + /* Backplane with single lane */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_1X = 4, + /* Backplane with two lane */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_2X = 8, + /* Chip2Chip */ + MLXSW_REG_PMTM_MODULE_TYPE_C2C = 10, +}; + +/* reg_pmtm_module_type + * Module type. + * Access: RW + */ +MLXSW_ITEM32(reg, pmtm, module_type, 0x04, 0, 4); + +static inline void mlxsw_reg_pmtm_pack(char *payload, u8 module) +{ + MLXSW_REG_ZERO(pmtm, payload); + mlxsw_reg_pmtm_module_set(payload, module); +} + +static inline void +mlxsw_reg_pmtm_unpack(char *payload, + enum mlxsw_reg_pmtm_module_type *module_type) +{ + *module_type = mlxsw_reg_pmtm_module_type_get(payload); +} + /* HTGT - Host Trap Group Table * ---------------------------- * Configures the properties for forwarding to CPU. @@ -5429,6 +5480,7 @@ enum mlxsw_reg_htgt_trap_group { enum mlxsw_reg_htgt_discard_trap_group { MLXSW_REG_HTGT_DISCARD_TRAP_GROUP_BASE = MLXSW_REG_HTGT_TRAP_GROUP_MAX, MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS, + MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS, }; /* reg_htgt_trap_group @@ -8411,6 +8463,7 @@ MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); #define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 +#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 #define MLXSW_REG_MCIA_EEPROM_SIZE 48 #define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 #define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 @@ -8446,6 +8499,14 @@ enum mlxsw_reg_mcia_eeprom_module_info { */ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); +/* This is used to access the optional upper pages (1-3) in the QSFP+ + * memory map. Page 1 is available on offset 256 through 383, page 2 - + * on offset 384 through 511, page 3 - on offset 512 through 639. + */ +#define MLXSW_REG_MCIA_PAGE_GET(off) (((off) - \ + MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) / \ + MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) + static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, u8 page_number, u16 device_addr, u8 size, u8 i2c_device_addr) @@ -8670,7 +8731,7 @@ mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(char *payload, u8 ttl, * properties. */ #define MLXSW_REG_MPAR_ID 0x901B -#define MLXSW_REG_MPAR_LEN 0x08 +#define MLXSW_REG_MPAR_LEN 0x0C MLXSW_REG_DEFINE(mpar, MLXSW_REG_MPAR_ID, MLXSW_REG_MPAR_LEN); @@ -9531,6 +9592,12 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); */ MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); +/* num_of_modules + * Number of modules. + * Access: RO + */ +MLXSW_ITEM32(reg, mgpir, num_of_modules, 0x04, 0, 8); + static inline void mlxsw_reg_mgpir_pack(char *payload) { MLXSW_REG_ZERO(mgpir, payload); @@ -9539,7 +9606,7 @@ static inline void mlxsw_reg_mgpir_pack(char *payload) static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, enum mlxsw_reg_mgpir_device_type *device_type, - u8 *devices_per_flash) + u8 *devices_per_flash, u8 *num_of_modules) { if (num_of_devices) *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); @@ -9548,6 +9615,8 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, if (devices_per_flash) *devices_per_flash = mlxsw_reg_mgpir_devices_per_flash_get(payload); + if (num_of_modules) + *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); } /* TNGCR - Tunneling NVE General Configuration Register @@ -10526,6 +10595,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(pbmc), MLXSW_REG(pspa), MLXSW_REG(pplr), + MLXSW_REG(pmtm), MLXSW_REG(htgt), MLXSW_REG(hpkt), MLXSW_REG(rgcr), diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 33a9fc9ef6a4..6534184cb942 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -26,7 +26,8 @@ enum mlxsw_res_id { MLXSW_RES_ID_MAX_LAG_MEMBERS, MLXSW_RES_ID_LOCAL_PORTS_IN_1X, MLXSW_RES_ID_LOCAL_PORTS_IN_2X, - MLXSW_RES_ID_MAX_BUFFER_SIZE, + MLXSW_RES_ID_LOCAL_PORTS_IN_4X, + MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER, MLXSW_RES_ID_CELL_SIZE, MLXSW_RES_ID_MAX_HEADROOM_SIZE, MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS, @@ -82,7 +83,8 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, [MLXSW_RES_ID_LOCAL_PORTS_IN_1X] = 0x2610, [MLXSW_RES_ID_LOCAL_PORTS_IN_2X] = 0x2611, - [MLXSW_RES_ID_MAX_BUFFER_SIZE] = 0x2802, /* Bytes */ + [MLXSW_RES_ID_LOCAL_PORTS_IN_4X] = 0x2612, + [MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */ [MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */ [MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */ [MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS] = 0x2901, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index dcf9562bce8a..556dca328bb5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -22,6 +22,7 @@ #include <linux/inetdevice.h> #include <linux/netlink.h> #include <linux/jhash.h> +#include <linux/log2.h> #include <net/switchdev.h> #include <net/pkt_cls.h> #include <net/tc_act/tc_mirred.h> @@ -48,7 +49,7 @@ #define MLXSW_SP1_FWREV_MAJOR 13 #define MLXSW_SP1_FWREV_MINOR 2000 -#define MLXSW_SP1_FWREV_SUBMINOR 1886 +#define MLXSW_SP1_FWREV_SUBMINOR 2308 #define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702 static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { @@ -63,6 +64,21 @@ static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { "." __stringify(MLXSW_SP1_FWREV_MINOR) \ "." __stringify(MLXSW_SP1_FWREV_SUBMINOR) ".mfa2" +#define MLXSW_SP2_FWREV_MAJOR 29 +#define MLXSW_SP2_FWREV_MINOR 2000 +#define MLXSW_SP2_FWREV_SUBMINOR 2308 + +static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = { + .major = MLXSW_SP2_FWREV_MAJOR, + .minor = MLXSW_SP2_FWREV_MINOR, + .subminor = MLXSW_SP2_FWREV_SUBMINOR, +}; + +#define MLXSW_SP2_FW_FILENAME \ + "mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \ + "." __stringify(MLXSW_SP2_FWREV_MINOR) \ + "." __stringify(MLXSW_SP2_FWREV_SUBMINOR) ".mfa2" + static const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum"; static const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2"; static const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3"; @@ -409,9 +425,7 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) } if (MLXSW_SP_FWREV_MINOR_TO_BRANCH(rev->minor) == MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor) && - (rev->minor > req_rev->minor || - (rev->minor == req_rev->minor && - rev->subminor >= req_rev->subminor))) + mlxsw_core_fw_rev_minor_subminor_validate(rev, req_rev)) return 0; dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n", @@ -735,35 +749,69 @@ mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl); } -static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, - u8 local_port, u8 *p_module, - u8 *p_width, u8 *p_lane) +static int +mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, + struct mlxsw_sp_port_mapping *port_mapping) { char pmlp_pl[MLXSW_REG_PMLP_LEN]; + bool separate_rxtx; + u8 module; + u8 width; int err; + int i; mlxsw_reg_pmlp_pack(pmlp_pl, local_port); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); if (err) return err; - *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); - *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); - *p_lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); + module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); + width = mlxsw_reg_pmlp_width_get(pmlp_pl); + separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl); + + if (width && !is_power_of_2(width)) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n", + local_port); + return -EINVAL; + } + + for (i = 0; i < width; i++) { + if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n", + local_port); + return -EINVAL; + } + if (separate_rxtx && + mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != + mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n", + local_port); + return -EINVAL; + } + if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n", + local_port); + return -EINVAL; + } + } + + port_mapping->module = module; + port_mapping->width = width; + port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); return 0; } -static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port, - u8 module, u8 width, u8 lane) +static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port) { + struct mlxsw_sp_port_mapping *port_mapping = &mlxsw_sp_port->mapping; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char pmlp_pl[MLXSW_REG_PMLP_LEN]; int i; mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port); - mlxsw_reg_pmlp_width_set(pmlp_pl, width); - for (i = 0; i < width; i++) { - mlxsw_reg_pmlp_module_set(pmlp_pl, i, module); - mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, lane + i); /* Rx & Tx */ + mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width); + for (i = 0; i < port_mapping->width; i++) { + mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module); + mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */ } return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); @@ -2914,9 +2962,22 @@ mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = { #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \ ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4) +static const enum ethtool_link_mode_bit_indices +mlxsw_sp2_mask_ethtool_400gaui_8[] = { + ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, +}; + +#define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \ + ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8) + #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0) #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1) #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2) +#define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3) static u8 mlxsw_sp_port_mask_width_get(u8 width) { @@ -2927,6 +2988,8 @@ static u8 mlxsw_sp_port_mask_width_get(u8 width) return MLXSW_SP_PORT_MASK_WIDTH_2X; case 4: return MLXSW_SP_PORT_MASK_WIDTH_4X; + case 8: + return MLXSW_SP_PORT_MASK_WIDTH_8X; default: WARN_ON_ONCE(1); return 0; @@ -2948,7 +3011,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100, }, { @@ -2957,7 +3021,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_1000, }, { @@ -2966,7 +3031,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_2_5GBASE_X_2_5GMII_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_2500, }, { @@ -2975,7 +3041,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_5000, }, { @@ -2984,14 +3051,16 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_10000, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G, .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_40000, }, { @@ -3000,7 +3069,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_25000, }, { @@ -3008,7 +3078,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_50000, }, { @@ -3022,7 +3093,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100000, }, { @@ -3036,9 +3108,17 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_200000, }, + { + .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8, + .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8, + .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_8X, + .speed = SPEED_400000, + }, }; #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode) @@ -3435,7 +3515,7 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { }; static int -mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 width) +mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; const struct mlxsw_sp_port_type_speed_ops *ops; @@ -3451,7 +3531,7 @@ mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 width) &base_speed); if (err) return err; - upper_speed = base_speed * width; + upper_speed = base_speed * mlxsw_sp_port->mapping.width; eth_proto_admin = ops->to_ptys_upper_speed(mlxsw_sp, upper_speed); ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, @@ -3612,15 +3692,18 @@ static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, } static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, - bool split, u8 module, u8 width, u8 lane) + u8 split_base_local_port, + struct mlxsw_sp_port_mapping *port_mapping) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + bool split = !!split_base_local_port; struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *dev; int err; err = mlxsw_core_port_init(mlxsw_sp->core, local_port, - module + 1, split, lane / width, + port_mapping->module + 1, split, + port_mapping->lane / port_mapping->width, mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac)); if (err) { @@ -3635,15 +3718,15 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_alloc_etherdev; } SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev); + dev_net_set(dev, mlxsw_sp_net(mlxsw_sp)); mlxsw_sp_port = netdev_priv(dev); mlxsw_sp_port->dev = dev; mlxsw_sp_port->mlxsw_sp = mlxsw_sp; mlxsw_sp_port->local_port = local_port; mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID; mlxsw_sp_port->split = split; - mlxsw_sp_port->mapping.module = module; - mlxsw_sp_port->mapping.width = width; - mlxsw_sp_port->mapping.lane = lane; + mlxsw_sp_port->split_base_local_port = split_base_local_port; + mlxsw_sp_port->mapping = *port_mapping; mlxsw_sp_port->link.autoneg = 1; INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); INIT_LIST_HEAD(&mlxsw_sp_port->mall_tc_list); @@ -3668,7 +3751,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, dev->netdev_ops = &mlxsw_sp_port_netdev_ops; dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; - err = mlxsw_sp_port_module_map(mlxsw_sp_port, module, width, lane); + err = mlxsw_sp_port_module_map(mlxsw_sp_port); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n", mlxsw_sp_port->local_port); @@ -3710,7 +3793,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_system_port_mapping_set; } - err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port, width); + err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n", mlxsw_sp_port->local_port); @@ -3933,14 +4016,13 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp) if (mlxsw_sp_port_created(mlxsw_sp, i)) mlxsw_sp_port_remove(mlxsw_sp, i); mlxsw_sp_cpu_port_remove(mlxsw_sp); - kfree(mlxsw_sp->port_to_module); kfree(mlxsw_sp->ports); } static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) { unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); - u8 module, width, lane; + struct mlxsw_sp_port_mapping *port_mapping; size_t alloc_size; int i; int err; @@ -3950,66 +4032,100 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) if (!mlxsw_sp->ports) return -ENOMEM; - mlxsw_sp->port_to_module = kmalloc_array(max_ports, sizeof(int), - GFP_KERNEL); - if (!mlxsw_sp->port_to_module) { - err = -ENOMEM; - goto err_port_to_module_alloc; - } - err = mlxsw_sp_cpu_port_create(mlxsw_sp); if (err) goto err_cpu_port_create; for (i = 1; i < max_ports; i++) { - /* Mark as invalid */ - mlxsw_sp->port_to_module[i] = -1; - - err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &module, - &width, &lane); - if (err) - goto err_port_module_info_get; - if (!width) + port_mapping = mlxsw_sp->port_mapping[i]; + if (!port_mapping) continue; - mlxsw_sp->port_to_module[i] = module; - err = mlxsw_sp_port_create(mlxsw_sp, i, false, - module, width, lane); + err = mlxsw_sp_port_create(mlxsw_sp, i, 0, port_mapping); if (err) goto err_port_create; } return 0; err_port_create: -err_port_module_info_get: for (i--; i >= 1; i--) if (mlxsw_sp_port_created(mlxsw_sp, i)) mlxsw_sp_port_remove(mlxsw_sp, i); mlxsw_sp_cpu_port_remove(mlxsw_sp); err_cpu_port_create: - kfree(mlxsw_sp->port_to_module); -err_port_to_module_alloc: kfree(mlxsw_sp->ports); return err; } -static u8 mlxsw_sp_cluster_base_port_get(u8 local_port) +static int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp) +{ + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + struct mlxsw_sp_port_mapping port_mapping; + int i; + int err; + + mlxsw_sp->port_mapping = kcalloc(max_ports, + sizeof(struct mlxsw_sp_port_mapping *), + GFP_KERNEL); + if (!mlxsw_sp->port_mapping) + return -ENOMEM; + + for (i = 1; i < max_ports; i++) { + err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &port_mapping); + if (err) + goto err_port_module_info_get; + if (!port_mapping.width) + continue; + + mlxsw_sp->port_mapping[i] = kmemdup(&port_mapping, + sizeof(port_mapping), + GFP_KERNEL); + if (!mlxsw_sp->port_mapping[i]) { + err = -ENOMEM; + goto err_port_module_info_dup; + } + } + return 0; + +err_port_module_info_get: +err_port_module_info_dup: + for (i--; i >= 1; i--) + kfree(mlxsw_sp->port_mapping[i]); + kfree(mlxsw_sp->port_mapping); + return err; +} + +static void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp) { - u8 offset = (local_port - 1) % MLXSW_SP_PORTS_PER_CLUSTER_MAX; + int i; + + for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) + kfree(mlxsw_sp->port_mapping[i]); + kfree(mlxsw_sp->port_mapping); +} + +static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width) +{ + u8 offset = (local_port - 1) % max_width; return local_port - offset; } -static int mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, - u8 module, unsigned int count, u8 offset) +static int +mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, + struct mlxsw_sp_port_mapping *port_mapping, + unsigned int count, u8 offset) { - u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count; + struct mlxsw_sp_port_mapping split_port_mapping; int err, i; + split_port_mapping = *port_mapping; + split_port_mapping.width /= count; for (i = 0; i < count; i++) { err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset, - true, module, width, i * width); + base_port, &split_port_mapping); if (err) goto err_port_create; + split_port_mapping.lane += split_port_mapping.width; } return 0; @@ -4022,45 +4138,55 @@ err_port_create: } static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, - u8 base_port, unsigned int count) + u8 base_port, + unsigned int count, u8 offset) { - u8 local_port, module, width = MLXSW_PORT_MODULE_MAX_WIDTH; + struct mlxsw_sp_port_mapping *port_mapping; int i; - /* Split by four means we need to re-create two ports, otherwise - * only one. - */ - count = count / 2; - - for (i = 0; i < count; i++) { - local_port = base_port + i * 2; - if (mlxsw_sp->port_to_module[local_port] < 0) + /* Go over original unsplit ports in the gap and recreate them. */ + for (i = 0; i < count * offset; i++) { + port_mapping = mlxsw_sp->port_mapping[base_port + i]; + if (!port_mapping) continue; - module = mlxsw_sp->port_to_module[local_port]; - - mlxsw_sp_port_create(mlxsw_sp, local_port, false, module, - width, 0); + mlxsw_sp_port_create(mlxsw_sp, base_port + i, 0, port_mapping); } } +static int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core, + unsigned int count, + unsigned int max_width) +{ + enum mlxsw_res_id local_ports_in_x_res_id; + int split_width = max_width / count; + + if (split_width == 1) + local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X; + else if (split_width == 2) + local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X; + else if (split_width == 4) + local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_4X; + else + return -EINVAL; + + if (!mlxsw_core_res_valid(mlxsw_core, local_ports_in_x_res_id)) + return -EINVAL; + return mlxsw_core_res_get(mlxsw_core, local_ports_in_x_res_id); +} + static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, unsigned int count, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - u8 local_ports_in_1x, local_ports_in_2x, offset; + struct mlxsw_sp_port_mapping port_mapping; struct mlxsw_sp_port *mlxsw_sp_port; - u8 module, cur_width, base_port; + int max_width; + u8 base_port; + int offset; int i; int err; - if (!MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_1X) || - !MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_2X)) - return -EIO; - - local_ports_in_1x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_1X); - local_ports_in_2x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_2X); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; if (!mlxsw_sp_port) { dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", @@ -4069,47 +4195,70 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - module = mlxsw_sp_port->mapping.module; - cur_width = mlxsw_sp_port->mapping.width; + /* Split ports cannot be split. */ + if (mlxsw_sp_port->split) { + netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); + NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further"); + return -EINVAL; + } + + max_width = mlxsw_core_module_max_width(mlxsw_core, + mlxsw_sp_port->mapping.module); + if (max_width < 0) { + netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module"); + return max_width; + } - if (count != 2 && count != 4) { - netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); - NL_SET_ERR_MSG_MOD(extack, "Port can only be split into 2 or 4 ports"); + /* Split port with non-max and 1 module width cannot be split. */ + if (mlxsw_sp_port->mapping.width != max_width || max_width == 1) { + netdev_err(mlxsw_sp_port->dev, "Port cannot be split\n"); + NL_SET_ERR_MSG_MOD(extack, "Port cannot be split"); return -EINVAL; } - if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) { - netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); - NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further"); + if (count == 1 || !is_power_of_2(count) || count > max_width) { + netdev_err(mlxsw_sp_port->dev, "Invalid split count\n"); + NL_SET_ERR_MSG_MOD(extack, "Invalid split count"); return -EINVAL; } - /* Make sure we have enough slave (even) ports for the split. */ - if (count == 2) { - offset = local_ports_in_2x; - base_port = local_port; - if (mlxsw_sp->ports[base_port + local_ports_in_2x]) { - netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); - NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); - return -EINVAL; - } - } else { - offset = local_ports_in_1x; - base_port = mlxsw_sp_cluster_base_port_get(local_port); - if (mlxsw_sp->ports[base_port + 1] || - mlxsw_sp->ports[base_port + 3]) { + offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width); + if (offset < 0) { + netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset"); + return -EINVAL; + } + + /* Only in case max split is being done, the local port and + * base port may differ. + */ + base_port = count == max_width ? + mlxsw_sp_cluster_base_port_get(local_port, max_width) : + local_port; + + for (i = 0; i < count * offset; i++) { + /* Expect base port to exist and also the one in the middle in + * case of maximal split count. + */ + if (i == 0 || (count == max_width && i == count / 2)) + continue; + + if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) { netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); return -EINVAL; } } + port_mapping = mlxsw_sp_port->mapping; + for (i = 0; i < count; i++) if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); - err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, module, count, - offset); + err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, &port_mapping, + count, offset); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n"); goto err_port_split_create; @@ -4118,7 +4267,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return 0; err_port_split_create: - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset); return err; } @@ -4126,19 +4275,13 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - u8 local_ports_in_1x, local_ports_in_2x, offset; struct mlxsw_sp_port *mlxsw_sp_port; - u8 cur_width, base_port; unsigned int count; + int max_width; + u8 base_port; + int offset; int i; - if (!MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_1X) || - !MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_2X)) - return -EIO; - - local_ports_in_1x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_1X); - local_ports_in_2x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_2X); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; if (!mlxsw_sp_port) { dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", @@ -4153,25 +4296,30 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - cur_width = mlxsw_sp_port->mapping.width; - count = cur_width == 1 ? 4 : 2; + max_width = mlxsw_core_module_max_width(mlxsw_core, + mlxsw_sp_port->mapping.module); + if (max_width < 0) { + netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module"); + return max_width; + } - if (count == 2) - offset = local_ports_in_2x; - else - offset = local_ports_in_1x; + count = max_width / mlxsw_sp_port->mapping.width; - base_port = mlxsw_sp_cluster_base_port_get(local_port); + offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width); + if (WARN_ON(offset < 0)) { + netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset"); + return -EINVAL; + } - /* Determine which ports to remove. */ - if (count == 2 && local_port >= base_port + 2) - base_port = base_port + 2; + base_port = mlxsw_sp_port->split_base_local_port; for (i = 0; i < count; i++) if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset); return 0; } @@ -4364,8 +4512,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, TRAP_TO_CPU, IPV6_MLD, false), /* L3 traps */ - MLXSW_SP_RXL_MARK(MTUERROR, TRAP_TO_CPU, ROUTER_EXP, false), - MLXSW_SP_RXL_MARK(TTLERROR, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_L3_MARK(LBERROR, MIRROR_TO_CPU, LBERROR, false), MLXSW_SP_RXL_MARK(IP2ME, TRAP_TO_CPU, IP2ME, false), MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP, @@ -4392,8 +4538,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, TRAP_TO_CPU, IPV6_ND, false), MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP, false), - MLXSW_SP_RXL_MARK(HOST_MISS_IPV4, TRAP_TO_CPU, HOST_MISS, false), - MLXSW_SP_RXL_MARK(HOST_MISS_IPV6, TRAP_TO_CPU, HOST_MISS, false), MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false), @@ -4408,7 +4552,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { /* Multicast Router Traps */ MLXSW_SP_RXL_MARK(IPV4_PIM, TRAP_TO_CPU, PIM, false), MLXSW_SP_RXL_MARK(IPV6_PIM, TRAP_TO_CPU, PIM, false), - MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false), MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), /* NVE traps */ @@ -4738,7 +4881,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused, unsigned long event, void *ptr); static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); int err; @@ -4750,6 +4894,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, if (err) return err; + mlxsw_core_emad_string_tlv_enable(mlxsw_core); + err = mlxsw_sp_base_mac_get(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n"); @@ -4831,7 +4977,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_acl_init; } - err = mlxsw_sp_router_init(mlxsw_sp); + err = mlxsw_sp_router_init(mlxsw_sp, extack); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); goto err_router_init; @@ -4864,7 +5010,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, * respin. */ mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event; - err = register_netdevice_notifier(&mlxsw_sp->netdevice_nb); + err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->netdevice_nb); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n"); goto err_netdev_notifier; @@ -4876,6 +5023,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_dpipe_init; } + err = mlxsw_sp_port_module_info_init(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n"); + goto err_port_module_info_init; + } + err = mlxsw_sp_ports_create(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); @@ -4885,9 +5038,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return 0; err_ports_create: + mlxsw_sp_port_module_info_fini(mlxsw_sp); +err_port_module_info_init: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: - unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); + unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->netdevice_nb); err_netdev_notifier: if (mlxsw_sp->clock) mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); @@ -4924,7 +5080,8 @@ err_fids_init: } static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); @@ -4944,14 +5101,17 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->listeners = mlxsw_sp1_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); - return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); + return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + mlxsw_sp->req_rev = &mlxsw_sp2_fw_rev; + mlxsw_sp->fw_filename = MLXSW_SP2_FW_FILENAME; mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; @@ -4964,7 +5124,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; - return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); + return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) @@ -4972,8 +5132,10 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); mlxsw_sp_ports_remove(mlxsw_sp); + mlxsw_sp_port_module_info_fini(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); - unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); + unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->netdevice_nb); if (mlxsw_sp->clock) { mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock); @@ -5165,14 +5327,61 @@ static int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core) &kvd_size_params); } +static int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_core); + struct devlink_resource_size_params span_size_params; + u32 max_span; + + if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN)) + return -EIO; + + max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN); + devlink_resource_size_params_init(&span_size_params, max_span, max_span, + 1, DEVLINK_RESOURCE_UNIT_ENTRY); + + return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN, + max_span, MLXSW_SP_RESOURCE_SPAN, + DEVLINK_RESOURCE_ID_PARENT_TOP, + &span_size_params); +} + static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core) { - return mlxsw_sp1_resources_kvd_register(mlxsw_core); + int err; + + err = mlxsw_sp1_resources_kvd_register(mlxsw_core); + if (err) + return err; + + err = mlxsw_sp_resources_span_register(mlxsw_core); + if (err) + goto err_resources_span_register; + + return 0; + +err_resources_span_register: + devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); + return err; } static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core) { - return mlxsw_sp2_resources_kvd_register(mlxsw_core); + int err; + + err = mlxsw_sp2_resources_kvd_register(mlxsw_core); + if (err) + return err; + + err = mlxsw_sp_resources_span_register(mlxsw_core); + if (err) + goto err_resources_span_register; + + return 0; + +err_resources_span_register: + devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); + return err; } static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, @@ -6565,3 +6774,4 @@ MODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table); MODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table); MODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table); MODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME); +MODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index b2a0028b1694..347bec9d1ecf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -14,6 +14,7 @@ #include <linux/dcbnl.h> #include <linux/in6.h> #include <linux/notifier.h> +#include <linux/net_namespace.h> #include <net/psample.h> #include <net/pkt_cls.h> #include <net/red.h> @@ -31,8 +32,6 @@ #define MLXSW_SP_MID_MAX 7000 -#define MLXSW_SP_PORTS_PER_CLUSTER_MAX 4 - #define MLXSW_SP_PORT_BASE_SPEED_25G 25000 /* Mb/s */ #define MLXSW_SP_PORT_BASE_SPEED_50G 50000 /* Mb/s */ @@ -47,6 +46,8 @@ #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS "chunks" #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS "large_chunks" +#define MLXSW_SP_RESOURCE_NAME_SPAN "span_agents" + enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD = 1, MLXSW_SP_RESOURCE_KVD_LINEAR, @@ -55,6 +56,7 @@ enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, + MLXSW_SP_RESOURCE_SPAN, }; struct mlxsw_sp_port; @@ -139,6 +141,12 @@ struct mlxsw_sp_port_type_speed_ops; struct mlxsw_sp_ptp_state; struct mlxsw_sp_ptp_ops; +struct mlxsw_sp_port_mapping { + u8 module; + u8 width; + u8 lane; +}; + struct mlxsw_sp { struct mlxsw_sp_port **ports; struct mlxsw_core *core; @@ -146,7 +154,7 @@ struct mlxsw_sp { unsigned char base_mac[ETH_ALEN]; const unsigned char *mac_mask; struct mlxsw_sp_upper *lags; - int *port_to_module; + struct mlxsw_sp_port_mapping **port_mapping; struct mlxsw_sp_sb *sb; struct mlxsw_sp_bridge *bridge; struct mlxsw_sp_router *router; @@ -255,11 +263,11 @@ struct mlxsw_sp_port { struct ieee_pfc *pfc; enum mlxsw_reg_qpts_trust_state trust_state; } dcb; - struct { - u8 module; - u8 width; - u8 lane; - } mapping; + struct mlxsw_sp_port_mapping mapping; /* mapping is constant during the + * mlxsw_sp_port lifetime, however + * the same localport can have + * different mapping. + */ /* TC handles */ struct list_head mall_tc_list; struct { @@ -283,6 +291,7 @@ struct mlxsw_sp_port { u16 egr_types; struct mlxsw_sp_ptp_port_stats stats; } ptp; + u8 split_base_local_port; }; struct mlxsw_sp_port_type_speed_ops { @@ -524,7 +533,8 @@ union mlxsw_sp_l3addr { struct in6_addr addr6; }; -int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); +int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, + struct netlink_ext_ack *extack); void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_netdevice_router_port_event(struct net_device *dev, unsigned long event, void *ptr); @@ -982,4 +992,9 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, const struct devlink_trap_group *group); +static inline struct net *mlxsw_sp_net(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_core_net(mlxsw_sp->core); +} + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index b9eeae37a4dc..968f0902e4fe 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -35,6 +35,7 @@ struct mlxsw_sp_sb_cm { }; #define MLXSW_SP_SB_INFI -1U +#define MLXSW_SP_SB_REST -2U struct mlxsw_sp_sb_pm { u32 min_buff; @@ -421,19 +422,16 @@ static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) .freeze_size = _freeze_size, \ } -#define MLXSW_SP1_SB_PR_INGRESS_SIZE 12440000 -#define MLXSW_SP1_SB_PR_EGRESS_SIZE 13232000 #define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp1_sb_pool_dess */ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { - MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP1_SB_PR_INGRESS_SIZE), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), - MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP1_SB_PR_EGRESS_SIZE, true, false), + MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, + true, false), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), @@ -445,19 +443,16 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { MLXSW_SP1_SB_PR_CPU_SIZE, true, false), }; -#define MLXSW_SP2_SB_PR_INGRESS_SIZE 35297568 -#define MLXSW_SP2_SB_PR_EGRESS_SIZE 35297568 #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp2_sb_pool_dess */ static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { - MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP2_SB_PR_INGRESS_SIZE), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), - MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP2_SB_PR_EGRESS_SIZE, true, false), + MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, + true, false), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), @@ -471,11 +466,33 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_sb_pr *prs, + const struct mlxsw_sp_sb_pool_des *pool_dess, size_t prs_len) { + /* Round down, unlike mlxsw_sp_bytes_cells(). */ + u32 sb_cells = div_u64(mlxsw_sp->sb->sb_size, mlxsw_sp->sb->cell_size); + u32 rest_cells[2] = {sb_cells, sb_cells}; int i; int err; + /* Calculate how much space to give to the "REST" pools in either + * direction. + */ + for (i = 0; i < prs_len; i++) { + enum mlxsw_reg_sbxx_dir dir = pool_dess[i].dir; + u32 size = prs[i].size; + u32 size_cells; + + if (size == MLXSW_SP_SB_INFI || size == MLXSW_SP_SB_REST) + continue; + + size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); + if (WARN_ON_ONCE(size_cells > rest_cells[dir])) + continue; + + rest_cells[dir] -= size_cells; + } + for (i = 0; i < prs_len; i++) { u32 size = prs[i].size; u32 size_cells; @@ -483,6 +500,10 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, if (size == MLXSW_SP_SB_INFI) { err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, 0, true); + } else if (size == MLXSW_SP_SB_REST) { + size_cells = rest_cells[pool_dess[i].dir]; + err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, + size_cells, false); } else { size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, @@ -904,7 +925,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) return -EIO; - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, GUARANTEED_SHARED_BUFFER)) return -EIO; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE)) @@ -915,7 +936,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) return -ENOMEM; mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, - MAX_BUFFER_SIZE); + GUARANTEED_SHARED_BUFFER); max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_HEADROOM_SIZE); /* Round down, because this limit must not be overstepped. */ @@ -926,6 +947,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_sb_ports_init; err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs, + mlxsw_sp->sb_vals->pool_dess, mlxsw_sp->sb_vals->pool_count); if (err) goto err_sb_prs_init; @@ -1013,7 +1035,8 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, mode = (enum mlxsw_reg_sbpr_mode) threshold_type; pr = &mlxsw_sp->sb_vals->prs[pool_index]; - if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) { + if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, + GUARANTEED_SHARED_BUFFER)) { NL_SET_ERR_MSG_MOD(extack, "Exceeded shared buffer size"); return -EINVAL; } @@ -1021,12 +1044,12 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, if (pr->freeze_mode && pr->mode != mode) { NL_SET_ERR_MSG_MOD(extack, "Changing this pool's threshold type is forbidden"); return -EINVAL; - }; + } if (pr->freeze_size && pr->size != size) { NL_SET_ERR_MSG_MOD(extack, "Changing this pool's size is forbidden"); return -EINVAL; - }; + } return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, pool_size, false); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 17f334b46c40..2153bcc4b585 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -870,7 +870,7 @@ void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fid_vni(fid, &vni))) goto out; - nve_dev = dev_get_by_index(&init_net, nve_ifindex); + nve_dev = dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex); if (!nve_dev) goto out; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index bdf53cf350f6..68cc6737d45c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c @@ -305,7 +305,8 @@ mlxsw_sp_qdisc_red_check_params(struct mlxsw_sp_port *mlxsw_sp_port, p->max); return -EINVAL; } - if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) { + if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, + GUARANTEED_SHARED_BUFFER)) { dev_err(mlxsw_sp->bus_info->dev, "spectrum: RED: max value %u is too big\n", p->max); return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 39d600c8b92d..30bfe3880faf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -16,6 +16,7 @@ #include <linux/if_macvlan.h> #include <linux/refcount.h> #include <linux/jhash.h> +#include <linux/net_namespace.h> #include <net/netevent.h> #include <net/neighbour.h> #include <net/arp.h> @@ -76,6 +77,8 @@ struct mlxsw_sp_router { struct notifier_block inet6addr_nb; const struct mlxsw_sp_rif_ops **rif_ops_arr; const struct mlxsw_sp_ipip_ops **ipip_ops_arr; + u32 adj_discard_index; + bool adj_discard_index_valid; }; struct mlxsw_sp_rif { @@ -366,6 +369,7 @@ enum mlxsw_sp_fib_entry_type { MLXSW_SP_FIB_ENTRY_TYPE_LOCAL, MLXSW_SP_FIB_ENTRY_TYPE_TRAP, MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE, + MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE, /* This is a special case of local delivery, where a packet should be * decapsulated on reception. Note that there is no corresponding ENCAP, @@ -1610,8 +1614,25 @@ static int mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_ipip_entry *ipip_entry, struct net_device *ul_dev, + bool *demote_this, struct netlink_ext_ack *extack) { + u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN; + enum mlxsw_sp_l3proto ul_proto; + union mlxsw_sp_l3addr saddr; + + /* Moving underlay to a different VRF might cause local address + * conflict, and the conflicting tunnels need to be demoted. + */ + ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto; + saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev); + if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto, + saddr, ul_tb_id, + ipip_entry)) { + *demote_this = true; + return 0; + } + return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, true, true, false, extack); } @@ -1762,6 +1783,7 @@ static int __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_ipip_entry *ipip_entry, struct net_device *ul_dev, + bool *demote_this, unsigned long event, struct netdev_notifier_info *info) { @@ -1776,6 +1798,7 @@ __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp, ipip_entry, ul_dev, + demote_this, extack); break; @@ -1802,13 +1825,31 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, ul_dev, ipip_entry))) { + struct mlxsw_sp_ipip_entry *prev; + bool demote_this = false; + err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry, - ul_dev, event, info); + ul_dev, &demote_this, + event, info); if (err) { mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp, ul_dev); return err; } + + if (demote_this) { + if (list_is_first(&ipip_entry->ipip_list_node, + &mlxsw_sp->router->ipip_list)) + prev = NULL; + else + /* This can't be cached from previous iteration, + * because that entry could be gone now. + */ + prev = list_prev_entry(ipip_entry, + ipip_list_node); + mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); + ipip_entry = prev; + } } return 0; @@ -2534,14 +2575,14 @@ static int mlxsw_sp_router_schedule_work(struct net *net, struct mlxsw_sp_netevent_work *net_work; struct mlxsw_sp_router *router; - if (!net_eq(net, &init_net)) + router = container_of(nb, struct mlxsw_sp_router, netevent_nb); + if (!net_eq(net, mlxsw_sp_net(router->mlxsw_sp))) return NOTIFY_DONE; net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC); if (!net_work) return NOTIFY_BAD; - router = container_of(nb, struct mlxsw_sp_router, netevent_nb); INIT_WORK(&net_work->work, cb); net_work->mlxsw_sp = router->mlxsw_sp; mlxsw_core_schedule_work(&net_work->work); @@ -4178,15 +4219,50 @@ mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl, } } +static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) +{ + enum mlxsw_reg_ratr_trap_action trap_action; + char ratr_pl[MLXSW_REG_RATR_LEN]; + int err; + + if (mlxsw_sp->router->adj_discard_index_valid) + return 0; + + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + &mlxsw_sp->router->adj_discard_index); + if (err) + return err; + + trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS; + mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true, + MLXSW_REG_RATR_TYPE_ETHERNET, + mlxsw_sp->router->adj_discard_index, rif_index); + mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); + if (err) + goto err_ratr_write; + + mlxsw_sp->router->adj_discard_index_valid = true; + + return 0; + +err_ratr_write: + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + mlxsw_sp->router->adj_discard_index); + return err; +} + static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry, enum mlxsw_reg_ralue_op op) { + struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group; char ralue_pl[MLXSW_REG_RALUE_LEN]; enum mlxsw_reg_ralue_trap_action trap_action; u16 trap_id = 0; u32 adjacency_index = 0; u16 ecmp_size = 0; + int err; /* In case the nexthop group adjacency index is valid, use it * with provided ECMP size. Otherwise, setup trap and pass @@ -4196,6 +4272,15 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; adjacency_index = fib_entry->nh_group->adj_index; ecmp_size = fib_entry->nh_group->ecmp_size; + } else if (!nh_group->adj_index_valid && nh_group->count && + nh_group->nh_rif) { + err = mlxsw_sp_adj_discard_write(mlxsw_sp, + nh_group->nh_rif->rif_index); + if (err) + return err; + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; + adjacency_index = mlxsw_sp->router->adj_discard_index; + ecmp_size = 1; } else { trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; trap_id = MLXSW_TRAP_ID_RTR_INGRESS0; @@ -4256,6 +4341,23 @@ static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp, } static int +mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fib_entry *fib_entry, + enum mlxsw_reg_ralue_op op) +{ + enum mlxsw_reg_ralue_trap_action trap_action; + char ralue_pl[MLXSW_REG_RALUE_LEN]; + u16 trap_id; + + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; + trap_id = MLXSW_TRAP_ID_RTR_INGRESS1; + + mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); + mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); +} + +static int mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry, enum mlxsw_reg_ralue_op op) @@ -4296,6 +4398,9 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op); case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op); + case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE: + return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry, + op); case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, fib_entry, op); @@ -4373,7 +4478,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, * can do so with a lower priority than packets directed * at the host, so use action type local instead of trap. */ - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE; return 0; case RTN_UNICAST: if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi)) @@ -5333,7 +5438,7 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp, else if (rt->fib6_type == RTN_BLACKHOLE) fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE; else if (rt->fib6_flags & RTF_REJECT) - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE; else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt)) fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; else @@ -5891,6 +5996,16 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp) continue; mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); } + + /* After flushing all the routes, it is not possible anyone is still + * using the adjacency index that is discarding packets, so free it in + * case it was allocated. + */ + if (!mlxsw_sp->router->adj_discard_index_valid) + return; + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + mlxsw_sp->router->adj_discard_index); + mlxsw_sp->router->adj_discard_index_valid = false; } static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp) @@ -6002,12 +6117,6 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info); fib_info_put(fib_work->fen_info.fi); break; - case FIB_EVENT_RULE_ADD: - /* if we get here, a rule was added that we do not support. - * just do the fib_abort - */ - mlxsw_sp_router_fib_abort(mlxsw_sp); - break; case FIB_EVENT_NH_ADD: /* fall through */ case FIB_EVENT_NH_DEL: mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event, @@ -6048,12 +6157,6 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) fib_work->fib6_work.nrt6); mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); break; - case FIB_EVENT_RULE_ADD: - /* if we get here, a rule was added that we do not support. - * just do the fib_abort - */ - mlxsw_sp_router_fib_abort(mlxsw_sp); - break; } rtnl_unlock(); kfree(fib_work); @@ -6095,12 +6198,6 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) &fib_work->ven_info); dev_put(fib_work->ven_info.dev); break; - case FIB_EVENT_RULE_ADD: - /* if we get here, a rule was added that we do not support. - * just do the fib_abort - */ - mlxsw_sp_router_fib_abort(mlxsw_sp); - break; } rtnl_unlock(); kfree(fib_work); @@ -6196,7 +6293,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event, rule = fr_info->rule; /* Rule only affects locally generated traffic */ - if (rule->iifindex == info->net->loopback_dev->ifindex) + if (rule->iifindex == mlxsw_sp_net(mlxsw_sp)->loopback_dev->ifindex) return 0; switch (info->family) { @@ -6233,8 +6330,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, struct mlxsw_sp_router *router; int err; - if (!net_eq(info->net, &init_net) || - (info->family != AF_INET && info->family != AF_INET6 && + if ((info->family != AF_INET && info->family != AF_INET6 && info->family != RTNL_FAMILY_IPMR && info->family != RTNL_FAMILY_IP6MR)) return NOTIFY_DONE; @@ -6246,9 +6342,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, case FIB_EVENT_RULE_DEL: err = mlxsw_sp_router_fib_rule_event(event, info, router->mlxsw_sp); - if (!err || info->extack) - return notifier_from_errno(err); - break; + return notifier_from_errno(err); case FIB_EVENT_ENTRY_ADD: case FIB_EVENT_ENTRY_REPLACE: /* fall through */ case FIB_EVENT_ENTRY_APPEND: /* fall through */ @@ -7957,9 +8051,10 @@ static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field) mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true); } -static void mlxsw_sp_mp4_hash_init(char *recr2_pl) +static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) { - bool only_l3 = !init_net.ipv4.sysctl_fib_multipath_hash_policy; + struct net *net = mlxsw_sp_net(mlxsw_sp); + bool only_l3 = !net->ipv4.sysctl_fib_multipath_hash_policy; mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP); @@ -7974,9 +8069,9 @@ static void mlxsw_sp_mp4_hash_init(char *recr2_pl) mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT); } -static void mlxsw_sp_mp6_hash_init(char *recr2_pl) +static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) { - bool only_l3 = !ip6_multipath_hash_policy(&init_net); + bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp)); mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP); @@ -8004,8 +8099,8 @@ static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp) seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0); mlxsw_reg_recr2_pack(recr2_pl, seed); - mlxsw_sp_mp4_hash_init(recr2_pl); - mlxsw_sp_mp6_hash_init(recr2_pl); + mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl); + mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl); } @@ -8036,7 +8131,8 @@ static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp) static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) { - bool usp = init_net.ipv4.sysctl_ip_fwd_update_priority; + struct net *net = mlxsw_sp_net(mlxsw_sp); + bool usp = net->ipv4.sysctl_ip_fwd_update_priority; char rgcr_pl[MLXSW_REG_RGCR_LEN]; u64 max_rifs; int err; @@ -8062,7 +8158,8 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); } -int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) +int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, + struct netlink_ext_ack *extack) { struct mlxsw_sp_router *router; int err; @@ -8138,8 +8235,9 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) goto err_dscp_init; mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; - err = register_fib_notifier(&mlxsw_sp->router->fib_nb, - mlxsw_sp_router_fib_dump_flush); + err = register_fib_notifier(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->router->fib_nb, + mlxsw_sp_router_fib_dump_flush, extack); if (err) goto err_register_fib_notifier; @@ -8178,7 +8276,8 @@ err_register_inetaddr_notifier: void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { - unregister_fib_notifier(&mlxsw_sp->router->fib_nb); + unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->router->fib_nb); unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 560a60e522f9..200d324e6d99 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -14,8 +14,23 @@ #include "spectrum_span.h" #include "spectrum_switchdev.h" +static u64 mlxsw_sp_span_occ_get(void *priv) +{ + const struct mlxsw_sp *mlxsw_sp = priv; + u64 occ = 0; + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + if (mlxsw_sp->span.entries[i].ref_count) + occ++; + } + + return occ; +} + int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) @@ -36,13 +51,19 @@ int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) curr->id = i; } + devlink_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_SPAN, + mlxsw_sp_span_occ_get, mlxsw_sp); + return 0; } void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; + devlink_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_SPAN); + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 5ecb45118400..a3af171c6358 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2591,7 +2591,7 @@ __mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp *mlxsw_sp, if (err) return err; - dev = __dev_get_by_index(&init_net, nve_ifindex); + dev = __dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex); if (!dev) return -EINVAL; *nve_dev = dev; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index 7c03b661ae7e..e0d7c49ffae0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -13,16 +13,27 @@ static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, void *priv); +static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx); #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ MLXSW_SP_TRAP_METADATA) +#define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \ + DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ + DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ + MLXSW_SP_TRAP_METADATA) + #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ MLXSW_RXL(mlxsw_sp_rx_drop_listener, DISCARD_##_id, SET_FW_DEFAULT, \ false, SP_##_group_id, DISCARD) +#define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ + MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \ + _action, false, SP_##_group_id, DISCARD) + static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), @@ -30,6 +41,23 @@ static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), + MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), + MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), + MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), + MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), + MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), + MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), + MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), + MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), + MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS), + MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS), }; static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { @@ -40,6 +68,28 @@ static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), + MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS), + MLXSW_SP_RXL_EXCEPTION(MTUERROR, ROUTER_EXP, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(TTLERROR, ROUTER_EXP, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(RPF, RPF, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, REMOTE_ROUTE, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, HOST_MISS, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, HOST_MISS, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, REMOTE_ROUTE, + TRAP_EXCEPTION_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, ROUTER_EXP, + TRAP_EXCEPTION_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, ROUTER_EXP, + TRAP_EXCEPTION_TO_CPU), }; /* Mapping between hardware trap and devlink trap. Multiple hardware traps can @@ -54,6 +104,25 @@ static u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER, + DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE, + DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET, + DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC, + DEVLINK_TRAP_GENERIC_ID_DIP_LB, + DEVLINK_TRAP_GENERIC_ID_SIP_MC, + DEVLINK_TRAP_GENERIC_ID_SIP_LB, + DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR, + DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC, + DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE, + DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, + DEVLINK_TRAP_GENERIC_ID_MTU_ERROR, + DEVLINK_TRAP_GENERIC_ID_TTL_ERROR, + DEVLINK_TRAP_GENERIC_ID_RPF, + DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE, + DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, + DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, + DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, + DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS, + DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS, }; static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, @@ -104,6 +173,30 @@ static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, consume_skb(skb); } +static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port)) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); + skb_pull(skb, ETH_HLEN); + skb->offload_fwd_mark = 1; + netif_receive_skb(skb); +} + int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) { struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); @@ -211,6 +304,7 @@ mlxsw_sp_trap_group_policer_init(struct mlxsw_sp *mlxsw_sp, u32 rate; switch (group->id) { + case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:/* fall through */ case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS: policer_id = MLXSW_SP_DISCARD_POLICER_ID; ir_units = MLXSW_REG_QPCR_IR_UNITS_M; @@ -242,6 +336,12 @@ __mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp, priority = 0; tc = 1; break; + case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS: + group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS; + policer_id = MLXSW_SP_DISCARD_POLICER_ID; + priority = 0; + tc = 1; + break; default: return -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c index 0d9356b3f65d..4ff1e623aa76 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchib.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchib.c @@ -446,7 +446,8 @@ static int mlxsw_sib_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) } static int mlxsw_sib_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core); int err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 1c14c051ee52..de6cb22f68b1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -992,6 +992,7 @@ static int __mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port, if (!dev) return -ENOMEM; SET_NETDEV_DEV(dev, mlxsw_sx->bus_info->dev); + dev_net_set(dev, mlxsw_core_net(mlxsw_sx->core)); mlxsw_sx_port = netdev_priv(dev); mlxsw_sx_port->dev = dev; mlxsw_sx_port->mlxsw_sx = mlxsw_sx; @@ -1563,7 +1564,8 @@ static int mlxsw_sx_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) } static int mlxsw_sx_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core); int err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index 7618f084cae9..0c1c142bb6b0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -49,6 +49,7 @@ enum { MLXSW_TRAP_ID_IPV6_DHCP = 0x69, MLXSW_TRAP_ID_IPV6_ALL_ROUTERS_LINK = 0x6F, MLXSW_TRAP_ID_RTR_INGRESS0 = 0x70, + MLXSW_TRAP_ID_RTR_INGRESS1 = 0x71, MLXSW_TRAP_ID_IPV6_PIM = 0x79, MLXSW_TRAP_ID_IPV6_VRRP = 0x7A, MLXSW_TRAP_ID_IPV4_BGP = 0x88, @@ -66,6 +67,8 @@ enum { MLXSW_TRAP_ID_NVE_ENCAP_ARP = 0xBD, MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6, MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7, + MLXSW_TRAP_ID_DISCARD_ROUTER2 = 0x130, + MLXSW_TRAP_ID_DISCARD_ROUTER3 = 0x131, MLXSW_TRAP_ID_DISCARD_ING_PACKET_SMAC_MC = 0x140, MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VTAG_ALLOW = 0x148, MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VLAN = 0x149, @@ -73,6 +76,18 @@ enum { MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_UC = 0x150, MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_MC_NULL = 0x151, MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_LB = 0x152, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_NON_IP_PACKET = 0x160, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_UC_DIP_MC_DMAC = 0x161, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_DIP_LB = 0x162, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_MC = 0x163, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_LB = 0x165, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_CORRUPTED_IP_HDR = 0x167, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_SIP_BC = 0x16A, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_DIP_LOCAL_NET = 0x16B, + MLXSW_TRAP_ID_DISCARD_ROUTER_LPM4 = 0x17B, + MLXSW_TRAP_ID_DISCARD_ROUTER_LPM6 = 0x17C, + MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_RESERVED_SCOPE = 0x1B0, + MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE = 0x1B1, MLXSW_TRAP_ID_ACL0 = 0x1C0, /* Multicast trap used for routes with trap action */ MLXSW_TRAP_ID_ACL1 = 0x1C1, |