]> err.no Git - linux-2.6/blobdiff - drivers/net/chelsio/subr.c
annotate chelsio
[linux-2.6] / drivers / net / chelsio / subr.c
index a90a3f95fcac452eb5a1aae7e5cab28d22712540..7adf30230c4f7123d03d91e2f9c500f26d4a49f8 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
  *                                                                           *
  * File: subr.c                                                              *
- * $Revision: 1.12 $                                                         *
- * $Date: 2005/03/23 07:41:27 $                                              *
+ * $Revision: 1.27 $                                                         *
+ * $Date: 2005/06/22 01:08:36 $                                              *
  * Description:                                                              *
  *  Various subroutines (intr,pio,etc.) used by Chelsio 10G Ethernet driver. *
  *  part of the Chelsio 10Gb Ethernet Driver.                                *
@@ -40,7 +40,6 @@
 #include "common.h"
 #include "elmer0.h"
 #include "regs.h"
-
 #include "gmac.h"
 #include "cphy.h"
 #include "sge.h"
  *     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 = t1_read_reg_4(adapter, reg) & mask;
+               u32 val = readl(adapter->regs + reg) & mask;
 
                if (!!val == polarity)
                        return 0;
@@ -80,13 +79,13 @@ static int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity,
 /*
  * 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;
 
-       t1_write_reg_4(adapter, A_TPI_ADDR, addr);
-       t1_write_reg_4(adapter, A_TPI_WR_DATA, value);
-       t1_write_reg_4(adapter, A_TPI_CSR, F_TPIWR);
+       writel(addr, adapter->regs + A_TPI_ADDR);
+       writel(value, adapter->regs + A_TPI_WR_DATA);
+       writel(F_TPIWR, adapter->regs + A_TPI_CSR);
 
        tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
                                   TPI_ATTEMPTS, 3);
@@ -100,21 +99,21 @@ int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)
 {
        int ret;
 
-       TPI_LOCK(adapter);
+       spin_lock(&adapter->tpi_lock);
        ret = __t1_tpi_write(adapter, addr, value);
-       TPI_UNLOCK(adapter);
+       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;
 
-       t1_write_reg_4(adapter, A_TPI_ADDR, addr);
-       t1_write_reg_4(adapter, A_TPI_CSR, 0);
+       writel(addr, adapter->regs + A_TPI_ADDR);
+       writel(0, adapter->regs + A_TPI_CSR);
 
        tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,
                                   TPI_ATTEMPTS, 3);
@@ -122,7 +121,7 @@ static int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
                CH_ALERT("%s: TPI read from 0x%x failed\n",
                         adapter->name, addr);
        else
-               *valp = t1_read_reg_4(adapter, A_TPI_RD_DATA);
+               *valp = readl(adapter->regs + A_TPI_RD_DATA);
        return tpi_busy;
 }
 
@@ -130,9 +129,9 @@ int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
 {
        int ret;
 
-       TPI_LOCK(adapter);
+       spin_lock(&adapter->tpi_lock);
        ret = __t1_tpi_read(adapter, addr, valp);
-       TPI_UNLOCK(adapter);
+       spin_unlock(&adapter->tpi_lock);
        return ret;
 }
 
@@ -141,7 +140,7 @@ int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)
  */
 static void t1_tpi_par(adapter_t *adapter, u32 value)
 {
-       t1_write_reg_4(adapter, A_TPI_PAR, V_TPIPAR(value));
+       writel(V_TPIPAR(value), adapter->regs + A_TPI_PAR);
 }
 
 /*
@@ -149,7 +148,7 @@ static void t1_tpi_par(adapter_t *adapter, u32 value)
  * 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;
@@ -169,23 +168,83 @@ static void t1_tpi_par(adapter_t *adapter, u32 value)
                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)
 {
        u32 pcix_cause;
 
-       pci_read_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, &pcix_cause);
+       pci_read_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, &pcix_cause);
 
        if (pcix_cause) {
                pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE,
-                                        pcix_cause);
+                                      pcix_cause);
                t1_fatal_err(adapter);    /* PCI errors are fatal */
        }
        return 0;
 }
 
