1*4882a593Smuzhiyun /*****************************************************************************
2*4882a593Smuzhiyun * *
3*4882a593Smuzhiyun * File: espi.c *
4*4882a593Smuzhiyun * $Revision: 1.14 $ *
5*4882a593Smuzhiyun * $Date: 2005/05/14 00:59:32 $ *
6*4882a593Smuzhiyun * Description: *
7*4882a593Smuzhiyun * Ethernet SPI functionality. *
8*4882a593Smuzhiyun * part of the Chelsio 10Gb Ethernet Driver. *
9*4882a593Smuzhiyun * *
10*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify *
11*4882a593Smuzhiyun * it under the terms of the GNU General Public License, version 2, as *
12*4882a593Smuzhiyun * published by the Free Software Foundation. *
13*4882a593Smuzhiyun * *
14*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License along *
15*4882a593Smuzhiyun * with this program; if not, see <http://www.gnu.org/licenses/>. *
16*4882a593Smuzhiyun * *
17*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED *
18*4882a593Smuzhiyun * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
19*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
20*4882a593Smuzhiyun * *
21*4882a593Smuzhiyun * http://www.chelsio.com *
22*4882a593Smuzhiyun * *
23*4882a593Smuzhiyun * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *
24*4882a593Smuzhiyun * All rights reserved. *
25*4882a593Smuzhiyun * *
26*4882a593Smuzhiyun * Maintainers: maintainers@chelsio.com *
27*4882a593Smuzhiyun * *
28*4882a593Smuzhiyun * Authors: Dimitrios Michailidis <dm@chelsio.com> *
29*4882a593Smuzhiyun * Tina Yang <tainay@chelsio.com> *
30*4882a593Smuzhiyun * Felix Marti <felix@chelsio.com> *
31*4882a593Smuzhiyun * Scott Bardone <sbardone@chelsio.com> *
32*4882a593Smuzhiyun * Kurt Ottaway <kottaway@chelsio.com> *
33*4882a593Smuzhiyun * Frank DiMambro <frank@chelsio.com> *
34*4882a593Smuzhiyun * *
35*4882a593Smuzhiyun * History: *
36*4882a593Smuzhiyun * *
37*4882a593Smuzhiyun ****************************************************************************/
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #include "common.h"
40*4882a593Smuzhiyun #include "regs.h"
41*4882a593Smuzhiyun #include "espi.h"
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun struct peespi {
44*4882a593Smuzhiyun adapter_t *adapter;
45*4882a593Smuzhiyun struct espi_intr_counts intr_cnt;
46*4882a593Smuzhiyun u32 misc_ctrl;
47*4882a593Smuzhiyun spinlock_t lock;
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \
51*4882a593Smuzhiyun F_RAMPARITYERR | F_DIP2PARITYERR)
52*4882a593Smuzhiyun #define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \
53*4882a593Smuzhiyun | F_MONITORED_INTERFACE)
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #define TRICN_CNFG 14
56*4882a593Smuzhiyun #define TRICN_CMD_READ 0x11
57*4882a593Smuzhiyun #define TRICN_CMD_WRITE 0x21
58*4882a593Smuzhiyun #define TRICN_CMD_ATTEMPTS 10
59*4882a593Smuzhiyun
tricn_write(adapter_t * adapter,int bundle_addr,int module_addr,int ch_addr,int reg_offset,u32 wr_data)60*4882a593Smuzhiyun static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
61*4882a593Smuzhiyun int ch_addr, int reg_offset, u32 wr_data)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun int busy, attempts = TRICN_CMD_ATTEMPTS;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun writel(V_WRITE_DATA(wr_data) |
66*4882a593Smuzhiyun V_REGISTER_OFFSET(reg_offset) |
67*4882a593Smuzhiyun V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) |
68*4882a593Smuzhiyun V_BUNDLE_ADDR(bundle_addr) |
69*4882a593Smuzhiyun V_SPI4_COMMAND(TRICN_CMD_WRITE),
70*4882a593Smuzhiyun adapter->regs + A_ESPI_CMD_ADDR);
71*4882a593Smuzhiyun writel(0, adapter->regs + A_ESPI_GOSTAT);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun do {
74*4882a593Smuzhiyun busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY;
75*4882a593Smuzhiyun } while (busy && --attempts);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (busy)
78*4882a593Smuzhiyun pr_err("%s: TRICN write timed out\n", adapter->name);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return busy;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
tricn_init(adapter_t * adapter)83*4882a593Smuzhiyun static int tricn_init(adapter_t *adapter)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun int i, sme = 1;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (!(readl(adapter->regs + A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) {
88*4882a593Smuzhiyun pr_err("%s: ESPI clock not ready\n", adapter->name);
89*4882a593Smuzhiyun return -1;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun writel(F_ESPI_RX_CORE_RST, adapter->regs + A_ESPI_RX_RESET);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (sme) {
95*4882a593Smuzhiyun tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81);
96*4882a593Smuzhiyun tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81);
97*4882a593Smuzhiyun tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun for (i = 1; i <= 8; i++)
100*4882a593Smuzhiyun tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
101*4882a593Smuzhiyun for (i = 1; i <= 2; i++)
102*4882a593Smuzhiyun tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
103*4882a593Smuzhiyun for (i = 1; i <= 3; i++)
104*4882a593Smuzhiyun tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
105*4882a593Smuzhiyun tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1);
106*4882a593Smuzhiyun tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1);
107*4882a593Smuzhiyun tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1);
108*4882a593Smuzhiyun tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80);
109*4882a593Smuzhiyun tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun writel(F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST,
112*4882a593Smuzhiyun adapter->regs + A_ESPI_RX_RESET);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
t1_espi_intr_enable(struct peespi * espi)117*4882a593Smuzhiyun void t1_espi_intr_enable(struct peespi *espi)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * Cannot enable ESPI interrupts on T1B because HW asserts the
123*4882a593Smuzhiyun * interrupt incorrectly, namely the driver gets ESPI interrupts
124*4882a593Smuzhiyun * but no data is actually dropped (can verify this reading the ESPI
125*4882a593Smuzhiyun * drop registers). Also, once the ESPI interrupt is asserted it
126*4882a593Smuzhiyun * cannot be cleared (HW bug).
127*4882a593Smuzhiyun */
128*4882a593Smuzhiyun enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK;
129*4882a593Smuzhiyun writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE);
130*4882a593Smuzhiyun writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
t1_espi_intr_clear(struct peespi * espi)133*4882a593Smuzhiyun void t1_espi_intr_clear(struct peespi *espi)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
136*4882a593Smuzhiyun writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS);
137*4882a593Smuzhiyun writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
t1_espi_intr_disable(struct peespi * espi)140*4882a593Smuzhiyun void t1_espi_intr_disable(struct peespi *espi)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE);
145*4882a593Smuzhiyun writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
t1_espi_intr_handler(struct peespi * espi)148*4882a593Smuzhiyun int t1_espi_intr_handler(struct peespi *espi)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (status & F_DIP4ERR)
153*4882a593Smuzhiyun espi->intr_cnt.DIP4_err++;
154*4882a593Smuzhiyun if (status & F_RXDROP)
155*4882a593Smuzhiyun espi->intr_cnt.rx_drops++;
156*4882a593Smuzhiyun if (status & F_TXDROP)
157*4882a593Smuzhiyun espi->intr_cnt.tx_drops++;
158*4882a593Smuzhiyun if (status & F_RXOVERFLOW)
159*4882a593Smuzhiyun espi->intr_cnt.rx_ovflw++;
160*4882a593Smuzhiyun if (status & F_RAMPARITYERR)
161*4882a593Smuzhiyun espi->intr_cnt.parity_err++;
162*4882a593Smuzhiyun if (status & F_DIP2PARITYERR) {
163*4882a593Smuzhiyun espi->intr_cnt.DIP2_parity_err++;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /*
166*4882a593Smuzhiyun * Must read the error count to clear the interrupt
167*4882a593Smuzhiyun * that it causes.
168*4882a593Smuzhiyun */
169*4882a593Smuzhiyun readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we
174*4882a593Smuzhiyun * write the status as is.
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun if (status && t1_is_T1B(espi->adapter))
177*4882a593Smuzhiyun status = 1;
178*4882a593Smuzhiyun writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS);
179*4882a593Smuzhiyun return 0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
t1_espi_get_intr_counts(struct peespi * espi)182*4882a593Smuzhiyun const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun return &espi->intr_cnt;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
espi_setup_for_pm3393(adapter_t * adapter)187*4882a593Smuzhiyun static void espi_setup_for_pm3393(adapter_t *adapter)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
192*4882a593Smuzhiyun writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1);
193*4882a593Smuzhiyun writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
194*4882a593Smuzhiyun writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3);
195*4882a593Smuzhiyun writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
196*4882a593Smuzhiyun writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
197*4882a593Smuzhiyun writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH);
198*4882a593Smuzhiyun writel(0x08000008, adapter->regs + A_ESPI_TRAIN);
199*4882a593Smuzhiyun writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
espi_setup_for_vsc7321(adapter_t * adapter)202*4882a593Smuzhiyun static void espi_setup_for_vsc7321(adapter_t *adapter)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
205*4882a593Smuzhiyun writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
206*4882a593Smuzhiyun writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
207*4882a593Smuzhiyun writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
208*4882a593Smuzhiyun writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
209*4882a593Smuzhiyun writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
210*4882a593Smuzhiyun writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter->regs + A_PORT_CONFIG);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun writel(0x08000008, adapter->regs + A_ESPI_TRAIN);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /*
216*4882a593Smuzhiyun * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug.
217*4882a593Smuzhiyun */
espi_setup_for_ixf1010(adapter_t * adapter,int nports)218*4882a593Smuzhiyun static void espi_setup_for_ixf1010(adapter_t *adapter, int nports)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
221*4882a593Smuzhiyun if (nports == 4) {
222*4882a593Smuzhiyun if (is_T2(adapter)) {
223*4882a593Smuzhiyun writel(0xf00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
224*4882a593Smuzhiyun writel(0x3c0, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
225*4882a593Smuzhiyun } else {
226*4882a593Smuzhiyun writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
227*4882a593Smuzhiyun writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun } else {
230*4882a593Smuzhiyun writel(0x1fff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
231*4882a593Smuzhiyun writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun writel(V_RX_NPORTS(nports) | V_TX_NPORTS(nports), adapter->regs + A_PORT_CONFIG);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
t1_espi_init(struct peespi * espi,int mac_type,int nports)237*4882a593Smuzhiyun int t1_espi_init(struct peespi *espi, int mac_type, int nports)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun u32 status_enable_extra = 0;
240*4882a593Smuzhiyun adapter_t *adapter = espi->adapter;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* Disable ESPI training. MACs that can handle it enable it below. */
243*4882a593Smuzhiyun writel(0, adapter->regs + A_ESPI_TRAIN);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun if (is_T2(adapter)) {
246*4882a593Smuzhiyun writel(V_OUT_OF_SYNC_COUNT(4) |
247*4882a593Smuzhiyun V_DIP2_PARITY_ERR_THRES(3) |
248*4882a593Smuzhiyun V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
249*4882a593Smuzhiyun writel(nports == 4 ? 0x200040 : 0x1000080,
250*4882a593Smuzhiyun adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
251*4882a593Smuzhiyun } else
252*4882a593Smuzhiyun writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun if (mac_type == CHBT_MAC_PM3393)
255*4882a593Smuzhiyun espi_setup_for_pm3393(adapter);
256*4882a593Smuzhiyun else if (mac_type == CHBT_MAC_VSC7321)
257*4882a593Smuzhiyun espi_setup_for_vsc7321(adapter);
258*4882a593Smuzhiyun else if (mac_type == CHBT_MAC_IXF1010) {
259*4882a593Smuzhiyun status_enable_extra = F_INTEL1010MODE;
260*4882a593Smuzhiyun espi_setup_for_ixf1010(adapter, nports);
261*4882a593Smuzhiyun } else
262*4882a593Smuzhiyun return -1;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun writel(status_enable_extra | F_RXSTATUSENABLE,
265*4882a593Smuzhiyun adapter->regs + A_ESPI_FIFO_STATUS_ENABLE);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (is_T2(adapter)) {
268*4882a593Smuzhiyun tricn_init(adapter);
269*4882a593Smuzhiyun /*
270*4882a593Smuzhiyun * Always position the control at the 1st port egress IN
271*4882a593Smuzhiyun * (sop,eop) counter to reduce PIOs for T/N210 workaround.
272*4882a593Smuzhiyun */
273*4882a593Smuzhiyun espi->misc_ctrl = readl(adapter->regs + A_ESPI_MISC_CONTROL);
274*4882a593Smuzhiyun espi->misc_ctrl &= ~MON_MASK;
275*4882a593Smuzhiyun espi->misc_ctrl |= F_MONITORED_DIRECTION;
276*4882a593Smuzhiyun if (adapter->params.nports == 1)
277*4882a593Smuzhiyun espi->misc_ctrl |= F_MONITORED_INTERFACE;
278*4882a593Smuzhiyun writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
279*4882a593Smuzhiyun spin_lock_init(&espi->lock);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
t1_espi_destroy(struct peespi * espi)285*4882a593Smuzhiyun void t1_espi_destroy(struct peespi *espi)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun kfree(espi);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
t1_espi_create(adapter_t * adapter)290*4882a593Smuzhiyun struct peespi *t1_espi_create(adapter_t *adapter)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun struct peespi *espi = kzalloc(sizeof(*espi), GFP_KERNEL);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (espi)
295*4882a593Smuzhiyun espi->adapter = adapter;
296*4882a593Smuzhiyun return espi;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun #if 0
300*4882a593Smuzhiyun void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun struct peespi *espi = adapter->espi;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (!is_T2(adapter))
305*4882a593Smuzhiyun return;
306*4882a593Smuzhiyun spin_lock(&espi->lock);
307*4882a593Smuzhiyun espi->misc_ctrl = (val & ~MON_MASK) |
308*4882a593Smuzhiyun (espi->misc_ctrl & MON_MASK);
309*4882a593Smuzhiyun writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
310*4882a593Smuzhiyun spin_unlock(&espi->lock);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun #endif /* 0 */
313*4882a593Smuzhiyun
t1_espi_get_mon(adapter_t * adapter,u32 addr,u8 wait)314*4882a593Smuzhiyun u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun struct peespi *espi = adapter->espi;
317*4882a593Smuzhiyun u32 sel;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (!is_T2(adapter))
320*4882a593Smuzhiyun return 0;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2);
323*4882a593Smuzhiyun if (!wait) {
324*4882a593Smuzhiyun if (!spin_trylock(&espi->lock))
325*4882a593Smuzhiyun return 0;
326*4882a593Smuzhiyun } else
327*4882a593Smuzhiyun spin_lock(&espi->lock);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if ((sel != (espi->misc_ctrl & MON_MASK))) {
330*4882a593Smuzhiyun writel(((espi->misc_ctrl & ~MON_MASK) | sel),
331*4882a593Smuzhiyun adapter->regs + A_ESPI_MISC_CONTROL);
332*4882a593Smuzhiyun sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
333*4882a593Smuzhiyun writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
334*4882a593Smuzhiyun } else
335*4882a593Smuzhiyun sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
336*4882a593Smuzhiyun spin_unlock(&espi->lock);
337*4882a593Smuzhiyun return sel;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun * This function is for T204 only.
342*4882a593Smuzhiyun * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
343*4882a593Smuzhiyun * one shot, since there is no per port counter on the out side.
344*4882a593Smuzhiyun */
t1_espi_get_mon_t204(adapter_t * adapter,u32 * valp,u8 wait)345*4882a593Smuzhiyun int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun struct peespi *espi = adapter->espi;
348*4882a593Smuzhiyun u8 i, nport = (u8)adapter->params.nports;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (!wait) {
351*4882a593Smuzhiyun if (!spin_trylock(&espi->lock))
352*4882a593Smuzhiyun return -1;
353*4882a593Smuzhiyun } else
354*4882a593Smuzhiyun spin_lock(&espi->lock);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) {
357*4882a593Smuzhiyun espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
358*4882a593Smuzhiyun F_MONITORED_DIRECTION;
359*4882a593Smuzhiyun writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun for (i = 0 ; i < nport; i++, valp++) {
362*4882a593Smuzhiyun if (i) {
363*4882a593Smuzhiyun writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
364*4882a593Smuzhiyun adapter->regs + A_ESPI_MISC_CONTROL);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
370*4882a593Smuzhiyun spin_unlock(&espi->lock);
371*4882a593Smuzhiyun return 0;
372*4882a593Smuzhiyun }
373