Commit 58a86c45 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlx5-fixes'

Saeed Mahameed says:

====================
Mellanox 100G mlx5 fixes 2016-10-25

This series contains some bug fixes for the mlx5 core and mlx5e driver.

From Daniel:
    - Cache line size determination at runtime, instead of using
      L1_CACHE_BYTES hard coded value, use cache_line_size()
    - Always Query HCA caps after setting them even on reset flow

From Mohamad:
    - Reorder netdev cleanup to uregister netdev before detaching it
      for the kernel to not complain about open resources such as vlans
    - Change the acl enable prototype to return status, for better error
      resiliency
    - Clear health sick bit when starting health poll after reset flow
    - Fix race between PCI error handlers and health work
    - PCI error recovery health care simulation, in case when the kernel
      PCI error handlers are not triggered for some internal firmware errors

From Noa:
    - Avoid passing dma address 0 to firmware when mapping system pages
      to the firmware

From Paul: Some straight forward flow steering fixes
    - Keep autogroups list ordered
    - Fix autogroups groups num not decreasing
    - Correctly initialize last use of flow counters

From Saeed:
    - Choose the nearest LRO timeout to the wanted one
      instead of blindly choosing "dev_cap.lro_timeout[2]"

This series has no conflict with the for-next pull request posted
earlier today ("Mellanox mlx5 core driver updates 2016-10-25").
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bf911e98 6b276190
...@@ -1019,7 +1019,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, ...@@ -1019,7 +1019,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
resp.qp_tab_size = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp); resp.qp_tab_size = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp);
if (mlx5_core_is_pf(dev->mdev) && MLX5_CAP_GEN(dev->mdev, bf)) if (mlx5_core_is_pf(dev->mdev) && MLX5_CAP_GEN(dev->mdev, bf))
resp.bf_reg_size = 1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size); resp.bf_reg_size = 1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size);
resp.cache_line_size = L1_CACHE_BYTES; resp.cache_line_size = cache_line_size();
resp.max_sq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq); resp.max_sq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq);
resp.max_rq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq); resp.max_rq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq);
resp.max_send_wqebb = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz); resp.max_send_wqebb = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz);
......
...@@ -52,7 +52,6 @@ enum { ...@@ -52,7 +52,6 @@ enum {
enum { enum {
MLX5_IB_SQ_STRIDE = 6, MLX5_IB_SQ_STRIDE = 6,
MLX5_IB_CACHE_LINE_SIZE = 64,
}; };
static const u32 mlx5_ib_opcode[] = { static const u32 mlx5_ib_opcode[] = {
......
...@@ -41,6 +41,13 @@ ...@@ -41,6 +41,13 @@
#include "mlx5_core.h" #include "mlx5_core.h"
struct mlx5_db_pgdir {
struct list_head list;
unsigned long *bitmap;
__be32 *db_page;
dma_addr_t db_dma;
};
/* Handling for queue buffers -- we allocate a bunch of memory and /* Handling for queue buffers -- we allocate a bunch of memory and
* register it in a memory region at HCA virtual address 0. * register it in a memory region at HCA virtual address 0.
*/ */
...@@ -102,17 +109,28 @@ EXPORT_SYMBOL_GPL(mlx5_buf_free); ...@@ -102,17 +109,28 @@ EXPORT_SYMBOL_GPL(mlx5_buf_free);
static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev, static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev,
int node) int node)
{ {
u32 db_per_page = PAGE_SIZE / cache_line_size();
struct mlx5_db_pgdir *pgdir; struct mlx5_db_pgdir *pgdir;
pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL); pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
if (!pgdir) if (!pgdir)
return NULL; return NULL;
bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE); pgdir->bitmap = kcalloc(BITS_TO_LONGS(db_per_page),
sizeof(unsigned long),
GFP_KERNEL);
if (!pgdir->bitmap) {
kfree(pgdir);
return NULL;
}
bitmap_fill(pgdir->bitmap, db_per_page);
pgdir->db_page = mlx5_dma_zalloc_coherent_node(dev, PAGE_SIZE, pgdir->db_page = mlx5_dma_zalloc_coherent_node(dev, PAGE_SIZE,
&pgdir->db_dma, node); &pgdir->db_dma, node);
if (!pgdir->db_page) { if (!pgdir->db_page) {
kfree(pgdir->bitmap);
kfree(pgdir); kfree(pgdir);
return NULL; return NULL;
} }
...@@ -123,18 +141,19 @@ static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev, ...@@ -123,18 +141,19 @@ static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev,
static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir, static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir,
struct mlx5_db *db) struct mlx5_db *db)
{ {
u32 db_per_page = PAGE_SIZE / cache_line_size();
int offset; int offset;
int i; int i;
i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE); i = find_first_bit(pgdir->bitmap, db_per_page);
if (i >= MLX5_DB_PER_PAGE) if (i >= db_per_page)
return -ENOMEM; return -ENOMEM;
__clear_bit(i, pgdir->bitmap); __clear_bit(i, pgdir->bitmap);
db->u.pgdir = pgdir; db->u.pgdir = pgdir;
db->index = i; db->index = i;
offset = db->index * L1_CACHE_BYTES; offset = db->index * cache_line_size();
db->db = pgdir->db_page + offset / sizeof(*pgdir->db_page); db->db = pgdir->db_page + offset / sizeof(*pgdir->db_page);
db->dma = pgdir->db_dma + offset; db->dma = pgdir->db_dma + offset;
...@@ -181,14 +200,16 @@ EXPORT_SYMBOL_GPL(mlx5_db_alloc); ...@@ -181,14 +200,16 @@ EXPORT_SYMBOL_GPL(mlx5_db_alloc);
void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db) void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db)
{ {
u32 db_per_page = PAGE_SIZE / cache_line_size();
mutex_lock(&dev->priv.pgdir_mutex); mutex_lock(&dev->priv.pgdir_mutex);
__set_bit(db->index, db->u.pgdir->bitmap); __set_bit(db->index, db->u.pgdir->bitmap);
if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) { if (bitmap_full(db->u.pgdir->bitmap, db_per_page)) {
dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
db->u.pgdir->db_page, db->u.pgdir->db_dma); db->u.pgdir->db_page, db->u.pgdir->db_dma);
list_del(&db->u.pgdir->list); list_del(&db->u.pgdir->list);
kfree(db->u.pgdir->bitmap);
kfree(db->u.pgdir); kfree(db->u.pgdir);
} }
......
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
#define MLX5_MPWRQ_SMALL_PACKET_THRESHOLD (128) #define MLX5_MPWRQ_SMALL_PACKET_THRESHOLD (128)
#define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (64 * 1024) #define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (64 * 1024)
#define MLX5E_DEFAULT_LRO_TIMEOUT 32
#define MLX5E_LRO_TIMEOUT_ARR_SIZE 4
#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC 0x10 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC 0x10
#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE 0x3 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE 0x3
#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS 0x20 #define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS 0x20
...@@ -221,6 +224,7 @@ struct mlx5e_params { ...@@ -221,6 +224,7 @@ struct mlx5e_params {
struct ieee_ets ets; struct ieee_ets ets;
#endif #endif
bool rx_am_enabled; bool rx_am_enabled;
u32 lro_timeout;
}; };
struct mlx5e_tstamp { struct mlx5e_tstamp {
...@@ -888,5 +892,6 @@ int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev); ...@@ -888,5 +892,6 @@ int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev); void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
struct rtnl_link_stats64 * struct rtnl_link_stats64 *
mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats); mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout);
#endif /* __MLX5_EN_H__ */ #endif /* __MLX5_EN_H__ */
...@@ -1971,9 +1971,7 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv) ...@@ -1971,9 +1971,7 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv)
MLX5_SET(tirc, tirc, lro_max_ip_payload_size, MLX5_SET(tirc, tirc, lro_max_ip_payload_size,
(priv->params.lro_wqe_sz - (priv->params.lro_wqe_sz -
ROUGH_MAX_L2_L3_HDR_SZ) >> 8); ROUGH_MAX_L2_L3_HDR_SZ) >> 8);
MLX5_SET(tirc, tirc, lro_timeout_period_usecs, MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout);
MLX5_CAP_ETH(priv->mdev,
lro_timer_supported_periods[2]));
} }
void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv) void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
...@@ -3401,6 +3399,18 @@ static void mlx5e_query_min_inline(struct mlx5_core_dev *mdev, ...@@ -3401,6 +3399,18 @@ static void mlx5e_query_min_inline(struct mlx5_core_dev *mdev,
} }
} }
u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout)
{
int i;
/* The supported periods are organized in ascending order */
for (i = 0; i < MLX5E_LRO_TIMEOUT_ARR_SIZE - 1; i++)
if (MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]) >= wanted_timeout)
break;
return MLX5_CAP_ETH(mdev, lro_timer_supported_periods[i]);
}
static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
struct net_device *netdev, struct net_device *netdev,
const struct mlx5e_profile *profile, const struct mlx5e_profile *profile,
...@@ -3419,6 +3429,9 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev, ...@@ -3419,6 +3429,9 @@ static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
priv->profile = profile; priv->profile = profile;
priv->ppriv = ppriv; priv->ppriv = ppriv;
priv->params.lro_timeout =
mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
priv->params.log_sq_size = MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE; priv->params.log_sq_size = MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
/* set CQE compression */ /* set CQE compression */
...@@ -4035,7 +4048,6 @@ void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv) ...@@ -4035,7 +4048,6 @@ void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv)
const struct mlx5e_profile *profile = priv->profile; const struct mlx5e_profile *profile = priv->profile;
struct net_device *netdev = priv->netdev; struct net_device *netdev = priv->netdev;
unregister_netdev(netdev);
destroy_workqueue(priv->wq); destroy_workqueue(priv->wq);
if (profile->cleanup) if (profile->cleanup)
profile->cleanup(priv); profile->cleanup(priv);
...@@ -4052,6 +4064,7 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv) ...@@ -4052,6 +4064,7 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv)
for (vport = 1; vport < total_vfs; vport++) for (vport = 1; vport < total_vfs; vport++)
mlx5_eswitch_unregister_vport_rep(esw, vport); mlx5_eswitch_unregister_vport_rep(esw, vport);
unregister_netdev(priv->netdev);
mlx5e_detach(mdev, vpriv); mlx5e_detach(mdev, vpriv);
mlx5e_destroy_netdev(mdev, priv); mlx5e_destroy_netdev(mdev, priv);
} }
......
...@@ -457,6 +457,7 @@ void mlx5e_vport_rep_unload(struct mlx5_eswitch *esw, ...@@ -457,6 +457,7 @@ void mlx5e_vport_rep_unload(struct mlx5_eswitch *esw,
struct mlx5e_priv *priv = rep->priv_data; struct mlx5e_priv *priv = rep->priv_data;
struct net_device *netdev = priv->netdev; struct net_device *netdev = priv->netdev;
unregister_netdev(netdev);
mlx5e_detach_netdev(esw->dev, netdev); mlx5e_detach_netdev(esw->dev, netdev);
mlx5e_destroy_netdev(esw->dev, priv); mlx5e_destroy_netdev(esw->dev, priv);
} }
...@@ -931,8 +931,8 @@ static void esw_vport_change_handler(struct work_struct *work) ...@@ -931,8 +931,8 @@ static void esw_vport_change_handler(struct work_struct *work)
mutex_unlock(&esw->state_lock); mutex_unlock(&esw->state_lock);
} }
static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
struct mlx5_vport *vport) struct mlx5_vport *vport)
{ {
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_group *vlan_grp = NULL; struct mlx5_flow_group *vlan_grp = NULL;
...@@ -949,9 +949,11 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, ...@@ -949,9 +949,11 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
int table_size = 2; int table_size = 2;
int err = 0; int err = 0;
if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support) || if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
!IS_ERR_OR_NULL(vport->egress.acl)) return -EOPNOTSUPP;
return;
if (!IS_ERR_OR_NULL(vport->egress.acl))
return 0;
esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n", esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n",
vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size)); vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
...@@ -959,12 +961,12 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, ...@@ -959,12 +961,12 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS); root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS);
if (!root_ns) { if (!root_ns) {
esw_warn(dev, "Failed to get E-Switch egress flow namespace\n"); esw_warn(dev, "Failed to get E-Switch egress flow namespace\n");
return; return -EIO;
} }
flow_group_in = mlx5_vzalloc(inlen); flow_group_in = mlx5_vzalloc(inlen);
if (!flow_group_in) if (!flow_group_in)
return; return -ENOMEM;
acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
if (IS_ERR(acl)) { if (IS_ERR(acl)) {
...@@ -1009,6 +1011,7 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, ...@@ -1009,6 +1011,7 @@ static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
mlx5_destroy_flow_group(vlan_grp); mlx5_destroy_flow_group(vlan_grp);
if (err && !IS_ERR_OR_NULL(acl)) if (err && !IS_ERR_OR_NULL(acl))
mlx5_destroy_flow_table(acl); mlx5_destroy_flow_table(acl);
return err;
} }
static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw,
...@@ -1041,8 +1044,8 @@ static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, ...@@ -1041,8 +1044,8 @@ static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
vport->egress.acl = NULL; vport->egress.acl = NULL;
} }
static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
struct mlx5_vport *vport) struct mlx5_vport *vport)
{ {
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_core_dev *dev = esw->dev; struct mlx5_core_dev *dev = esw->dev;
...@@ -1063,9 +1066,11 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, ...@@ -1063,9 +1066,11 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
int table_size = 4; int table_size = 4;
int err = 0; int err = 0;
if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) || if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
!IS_ERR_OR_NULL(vport->ingress.acl)) return -EOPNOTSUPP;
return;
if (!IS_ERR_OR_NULL(vport->ingress.acl))
return 0;
esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", 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->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
...@@ -1073,12 +1078,12 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, ...@@ -1073,12 +1078,12 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS); root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS);
if (!root_ns) { if (!root_ns) {
esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n"); esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n");
return; return -EIO;
} }
flow_group_in = mlx5_vzalloc(inlen); flow_group_in = mlx5_vzalloc(inlen);
if (!flow_group_in) if (!flow_group_in)
return; return -ENOMEM;
acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
if (IS_ERR(acl)) { if (IS_ERR(acl)) {
...@@ -1167,6 +1172,7 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, ...@@ -1167,6 +1172,7 @@ static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
} }
kvfree(flow_group_in); kvfree(flow_group_in);
return err;
} }
static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
...@@ -1225,7 +1231,13 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, ...@@ -1225,7 +1231,13 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
return 0; return 0;
} }
esw_vport_enable_ingress_acl(esw, vport); 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;
}
esw_debug(esw->dev, esw_debug(esw->dev,
"vport[%d] configure ingress rules, vlan(%d) qos(%d)\n", "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
...@@ -1299,7 +1311,13 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, ...@@ -1299,7 +1311,13 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
return 0; return 0;
} }
esw_vport_enable_egress_acl(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, esw_debug(esw->dev,
"vport[%d] configure egress rules, vlan(%d) qos(%d)\n", "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
......
...@@ -436,6 +436,9 @@ static void del_flow_group(struct fs_node *node) ...@@ -436,6 +436,9 @@ static void del_flow_group(struct fs_node *node)
fs_get_obj(ft, fg->node.parent); fs_get_obj(ft, fg->node.parent);
dev = get_dev(&ft->node); dev = get_dev(&ft->node);
if (ft->autogroup.active)
ft->autogroup.num_groups--;
if (mlx5_cmd_destroy_flow_group(dev, ft, fg->id)) if (mlx5_cmd_destroy_flow_group(dev, ft, fg->id))
mlx5_core_warn(dev, "flow steering can't destroy fg %d of ft %d\n", mlx5_core_warn(dev, "flow steering can't destroy fg %d of ft %d\n",
fg->id, ft->id); fg->id, ft->id);
...@@ -879,7 +882,7 @@ static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table * ...@@ -879,7 +882,7 @@ static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table *
tree_init_node(&fg->node, !is_auto_fg, del_flow_group); tree_init_node(&fg->node, !is_auto_fg, del_flow_group);
tree_add_node(&fg->node, &ft->node); tree_add_node(&fg->node, &ft->node);
/* Add node to group list */ /* Add node to group list */
list_add(&fg->node.list, ft->node.children.prev); list_add(&fg->node.list, prev_fg);
return fg; return fg;
} }
...@@ -893,7 +896,7 @@ struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft, ...@@ -893,7 +896,7 @@ struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft,
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
lock_ref_node(&ft->node); lock_ref_node(&ft->node);
fg = create_flow_group_common(ft, fg_in, &ft->node.children, false); fg = create_flow_group_common(ft, fg_in, ft->node.children.prev, false);
unlock_ref_node(&ft->node); unlock_ref_node(&ft->node);
return fg; return fg;
...@@ -1012,7 +1015,7 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft, ...@@ -1012,7 +1015,7 @@ static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
u32 *match_criteria) u32 *match_criteria)
{ {
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct list_head *prev = &ft->node.children; struct list_head *prev = ft->node.children.prev;
unsigned int candidate_index = 0; unsigned int candidate_index = 0;
struct mlx5_flow_group *fg; struct mlx5_flow_group *fg;
void *match_criteria_addr; void *match_criteria_addr;
......
...@@ -218,6 +218,7 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) ...@@ -218,6 +218,7 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
goto err_out; goto err_out;
if (aging) { if (aging) {
counter->cache.lastuse = jiffies;
counter->aging = true; counter->aging = true;
spin_lock(&fc_stats->addlist_lock); spin_lock(&fc_stats->addlist_lock);
......
...@@ -61,10 +61,15 @@ enum { ...@@ -61,10 +61,15 @@ enum {
enum { enum {
MLX5_NIC_IFC_FULL = 0, MLX5_NIC_IFC_FULL = 0,
MLX5_NIC_IFC_DISABLED = 1, MLX5_NIC_IFC_DISABLED = 1,
MLX5_NIC_IFC_NO_DRAM_NIC = 2 MLX5_NIC_IFC_NO_DRAM_NIC = 2,
MLX5_NIC_IFC_INVALID = 3
}; };
static u8 get_nic_interface(struct mlx5_core_dev *dev) enum {
MLX5_DROP_NEW_HEALTH_WORK,
};
static u8 get_nic_state(struct mlx5_core_dev *dev)
{ {
return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3; return (ioread32be(&dev->iseg->cmdq_addr_l_sz) >> 8) & 3;
} }
...@@ -97,7 +102,7 @@ static int in_fatal(struct mlx5_core_dev *dev) ...@@ -97,7 +102,7 @@ static int in_fatal(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health; struct mlx5_core_health *health = &dev->priv.health;
struct health_buffer __iomem *h = health->health; struct health_buffer __iomem *h = health->health;
if (get_nic_interface(dev) == MLX5_NIC_IFC_DISABLED) if (get_nic_state(dev) == MLX5_NIC_IFC_DISABLED)
return 1; return 1;
if (ioread32be(&h->fw_ver) == 0xffffffff) if (ioread32be(&h->fw_ver) == 0xffffffff)
...@@ -127,7 +132,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev) ...@@ -127,7 +132,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev)
static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
{ {
u8 nic_interface = get_nic_interface(dev); u8 nic_interface = get_nic_state(dev);
switch (nic_interface) { switch (nic_interface) {
case MLX5_NIC_IFC_FULL: case MLX5_NIC_IFC_FULL:
...@@ -149,8 +154,34 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) ...@@ -149,8 +154,34 @@ static void mlx5_handle_bad_state(struct mlx5_core_dev *dev)
mlx5_disable_device(dev); mlx5_disable_device(dev);
} }
static void health_recover(struct work_struct *work)
{
struct mlx5_core_health *health;
struct delayed_work *dwork;
struct mlx5_core_dev *dev;
struct mlx5_priv *priv;
u8 nic_state;
dwork = container_of(work, struct delayed_work, work);
health = container_of(dwork, struct mlx5_core_health, recover_work);
priv = container_of(health, struct mlx5_priv, health);
dev = container_of(priv, struct mlx5_core_dev, priv);
nic_state = get_nic_state(dev);
if (nic_state == MLX5_NIC_IFC_INVALID) {
dev_err(&dev->pdev->dev, "health recovery flow aborted since the nic state is invalid\n");
return;
}
dev_err(&dev->pdev->dev, "starting health recovery flow\n");
mlx5_recover_device(dev);
}
/* How much time to wait until health resetting the driver (in msecs) */
#define MLX5_RECOVERY_DELAY_MSECS 60000
static void health_care(struct work_struct *work) static void health_care(struct work_struct *work)
{ {
unsigned long recover_delay = msecs_to_jiffies(MLX5_RECOVERY_DELAY_MSECS);
struct mlx5_core_health *health; struct mlx5_core_health *health;
struct mlx5_core_dev *dev; struct mlx5_core_dev *dev;
struct mlx5_priv *priv; struct mlx5_priv *priv;
...@@ -160,6 +191,14 @@ static void health_care(struct work_struct *work) ...@@ -160,6 +191,14 @@ static void health_care(struct work_struct *work)
dev = container_of(priv, struct mlx5_core_dev, priv); dev = container_of(priv, struct mlx5_core_dev, priv);
mlx5_core_warn(dev, "handling bad device here\n"); mlx5_core_warn(dev, "handling bad device here\n");
mlx5_handle_bad_state(dev); mlx5_handle_bad_state(dev);
spin_lock(&health->wq_lock);
if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
schedule_delayed_work(&health->recover_work, recover_delay);
else
dev_err(&dev->pdev->dev,
"new health works are not permitted at this stage\n");
spin_unlock(&health->wq_lock);
} }
static const char *hsynd_str(u8 synd) static const char *hsynd_str(u8 synd)
...@@ -272,7 +311,13 @@ static void poll_health(unsigned long data) ...@@ -272,7 +311,13 @@ static void poll_health(unsigned long data)
if (in_fatal(dev) && !health->sick) { if (in_fatal(dev) && !health->sick) {
health->sick = true; health->sick = true;
print_health_info(dev); print_health_info(dev);
schedule_work(&health->work); spin_lock(&health->wq_lock);
if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
queue_work(health->wq, &health->work);
else
dev_err(&dev->pdev->dev,
"new health works are not permitted at this stage\n");
spin_unlock(&health->wq_lock);
} }
} }
...@@ -281,6 +326,8 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) ...@@ -281,6 +326,8 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health; struct mlx5_core_health *health = &dev->priv.health;
init_timer(&health->timer); init_timer(&health->timer);
health->sick = 0;
clear_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
health->health = &dev->iseg->health; health->health = &dev->iseg->health;
health->health_counter = &dev->iseg->health_counter; health->health_counter = &dev->iseg->health_counter;
...@@ -297,11 +344,22 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev) ...@@ -297,11 +344,22 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev)
del_timer_sync(&health->timer); del_timer_sync(&health->timer);
} }
void mlx5_drain_health_wq(struct mlx5_core_dev *dev)
{
struct mlx5_core_health *health = &dev->priv.health;
spin_lock(&health->wq_lock);
set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
spin_unlock(&health->wq_lock);
cancel_delayed_work_sync(&health->recover_work);
cancel_work_sync(&health->work);
}
void mlx5_health_cleanup(struct mlx5_core_dev *dev) void mlx5_health_cleanup(struct mlx5_core_dev *dev)
{ {
struct mlx5_core_health *health = &dev->priv.health; struct mlx5_core_health *health = &dev->priv.health;
flush_work(&health->work); destroy_workqueue(health->wq);
} }
int mlx5_health_init(struct mlx5_core_dev *dev) int mlx5_health_init(struct mlx5_core_dev *dev)
...@@ -316,9 +374,13 @@ int mlx5_health_init(struct mlx5_core_dev *dev) ...@@ -316,9 +374,13 @@ int mlx5_health_init(struct mlx5_core_dev *dev)
strcpy(name, "mlx5_health"); strcpy(name, "mlx5_health");
strcat(name, dev_name(&dev->pdev->dev)); strcat(name, dev_name(&dev->pdev->dev));
health->wq = create_singlethread_workqueue(name);
kfree(name); kfree(name);
if (!health->wq)
return -ENOMEM;
spin_lock_init(&health->wq_lock);
INIT_WORK(&health->work, health_care); INIT_WORK(&health->work, health_care);
INIT_DELAYED_WORK(&health->recover_work, health_recover);
return 0; return 0;
} }
...@@ -844,12 +844,6 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv) ...@@ -844,12 +844,6 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
struct pci_dev *pdev = dev->pdev; struct pci_dev *pdev = dev->pdev;
int err; int err;
err = mlx5_query_hca_caps(dev);
if (err) {
dev_err(&pdev->dev, "query hca failed\n");
goto out;
}
err = mlx5_query_board_id(dev); err = mlx5_query_board_id(dev);
if (err) { if (err) {
dev_err(&pdev->dev, "query board id failed\n"); dev_err(&pdev->dev, "query board id failed\n");
...@@ -1023,6 +1017,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, ...@@ -1023,6 +1017,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
mlx5_start_health_poll(dev); mlx5_start_health_poll(dev);
err = mlx5_query_hca_caps(dev);
if (err) {
dev_err(&pdev->dev, "query hca failed\n");
goto err_stop_poll;
}
if (boot && mlx5_init_once(dev, priv)) { if (boot && mlx5_init_once(dev, priv)) {
dev_err(&pdev->dev, "sw objs init failed\n"); dev_err(&pdev->dev, "sw objs init failed\n");
goto err_stop_poll; goto err_stop_poll;
...@@ -1313,10 +1313,16 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, ...@@ -1313,10 +1313,16 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev,
struct mlx5_priv *priv = &dev->priv; struct mlx5_priv *priv = &dev->priv;
dev_info(&pdev->dev, "%s was called\n", __func__); dev_info(&pdev->dev, "%s was called\n", __func__);
mlx5_enter_error_state(dev); mlx5_enter_error_state(dev);
mlx5_unload_one(dev, priv, false); mlx5_unload_one(dev, priv, false);
pci_save_state(pdev); /* In case of kernel call save the pci state and drain health wq */
mlx5_pci_disable_device(dev); if (state) {
pci_save_state(pdev);
mlx5_drain_health_wq(dev);
mlx5_pci_disable_device(dev);
}
return state == pci_channel_io_perm_failure ? return state == pci_channel_io_perm_failure ?
PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
} }
...@@ -1373,11 +1379,6 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev) ...@@ -1373,11 +1379,6 @@ static pci_ers_result_t mlx5_pci_slot_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_RECOVERED; return PCI_ERS_RESULT_RECOVERED;
} }
void mlx5_disable_device(struct mlx5_core_dev *dev)
{
mlx5_pci_err_detected(dev->pdev, 0);
}
static void mlx5_pci_resume(struct pci_dev *pdev) static void mlx5_pci_resume(struct pci_dev *pdev)
{ {
struct mlx5_core_dev *dev = pci_get_drvdata(pdev); struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
...@@ -1427,6 +1428,18 @@ static const struct pci_device_id mlx5_core_pci_table[] = { ...@@ -1427,6 +1428,18 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table); MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table);
void mlx5_disable_device(struct mlx5_core_dev *dev)
{
mlx5_pci_err_detected(dev->pdev, 0);
}
void mlx5_recover_device(struct mlx5_core_dev *dev)
{
mlx5_pci_disable_device(dev);
if (mlx5_pci_slot_reset(dev->pdev) == PCI_ERS_RESULT_RECOVERED)
mlx5_pci_resume(dev->pdev);
}
static struct pci_driver mlx5_core_driver = { static struct pci_driver mlx5_core_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = mlx5_core_pci_table, .id_table = mlx5_core_pci_table,
......
...@@ -83,6 +83,7 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, ...@@ -83,6 +83,7 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
unsigned long param); unsigned long param);
void mlx5_enter_error_state(struct mlx5_core_dev *dev); void mlx5_enter_error_state(struct mlx5_core_dev *dev);
void mlx5_disable_device(struct mlx5_core_dev *dev); void mlx5_disable_device(struct mlx5_core_dev *dev);
void mlx5_recover_device(struct mlx5_core_dev *dev);
int mlx5_sriov_init(struct mlx5_core_dev *dev); int mlx5_sriov_init(struct mlx5_core_dev *dev);
void mlx5_sriov_cleanup(struct mlx5_core_dev *dev); void mlx5_sriov_cleanup(struct mlx5_core_dev *dev);
int mlx5_sriov_attach(struct mlx5_core_dev *dev); int mlx5_sriov_attach(struct mlx5_core_dev *dev);
......
...@@ -209,6 +209,7 @@ static void free_4k(struct mlx5_core_dev *dev, u64 addr) ...@@ -209,6 +209,7 @@ static void free_4k(struct mlx5_core_dev *dev, u64 addr)
static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id)
{ {
struct page *page; struct page *page;
u64 zero_addr = 1;
u64 addr; u64 addr;
int err; int err;
int nid = dev_to_node(&dev->pdev->dev); int nid = dev_to_node(&dev->pdev->dev);
...@@ -218,26 +219,35 @@ static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) ...@@ -218,26 +219,35 @@ static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id)
mlx5_core_warn(dev, "failed to allocate page\n"); mlx5_core_warn(dev, "failed to allocate page\n");
return -ENOMEM; return -ENOMEM;
} }
map:
addr = dma_map_page(&dev->pdev->dev, page, 0, addr = dma_map_page(&dev->pdev->dev, page, 0,
PAGE_SIZE, DMA_BIDIRECTIONAL); PAGE_SIZE, DMA_BIDIRECTIONAL);
if (dma_mapping_error(&dev->pdev->dev, addr)) { if (dma_mapping_error(&dev->pdev->dev, addr)) {
mlx5_core_warn(dev, "failed dma mapping page\n"); mlx5_core_warn(dev, "failed dma mapping page\n");
err = -ENOMEM; err = -ENOMEM;
goto out_alloc; goto err_mapping;
} }
/* Firmware doesn't support page with physical address 0 */
if (addr == 0) {
zero_addr = addr;
goto map;
}
err = insert_page(dev, addr, page, func_id); err = insert_page(dev, addr, page, func_id);
if (err) { if (err) {
mlx5_core_err(dev, "failed to track allocated page\n"); mlx5_core_err(dev, "failed to track allocated page\n");
goto out_mapping; dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE,
DMA_BIDIRECTIONAL);
} }
return 0; err_mapping:
if (err)
out_mapping: __free_page(page);
dma_unmap_page(&dev->pdev->dev, addr, PAGE_SIZE, DMA_BIDIRECTIONAL);
out_alloc: if (zero_addr == 0)
__free_page(page); dma_unmap_page(&dev->pdev->dev, zero_addr, PAGE_SIZE,
DMA_BIDIRECTIONAL);
return err; return err;
} }
......
...@@ -418,8 +418,12 @@ struct mlx5_core_health { ...@@ -418,8 +418,12 @@ struct mlx5_core_health {
u32 prev; u32 prev;
int miss_counter; int miss_counter;
bool sick; bool sick;
/* wq spinlock to synchronize draining */
spinlock_t wq_lock;
struct workqueue_struct *wq; struct workqueue_struct *wq;
unsigned long flags;
struct work_struct work; struct work_struct work;
struct delayed_work recover_work;
}; };
struct mlx5_cq_table { struct mlx5_cq_table {
...@@ -625,10 +629,6 @@ struct mlx5_db { ...@@ -625,10 +629,6 @@ struct mlx5_db {
int index; int index;
}; };
enum {
MLX5_DB_PER_PAGE = PAGE_SIZE / L1_CACHE_BYTES,
};
enum { enum {
MLX5_COMP_EQ_SIZE = 1024, MLX5_COMP_EQ_SIZE = 1024,
}; };
...@@ -638,13 +638,6 @@ enum { ...@@ -638,13 +638,6 @@ enum {
MLX5_PTYS_EN = 1 << 2, MLX5_PTYS_EN = 1 << 2,
}; };
struct mlx5_db_pgdir {
struct list_head list;
DECLARE_BITMAP(bitmap, MLX5_DB_PER_PAGE);
__be32 *db_page;
dma_addr_t db_dma;
};
typedef void (*mlx5_cmd_cbk_t)(int status, void *context); typedef void (*mlx5_cmd_cbk_t)(int status, void *context);
struct mlx5_cmd_work_ent { struct mlx5_cmd_work_ent {
...@@ -789,6 +782,7 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev); ...@@ -789,6 +782,7 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev);
int mlx5_health_init(struct mlx5_core_dev *dev); int mlx5_health_init(struct mlx5_core_dev *dev);
void mlx5_start_health_poll(struct mlx5_core_dev *dev); void mlx5_start_health_poll(struct mlx5_core_dev *dev);
void mlx5_stop_health_poll(struct mlx5_core_dev *dev); void mlx5_stop_health_poll(struct mlx5_core_dev *dev);
void mlx5_drain_health_wq(struct mlx5_core_dev *dev);
int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,
struct mlx5_buf *buf, int node); struct mlx5_buf *buf, int node);
int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf); int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *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