+#ifdef CONFIG_CHELSIO_T1_COUGAR
+#include "cspi.h"
+#endif
+#ifdef CONFIG_CHELSIO_T1_1G
+#include "fpga_defs.h"
+
+/*
+ * PHY interrupt handler for FPGA boards.
+ */
+static int fpga_phy_intr_handler(adapter_t *adapter)
+{
+       int p;
+       u32 cause = readl(adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
+
+       for_each_port(adapter, p)
+               if (cause & (1 << p)) {
+                       struct cphy *phy = adapter->port[p].phy;
+                       int phy_cause = phy->ops->interrupt_handler(phy);
+
+                       if (phy_cause & cphy_cause_link_change)
+                               t1_link_changed(adapter, p);
+               }
+       writel(cause, adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
+       return 0;
+}
+
+/*
+ * Slow path interrupt handler for FPGAs.
+ */
+static int fpga_slow_intr(adapter_t *adapter)
+{
+       u32 cause = readl(adapter->regs + A_PL_CAUSE);
+
+       cause &= ~F_PL_INTR_SGE_DATA;
+       if (cause & F_PL_INTR_SGE_ERR)
+               t1_sge_intr_error_handler(adapter->sge);
+
+       if (cause & FPGA_PCIX_INTERRUPT_GMAC)
+               fpga_phy_intr_handler(adapter);
+
+       if (cause & FPGA_PCIX_INTERRUPT_TP) {
+               /*
+                * FPGA doesn't support MC4 interrupts and it requires
+                * this odd layer of indirection for MC5.
+                */
+               u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
+
+               /* Clear TP interrupt */
+               writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
+       }
+       if (cause & FPGA_PCIX_INTERRUPT_PCIX)
+               t1_pci_intr_handler(adapter);
+
+       /* Clear the interrupts just processed. */
+       if (cause)
+               writel(cause, adapter->regs + A_PL_CAUSE);
+
+       return cause != 0;
+}
+#endif
 
 /*
  * Wait until Elmer's MI1 interface is ready for new operations.
@@ -203,8 +262,7 @@ static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
                        udelay(10);
        } while (busy && --attempts);
        if (busy)
-               CH_ALERT("%s: MDIO operation timed out\n",
-                        adapter->name);
+               CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
        return busy;
 }
 
@@ -222,12 +280,62 @@ static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)
        t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
 }
 
+#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+/*
+ * Elmer MI1 MDIO read/write operations.
+ */
+static int mi1_mdio_read(adapter_t *adapter, int phy_addr, int mmd_addr,
+                        int reg_addr, unsigned int *valp)
+{
+       u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);
+
+       if (mmd_addr)
+               return -EINVAL;
+
+       spin_lock(&adapter->tpi_lock);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
+       __t1_tpi_write(adapter,
+                       A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ);
+       mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
+       __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, valp);
+       spin_unlock(&adapter->tpi_lock);
+       return 0;
+}
+
+static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
+                         int reg_addr, unsigned int val)
+{
+       u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);
+
+       if (mmd_addr)
+               return -EINVAL;
+
+       spin_lock(&adapter->tpi_lock);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
+       __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);
+       __t1_tpi_write(adapter,
+                       A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_WRITE);
+       mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);
+       spin_unlock(&adapter->tpi_lock);
+       return 0;
+}
+
+#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+static const struct mdio_ops mi1_mdio_ops = {
+       .init = mi1_mdio_init,
+       .read = mi1_mdio_read,
+       .write = mi1_mdio_write
+};
+#endif
+
+#endif
+
 static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
                             int reg_addr, unsigned int *valp)
 {
        u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
 
-       TPI_LOCK(adapter);
+       spin_lock(&adapter->tpi_lock);
 
        /* Write the address we want. */
        __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
@@ -237,12 +345,13 @@ static int mi1_mdio_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
        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);
-       TPI_UNLOCK(adapter);
+       spin_unlock(&adapter->tpi_lock);
        return 0;
 }
 
@@ -251,7 +360,7 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
 {
        u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);
 
-       TPI_LOCK(adapter);
+       spin_lock(&adapter->tpi_lock);
 
        /* Write the address we want. */
        __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);
@@ -264,57 +373,179 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
        __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);
-       TPI_UNLOCK(adapter);
+       spin_unlock(&adapter->tpi_lock);
        return 0;
 }
 
