summary refs log tree commit diff
path: root/drivers/net/chelsio/espi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/chelsio/espi.c')
-rw-r--r--drivers/net/chelsio/espi.c205
1 files changed, 120 insertions, 85 deletions
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index 542e5e065c6f..4192f0f5b3ee 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -81,46 +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     stat            = 0;
-	int     timeout         = 0;
-	int     is_ready        = 0;
+	int i, sme = 1;
 
-	/* 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 */
-	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);
+	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);
+	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;
 }
@@ -143,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);
 }
@@ -157,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)
@@ -177,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);
 	}
 
 	/*
@@ -192,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)
@@ -210,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)
+{
+        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)
 {
-	u32 cnt;
+	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);
@@ -229,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);
@@ -271,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);
 	}
@@ -299,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);
@@ -310,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;
+}