diff options
| author | Vasanthy Kolluri <vkolluri@cisco.com> | 2010-06-24 06:50:00 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-06-25 23:46:01 -0400 |
| commit | 99ef563901a18d44a6c2eadd2b958e2e83aeca51 (patch) | |
| tree | 29bbf0fe2457effbaa62281eca6aff2191cc9f75 | |
| parent | f8cac14acff870203ea7f61f1a92c5486d1774fa (diff) | |
enic: Use a lighter reset operation for enic devices
The port profile information for a dynamic enic device is set by the upper
layers, that are oblivious to the device reset operation. We do not want a
reset operation erase the network state of a dynamic enic device as there
is no way to set up the port profile information again. Hence a lighter
reset operation called hang reset is used. Hang reset, unlike soft reset
does not reset the network state and resets the host side state only.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com>
Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/enic/enic_main.c | 16 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_dev.c | 38 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_dev.h | 2 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_devcmd.h | 7 |
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) | |||
| 812 | return net_stats; | 812 | return net_stats; |
| 813 | } | 813 | } |
| 814 | 814 | ||
| 815 | static void enic_reset_mcaddrs(struct enic *enic) | 815 | static void enic_reset_multicast_list(struct enic *enic) |
| 816 | { | 816 | { |
| 817 | enic->mc_count = 0; | 817 | enic->mc_count = 0; |
| 818 | enic->flags = 0; | ||
| 818 | } | 819 | } |
| 819 | 820 | ||
| 820 | static int enic_set_mac_addr(struct net_device *netdev, char *addr) | 821 | static int enic_set_mac_addr(struct net_device *netdev, char *addr) |
| @@ -1847,15 +1848,15 @@ static int enic_dev_open(struct enic *enic) | |||
| 1847 | return err; | 1848 | return err; |
| 1848 | } | 1849 | } |
| 1849 | 1850 | ||
| 1850 | static int enic_dev_soft_reset(struct enic *enic) | 1851 | static int enic_dev_hang_reset(struct enic *enic) |
| 1851 | { | 1852 | { |
| 1852 | int err; | 1853 | int err; |
| 1853 | 1854 | ||
| 1854 | err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset, | 1855 | err = enic_dev_wait(enic->vdev, vnic_dev_hang_reset, |
| 1855 | vnic_dev_soft_reset_done, 0); | 1856 | vnic_dev_hang_reset_done, 0); |
| 1856 | if (err) | 1857 | if (err) |
| 1857 | printk(KERN_ERR PFX | 1858 | printk(KERN_ERR PFX |
| 1858 | "vNIC soft reset failed, err %d.\n", err); | 1859 | "vNIC hang reset failed, err %d.\n", err); |
| 1859 | 1860 | ||
| 1860 | return err; | 1861 | return err; |
| 1861 | } | 1862 | } |
| @@ -1906,9 +1907,8 @@ static void enic_reset(struct work_struct *work) | |||
| 1906 | spin_unlock(&enic->devcmd_lock); | 1907 | spin_unlock(&enic->devcmd_lock); |
| 1907 | 1908 | ||
| 1908 | enic_stop(enic->netdev); | 1909 | enic_stop(enic->netdev); |
| 1909 | enic_dev_soft_reset(enic); | 1910 | enic_dev_hang_reset(enic); |
| 1910 | vnic_dev_init(enic->vdev, 0); | 1911 | enic_reset_multicast_list(enic); |
| 1911 | enic_reset_mcaddrs(enic); | ||
| 1912 | enic_init_vnic_resources(enic); | 1912 | enic_init_vnic_resources(enic); |
| 1913 | enic_set_niccfg(enic); | 1913 | enic_set_niccfg(enic); |
| 1914 | enic_dev_set_ig_vlan_rewrite_mode(enic); | 1914 | 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) | |||
| 486 | return 0; | 486 | return 0; |
| 487 | } | 487 | } |
| 488 | 488 | ||
| 489 | int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg) | ||
| 490 | { | ||
| 491 | u64 a0 = (u32)arg, a1 = 0; | ||
| 492 | int wait = 1000; | ||
| 493 | int err; | ||
| 494 | |||
| 495 | err = vnic_dev_cmd(vdev, CMD_HANG_RESET, &a0, &a1, wait); | ||
| 496 | if (err == ERR_ECMDUNKNOWN) { | ||
| 497 | err = vnic_dev_soft_reset(vdev, arg); | ||
| 498 | if (err) | ||
| 499 | return err; | ||
| 500 | |||
| 501 | return vnic_dev_init(vdev, 0); | ||
| 502 | } | ||
| 503 | |||
| 504 | return err; | ||
| 505 | } | ||
| 506 | |||
| 507 | int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done) | ||
| 508 | { | ||
| 509 | u64 a0 = 0, a1 = 0; | ||
| 510 | int wait = 1000; | ||
| 511 | int err; | ||
| 512 | |||
| 513 | *done = 0; | ||
| 514 | |||
| 515 | err = vnic_dev_cmd(vdev, CMD_HANG_RESET_STATUS, &a0, &a1, wait); | ||
| 516 | if (err) { | ||
| 517 | if (err == ERR_ECMDUNKNOWN) | ||
| 518 | return vnic_dev_soft_reset_done(vdev, done); | ||
| 519 | return err; | ||
| 520 | } | ||
| 521 | |||
| 522 | *done = (a0 == 0); | ||
| 523 | |||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 489 | int vnic_dev_hang_notify(struct vnic_dev *vdev) | 527 | int vnic_dev_hang_notify(struct vnic_dev *vdev) |
| 490 | { | 528 | { |
| 491 | u64 a0, a1; | 529 | 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); | |||
| 129 | int vnic_dev_deinit(struct vnic_dev *vdev); | 129 | int vnic_dev_deinit(struct vnic_dev *vdev); |
| 130 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg); | 130 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg); |
| 131 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); | 131 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); |
| 132 | int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg); | ||
| 133 | int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done); | ||
| 132 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, | 134 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, |
| 133 | enum vnic_dev_intr_mode intr_mode); | 135 | enum vnic_dev_intr_mode intr_mode); |
| 134 | enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); | 136 | 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 { | |||
| 212 | */ | 212 | */ |
| 213 | CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38), | 213 | CMD_IAR = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 38), |
| 214 | 214 | ||
| 215 | /* initiate hangreset, like softreset after hang detected */ | ||
| 216 | CMD_HANG_RESET = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 39), | ||
| 217 | |||
| 218 | /* hangreset status: | ||
| 219 | * out: a0=0 reset complete, a0=1 reset in progress */ | ||
| 220 | CMD_HANG_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 40), | ||
| 221 | |||
| 215 | /* | 222 | /* |
| 216 | * Set hw ingress packet vlan rewrite mode: | 223 | * Set hw ingress packet vlan rewrite mode: |
| 217 | * in: (u32)a0=new vlan rewrite mode | 224 | * in: (u32)a0=new vlan rewrite mode |
