Commit 14676c04 authored by David S. Miller's avatar David S. Miller

Merge tag 'mlx5-fixes-2022-01-06' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
mlx5 fixes 2022-01-06

This series provides bug fixes to mlx5 driver.
Please pull and let me know if there is any problem.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 29507144 4f6626b0
......@@ -148,8 +148,12 @@ static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
if (!refcount_dec_and_test(&ent->refcnt))
return;
if (ent->idx >= 0)
cmd_free_index(ent->cmd, ent->idx);
if (ent->idx >= 0) {
struct mlx5_cmd *cmd = ent->cmd;
cmd_free_index(cmd, ent->idx);
up(ent->page_queue ? &cmd->pages_sem : &cmd->sem);
}
cmd_free_ent(ent);
}
......@@ -900,25 +904,6 @@ static bool opcode_allowed(struct mlx5_cmd *cmd, u16 opcode)
return cmd->allowed_opcode == opcode;
}
static int cmd_alloc_index_retry(struct mlx5_cmd *cmd)
{
unsigned long alloc_end = jiffies + msecs_to_jiffies(1000);
int idx;
retry:
idx = cmd_alloc_index(cmd);
if (idx < 0 && time_before(jiffies, alloc_end)) {
/* Index allocation can fail on heavy load of commands. This is a temporary
* situation as the current command already holds the semaphore, meaning that
* another command completion is being handled and it is expected to release
* the entry index soon.
*/
cpu_relax();
goto retry;
}
return idx;
}
bool mlx5_cmd_is_down(struct mlx5_core_dev *dev)
{
return pci_channel_offline(dev->pdev) ||
......@@ -946,7 +931,7 @@ static void cmd_work_handler(struct work_struct *work)
sem = ent->page_queue ? &cmd->pages_sem : &cmd->sem;
down(sem);
if (!ent->page_queue) {
alloc_ret = cmd_alloc_index_retry(cmd);
alloc_ret = cmd_alloc_index(cmd);
if (alloc_ret < 0) {
mlx5_core_err_rl(dev, "failed to allocate command entry\n");
if (ent->callback) {
......@@ -1602,8 +1587,6 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
vector = vec & 0xffffffff;
for (i = 0; i < (1 << cmd->log_sz); i++) {
if (test_bit(i, &vector)) {
struct semaphore *sem;
ent = cmd->ent_arr[i];
/* if we already completed the command, ignore it */
......@@ -1626,10 +1609,6 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
cmd_ent_put(ent);
if (ent->page_queue)
sem = &cmd->pages_sem;
else
sem = &cmd->sem;
ent->ts2 = ktime_get_ns();
memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
dump_command(dev, ent, 0);
......@@ -1683,7 +1662,6 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force
*/
complete(&ent->done);
}
up(sem);
}
}
}
......
......@@ -1579,6 +1579,8 @@ mlx5e_init_fib_work_ipv4(struct mlx5e_priv *priv,
struct net_device *fib_dev;
fen_info = container_of(info, struct fib_entry_notifier_info, info);
if (fen_info->fi->nh)
return NULL;
fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
if (!fib_dev || fib_dev->netdev_ops != &mlx5e_netdev_ops ||
fen_info->dst_len != 32)
......
......@@ -11,13 +11,13 @@ static int mlx5e_xsk_map_pool(struct mlx5e_priv *priv,
{
struct device *dev = mlx5_core_dma_dev(priv->mdev);
return xsk_pool_dma_map(pool, dev, 0);
return xsk_pool_dma_map(pool, dev, DMA_ATTR_SKIP_CPU_SYNC);
}
static void mlx5e_xsk_unmap_pool(struct mlx5e_priv *priv,
struct xsk_buff_pool *pool)
{
return xsk_pool_dma_unmap(pool, 0);
return xsk_pool_dma_unmap(pool, DMA_ATTR_SKIP_CPU_SYNC);
}
static int mlx5e_xsk_get_pools(struct mlx5e_xsk *xsk)
......
......@@ -4789,15 +4789,22 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
}
if (mlx5_vxlan_allowed(mdev->vxlan) || mlx5_geneve_tx_allowed(mdev)) {
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
netdev->vlan_features |= NETIF_F_GSO_UDP_TUNNEL;
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM;
netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM;
netdev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM;
netdev->vlan_features |= NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM;
}
if (mlx5e_tunnel_proto_supported_tx(mdev, IPPROTO_GRE)) {
netdev->hw_features |= NETIF_F_GSO_GRE;
netdev->hw_enc_features |= NETIF_F_GSO_GRE;
netdev->gso_partial_features |= NETIF_F_GSO_GRE;
netdev->hw_features |= NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM;
netdev->hw_enc_features |= NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM;
netdev->gso_partial_features |= NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM;
}
if (mlx5e_tunnel_proto_supported_tx(mdev, IPPROTO_IPIP)) {
......
......@@ -50,6 +50,7 @@
#include "fs_core.h"
#include "lib/mlx5.h"
#include "lib/devcom.h"
#include "lib/vxlan.h"
#define CREATE_TRACE_POINTS
#include "diag/en_rep_tracepoint.h"
#include "en_accel/ipsec.h"
......@@ -1027,6 +1028,7 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv)
rtnl_lock();
if (netif_running(netdev))
mlx5e_open(netdev);
udp_tunnel_nic_reset_ntf(priv->netdev);
netif_device_attach(netdev);
rtnl_unlock();
}
......@@ -1048,6 +1050,7 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
mlx5_notifier_unregister(mdev, &priv->events_nb);
mlx5e_rep_tc_disable(priv);
mlx5_lag_remove_netdev(mdev, priv->netdev);
mlx5_vxlan_reset_to_default(mdev->vxlan);
}
static MLX5E_DEFINE_STATS_GRP(sw_rep, 0);
......
......@@ -278,8 +278,8 @@ static inline int mlx5e_page_alloc_pool(struct mlx5e_rq *rq,
if (unlikely(!dma_info->page))
return -ENOMEM;
dma_info->addr = dma_map_page(rq->pdev, dma_info->page, 0,
PAGE_SIZE, rq->buff.map_dir);
dma_info->addr = dma_map_page_attrs(rq->pdev, dma_info->page, 0, PAGE_SIZE,
rq->buff.map_dir, DMA_ATTR_SKIP_CPU_SYNC);
if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
page_pool_recycle_direct(rq->page_pool, dma_info->page);
dma_info->page = NULL;
......@@ -300,7 +300,8 @@ static inline int mlx5e_page_alloc(struct mlx5e_rq *rq,
void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info)
{
dma_unmap_page(rq->pdev, dma_info->addr, PAGE_SIZE, rq->buff.map_dir);
dma_unmap_page_attrs(rq->pdev, dma_info->addr, PAGE_SIZE, rq->buff.map_dir,
DMA_ATTR_SKIP_CPU_SYNC);
}
void mlx5e_page_release_dynamic(struct mlx5e_rq *rq,
......
......@@ -1949,6 +1949,111 @@ u8 mlx5e_tc_get_ip_version(struct mlx5_flow_spec *spec, bool outer)
return ip_version;
}
/* Tunnel device follows RFC 6040, see include/net/inet_ecn.h.
* And changes inner ip_ecn depending on inner and outer ip_ecn as follows:
* +---------+----------------------------------------+
* |Arriving | Arriving Outer Header |
* | Inner +---------+---------+---------+----------+
* | Header | Not-ECT | ECT(0) | ECT(1) | CE |
* +---------+---------+---------+---------+----------+
* | Not-ECT | Not-ECT | Not-ECT | Not-ECT | <drop> |
* | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE* |
* | ECT(1) | ECT(1) | ECT(1) | ECT(1)* | CE* |
* | CE | CE | CE | CE | CE |
* +---------+---------+---------+---------+----------+
*
* Tc matches on inner after decapsulation on tunnel device, but hw offload matches
* the inner ip_ecn value before hardware decap action.
*
* Cells marked are changed from original inner packet ip_ecn value during decap, and
* so matching those values on inner ip_ecn before decap will fail.
*
* The following helper allows offload when inner ip_ecn won't be changed by outer ip_ecn,
* except for the outer ip_ecn = CE, where in all cases inner ip_ecn will be changed to CE,
* and such we can drop the inner ip_ecn=CE match.
*/
static int mlx5e_tc_verify_tunnel_ecn(struct mlx5e_priv *priv,
struct flow_cls_offload *f,
bool *match_inner_ecn)
{
u8 outer_ecn_mask = 0, outer_ecn_key = 0, inner_ecn_mask = 0, inner_ecn_key = 0;
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct netlink_ext_ack *extack = f->common.extack;
struct flow_match_ip match;
*match_inner_ecn = true;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IP)) {
flow_rule_match_enc_ip(rule, &match);
outer_ecn_key = match.key->tos & INET_ECN_MASK;
outer_ecn_mask = match.mask->tos & INET_ECN_MASK;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
flow_rule_match_ip(rule, &match);
inner_ecn_key = match.key->tos & INET_ECN_MASK;
inner_ecn_mask = match.mask->tos & INET_ECN_MASK;
}
if (outer_ecn_mask != 0 && outer_ecn_mask != INET_ECN_MASK) {
NL_SET_ERR_MSG_MOD(extack, "Partial match on enc_tos ecn bits isn't supported");
netdev_warn(priv->netdev, "Partial match on enc_tos ecn bits isn't supported");
return -EOPNOTSUPP;
}
if (!outer_ecn_mask) {
if (!inner_ecn_mask)
return 0;
NL_SET_ERR_MSG_MOD(extack,
"Matching on tos ecn bits without also matching enc_tos ecn bits isn't supported");
netdev_warn(priv->netdev,
"Matching on tos ecn bits without also matching enc_tos ecn bits isn't supported");
return -EOPNOTSUPP;
}
if (inner_ecn_mask && inner_ecn_mask != INET_ECN_MASK) {
NL_SET_ERR_MSG_MOD(extack,
"Partial match on tos ecn bits with match on enc_tos ecn bits isn't supported");
netdev_warn(priv->netdev,
"Partial match on tos ecn bits with match on enc_tos ecn bits isn't supported");
return -EOPNOTSUPP;
}
if (!inner_ecn_mask)
return 0;
/* Both inner and outer have full mask on ecn */
if (outer_ecn_key == INET_ECN_ECT_1) {
/* inner ecn might change by DECAP action */
NL_SET_ERR_MSG_MOD(extack, "Match on enc_tos ecn = ECT(1) isn't supported");
netdev_warn(priv->netdev, "Match on enc_tos ecn = ECT(1) isn't supported");
return -EOPNOTSUPP;
}
if (outer_ecn_key != INET_ECN_CE)
return 0;
if (inner_ecn_key != INET_ECN_CE) {
/* Can't happen in software, as packet ecn will be changed to CE after decap */
NL_SET_ERR_MSG_MOD(extack,
"Match on tos enc_tos ecn = CE while match on tos ecn != CE isn't supported");
netdev_warn(priv->netdev,
"Match on tos enc_tos ecn = CE while match on tos ecn != CE isn't supported");
return -EOPNOTSUPP;
}
/* outer ecn = CE, inner ecn = CE, as decap will change inner ecn to CE in anycase,
* drop match on inner ecn
*/
*match_inner_ecn = false;
return 0;
}
static int parse_tunnel_attr(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow,
struct mlx5_flow_spec *spec,
......@@ -2144,6 +2249,7 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
enum fs_flow_table_type fs_type;
bool match_inner_ecn = true;
u16 addr_type = 0;
u8 ip_proto = 0;
u8 *match_level;
......@@ -2197,6 +2303,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
headers_c = get_match_inner_headers_criteria(spec);
headers_v = get_match_inner_headers_value(spec);
}
err = mlx5e_tc_verify_tunnel_ecn(priv, f, &match_inner_ecn);
if (err)
return err;
}
err = mlx5e_flower_parse_meta(filter_dev, f);
......@@ -2420,10 +2530,12 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
struct flow_match_ip match;
flow_rule_match_ip(rule, &match);
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn,
match.mask->tos & 0x3);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn,
match.key->tos & 0x3);
if (match_inner_ecn) {
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_ecn,
match.mask->tos & 0x3);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn,
match.key->tos & 0x3);
}
MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_dscp,
match.mask->tos >> 2);
......
......@@ -295,26 +295,28 @@ esw_setup_chain_src_port_rewrite(struct mlx5_flow_destination *dest,
int *i)
{
struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
int j, err;
int err;
if (!(attr->flags & MLX5_ESW_ATTR_FLAG_SRC_REWRITE))
return -EOPNOTSUPP;
for (j = esw_attr->split_count; j < esw_attr->out_count; j++, (*i)++) {
err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain, 1, 0, *i);
if (err)
goto err_setup_chain;
/* flow steering cannot handle more than one dest with the same ft
* in a single flow
*/
if (esw_attr->out_count - esw_attr->split_count > 1)
return -EOPNOTSUPP;
if (esw_attr->dests[j].pkt_reformat) {
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_act->pkt_reformat = esw_attr->dests[j].pkt_reformat;
}
err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain, 1, 0, *i);
if (err)
return err;
if (esw_attr->dests[esw_attr->split_count].pkt_reformat) {
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_act->pkt_reformat = esw_attr->dests[esw_attr->split_count].pkt_reformat;
}
return 0;
(*i)++;
err_setup_chain:
esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, j);
return err;
return 0;
}
static void esw_cleanup_chain_src_port_rewrite(struct mlx5_eswitch *esw,
......
......@@ -268,10 +268,8 @@ static int mlx5_lag_fib_event(struct notifier_block *nb,
fen_info = container_of(info, struct fib_entry_notifier_info,
info);
fi = fen_info->fi;
if (fi->nh) {
NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
return notifier_from_errno(-EINVAL);
}
if (fi->nh)
return NOTIFY_DONE;
fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev;
if (fib_dev != ldev->pf[MLX5_LAG_P1].netdev &&
fib_dev != ldev->pf[MLX5_LAG_P2].netdev) {
......
......@@ -30,10 +30,7 @@ bool mlx5_sf_dev_allocated(const struct mlx5_core_dev *dev)
{
struct mlx5_sf_dev_table *table = dev->priv.sf_dev_table;
if (!mlx5_sf_dev_supported(dev))
return false;
return !xa_empty(&table->devices);
return table && !xa_empty(&table->devices);
}
static ssize_t sfnum_show(struct device *dev, struct device_attribute *attr, char *buf)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment