fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / chelsio / espi.c
index e824aca..4192f0f 100644 (file)
@@ -81,54 +81,36 @@ static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
        return busy;
 }
 
-/* 1. Deassert rx_reset_core. */
-/* 2. Program TRICN_CNFG registers. */
-/* 3. Deassert rx_reset_link */
 static int tricn_init(adapter_t *adapter)
 {
-       int     i               = 0;
-       int     sme             = 1;
-       int     stat            = 0;
-       int     timeout         = 0;
-       int     is_ready        = 0;
-       int     dynamic_deskew  = 0;
+       int i, sme = 1;
 
-       if (dynamic_deskew)
-               sme = 0;
-
-
-       /* 1 */
-       timeout=1000;
-       do {
-               stat = readl(adapter->regs + A_ESPI_RX_RESET);
-               is_ready = (stat & 0x4);
-               timeout--;
-               udelay(5);
-       } while (!is_ready || (timeout==0));
-       writel(0x2, adapter->regs + A_ESPI_RX_RESET);
-       if (timeout==0)
-       {
-               CH_ERR("ESPI : ERROR : Timeout tricn_init() \n");
-               t1_fatal_err(adapter);
+       if (!(readl(adapter->regs + A_ESPI_RX_RESET)  & F_RX_CLK_STATUS)) {
+               CH_ERR("%s: ESPI clock not ready\n", adapter->name);
+               return -1;
        }
 
-       /* 2 */
+       writel(F_ESPI_RX_CORE_RST, adapter->regs + A_ESPI_RX_RESET);
+
        if (sme) {
                tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81);
                tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81);
                tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81);
        }
-       for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
-       for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
-       for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
-       for (i=4; i<= 4; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
-       for (i=5; i<= 5; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
-       for (i=6; i<= 6; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
-       for (i=7; i<= 7; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0x80);
-       for (i=8; i<= 8; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
-
-       /* 3 */
-       writel(0x3, adapter->regs + A_ESPI_RX_RESET);
+       for (i = 1; i <= 8; i++)
+               tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
+       for (i = 1; i <= 2; i++)
+               tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
+       for (i = 1; i <= 3; i++)
+               tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
+       tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1);
+       tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1);
+       tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1);
+       tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80);
+       tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1);
+
+       writel(F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST,
+              adapter->regs + A_ESPI_RX_RESET);
 
        return 0;
 }
@@ -151,6 +133,7 @@ void t1_espi_intr_enable(struct peespi *espi)
 
 void t1_espi_intr_clear(struct peespi *espi)
 {
+       readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
        writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS);
        writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE);
 }
@@ -165,7 +148,6 @@ void t1_espi_intr_disable(struct peespi *espi)
 
 int t1_espi_intr_handler(struct peespi *espi)
 {
-       u32 cnt;
        u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
 
        if (status & F_DIP4ERR)
@@ -185,7 +167,7 @@ int t1_espi_intr_handler(struct peespi *espi)
                 * Must read the error count to clear the interrupt
                 * that it causes.
                 */
-               cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
+               readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
        }
 
        /*
@@ -200,7 +182,7 @@ int t1_espi_intr_handler(struct peespi *espi)
 
 const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi)
 {
-    return &espi->intr_cnt;
+       return &espi->intr_cnt;
 }
 
 static void espi_setup_for_pm3393(adapter_t *adapter)
@@ -218,17 +200,45 @@ static void espi_setup_for_pm3393(adapter_t *adapter)
        writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG);
 }
 
-/* T2 Init part --  */
-/* 1. Set T_ESPI_MISCCTRL_ADDR */
-/* 2. Init ESPI registers. */
-/* 3. Init TriCN Hard Macro */
-int t1_espi_init(struct peespi *espi, int mac_type, int nports)
+static void espi_setup_for_vsc7321(adapter_t *adapter)
 {
-       u32 cnt;
+        writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+        writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+        writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+       writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
+       writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
+       writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
+       writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter->regs + A_PORT_CONFIG);
 
