162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/***************************************************************************** 362306a36Sopenharmony_ci * * 462306a36Sopenharmony_ci * File: espi.c * 562306a36Sopenharmony_ci * $Revision: 1.14 $ * 662306a36Sopenharmony_ci * $Date: 2005/05/14 00:59:32 $ * 762306a36Sopenharmony_ci * Description: * 862306a36Sopenharmony_ci * Ethernet SPI functionality. * 962306a36Sopenharmony_ci * part of the Chelsio 10Gb Ethernet Driver. * 1062306a36Sopenharmony_ci * * 1162306a36Sopenharmony_ci * * 1262306a36Sopenharmony_ci * http://www.chelsio.com * 1362306a36Sopenharmony_ci * * 1462306a36Sopenharmony_ci * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * 1562306a36Sopenharmony_ci * All rights reserved. * 1662306a36Sopenharmony_ci * * 1762306a36Sopenharmony_ci * Maintainers: maintainers@chelsio.com * 1862306a36Sopenharmony_ci * * 1962306a36Sopenharmony_ci * Authors: Dimitrios Michailidis <dm@chelsio.com> * 2062306a36Sopenharmony_ci * Tina Yang <tainay@chelsio.com> * 2162306a36Sopenharmony_ci * Felix Marti <felix@chelsio.com> * 2262306a36Sopenharmony_ci * Scott Bardone <sbardone@chelsio.com> * 2362306a36Sopenharmony_ci * Kurt Ottaway <kottaway@chelsio.com> * 2462306a36Sopenharmony_ci * Frank DiMambro <frank@chelsio.com> * 2562306a36Sopenharmony_ci * * 2662306a36Sopenharmony_ci * History: * 2762306a36Sopenharmony_ci * * 2862306a36Sopenharmony_ci ****************************************************************************/ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "common.h" 3162306a36Sopenharmony_ci#include "regs.h" 3262306a36Sopenharmony_ci#include "espi.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct peespi { 3562306a36Sopenharmony_ci adapter_t *adapter; 3662306a36Sopenharmony_ci struct espi_intr_counts intr_cnt; 3762306a36Sopenharmony_ci u32 misc_ctrl; 3862306a36Sopenharmony_ci spinlock_t lock; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \ 4262306a36Sopenharmony_ci F_RAMPARITYERR | F_DIP2PARITYERR) 4362306a36Sopenharmony_ci#define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \ 4462306a36Sopenharmony_ci | F_MONITORED_INTERFACE) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define TRICN_CNFG 14 4762306a36Sopenharmony_ci#define TRICN_CMD_READ 0x11 4862306a36Sopenharmony_ci#define TRICN_CMD_WRITE 0x21 4962306a36Sopenharmony_ci#define TRICN_CMD_ATTEMPTS 10 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, 5262306a36Sopenharmony_ci int ch_addr, int reg_offset, u32 wr_data) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci int busy, attempts = TRICN_CMD_ATTEMPTS; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci writel(V_WRITE_DATA(wr_data) | 5762306a36Sopenharmony_ci V_REGISTER_OFFSET(reg_offset) | 5862306a36Sopenharmony_ci V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) | 5962306a36Sopenharmony_ci V_BUNDLE_ADDR(bundle_addr) | 6062306a36Sopenharmony_ci V_SPI4_COMMAND(TRICN_CMD_WRITE), 6162306a36Sopenharmony_ci adapter->regs + A_ESPI_CMD_ADDR); 6262306a36Sopenharmony_ci writel(0, adapter->regs + A_ESPI_GOSTAT); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci do { 6562306a36Sopenharmony_ci busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY; 6662306a36Sopenharmony_ci } while (busy && --attempts); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (busy) 6962306a36Sopenharmony_ci pr_err("%s: TRICN write timed out\n", adapter->name); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return busy; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int tricn_init(adapter_t *adapter) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int i, sme = 1; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (!(readl(adapter->regs + A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) { 7962306a36Sopenharmony_ci pr_err("%s: ESPI clock not ready\n", adapter->name); 8062306a36Sopenharmony_ci return -1; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci writel(F_ESPI_RX_CORE_RST, adapter->regs + A_ESPI_RX_RESET); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (sme) { 8662306a36Sopenharmony_ci tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); 8762306a36Sopenharmony_ci tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); 8862306a36Sopenharmony_ci tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci for (i = 1; i <= 8; i++) 9162306a36Sopenharmony_ci tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); 9262306a36Sopenharmony_ci for (i = 1; i <= 2; i++) 9362306a36Sopenharmony_ci tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); 9462306a36Sopenharmony_ci for (i = 1; i <= 3; i++) 9562306a36Sopenharmony_ci tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); 9662306a36Sopenharmony_ci tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1); 9762306a36Sopenharmony_ci tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1); 9862306a36Sopenharmony_ci tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1); 9962306a36Sopenharmony_ci tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80); 10062306a36Sopenharmony_ci tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci writel(F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST, 10362306a36Sopenharmony_ci adapter->regs + A_ESPI_RX_RESET); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_civoid t1_espi_intr_enable(struct peespi *espi) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * Cannot enable ESPI interrupts on T1B because HW asserts the 11462306a36Sopenharmony_ci * interrupt incorrectly, namely the driver gets ESPI interrupts 11562306a36Sopenharmony_ci * but no data is actually dropped (can verify this reading the ESPI 11662306a36Sopenharmony_ci * drop registers). Also, once the ESPI interrupt is asserted it 11762306a36Sopenharmony_ci * cannot be cleared (HW bug). 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; 12062306a36Sopenharmony_ci writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE); 12162306a36Sopenharmony_ci writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_civoid t1_espi_intr_clear(struct peespi *espi) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); 12762306a36Sopenharmony_ci writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS); 12862306a36Sopenharmony_ci writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_civoid t1_espi_intr_disable(struct peespi *espi) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE); 13662306a36Sopenharmony_ci writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciint t1_espi_intr_handler(struct peespi *espi) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (status & F_DIP4ERR) 14462306a36Sopenharmony_ci espi->intr_cnt.DIP4_err++; 14562306a36Sopenharmony_ci if (status & F_RXDROP) 14662306a36Sopenharmony_ci espi->intr_cnt.rx_drops++; 14762306a36Sopenharmony_ci if (status & F_TXDROP) 14862306a36Sopenharmony_ci espi->intr_cnt.tx_drops++; 14962306a36Sopenharmony_ci if (status & F_RXOVERFLOW) 15062306a36Sopenharmony_ci espi->intr_cnt.rx_ovflw++; 15162306a36Sopenharmony_ci if (status & F_RAMPARITYERR) 15262306a36Sopenharmony_ci espi->intr_cnt.parity_err++; 15362306a36Sopenharmony_ci if (status & F_DIP2PARITYERR) { 15462306a36Sopenharmony_ci espi->intr_cnt.DIP2_parity_err++; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * Must read the error count to clear the interrupt 15862306a36Sopenharmony_ci * that it causes. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we 16562306a36Sopenharmony_ci * write the status as is. 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci if (status && t1_is_T1B(espi->adapter)) 16862306a36Sopenharmony_ci status = 1; 16962306a36Sopenharmony_ci writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciconst struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci return &espi->intr_cnt; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void espi_setup_for_pm3393(adapter_t *adapter) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); 18362306a36Sopenharmony_ci writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1); 18462306a36Sopenharmony_ci writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); 18562306a36Sopenharmony_ci writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3); 18662306a36Sopenharmony_ci writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); 18762306a36Sopenharmony_ci writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); 18862306a36Sopenharmony_ci writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH); 18962306a36Sopenharmony_ci writel(0x08000008, adapter->regs + A_ESPI_TRAIN); 19062306a36Sopenharmony_ci writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void espi_setup_for_vsc7321(adapter_t *adapter) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); 19662306a36Sopenharmony_ci writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); 19762306a36Sopenharmony_ci writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); 19862306a36Sopenharmony_ci writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); 19962306a36Sopenharmony_ci writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); 20062306a36Sopenharmony_ci writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); 20162306a36Sopenharmony_ci writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter->regs + A_PORT_CONFIG); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci writel(0x08000008, adapter->regs + A_ESPI_TRAIN); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic void espi_setup_for_ixf1010(adapter_t *adapter, int nports) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); 21262306a36Sopenharmony_ci if (nports == 4) { 21362306a36Sopenharmony_ci if (is_T2(adapter)) { 21462306a36Sopenharmony_ci writel(0xf00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); 21562306a36Sopenharmony_ci writel(0x3c0, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); 21662306a36Sopenharmony_ci } else { 21762306a36Sopenharmony_ci writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); 21862306a36Sopenharmony_ci writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci } else { 22162306a36Sopenharmony_ci writel(0x1fff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); 22262306a36Sopenharmony_ci writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci writel(V_RX_NPORTS(nports) | V_TX_NPORTS(nports), adapter->regs + A_PORT_CONFIG); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciint t1_espi_init(struct peespi *espi, int mac_type, int nports) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci u32 status_enable_extra = 0; 23162306a36Sopenharmony_ci adapter_t *adapter = espi->adapter; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Disable ESPI training. MACs that can handle it enable it below. */ 23462306a36Sopenharmony_ci writel(0, adapter->regs + A_ESPI_TRAIN); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (is_T2(adapter)) { 23762306a36Sopenharmony_ci writel(V_OUT_OF_SYNC_COUNT(4) | 23862306a36Sopenharmony_ci V_DIP2_PARITY_ERR_THRES(3) | 23962306a36Sopenharmony_ci V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); 24062306a36Sopenharmony_ci writel(nports == 4 ? 0x200040 : 0x1000080, 24162306a36Sopenharmony_ci adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); 24262306a36Sopenharmony_ci } else 24362306a36Sopenharmony_ci writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (mac_type == CHBT_MAC_PM3393) 24662306a36Sopenharmony_ci espi_setup_for_pm3393(adapter); 24762306a36Sopenharmony_ci else if (mac_type == CHBT_MAC_VSC7321) 24862306a36Sopenharmony_ci espi_setup_for_vsc7321(adapter); 24962306a36Sopenharmony_ci else if (mac_type == CHBT_MAC_IXF1010) { 25062306a36Sopenharmony_ci status_enable_extra = F_INTEL1010MODE; 25162306a36Sopenharmony_ci espi_setup_for_ixf1010(adapter, nports); 25262306a36Sopenharmony_ci } else 25362306a36Sopenharmony_ci return -1; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci writel(status_enable_extra | F_RXSTATUSENABLE, 25662306a36Sopenharmony_ci adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (is_T2(adapter)) { 25962306a36Sopenharmony_ci tricn_init(adapter); 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * Always position the control at the 1st port egress IN 26262306a36Sopenharmony_ci * (sop,eop) counter to reduce PIOs for T/N210 workaround. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci espi->misc_ctrl = readl(adapter->regs + A_ESPI_MISC_CONTROL); 26562306a36Sopenharmony_ci espi->misc_ctrl &= ~MON_MASK; 26662306a36Sopenharmony_ci espi->misc_ctrl |= F_MONITORED_DIRECTION; 26762306a36Sopenharmony_ci if (adapter->params.nports == 1) 26862306a36Sopenharmony_ci espi->misc_ctrl |= F_MONITORED_INTERFACE; 26962306a36Sopenharmony_ci writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 27062306a36Sopenharmony_ci spin_lock_init(&espi->lock); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_civoid t1_espi_destroy(struct peespi *espi) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci kfree(espi); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistruct peespi *t1_espi_create(adapter_t *adapter) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct peespi *espi = kzalloc(sizeof(*espi), GFP_KERNEL); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (espi) 28662306a36Sopenharmony_ci espi->adapter = adapter; 28762306a36Sopenharmony_ci return espi; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci#if 0 29162306a36Sopenharmony_civoid t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct peespi *espi = adapter->espi; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!is_T2(adapter)) 29662306a36Sopenharmony_ci return; 29762306a36Sopenharmony_ci spin_lock(&espi->lock); 29862306a36Sopenharmony_ci espi->misc_ctrl = (val & ~MON_MASK) | 29962306a36Sopenharmony_ci (espi->misc_ctrl & MON_MASK); 30062306a36Sopenharmony_ci writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 30162306a36Sopenharmony_ci spin_unlock(&espi->lock); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci#endif /* 0 */ 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciu32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct peespi *espi = adapter->espi; 30862306a36Sopenharmony_ci u32 sel; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!is_T2(adapter)) 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); 31462306a36Sopenharmony_ci if (!wait) { 31562306a36Sopenharmony_ci if (!spin_trylock(&espi->lock)) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci } else 31862306a36Sopenharmony_ci spin_lock(&espi->lock); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if ((sel != (espi->misc_ctrl & MON_MASK))) { 32162306a36Sopenharmony_ci writel(((espi->misc_ctrl & ~MON_MASK) | sel), 32262306a36Sopenharmony_ci adapter->regs + A_ESPI_MISC_CONTROL); 32362306a36Sopenharmony_ci sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); 32462306a36Sopenharmony_ci writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 32562306a36Sopenharmony_ci } else 32662306a36Sopenharmony_ci sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); 32762306a36Sopenharmony_ci spin_unlock(&espi->lock); 32862306a36Sopenharmony_ci return sel; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* 33262306a36Sopenharmony_ci * This function is for T204 only. 33362306a36Sopenharmony_ci * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in 33462306a36Sopenharmony_ci * one shot, since there is no per port counter on the out side. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ciint t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct peespi *espi = adapter->espi; 33962306a36Sopenharmony_ci u8 i, nport = (u8)adapter->params.nports; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!wait) { 34262306a36Sopenharmony_ci if (!spin_trylock(&espi->lock)) 34362306a36Sopenharmony_ci return -1; 34462306a36Sopenharmony_ci } else 34562306a36Sopenharmony_ci spin_lock(&espi->lock); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) { 34862306a36Sopenharmony_ci espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | 34962306a36Sopenharmony_ci F_MONITORED_DIRECTION; 35062306a36Sopenharmony_ci writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci for (i = 0 ; i < nport; i++, valp++) { 35362306a36Sopenharmony_ci if (i) { 35462306a36Sopenharmony_ci writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i), 35562306a36Sopenharmony_ci adapter->regs + A_ESPI_MISC_CONTROL); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 36162306a36Sopenharmony_ci spin_unlock(&espi->lock); 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 364