|
@@ -108,6 +108,8 @@ MODULE_PARM_DESC(enable_64b_cqe_eqe,
|
|
|
MLX4_FUNC_CAP_EQE_CQE_STRIDE | \
|
|
|
MLX4_FUNC_CAP_DMFS_A0_STATIC)
|
|
|
|
|
|
+#define RESET_PERSIST_MASK_FLAGS (MLX4_FLAG_SRIOV)
|
|
|
+
|
|
|
static char mlx4_version[] =
|
|
|
DRV_NAME ": Mellanox ConnectX core driver v"
|
|
|
DRV_VERSION " (" DRV_RELDATE ")\n";
|
|
@@ -1579,6 +1581,50 @@ static void mlx4_close_fw(struct mlx4_dev *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int mlx4_comm_check_offline(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+#define COMM_CHAN_OFFLINE_OFFSET 0x09
|
|
|
+
|
|
|
+ u32 comm_flags;
|
|
|
+ u32 offline_bit;
|
|
|
+ unsigned long end;
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+
|
|
|
+ end = msecs_to_jiffies(MLX4_COMM_OFFLINE_TIME_OUT) + jiffies;
|
|
|
+ while (time_before(jiffies, end)) {
|
|
|
+ comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm +
|
|
|
+ MLX4_COMM_CHAN_FLAGS));
|
|
|
+ offline_bit = (comm_flags &
|
|
|
+ (u32)(1 << COMM_CHAN_OFFLINE_OFFSET));
|
|
|
+ if (!offline_bit)
|
|
|
+ return 0;
|
|
|
+ /* There are cases as part of AER/Reset flow that PF needs
|
|
|
+ * around 100 msec to load. We therefore sleep for 100 msec
|
|
|
+ * to allow other tasks to make use of that CPU during this
|
|
|
+ * time interval.
|
|
|
+ */
|
|
|
+ msleep(100);
|
|
|
+ }
|
|
|
+ mlx4_err(dev, "Communication channel is offline.\n");
|
|
|
+ return -EIO;
|
|
|
+}
|
|
|
+
|
|
|
+static void mlx4_reset_vf_support(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+#define COMM_CHAN_RST_OFFSET 0x1e
|
|
|
+
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ u32 comm_rst;
|
|
|
+ u32 comm_caps;
|
|
|
+
|
|
|
+ comm_caps = swab32(readl((__iomem char *)priv->mfunc.comm +
|
|
|
+ MLX4_COMM_CHAN_CAPS));
|
|
|
+ comm_rst = (comm_caps & (u32)(1 << COMM_CHAN_RST_OFFSET));
|
|
|
+
|
|
|
+ if (comm_rst)
|
|
|
+ dev->caps.vf_caps |= MLX4_VF_CAP_FLAG_RESET;
|
|
|
+}
|
|
|
+
|
|
|
static int mlx4_init_slave(struct mlx4_dev *dev)
|
|
|
{
|
|
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
|
@@ -1594,6 +1640,12 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
|
|
|
|
|
|
mutex_lock(&priv->cmd.slave_cmd_mutex);
|
|
|
priv->cmd.max_cmds = 1;
|
|
|
+ if (mlx4_comm_check_offline(dev)) {
|
|
|
+ mlx4_err(dev, "PF is not responsive, skipping initialization\n");
|
|
|
+ goto err_offline;
|
|
|
+ }
|
|
|
+
|
|
|
+ mlx4_reset_vf_support(dev);
|
|
|
mlx4_warn(dev, "Sending reset\n");
|
|
|
ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0,
|
|
|
MLX4_COMM_TIME);
|
|
@@ -1637,6 +1689,7 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
|
|
|
|
|
|
err:
|
|
|
mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0);
|
|
|
+err_offline:
|
|
|
mutex_unlock(&priv->cmd.slave_cmd_mutex);
|
|
|
return -EIO;
|
|
|
}
|
|
@@ -2494,11 +2547,19 @@ static void mlx4_free_ownership(struct mlx4_dev *dev)
|
|
|
!!((flags) & MLX4_FLAG_MASTER))
|
|
|
|
|
|
static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev,
|
|
|
- u8 total_vfs, int existing_vfs)
|
|
|
+ u8 total_vfs, int existing_vfs, int reset_flow)
|
|
|
{
|
|
|
u64 dev_flags = dev->flags;
|
|
|
int err = 0;
|
|
|
|
|
|
+ if (reset_flow) {
|
|
|
+ dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!dev->dev_vfs)
|
|
|
+ goto free_mem;
|
|
|
+ return dev_flags;
|
|
|
+ }
|
|
|
+
|
|
|
atomic_inc(&pf_loading);
|
|
|
if (dev->flags & MLX4_FLAG_SRIOV) {
|
|
|
if (existing_vfs != total_vfs) {
|
|
@@ -2533,6 +2594,7 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev,
|
|
|
|
|
|
disable_sriov:
|
|
|
atomic_dec(&pf_loading);
|
|
|
+free_mem:
|
|
|
dev->persist->num_vfs = 0;
|
|
|
kfree(dev->dev_vfs);
|
|
|
return dev_flags & ~MLX4_FLAG_MASTER;
|
|
@@ -2557,7 +2619,8 @@ static int mlx4_check_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap
|
|
|
}
|
|
|
|
|
|
static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
|
|
|
- int total_vfs, int *nvfs, struct mlx4_priv *priv)
|
|
|
+ int total_vfs, int *nvfs, struct mlx4_priv *priv,
|
|
|
+ int reset_flow)
|
|
|
{
|
|
|
struct mlx4_dev *dev;
|
|
|
unsigned sum = 0;
|
|
@@ -2679,8 +2742,10 @@ slave_start:
|
|
|
goto err_fw;
|
|
|
|
|
|
if (!(dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) {
|
|
|
- u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs,
|
|
|
- existing_vfs);
|
|
|
+ u64 dev_flags = mlx4_enable_sriov(dev, pdev,
|
|
|
+ total_vfs,
|
|
|
+ existing_vfs,
|
|
|
+ reset_flow);
|
|
|
|
|
|
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
|
|
|
dev->flags = dev_flags;
|
|
@@ -2722,7 +2787,7 @@ slave_start:
|
|
|
if (dev->flags & MLX4_FLAG_SRIOV) {
|
|
|
if (!existing_vfs)
|
|
|
pci_disable_sriov(pdev);
|
|
|
- if (mlx4_is_master(dev))
|
|
|
+ if (mlx4_is_master(dev) && !reset_flow)
|
|
|
atomic_dec(&pf_loading);
|
|
|
dev->flags &= ~MLX4_FLAG_SRIOV;
|
|
|
}
|
|
@@ -2736,7 +2801,8 @@ slave_start:
|
|
|
}
|
|
|
|
|
|
if (mlx4_is_master(dev) && (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) {
|
|
|
- u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, existing_vfs);
|
|
|
+ u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs,
|
|
|
+ existing_vfs, reset_flow);
|
|
|
|
|
|
if ((dev->flags ^ dev_flags) & (MLX4_FLAG_MASTER | MLX4_FLAG_SLAVE)) {
|
|
|
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_VHCR);
|
|
@@ -2848,6 +2914,17 @@ slave_start:
|
|
|
goto err_steer;
|
|
|
|
|
|
mlx4_init_quotas(dev);
|
|
|
+ /* When PF resources are ready arm its comm channel to enable
|
|
|
+ * getting commands
|
|
|
+ */
|
|
|
+ if (mlx4_is_master(dev)) {
|
|
|
+ err = mlx4_ARM_COMM_CHANNEL(dev);
|
|
|
+ if (err) {
|
|
|
+ mlx4_err(dev, " Failed to arm comm channel eq: %x\n",
|
|
|
+ err);
|
|
|
+ goto err_steer;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
for (port = 1; port <= dev->caps.num_ports; port++) {
|
|
|
err = mlx4_init_port_info(dev, port);
|
|
@@ -2866,7 +2943,7 @@ slave_start:
|
|
|
|
|
|
priv->removed = 0;
|
|
|
|
|
|
- if (mlx4_is_master(dev) && dev->persist->num_vfs)
|
|
|
+ if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow)
|
|
|
atomic_dec(&pf_loading);
|
|
|
|
|
|
kfree(dev_cap);
|
|
@@ -2925,10 +3002,12 @@ err_cmd:
|
|
|
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
|
|
|
|
|
|
err_sriov:
|
|
|
- if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs)
|
|
|
+ if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) {
|
|
|
pci_disable_sriov(pdev);
|
|
|
+ dev->flags &= ~MLX4_FLAG_SRIOV;
|
|
|
+ }
|
|
|
|
|
|
- if (mlx4_is_master(dev) && dev->persist->num_vfs)
|
|
|
+ if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow)
|
|
|
atomic_dec(&pf_loading);
|
|
|
|
|
|
kfree(priv->dev.dev_vfs);
|
|
@@ -3073,7 +3152,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data,
|
|
|
if (err)
|
|
|
goto err_release_regions;
|
|
|
|
|
|
- err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv);
|
|
|
+ err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 0);
|
|
|
if (err)
|
|
|
goto err_catas;
|
|
|
|
|
@@ -3131,9 +3210,11 @@ static void mlx4_clean_dev(struct mlx4_dev *dev)
|
|
|
{
|
|
|
struct mlx4_dev_persistent *persist = dev->persist;
|
|
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ unsigned long flags = (dev->flags & RESET_PERSIST_MASK_FLAGS);
|
|
|
|
|
|
memset(priv, 0, sizeof(*priv));
|
|
|
priv->dev.persist = persist;
|
|
|
+ priv->dev.flags = flags;
|
|
|
}
|
|
|
|
|
|
static void mlx4_unload_one(struct pci_dev *pdev)
|
|
@@ -3143,7 +3224,6 @@ static void mlx4_unload_one(struct pci_dev *pdev)
|
|
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
int pci_dev_data;
|
|
|
int p, i;
|
|
|
- int active_vfs = 0;
|
|
|
|
|
|
if (priv->removed)
|
|
|
return;
|
|
@@ -3157,14 +3237,6 @@ static void mlx4_unload_one(struct pci_dev *pdev)
|
|
|
|
|
|
pci_dev_data = priv->pci_dev_data;
|
|
|
|
|
|
- /* Disabling SR-IOV is not allowed while there are active vf's */
|
|
|
- if (mlx4_is_master(dev)) {
|
|
|
- active_vfs = mlx4_how_many_lives_vf(dev);
|
|
|
- if (active_vfs) {
|
|
|
- pr_warn("Removing PF when there are active VF's !!\n");
|
|
|
- pr_warn("Will not disable SR-IOV.\n");
|
|
|
- }
|
|
|
- }
|
|
|
mlx4_stop_sense(dev);
|
|
|
mlx4_unregister_device(dev);
|
|
|
|
|
@@ -3208,12 +3280,6 @@ static void mlx4_unload_one(struct pci_dev *pdev)
|
|
|
|
|
|
if (dev->flags & MLX4_FLAG_MSI_X)
|
|
|
pci_disable_msix(pdev);
|
|
|
- if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) {
|
|
|
- mlx4_warn(dev, "Disabling SR-IOV\n");
|
|
|
- pci_disable_sriov(pdev);
|
|
|
- dev->flags &= ~MLX4_FLAG_SRIOV;
|
|
|
- dev->persist->num_vfs = 0;
|
|
|
- }
|
|
|
|
|
|
if (!mlx4_is_slave(dev))
|
|
|
mlx4_free_ownership(dev);
|
|
@@ -3235,11 +3301,21 @@ static void mlx4_remove_one(struct pci_dev *pdev)
|
|
|
struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
|
|
|
struct mlx4_dev *dev = persist->dev;
|
|
|
struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+ int active_vfs = 0;
|
|
|
|
|
|
mutex_lock(&persist->interface_state_mutex);
|
|
|
persist->interface_state |= MLX4_INTERFACE_STATE_DELETION;
|
|
|
mutex_unlock(&persist->interface_state_mutex);
|
|
|
|
|
|
+ /* Disabling SR-IOV is not allowed while there are active vf's */
|
|
|
+ if (mlx4_is_master(dev) && dev->flags & MLX4_FLAG_SRIOV) {
|
|
|
+ active_vfs = mlx4_how_many_lives_vf(dev);
|
|
|
+ if (active_vfs) {
|
|
|
+ pr_warn("Removing PF when there are active VF's !!\n");
|
|
|
+ pr_warn("Will not disable SR-IOV.\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* device marked to be under deletion running now without the lock
|
|
|
* letting other tasks to be terminated
|
|
|
*/
|
|
@@ -3248,6 +3324,11 @@ static void mlx4_remove_one(struct pci_dev *pdev)
|
|
|
else
|
|
|
mlx4_info(dev, "%s: interface is down\n", __func__);
|
|
|
mlx4_catas_end(dev);
|
|
|
+ if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) {
|
|
|
+ mlx4_warn(dev, "Disabling SR-IOV\n");
|
|
|
+ pci_disable_sriov(pdev);
|
|
|
+ }
|
|
|
+
|
|
|
pci_release_regions(pdev);
|
|
|
pci_disable_device(pdev);
|
|
|
kfree(dev->persist);
|
|
@@ -3287,7 +3368,7 @@ int mlx4_restart_one(struct pci_dev *pdev)
|
|
|
memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs));
|
|
|
|
|
|
mlx4_unload_one(pdev);
|
|
|
- err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv);
|
|
|
+ err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 1);
|
|
|
if (err) {
|
|
|
mlx4_err(dev, "%s: ERROR: mlx4_load_one failed, pci_name=%s, err=%d\n",
|
|
|
__func__, pci_name(pdev), err);
|
|
@@ -3397,7 +3478,7 @@ static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
|
|
|
mutex_lock(&persist->interface_state_mutex);
|
|
|
if (!(persist->interface_state & MLX4_INTERFACE_STATE_UP)) {
|
|
|
ret = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs,
|
|
|
- priv);
|
|
|
+ priv, 1);
|
|
|
if (ret) {
|
|
|
mlx4_err(dev, "%s: mlx4_load_one failed, ret=%d\n",
|
|
|
__func__, ret);
|