summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/enic/enic_main.c16
-rw-r--r--drivers/net/enic/vnic_dev.c38
-rw-r--r--drivers/net/enic/vnic_dev.h2
-rw-r--r--drivers/net/enic/vnic_devcmd.h7
4 files changed, 55 insertions, 8 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 7f98af1eb1ea..d7434b7b4c52 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -812,9 +812,10 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev)
return net_stats;
}
-static void enic_reset_mcaddrs(struct enic *enic)
+static void enic_reset_multicast_list(struct enic *enic)
{
enic->mc_count = 0;
+ enic->flags = 0;
}
static int enic_set_mac_addr(struct net_device *netdev, char *addr)
@@ -1847,15 +1848,15 @@ static int enic_dev_open(struct enic *enic)
return err;
}
-static int enic_dev_soft_reset(struct enic *enic)
+static int enic_dev_hang_reset(struct enic *enic)
{
int err;
- err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset,
- vnic_dev_soft_reset_done, 0);
+ err = enic_dev_wait(enic->vdev, vnic_dev_hang_reset,
+ vnic_dev_hang_reset_done, 0);
if (err)
printk(KERN_ERR PFX
- "vNIC soft reset failed, err %d.\n", err);
+ "vNIC hang reset failed, err %d.\n", err);
return err;
}
@@ -1906,9 +1907,8 @@ static void enic_reset(struct work_struct *work)
spin_unlock(&enic->devcmd_lock);
enic_stop(enic->netdev);
- enic_dev_soft_reset(enic);
- vnic_dev_init(enic->vdev, 0);
- enic_reset_mcaddrs(enic);
+ enic_dev_hang_reset(enic);
+ enic_reset_multicast_list(enic);
enic_init_vnic_resources(enic);
enic_set_niccfg(enic);
enic_dev_set_ig_vlan_rewrite_mode(enic);
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index e3742faa06fe..c93012f2faa9 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -486,6 +486,44 @@ int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
return 0;
}
+int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg)
+{
+ u64 a0 = (u32)arg, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ err = vnic_dev_cmd(vdev, CMD_HANG_RESET, &a0, &a1, wait);
+ if (err == ERR_ECMDUNKNOWN) {
+ err = vnic_dev_soft_reset(vdev, arg);
+ if (err)
+ return err;
+
+ return vnic_dev_init(vdev, 0);
+ }
+
+ return err;
+}
+
+int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done)
+{
+ u64 a0 = 0, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ *done = 0;
+
+ err = vnic_dev_cmd(vdev, CMD_HANG_RESET_STATUS, &a0, &a1, wait);
+ if (err) {
+ if (err == ERR_ECMDUNKNOWN)
+ return vnic_dev_soft_reset_done(vdev, done);
+ return err;
+ }
+
+ *done = (a0 == 0);
+
+ return 0;
+}
+
int vnic_dev_hang_notify(struct vnic_dev *vdev)
{
u64 a0, a1;
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
index 780c3cd73292..4980615fcee2 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/enic/vnic_dev.h
@@ -129,6 +129,8 @@ int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
int vnic_dev_deinit(struct vnic_dev *vdev);
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
+int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
+int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
enum vnic_dev_intr_mode intr_mode);
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
index c5ff4ff2ed26..1c4fb35671fa 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -212,6 +212,13 @@ enum vnic_devcmd_cmd {
*/
CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38),
+ /* initiate hangreset, like softreset after hang detected */
+ CMD_HANG_RESET = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 39),
+
+ /* hangreset status:
+ * out: a0=0 reset complete, a0=1 reset in progress */
+ CMD_HANG_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 40),
+
/*
* Set hw ingress packet vlan rewrite mode:
* in: (u32)a0=new vlan rewrite mode