]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/bna/bfa_ioc_ct.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / net / bna / bfa_ioc_ct.c
index 121cfd6d48b1eb7fe8a5f15223e4f4b3d40cea76..469997c4ffd196a4609c58daf83c6112d4fc4995 100644 (file)
 #include "bfi_ctreg.h"
 #include "bfa_defs.h"
 
+#define bfa_ioc_ct_sync_pos(__ioc)     \
+               ((u32) (1 << bfa_ioc_pcifn(__ioc)))
+#define BFA_IOC_SYNC_REQD_SH           16
+#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff)
+#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000)
+#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH)
+#define bfa_ioc_ct_sync_reqd_pos(__ioc) \
+               (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH)
+
 /*
  * forward declarations
  */
@@ -30,8 +39,12 @@ static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_reg_init(struct bfa_ioc *ioc);
 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_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc);
 static void bfa_ioc_ct_ownership_reset(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);
+static bool bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc);
 static enum bfa_status bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode);
 
 static struct bfa_ioc_hwif nw_hwif_ct;
@@ -48,8 +61,12 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc)
        nw_hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
        nw_hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
        nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
-       nw_hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+       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_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;
+       nw_hwif_ct.ioc_sync_complete = bfa_ioc_ct_sync_complete;
 
        ioc->ioc_hwif = &nw_hwif_ct;
 }
@@ -86,6 +103,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc)
        if (usecnt == 0) {
                writel(1, ioc->ioc_regs.ioc_usage_reg);
                bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+               writel(0, ioc->ioc_regs.ioc_fail_sync);
                return true;
        }
 
@@ -149,12 +167,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc)
  * Notify other functions on HB failure.
  */
 static void
-bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc)
+bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc)
 {
        if (ioc->cna) {
                writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+               writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt);
                /* Wait for halt to take effect */
                readl(ioc->ioc_regs.ll_halt);
+               readl(ioc->ioc_regs.alt_ll_halt);
        } else {
                writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
                readl(ioc->ioc_regs.err_set);
@@ -206,15 +226,19 @@ bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
        if (ioc->port_id == 0) {
                ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
                ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+               ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG;
                ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
                ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
                ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+               ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1;
        } else {
                ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
                ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+               ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG;
                ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
                ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
                ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+               ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0;
        }
 
        /*
@@ -232,6 +256,7 @@ bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
        ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
        ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
        ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+       ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC);
 
        /**
         * sram memory access
@@ -317,6 +342,77 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
        bfa_nw_ioc_hw_sem_release(ioc);
 }
 
+/**
+ * Synchronized IOC failure processing routines
+ */
+static void
+bfa_ioc_ct_sync_join(struct bfa_ioc *ioc)
+{
+       u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+       u32 sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc);
+
+       writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc)
+{
+       u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+       u32 sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) |
+                                       bfa_ioc_ct_sync_pos(ioc);
+
+       writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static void
+bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc)
+{
+       u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+
+       writel((r32 | bfa_ioc_ct_sync_pos(ioc)), ioc->ioc_regs.ioc_fail_sync);
+}
+
+static bool
+bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc)
+{
+       u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync);
+       u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32);
+       u32 sync_ackd = bfa_ioc_ct_get_sync_ackd(r32);
+       u32 tmp_ackd;
+
+       if (sync_ackd == 0)
+               return true;
+
+       /**
+        * The check below is to see whether any other PCI fn
+        * has reinitialized the ASIC (reset sync_ackd bits)
+        * and failed again while this IOC was waiting for hw
+        * semaphore (in bfa_iocpf_sm_semwait()).
+        */
+       tmp_ackd = sync_ackd;
+       if ((sync_reqd &  bfa_ioc_ct_sync_pos(ioc)) &&
+                       !(sync_ackd & bfa_ioc_ct_sync_pos(ioc)))
+               sync_ackd |= bfa_ioc_ct_sync_pos(ioc);
+
+       if (sync_reqd == sync_ackd) {
+               writel(bfa_ioc_ct_clear_sync_ackd(r32),
+                               ioc->ioc_regs.ioc_fail_sync);
+               writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+               writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate);
+               return true;
+       }
+
+       /**
+        * If another PCI fn reinitialized and failed again while
+        * this IOC was waiting for hw sem, the sync_ackd bit for
+        * this IOC need to be set again to allow reinitialization.
+        */
+       if (tmp_ackd != sync_ackd)
+               writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync);
+
+       return false;
+}
+
 static enum bfa_status
 bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode)
 {