-static struct mdio_ops mi1_mdio_ext_ops = {
-       mi1_mdio_init,
-       mi1_mdio_ext_read,
-       mi1_mdio_ext_write
+static const struct mdio_ops mi1_mdio_ext_ops = {
+       .init = mi1_mdio_init,
+       .read = mi1_mdio_ext_read,
+       .write = mi1_mdio_ext_write
 };
 
 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_N110, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*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 N110 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_N210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*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 N210 1x10GBaseX NIC" },
+static const struct board_info t1_board[] = {
+       {
+               .board          = CHBT_BOARD_CHT110,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full,
+               .chip_term      = CHBT_TERM_T1,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_MY3126,
+               .clock_core     = 125000000,
+               .clock_mc3      = 150000000,
+               .clock_mc4      = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 1,
+               .mdio_mdiinv    = 1,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 1,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_my3126_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio T110 1x10GBase-CX4 TOE",
+       },
+
+       {
+               .board          = CHBT_BOARD_N110,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+               .chip_term      = CHBT_TERM_T1,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_88X2010,
+               .clock_core     = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 0,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_mv88x201x_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio N110 1x10GBaseX NIC",
+       },
+
+       {
+               .board          = CHBT_BOARD_N210,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_88X2010,
+               .clock_core     = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 0,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_mv88x201x_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio N210 1x10GBaseX NIC",
+       },
+
+       {
+               .board          = CHBT_BOARD_CHT210,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_88X2010,
+               .clock_core     = 125000000,
+               .clock_mc3      = 133000000,
+               .clock_mc4      = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 0,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_mv88x201x_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio T210 1x10GBaseX TOE",
+       },
+
+       {
+               .board          = CHBT_BOARD_CHT210,
+               .port_number    = 1,
+               .caps           = SUPPORTED_10000baseT_Full,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_PM3393,
+               .chip_phy       = CHBT_PHY_MY3126,
+               .clock_core     = 125000000,
+               .clock_mc3      = 133000000,
+               .clock_mc4      = 125000000,
+               .espi_nports    = 1,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 1,
+               .mdio_mdiinv    = 1,
+               .mdio_mdc       = 1,
+               .mdio_phybaseaddr = 1,
+               .gmac           = &t1_pm3393_ops,
+               .gphy           = &t1_my3126_ops,
+               .mdio_ops       = &mi1_mdio_ext_ops,
+               .desc           = "Chelsio T210 1x10GBase-CX4 TOE",
+       },
+
+#ifdef CONFIG_CHELSIO_T1_1G
+       {
+               .board          = CHBT_BOARD_CHN204,
+               .port_number    = 4,
+               .caps           = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+                               | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+                               | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+                                 SUPPORTED_PAUSE | SUPPORTED_TP,
+               .chip_term      = CHBT_TERM_T2,
+               .chip_mac       = CHBT_MAC_VSC7321,
+               .chip_phy       = CHBT_PHY_88E1111,
+               .clock_core     = 100000000,
+               .espi_nports    = 4,
+               .clock_elmer0   = 44,
+               .mdio_mdien     = 0,
+               .mdio_mdiinv    = 0,
+               .mdio_mdc       = 0,
+               .mdio_phybaseaddr = 4,
+               .gmac           = &t1_vsc7326_ops,
+               .gphy           = &t1_mv88e1xxx_ops,
+               .mdio_ops       = &mi1_mdio_ops,
+               .desc           = "Chelsio N204 4x100/1000BaseT NIC",
+       },
+#endif
 
 };
 
 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);
+
 /*
  * Return the board_info structure with a given index.  Out-of-range indices
  * return NULL.
  */
 const struct board_info *t1_get_board_info(unsigned int board_id)
 {
-       return board_id < DIMOF(t1_board) ? &t1_board[board_id] : NULL;
+       return board_id < ARRAY_SIZE(t1_board) ? &t1_board[board_id] : NULL;
 }
 
 struct chelsio_vpd_t {
@@ -332,10 +563,11 @@ struct chelsio_vpd_t {
  * written to the Control register. The hardware device will set the flag to a
  * one when 4B have been transferred to the Data register.
  */
-int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
+int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data)
 {
        int i = EEPROM_MAX_POLL;
        u16 val;
+       u32 v;
 
        if (addr >= EEPROMSIZE || (addr & 3))
                return -EINVAL;
@@ -351,8 +583,8 @@ int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
                       adapter->name, addr);
                return -EIO;
        }
