diff options
Diffstat (limited to 'drivers/net/chelsio/espi.c')
-rw-r--r-- | drivers/net/chelsio/espi.c | 203 |
1 files changed, 119 insertions, 84 deletions
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c index 40af47b795e..4192f0f5b3e 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); } /* @@ -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; +} |