[PATCH] chelsio: add support for other 10G boards

Add support for other versions of the 10G Chelsio boards.
This is basically a port of the vendor driver with the
TOE features removed.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index e4473ec..d41d15a 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -43,6 +43,7 @@
 #include "gmac.h"
 #include "cphy.h"
 #include "sge.h"
+#include "tp.h"
 #include "espi.h"
 
 /**
@@ -59,7 +60,7 @@
  *	otherwise.
  */
 static int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity,
-		    int attempts, int delay)
+			   int attempts, int delay)
 {
 	while (1) {
 		u32 val = readl(adapter->regs + reg) & mask;
@@ -78,7 +79,7 @@
 /*
  * Write a register over the TPI interface (unlocked and locked versions).
  */
-static int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
+int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
 {
 	int tpi_busy;
 
@@ -98,16 +99,16 @@
 {
 	int ret;
 
-	spin_lock(&(adapter)->tpi_lock);
+	spin_lock(&adapter->tpi_lock);
 	ret = __t1_tpi_write(adapter, addr, value);
-	spin_unlock(&(adapter)->tpi_lock);
+	spin_unlock(&adapter->tpi_lock);
 	return ret;
 }
 
 /*
  * Read a register over the TPI interface (unlocked and locked versions).
  */
-static int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
+int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
 {
 	int tpi_busy;
 
@@ -128,18 +129,26 @@
 {
 	int ret;
 
-	spin_lock(&(adapter)->tpi_lock);
+	spin_lock(&adapter->tpi_lock);
 	ret = __t1_tpi_read(adapter, addr, valp);
-	spin_unlock(&(adapter)->tpi_lock);
+	spin_unlock(&adapter->tpi_lock);
 	return ret;
 }
 
 /*
+ * Set a TPI parameter.
+ */
+static void t1_tpi_par(adapter_t *adapter, u32 value)
+{
+	writel(V_TPIPAR(value), adapter->regs + A_TPI_PAR);
+}
+
+/*
  * Called when a port's link settings change to propagate the new values to the
  * associated PHY and MAC.  After performing the common tasks it invokes an
  * OS-specific handler.
  */
-/* static */ void link_changed(adapter_t *adapter, int port_id)
+void t1_link_changed(adapter_t *adapter, int port_id)
 {
 	int link_ok, speed, duplex, fc;
 	struct cphy *phy = adapter->port[port_id].phy;
@@ -159,7 +168,7 @@
 		mac->ops->set_speed_duplex_fc(mac, speed, duplex, fc);
 		lc->fc = (unsigned char)fc;
 	}
-	t1_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+	t1_link_negotiated(adapter, port_id, link_ok, speed, duplex, fc);
 }
 
 static int t1_pci_intr_handler(adapter_t *adapter)
@@ -217,7 +226,7 @@
 {
 	u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
 
-	spin_lock(&(adapter)->tpi_lock);
+	spin_lock(&adapter->tpi_lock);
 
 	/* Write the address we want. */
 	__t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
@@ -227,12 +236,13 @@
 	mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
 
 	/* Write the operation we want. */
-	__t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_READ);
+	__t1_tpi_write(adapter,
+			A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_READ);
 	mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
 
 	/* Read the data. */
 	__t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
-	spin_unlock(&(adapter)->tpi_lock);
+	spin_unlock(&adapter->tpi_lock);
 	return 0;
 }
 
@@ -241,7 +251,7 @@
 {
 	u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
 
-	spin_lock(&(adapter)->tpi_lock);
+	spin_lock(&adapter->tpi_lock);
 
 	/* Write the address we want. */
 	__t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
@@ -254,7 +264,7 @@
 	__t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);
 	__t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_WRITE);
 	mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
-	spin_unlock(&(adapter)->tpi_lock);
+	spin_unlock(&adapter->tpi_lock);
 	return 0;
 }
 