-       pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, data);
-       *data = le32_to_cpu(*data);
+       pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, &v);
+       *data = cpu_to_le32(v);
        return 0;
 }
 
@@ -362,7 +594,7 @@ static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd)
 
        for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32))
                ret = t1_seeprom_read(adapter, addr,
-                                     (u32 *)((u8 *)vpd + addr));
+                                     (__le32 *)((u8 *)vpd + addr));
 
        return ret;
 }
@@ -399,9 +631,14 @@ int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
        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);
 
@@ -412,11 +649,15 @@ int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
                        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);
@@ -427,15 +668,58 @@ int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
 /*
  * 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;
+       struct cphy *phy;
        int phy_cause;
-       u32 cause;
+       u32 cause;
 
        t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause);
 
        switch (board_info(adapter)->board) {
+#ifdef CONFIG_CHELSIO_T1_1G
+       case CHBT_BOARD_CHT204:
+       case CHBT_BOARD_CHT204E:
+       case CHBT_BOARD_CHN204:
+       case CHBT_BOARD_CHT204V: {
+               int i, port_bit;
+               for_each_port(adapter, i) {
+                       port_bit = i + 1;
+                       if (!(cause & (1 << port_bit)))
+                               continue;
+
+                       phy = adapter->port[i].phy;
+                       phy_cause = phy->ops->interrupt_handler(phy);
+                       if (phy_cause & cphy_cause_link_change)
+                               t1_link_changed(adapter, i);
+               }
+               break;
+       }
+       case CHBT_BOARD_CHT101:
+               if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
+                       phy = adapter->port[0].phy;
+                       phy_cause = phy->ops->interrupt_handler(phy);
+                       if (phy_cause & cphy_cause_link_change)
+                               t1_link_changed(adapter, 0);
+               }
+               break;
+       case CHBT_BOARD_7500: {
+               int p;
+               /*
+                * Elmer0's interrupt cause isn't useful here because there is
+                * only one bit that can be set for all 4 ports.  This means
+                * we are forced to check every PHY's interrupt status
+                * register to see who initiated the interrupt.
+                */
+               for_each_port(adapter, p) {
+                       phy = adapter->port[p].phy;
+                       phy_cause = phy->ops->interrupt_handler(phy);
+                       if (phy_cause & cphy_cause_link_change)
+                           t1_link_changed(adapter, p);
+               }
+               break;
+       }
+#endif
        case CHBT_BOARD_CHT210:
        case CHBT_BOARD_N210:
        case CHBT_BOARD_N110:
@@ -443,12 +727,12 @@ int elmer0_ext_intr_handler(adapter_t *adapter)
                        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",
+               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;
@@ -458,11 +742,37 @@ int elmer0_ext_intr_handler(adapter_t *adapter)
                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",
+                       t1_tpi_read(adapter,
+                                       A_ELMER0_GPI_STAT, &mod_detect);
+                       CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
                               mod_detect ? "removed" : "inserted");
-               }
+               }
                break;
+#ifdef CONFIG_CHELSIO_T1_COUGAR
+       case CHBT_BOARD_COUGAR:
+               if (adapter->params.nports == 1) {
+                       if (cause & ELMER0_GP_BIT1) {         /* Vitesse MAC */
+                               struct cmac *mac = adapter->port[0].mac;
+                               mac->ops->interrupt_handler(mac);
+                       }
+                       if (cause & ELMER0_GP_BIT5) {     /* XPAK MOD_DETECT */
+                       }
+               } else {
+                       int i, port_bit;
+
+                       for_each_port(adapter, i) {
+                               port_bit = i ? i + 1 : 0;
+                               if (!(cause & (1 << port_bit)))
+                                       continue;
+
+                               phy = adapter->port[i].phy;
+                               phy_cause = phy->ops->interrupt_handler(phy);
+                               if (phy_cause & cphy_cause_link_change)
+                                       t1_link_changed(adapter, i);
+                       }
+               }
+               break;
+#endif
        }
        t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
        return 0;
