diff options
author | Rasesh Mody <rmody@brocade.com> | 2011-04-14 08:05:18 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-14 13:39:44 -0700 |
commit | 79ea6c8966b861f80e77a14b2acf581563f3c83e (patch) | |
tree | d2a556b6e833a88519faca8e064725bdfabcbe5f /drivers/net/bna/bfa_ioc_ct.c | |
parent | dd5030404695d81792a21cba575e02b21a2f275a (diff) |
bna: fix for clean fw re-initialization
During a kernel crash, bna control path state machine and firmware do not
get a notification and hence are not cleanly shutdown. The registers
holding driver/IOC state information are not reset back to valid
disabled/parking values. This causes subsequent driver initialization
to hang during kdump kernel boot. This patch, during the initialization
of first PCI function, resets corresponding register when unclean shutown
is detect by reading chip registers. This will make sure that ioc/fw
gets clean re-initialization.
Signed-off-by: Debashis Dutt <ddutt@brocade.com>
Signed-off-by: Rasesh Mody <rmody@brocade.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bna/bfa_ioc_ct.c')
-rw-r--r-- | drivers/net/bna/bfa_ioc_ct.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c index 469997c4ffd1..87aecdf22cf9 100644 --- a/drivers/net/bna/bfa_ioc_ct.c +++ b/drivers/net/bna/bfa_ioc_ct.c @@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc); static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix); static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc); +static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc); @@ -63,6 +64,7 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc) nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; + nw_hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; @@ -345,6 +347,32 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc) /** * Synchronized IOC failure processing routines */ +static bool +bfa_ioc_ct_sync_start(struct bfa_ioc *ioc) +{ + u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync); + u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); + + /* + * Driver load time. If the sync required bit for this PCI fn + * is set, it is due to an unclean exit by the driver for this + * PCI fn in the previous incarnation. Whoever comes here first + * should clean it up, no matter which PCI fn. + */ + + if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) { + writel(0, ioc->ioc_regs.ioc_fail_sync); + writel(1, ioc->ioc_regs.ioc_usage_reg); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); + return true; + } + + return bfa_ioc_ct_sync_complete(ioc); +} +/** + * Synchronized IOC failure processing routines + */ static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc) { |