@@ -265,12 +275,25 @@
 };
 
 enum {
+	CH_BRD_T110_1CU,
 	CH_BRD_N110_1F,
 	CH_BRD_N210_1F,
+	CH_BRD_T210_1F,
+	CH_BRD_T210_1CU,
+	CH_BRD_N204_4CU,
 };
 
 static struct board_info t1_board[] = {
 
+{ CHBT_BOARD_CHT110, 1/*ports#*/,
+  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1,
+  CHBT_MAC_PM3393, CHBT_PHY_MY3126,
+  125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
+  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
+  1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
+  &t1_my3126_ops, &mi1_mdio_ext_ops,
+  "Chelsio T110 1x10GBase-CX4 TOE" },
+
 { CHBT_BOARD_N110, 1/*ports#*/,
   SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
   CHBT_MAC_PM3393, CHBT_PHY_88X2010,
@@ -289,12 +312,36 @@
   &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
   "Chelsio N210 1x10GBaseX NIC" },
 
+{ CHBT_BOARD_CHT210, 1/*ports#*/,
+  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
+  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
+  125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
+  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
+  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
+  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
+  "Chelsio T210 1x10GBaseX TOE" },
+
+{ CHBT_BOARD_CHT210, 1/*ports#*/,
+  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
+  CHBT_MAC_PM3393, CHBT_PHY_MY3126,
+  125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
+  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
+  1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
+  &t1_my3126_ops, &mi1_mdio_ext_ops,
+  "Chelsio T210 1x10GBase-CX4 TOE" },
+
+
 };
 
 struct pci_device_id t1_pci_tbl[] = {
+	CH_DEVICE(8, 0, CH_BRD_T110_1CU),
+	CH_DEVICE(8, 1, CH_BRD_T110_1CU),
 	CH_DEVICE(7, 0, CH_BRD_N110_1F),
 	CH_DEVICE(10, 1, CH_BRD_N210_1F),
-	{ 0, }
+	CH_DEVICE(11, 1, CH_BRD_T210_1F),
+	CH_DEVICE(14, 1, CH_BRD_T210_1CU),
+	CH_DEVICE(16, 1, CH_BRD_N204_4CU),
+	{ 0 }
 };
 
 MODULE_DEVICE_TABLE(pci, t1_pci_tbl);
@@ -390,9 +437,14 @@
 	if (lc->supported & SUPPORTED_Autoneg) {
 		lc->advertising &= ~(ADVERTISED_ASYM_PAUSE | ADVERTISED_PAUSE);
 		if (fc) {
-			lc->advertising |= ADVERTISED_ASYM_PAUSE;
-			if (fc == (PAUSE_RX | PAUSE_TX))
+			if (fc == ((PAUSE_RX | PAUSE_TX) &
+				   (mac->adapter->params.nports < 2)))
 				lc->advertising |= ADVERTISED_PAUSE;
+			else {
+				lc->advertising |= ADVERTISED_ASYM_PAUSE;
+				if (fc == PAUSE_RX)
+					lc->advertising |= ADVERTISED_PAUSE;
+			}
 		}
 		phy->ops->advertise(phy, lc->advertising);
 
@@ -403,11 +455,15 @@
 			mac->ops->set_speed_duplex_fc(mac, lc->speed,
 						      lc->duplex, fc);
 			/* Also disables autoneg */
+			phy->state = PHY_AUTONEG_RDY;
 			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
 			phy->ops->reset(phy, 0);
-		} else
+		} else {
+			phy->state = PHY_AUTONEG_EN;
 			phy->ops->autoneg_enable(phy); /* also resets PHY */
+		}
 	} else {
+		phy->state = PHY_AUTONEG_RDY;
 		mac->ops->set_speed_duplex_fc(mac, -1, -1, fc);
 		lc->fc = (unsigned char)fc;
 		phy->ops->reset(phy, 0);
@@ -418,7 +474,7 @@
 /*
  * External interrupt handler for boards using elmer0.
  */
-int elmer0_ext_intr_handler(adapter_t *adapter)
+int t1_elmer0_ext_intr_handler(adapter_t *adapter)
 {
 	struct cphy *phy;
 	int phy_cause;
@@ -427,15 +483,34 @@
 	t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause);
 
 	switch (board_info(adapter)->board) {
+	case CHBT_BOARD_CHT210:
 	case CHBT_BOARD_N210:
 	case CHBT_BOARD_N110:
 		if (cause & ELMER0_GP_BIT6) { /* Marvell 88x2010 interrupt */
 			phy = adapter->port[0].phy;
 			phy_cause = phy->ops->interrupt_handler(phy);
 			if (phy_cause & cphy_cause_link_change)
-				link_changed(adapter, 0);
+				t1_link_changed(adapter, 0);
 		}
 		break;
+	case CHBT_BOARD_8000:
+	case CHBT_BOARD_CHT110:
+    		CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
+		       cause);
+		if (cause & ELMER0_GP_BIT1) {        /* PMC3393 INTB */
+			struct cmac *mac = adapter->port[0].mac;
+
+			mac->ops->interrupt_handler(mac);
+		}
+		if (cause & ELMER0_GP_BIT5) {        /* XPAK MOD_DETECT */
+			u32 mod_detect;
+
+			t1_tpi_read(adapter,
+					A_ELMER0_GPI_STAT, &mod_detect);
+	    		CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
+			       mod_detect ? "removed" : "inserted");
+    		}
+		break;
 	}
 	t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
 	return 0;