@@ -490,15 +800,15 @@ void t1_interrupts_enable(adapter_t *adapter)
 
        /* Enable PCIX & external chip interrupts on ASIC boards. */
        if (t1_is_asic(adapter)) {
-               u32 pl_intr = t1_read_reg_4(adapter, A_PL_ENABLE);
+               u32 pl_intr = readl(adapter->regs + A_PL_ENABLE);
 
                /* PCI-X interrupts */
                pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE,
-                                        0xffffffff);
+                                      0xffffffff);
 
                adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
                pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX;
-               t1_write_reg_4(adapter, A_PL_ENABLE, pl_intr);
+               writel(pl_intr, adapter->regs + A_PL_ENABLE);
        }
 }
 
@@ -520,7 +830,7 @@ void t1_interrupts_disable(adapter_t* adapter)
 
        /* Disable PCIX & external chip interrupts. */
        if (t1_is_asic(adapter))
-               t1_write_reg_4(adapter, A_PL_ENABLE, 0);
+               writel(0, adapter->regs + A_PL_ENABLE);
 
        /* PCI-X interrupts */
        pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -546,10 +856,10 @@ void t1_interrupts_clear(adapter_t* adapter)
 
        /* Enable interrupts for external devices. */
        if (t1_is_asic(adapter)) {
-               u32 pl_intr = t1_read_reg_4(adapter, A_PL_CAUSE);
+               u32 pl_intr = readl(adapter->regs + A_PL_CAUSE);
 
-               t1_write_reg_4(adapter, A_PL_CAUSE,
-                              pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX);
+               writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX,
+                      adapter->regs + A_PL_CAUSE);
        }
 
        /* PCI-X interrupts */
@@ -561,7 +871,7 @@ void t1_interrupts_clear(adapter_t* adapter)
  */
 static int asic_slow_intr(adapter_t *adapter)
 {
-       u32 cause = t1_read_reg_4(adapter, A_PL_CAUSE);
+       u32 cause = readl(adapter->regs + A_PL_CAUSE);
 
        cause &= adapter->slow_intr_mask;
        if (!cause)
@@ -578,24 +888,28 @@ static int asic_slow_intr(adapter_t *adapter)
                t1_elmer0_ext_intr(adapter);
 
        /* Clear the interrupts just processed. */
-       t1_write_reg_4(adapter, A_PL_CAUSE, cause);
-       (void)t1_read_reg_4(adapter, A_PL_CAUSE); /* flush writes */
+       writel(cause, adapter->regs + A_PL_CAUSE);
+       readl(adapter->regs + A_PL_CAUSE); /* flush writes */
        return 1;
 }
 
 int t1_slow_intr_handler(adapter_t *adapter)
 {
+#ifdef CONFIG_CHELSIO_T1_1G
+       if (!t1_is_asic(adapter))
+               return fpga_slow_intr(adapter);
+#endif
        return asic_slow_intr(adapter);
 }
 
 /* Power sequencing is a work-around for Intel's XPAKs. */
 static void power_sequence_xpak(adapter_t* adapter)
 {
-       u32 mod_detect;
-       u32 gpo;
+       u32 mod_detect;
+       u32 gpo;
 
-       /* Check for XPAK */
-       t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+       /* 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);
@@ -612,7 +926,7 @@ int __devinit t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
        if (p->chip_version == CHBT_TERM_T1 ||
            p->chip_version == CHBT_TERM_T2 ||
            p->chip_version == CHBT_TERM_FPGA) {
-               u32 val = t1_read_reg_4(adapter, A_TP_PC_CONFIG);
+               u32 val = readl(adapter->regs + A_TP_PC_CONFIG);
 
                val = G_TP_PC_REV(val);
                if (val == 2)
@@ -638,18 +952,33 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
        case CHBT_BOARD_N210:
        case CHBT_BOARD_CHT210:
        case CHBT_BOARD_COUGAR:
-               t1_tpi_par(adapter, 0xf);
-               t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+               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);
+               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);
+               /* TBD XXX Might not need.  This fixes a problem
+                *         described in the Intel SR XPAK errata.
+                */
+               power_sequence_xpak(adapter);
+               break;
+#ifdef CONFIG_CHELSIO_T1_1G
+       case CHBT_BOARD_CHT204E:
+               /* add config space write here */
+       case CHBT_BOARD_CHT204:
+       case CHBT_BOARD_CHT204V:
+       case CHBT_BOARD_CHN204:
+               t1_tpi_par(adapter, 0xf);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
                break;
+       case CHBT_BOARD_CHT101:
+       case CHBT_BOARD_7500:
+               t1_tpi_par(adapter, 0xf);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
+               break;
+#endif
        }
        return 0;
 }