+       writel(0x08000008, adapter->regs + A_ESPI_TRAIN);
+}
+
+/*
+ * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug.
+ */
+static void espi_setup_for_ixf1010(adapter_t *adapter, int nports)
+{
+       writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
+       if (nports == 4) {
+               if (is_T2(adapter)) {
+                       writel(0xf00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
+                       writel(0x3c0, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
+               } else {
+                       writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
+                       writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
+               }
+       } else {
+               writel(0x1fff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
+               writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
+       }
+       writel(V_RX_NPORTS(nports) | V_TX_NPORTS(nports), adapter->regs + A_PORT_CONFIG);
+
+}
+
+int t1_espi_init(struct peespi *espi, int mac_type, int nports)
+{
        u32 status_enable_extra = 0;
        adapter_t *adapter = espi->adapter;
-       u32 status, burstval = 0x800100;
 
        /* Disable ESPI training.  MACs that can handle it enable it below. */
        writel(0, adapter->regs + A_ESPI_TRAIN);
@@ -237,38 +247,20 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports)
                writel(V_OUT_OF_SYNC_COUNT(4) |
                       V_DIP2_PARITY_ERR_THRES(3) |
                       V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
-               if (nports == 4) {
-                       /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */
-                       burstval = 0x200040;
-               }
-       }
-       writel(burstval, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+               writel(nports == 4 ? 0x200040 : 0x1000080,
+                      adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+       } else
+               writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
 
-       switch (mac_type) {
-       case CHBT_MAC_PM3393:
+       if (mac_type == CHBT_MAC_PM3393)
                espi_setup_for_pm3393(adapter);
-               break;
-       default:
+       else if (mac_type == CHBT_MAC_VSC7321)
+               espi_setup_for_vsc7321(adapter);
+       else if (mac_type == CHBT_MAC_IXF1010) {
+               status_enable_extra = F_INTEL1010MODE;
+               espi_setup_for_ixf1010(adapter, nports);
+       } else
                return -1;
-       }
-
-       /*
-        * Make sure any pending interrupts from the SPI are
-        * Cleared before enabling the interrupt.
-        */
-       writel(ESPI_INTR_MASK, espi->adapter->regs + A_ESPI_INTR_ENABLE);
-       status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
-       if (status & F_DIP2PARITYERR) {
-               cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
-       }
-
-       /*
-        * For T1B we need to write 1 to clear ESPI interrupts.  For T2+ we
-        * write the status as is.
-        */
-       if (status && t1_is_T1B(espi->adapter))
-               status = 1;
-       writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS);
 
        writel(status_enable_extra | F_RXSTATUSENABLE,
               adapter->regs + A_ESPI_FIFO_STATUS_ENABLE);
@@ -279,9 +271,11 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports)
                 * Always position the control at the 1st port egress IN
                 * (sop,eop) counter to reduce PIOs for T/N210 workaround.
                 */
-               espi->misc_ctrl = (readl(adapter->regs + A_ESPI_MISC_CONTROL)
-                                  & ~MON_MASK) | (F_MONITORED_DIRECTION
-                                  | F_MONITORED_INTERFACE);
+               espi->misc_ctrl = readl(adapter->regs + A_ESPI_MISC_CONTROL);
+               espi->misc_ctrl &= ~MON_MASK;
+               espi->misc_ctrl |= F_MONITORED_DIRECTION;
+               if (adapter->params.nports == 1)
+                       espi->misc_ctrl |= F_MONITORED_INTERFACE;
                writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
                spin_lock_init(&espi->lock);
        }
@@ -307,8 +301,7 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
 {
        struct peespi *espi = adapter->espi;
 
-       if (!is_T2(adapter))
-               return;
+       if (!is_T2(adapter)) return;
        spin_lock(&espi->lock);
        espi->misc_ctrl = (val & ~MON_MASK) |
                          (espi->misc_ctrl & MON_MASK);
@@ -318,27 +311,61 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
 
 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
 {
-       u32 sel;
-
        struct peespi *espi = adapter->espi;
+       u32 sel;
 
        if (!is_T2(adapter))
                return 0;
+
        sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2);
        if (!wait) {
                if (!spin_trylock(&espi->lock))
                        return 0;
-       }
-       else
+       } else
                spin_lock(&espi->lock);
+
        if ((sel != (espi->misc_ctrl & MON_MASK))) {
                writel(((espi->misc_ctrl & ~MON_MASK) | sel),
                       adapter->regs + A_ESPI_MISC_CONTROL);
                sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
                writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
-       }
-       else
+       } else
                sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
        spin_unlock(&espi->lock);
        return sel;
 }
+
+/*
+ * This function is for T204 only.
+ * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
+ * one shot, since there is no per port counter on the out side.
+ */
+int
+t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
+{
+        struct peespi *espi = adapter->espi;
+       u8 i, nport = (u8)adapter->params.nports;
+
+        if (!wait) {
+                if (!spin_trylock(&espi->lock))
+                        return -1;
+        } else
+                spin_lock(&espi->lock);
+
+       if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
+               espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
+                                       F_MONITORED_DIRECTION;
+                writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+       }
+       for (i = 0 ; i < nport; i++, valp++) {
+               if (i) {
+                       writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
+                              adapter->regs + A_ESPI_MISC_CONTROL);
+               }
+                *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+        }
+
+        writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+        spin_unlock(&espi->lock);
+        return 0;
+}