@@ -445,11 +520,11 @@
 void t1_interrupts_enable(adapter_t *adapter)
 {
 	unsigned int i;
-	u32 pl_intr;
 
-	adapter->slow_intr_mask = F_PL_INTR_SGE_ERR;
+	adapter->slow_intr_mask = F_PL_INTR_SGE_ERR | F_PL_INTR_TP;
 
 	t1_sge_intr_enable(adapter->sge);
+	t1_tp_intr_enable(adapter->tp);
 	if (adapter->espi) {
 		adapter->slow_intr_mask |= F_PL_INTR_ESPI;
 		t1_espi_intr_enable(adapter->espi);
@@ -462,15 +537,17 @@
 	}
 
 	/* Enable PCIX & external chip interrupts on ASIC boards. */
-	pl_intr = readl(adapter->regs + A_PL_ENABLE);
+	if (t1_is_asic(adapter)) {
+		u32 pl_intr = readl(adapter->regs + A_PL_ENABLE);
 
-	/* PCI-X interrupts */
-	pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE,
-			       0xffffffff);
+		/* PCI-X interrupts */
+		pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE,
+				       0xffffffff);
 
-	adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
-	pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
-	writel(pl_intr, adapter->regs + A_PL_ENABLE);
+		adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
+		pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
+		writel(pl_intr, adapter->regs + A_PL_ENABLE);
+	}
 }
 
 /* Disables all interrupts. */
@@ -479,6 +556,7 @@
 	unsigned int i;
 
 	t1_sge_intr_disable(adapter->sge);
+	t1_tp_intr_disable(adapter->tp);
 	if (adapter->espi)
 		t1_espi_intr_disable(adapter->espi);
 
@@ -489,7 +567,8 @@
 	}
 
 	/* Disable PCIX & external chip interrupts. */
-	writel(0, adapter->regs + A_PL_ENABLE);
+	if (t1_is_asic(adapter))
+	    	writel(0, adapter->regs + A_PL_ENABLE);
 
 	/* PCI-X interrupts */
 	pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -501,10 +580,9 @@
 void t1_interrupts_clear(adapter_t* adapter)
 {
 	unsigned int i;
-	u32 pl_intr;
-
 
 	t1_sge_intr_clear(adapter->sge);
+	t1_tp_intr_clear(adapter->tp);
 	if (adapter->espi)
 		t1_espi_intr_clear(adapter->espi);
 
@@ -515,10 +593,12 @@
 	}
 
 	/* Enable interrupts for external devices. */