@@ -663,14 +992,18 @@ int t1_init_hw_modules(adapter_t *adapter)
        int err = -EIO;
        const struct board_info *bi = board_info(adapter);
 
-       if (!adapter->mc4) {
-               u32 val = t1_read_reg_4(adapter, A_MC4_CFG);
+       if (!bi->clock_mc4) {
+               u32 val = readl(adapter->regs + A_MC4_CFG);
 
-               t1_write_reg_4(adapter, A_MC4_CFG, val | F_READY | F_MC4_SLOW);
-               t1_write_reg_4(adapter, A_MC5_CONFIG,
-                              F_M_BUS_ENABLE | F_TCAM_RESET);
+               writel(val | F_READY | F_MC4_SLOW, adapter->regs + A_MC4_CFG);
+               writel(F_M_BUS_ENABLE | F_TCAM_RESET,
+                      adapter->regs + A_MC5_CONFIG);
        }
 
+#ifdef CONFIG_CHELSIO_T1_COUGAR
+       if (adapter->cspi && t1_cspi_init(adapter->cspi))
+               goto out_err;
+#endif
        if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
                                          bi->espi_nports))
                goto out_err;
@@ -683,16 +1016,16 @@ int t1_init_hw_modules(adapter_t *adapter)
                goto out_err;
 
        err = 0;
- out_err:
+out_err:
        return err;
 }
 
 /*
  * Determine a card's PCI mode.
  */
-static void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p)
+static void __devinit get_pci_mode(adapter_t *adapter, struct chelsio_pci_params *p)
 {
-       static unsigned short speed_map[] = { 33, 66, 100, 133 };
+       static const unsigned short speed_map[] = { 33, 66, 100, 133 };
        u32 pci_mode;
 
        pci_read_config_dword(adapter->pdev, A_PCICFG_MODE, &pci_mode);
@@ -724,6 +1057,10 @@ void t1_free_sw_modules(adapter_t *adapter)
                t1_tp_destroy(adapter->tp);
        if (adapter->espi)
                t1_espi_destroy(adapter->espi);
+#ifdef CONFIG_CHELSIO_T1_COUGAR
+       if (adapter->cspi)
+               t1_cspi_destroy(adapter->cspi);
+#endif
 }
 
 static void __devinit init_link_config(struct link_config *lc,
@@ -743,6 +1080,13 @@ static void __devinit init_link_config(struct link_config *lc,
        }
 }
 
+#ifdef CONFIG_CHELSIO_T1_COUGAR
+       if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
+               CH_ERR("%s: CSPI initialization failed\n",
+                      adapter->name);
+               goto error;
+       }
+#endif
 
 /*
  * Allocate and initialize the data structures that hold the SW state of
@@ -764,8 +1108,6 @@ int __devinit t1_init_sw_modules(adapter_t *adapter,
                goto error;
        }
 
-
-
        if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) {
                CH_ERR("%s: ESPI initialization failed\n",
                       adapter->name);
@@ -814,10 +1156,10 @@ int __devinit t1_init_sw_modules(adapter_t *adapter,
                        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",
-                              port_name(adapter, i));
+                              adapter->port[i].dev->name);
                        goto error;
                }
-               t1_set_hw_addr(adapter, i, hw_addr);
+               memcpy(adapter->port[i].dev->dev_addr, hw_addr, ETH_ALEN);
                init_link_config(&adapter->port[i].link_config, bi);
        }
 
@@ -825,7 +1167,7 @@ int __devinit t1_init_sw_modules(adapter_t *adapter,
        t1_interrupts_clear(adapter);
        return 0;
 
- error:
+error:
        t1_free_sw_modules(adapter);
        return -1;
 }