-	pl_intr = readl(adapter->regs + A_PL_CAUSE);
+	if (t1_is_asic(adapter)) {
+		u32 pl_intr = readl(adapter->regs + A_PL_CAUSE);
 
-	writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX,
-	       adapter->regs + A_PL_CAUSE);
+		writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX,
+		       adapter->regs + A_PL_CAUSE);
+	}
 
 	/* PCI-X interrupts */
 	pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, 0xffffffff);
@@ -527,7 +607,7 @@
 /*
  * Slow path interrupt handler for ASICs.
  */
-int t1_slow_intr_handler(adapter_t *adapter)
+static int asic_slow_intr(adapter_t *adapter)
 {
 	u32 cause = readl(adapter->regs + A_PL_CAUSE);
 
@@ -536,89 +616,50 @@
 		return 0;
 	if (cause & F_PL_INTR_SGE_ERR)
 		t1_sge_intr_error_handler(adapter->sge);
+	if (cause & F_PL_INTR_TP)
+		t1_tp_intr_handler(adapter->tp);
 	if (cause & F_PL_INTR_ESPI)
 		t1_espi_intr_handler(adapter->espi);
 	if (cause & F_PL_INTR_PCIX)
 		t1_pci_intr_handler(adapter);
 	if (cause & F_PL_INTR_EXT)
-		t1_elmer0_ext_intr(adapter);
+		t1_elmer0_ext_intr_handler(adapter);
 
 	/* Clear the interrupts just processed. */
 	writel(cause, adapter->regs + A_PL_CAUSE);
-	(void)readl(adapter->regs + A_PL_CAUSE); /* flush writes */
+	readl(adapter->regs + A_PL_CAUSE); /* flush writes */
 	return 1;
 }
 
-/* Pause deadlock avoidance parameters */
-#define DROP_MSEC 16
-#define DROP_PKTS_CNT  1
-
-static void set_csum_offload(adapter_t *adapter, u32 csum_bit, int enable)
+int t1_slow_intr_handler(adapter_t *adapter)
 {
-	u32 val = readl(adapter->regs + A_TP_GLOBAL_CONFIG);
-
-	if (enable)
-		val |= csum_bit;
-	else
-		val &= ~csum_bit;
-	writel(val, adapter->regs + A_TP_GLOBAL_CONFIG);
+	return asic_slow_intr(adapter);
 }
 
-void t1_tp_set_ip_checksum_offload(adapter_t *adapter, int enable)
+/* Power sequencing is a work-around for Intel's XPAKs. */
+static void power_sequence_xpak(adapter_t* adapter)
 {
-	set_csum_offload(adapter, F_IP_CSUM, enable);
-}
+    	u32 mod_detect;
+    	u32 gpo;
 
-void t1_tp_set_udp_checksum_offload(adapter_t *adapter, int enable)
-{
-	set_csum_offload(adapter, F_UDP_CSUM, enable);
-}
-
-void t1_tp_set_tcp_checksum_offload(adapter_t *adapter, int enable)
-{
-	set_csum_offload(adapter, F_TCP_CSUM, enable);
-}
-
-static void t1_tp_reset(adapter_t *adapter, unsigned int tp_clk)
-{
-	u32 val;
-
-	val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
-	      F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
-	val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
-	       F_TP_IN_ESPI_CHECK_TCP_CSUM;
-	writel(val, adapter->regs + A_TP_IN_CONFIG);
-	writel(F_TP_OUT_CSPI_CPL |
-	       F_TP_OUT_ESPI_ETHERNET |
-	       F_TP_OUT_ESPI_GENERATE_IP_CSUM |
-	       F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
-	       adapter->regs + A_TP_OUT_CONFIG);
-
-	val = readl(adapter->regs + A_TP_GLOBAL_CONFIG);
-	val &= ~(F_IP_CSUM | F_UDP_CSUM | F_TCP_CSUM);
-	writel(val, adapter->regs + A_TP_GLOBAL_CONFIG);
-
-	/*
-	 * Enable pause frame deadlock prevention.
-	 */
-	if (is_T2(adapter)) {
-		u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
-
-		writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
-		       V_DROP_TICKS_CNT(drop_ticks) |
-		       V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
-		       adapter->regs + A_TP_TX_DROP_CONFIG);
+    	/* Check for XPAK */
+    	t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+	if (!(ELMER0_GP_BIT5 & mod_detect)) {
+		/* XPAK is present */
+		t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
+		gpo |= ELMER0_GP_BIT18;
+		t1_tpi_write(adapter, A_ELMER0_GPO, gpo);
 	}
-
-	writel(F_TP_RESET, adapter->regs + A_TP_RESET);
 }
 
 int __devinit t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
 			       struct adapter_params *p)
 {
 	p->chip_version = bi->chip_term;
+	p->is_asic = (p->chip_version != CHBT_TERM_FPGA);
 	if (p->chip_version == CHBT_TERM_T1 ||
-	    p->chip_version == CHBT_TERM_T2) {
+	    p->chip_version == CHBT_TERM_T2 ||
+	    p->chip_version == CHBT_TERM_FPGA) {
 		u32 val = readl(adapter->regs + A_TP_PC_CONFIG);
 
 		val = G_TP_PC_REV(val);
@@ -640,10 +681,22 @@
 static int board_init(adapter_t *adapter, const struct board_info *bi)
 {
 	switch (bi->board) {
+	case CHBT_BOARD_8000:
 	case CHBT_BOARD_N110:
 	case CHBT_BOARD_N210:
-		writel(V_TPIPAR(0xf), adapter->regs + A_TPI_PAR);
-		t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+	case CHBT_BOARD_CHT210:
+	case CHBT_BOARD_COUGAR:
+    		t1_tpi_par(adapter, 0xf);
+    		t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+		break;
+	case CHBT_BOARD_CHT110:
+    		t1_tpi_par(adapter, 0xf);
+    		t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
+
+    		/* TBD XXX Might not need.  This fixes a problem
+     		 *         described in the Intel SR XPAK errata.
+     		 */
+    		power_sequence_xpak(adapter);
 		break;
 	}
 	return 0;
@@ -670,7 +723,8 @@
 					  bi->espi_nports))
 		goto out_err;
 
-	t1_tp_reset(adapter, bi->clock_core);
+	if (t1_tp_reset(adapter->tp, &adapter->params.tp, bi->clock_core))
+		goto out_err;
 
 	err = t1_sge_configure(adapter->sge, &adapter->params.sge);
 	if (err)
@@ -714,6 +768,8 @@
 
 	if (adapter->sge)
 		t1_sge_destroy(adapter->sge);
+	if (adapter->tp)
+		t1_tp_destroy(adapter->tp);
 	if (adapter->espi)
 		t1_espi_destroy(adapter->espi);
 }
@@ -762,6 +818,13 @@
 		goto error;
 	}
 
+	adapter->tp = t1_tp_create(adapter, &adapter->params.tp);
+	if (!adapter->tp) {
+		CH_ERR("%s: TP initialization failed\n",
+		       adapter->name);
+		goto error;
+	}
+
 	board_init(adapter, bi);
 	bi->mdio_ops->init(adapter, bi);
 	if (bi->gphy->reset)
@@ -793,7 +856,9 @@
 		 * Get the port's MAC addresses either from the EEPROM if one
 		 * exists or the one hardcoded in the MAC.
 		 */
-		if (vpd_macaddress_get(adapter, i, hw_addr)) {
+		if (!t1_is_asic(adapter) || bi->chip_mac == CHBT_MAC_DUMMY)
+			mac->ops->macaddress_get(mac, hw_addr);
+		else if (vpd_macaddress_get(adapter, i, hw_addr)) {
 			CH_ERR("%s: could not read MAC address from VPD ROM\n",
 			       adapter->port[i].dev->name);
 			goto error;
@@ -806,7 +871,7 @@
 	t1_interrupts_clear(adapter);
 	return 0;
 
- error:
+error:
 	t1_free_sw_modules(adapter);
 	return -1;
 }