1*d39a76e7Sxw161283 /*
2*d39a76e7Sxw161283 * CDDL HEADER START
3*d39a76e7Sxw161283 *
4*d39a76e7Sxw161283 * The contents of this file are subject to the terms of the
5*d39a76e7Sxw161283 * Common Development and Distribution License (the "License").
6*d39a76e7Sxw161283 * You may not use this file except in compliance with the License.
7*d39a76e7Sxw161283 *
8*d39a76e7Sxw161283 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d39a76e7Sxw161283 * or http://www.opensolaris.org/os/licensing.
10*d39a76e7Sxw161283 * See the License for the specific language governing permissions
11*d39a76e7Sxw161283 * and limitations under the License.
12*d39a76e7Sxw161283 *
13*d39a76e7Sxw161283 * When distributing Covered Code, include this CDDL HEADER in each
14*d39a76e7Sxw161283 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d39a76e7Sxw161283 * If applicable, add the following below this CDDL HEADER, with the
16*d39a76e7Sxw161283 * fields enclosed by brackets "[]" replaced with your own identifying
17*d39a76e7Sxw161283 * information: Portions Copyright [yyyy] [name of copyright owner]
18*d39a76e7Sxw161283 *
19*d39a76e7Sxw161283 * CDDL HEADER END
20*d39a76e7Sxw161283 */
21*d39a76e7Sxw161283
22*d39a76e7Sxw161283 /*
23*d39a76e7Sxw161283 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved.
24*d39a76e7Sxw161283 */
25*d39a76e7Sxw161283
26*d39a76e7Sxw161283 #include "common.h"
27*d39a76e7Sxw161283 #include "regs.h"
28*d39a76e7Sxw161283 #include "espi.h"
29*d39a76e7Sxw161283
30*d39a76e7Sxw161283 struct peespi {
31*d39a76e7Sxw161283 adapter_t *adapter;
32*d39a76e7Sxw161283 struct espi_intr_counts intr_cnt;
33*d39a76e7Sxw161283 u32 misc_ctrl;
34*d39a76e7Sxw161283 SPINLOCK lock;
35*d39a76e7Sxw161283 };
36*d39a76e7Sxw161283
37*d39a76e7Sxw161283 #define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \
38*d39a76e7Sxw161283 F_RAMPARITYERR | F_DIP2PARITYERR)
39*d39a76e7Sxw161283 #define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \
40*d39a76e7Sxw161283 | F_MONITORED_INTERFACE)
41*d39a76e7Sxw161283
42*d39a76e7Sxw161283 #define TRICN_CNFG 14
43*d39a76e7Sxw161283 #define TRICN_CMD_READ 0x11
44*d39a76e7Sxw161283 #define TRICN_CMD_WRITE 0x21
45*d39a76e7Sxw161283 #define TRICN_CMD_ATTEMPTS 10
46*d39a76e7Sxw161283
tricn_write(adapter_t * adapter,int bundle_addr,int module_addr,int ch_addr,int reg_offset,u32 wr_data)47*d39a76e7Sxw161283 static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
48*d39a76e7Sxw161283 int ch_addr, int reg_offset, u32 wr_data)
49*d39a76e7Sxw161283 {
50*d39a76e7Sxw161283 int busy;
51*d39a76e7Sxw161283
52*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_CMD_ADDR, V_WRITE_DATA(wr_data) |
53*d39a76e7Sxw161283 V_REGISTER_OFFSET(reg_offset) |
54*d39a76e7Sxw161283 V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) |
55*d39a76e7Sxw161283 V_BUNDLE_ADDR(bundle_addr) |
56*d39a76e7Sxw161283 V_SPI4_COMMAND(TRICN_CMD_WRITE));
57*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_GOSTAT, 0);
58*d39a76e7Sxw161283
59*d39a76e7Sxw161283 busy = t1_wait_op_done(adapter, A_ESPI_GOSTAT, F_ESPI_CMD_BUSY, 0,
60*d39a76e7Sxw161283 TRICN_CMD_ATTEMPTS, 0);
61*d39a76e7Sxw161283
62*d39a76e7Sxw161283 if (busy)
63*d39a76e7Sxw161283 CH_ERR("%s: TRICN write timed out\n", adapter_name(adapter));
64*d39a76e7Sxw161283
65*d39a76e7Sxw161283 return busy;
66*d39a76e7Sxw161283 }
67*d39a76e7Sxw161283
68*d39a76e7Sxw161283 #if 0
69*d39a76e7Sxw161283 static int tricn_read(adapter_t *adapter, int bundle_addr, int module_addr,
70*d39a76e7Sxw161283 int ch_addr, int reg_offset, u8 *rd_data)
71*d39a76e7Sxw161283 {
72*d39a76e7Sxw161283 int busy, attempts = TRICN_CMD_ATTEMPTS;
73*d39a76e7Sxw161283 u32 status;
74*d39a76e7Sxw161283
75*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_CMD_ADDR,
76*d39a76e7Sxw161283 V_REGISTER_OFFSET(reg_offset) |
77*d39a76e7Sxw161283 V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) |
78*d39a76e7Sxw161283 V_BUNDLE_ADDR(bundle_addr) |
79*d39a76e7Sxw161283 V_SPI4_COMMAND(TRICN_CMD_READ));
80*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_GOSTAT, 0);
81*d39a76e7Sxw161283
82*d39a76e7Sxw161283 do {
83*d39a76e7Sxw161283 status = t1_read_reg_4(adapter, A_ESPI_GOSTAT);
84*d39a76e7Sxw161283 busy = status & F_ESPI_CMD_BUSY;
85*d39a76e7Sxw161283 } while (busy && --attempts);
86*d39a76e7Sxw161283
87*d39a76e7Sxw161283 if (busy)
88*d39a76e7Sxw161283 CH_ERR("%s: TRICN read timed out\n", adapter_name(adapter));
89*d39a76e7Sxw161283 else
90*d39a76e7Sxw161283 *rd_data = G_READ_DATA(status);
91*d39a76e7Sxw161283 return busy;
92*d39a76e7Sxw161283 }
93*d39a76e7Sxw161283 #endif
94*d39a76e7Sxw161283
tricn_init(adapter_t * adapter)95*d39a76e7Sxw161283 static int tricn_init(adapter_t *adapter)
96*d39a76e7Sxw161283 {
97*d39a76e7Sxw161283 int i, sme = 1;
98*d39a76e7Sxw161283
99*d39a76e7Sxw161283 if (!(t1_read_reg_4(adapter, A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) {
100*d39a76e7Sxw161283 CH_ERR("%s: ESPI clock not ready\n", adapter_name(adapter));
101*d39a76e7Sxw161283 return (-1);
102*d39a76e7Sxw161283 }
103*d39a76e7Sxw161283
104*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_RESET, F_ESPI_RX_CORE_RST);
105*d39a76e7Sxw161283
106*d39a76e7Sxw161283 if (sme) {
107*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81);
108*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81);
109*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81);
110*d39a76e7Sxw161283 }
111*d39a76e7Sxw161283 for (i=1; i<= 8; i++) (void) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
112*d39a76e7Sxw161283 for (i=1; i<= 2; i++) (void) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
113*d39a76e7Sxw161283 for (i=1; i<= 3; i++) (void) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
114*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1);
115*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1);
116*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1);
117*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80);
118*d39a76e7Sxw161283 (void) tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1);
119*d39a76e7Sxw161283
120*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_RESET, F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST);
121*d39a76e7Sxw161283
122*d39a76e7Sxw161283 return 0;
123*d39a76e7Sxw161283 }
124*d39a76e7Sxw161283
t1_espi_intr_enable(struct peespi * espi)125*d39a76e7Sxw161283 void t1_espi_intr_enable(struct peespi *espi)
126*d39a76e7Sxw161283 {
127*d39a76e7Sxw161283 u32 enable, pl_intr = t1_read_reg_4(espi->adapter, A_PL_ENABLE);
128*d39a76e7Sxw161283
129*d39a76e7Sxw161283 /*
130*d39a76e7Sxw161283 * Cannot enable ESPI interrupts on T1B because HW asserts the
131*d39a76e7Sxw161283 * interrupt incorrectly, namely the driver gets ESPI interrupts
132*d39a76e7Sxw161283 * but no data is actually dropped (can verify this reading the ESPI
133*d39a76e7Sxw161283 * drop registers). Also, once the ESPI interrupt is asserted it
134*d39a76e7Sxw161283 * cannot be cleared (HW bug).
135*d39a76e7Sxw161283 */
136*d39a76e7Sxw161283 enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK;
137*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, enable);
138*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_PL_ENABLE, pl_intr | F_PL_INTR_ESPI);
139*d39a76e7Sxw161283 }
140*d39a76e7Sxw161283
t1_espi_intr_clear(struct peespi * espi)141*d39a76e7Sxw161283 void t1_espi_intr_clear(struct peespi *espi)
142*d39a76e7Sxw161283 {
143*d39a76e7Sxw161283 (void) t1_read_reg_4(espi->adapter, A_ESPI_DIP2_ERR_COUNT);
144*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, 0xffffffff);
145*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_PL_CAUSE, F_PL_INTR_ESPI);
146*d39a76e7Sxw161283 }
147*d39a76e7Sxw161283
t1_espi_intr_disable(struct peespi * espi)148*d39a76e7Sxw161283 void t1_espi_intr_disable(struct peespi *espi)
149*d39a76e7Sxw161283 {
150*d39a76e7Sxw161283 u32 pl_intr = t1_read_reg_4(espi->adapter, A_PL_ENABLE);
151*d39a76e7Sxw161283
152*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, 0);
153*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_PL_ENABLE, pl_intr & ~F_PL_INTR_ESPI);
154*d39a76e7Sxw161283 }
155*d39a76e7Sxw161283
t1_espi_intr_handler(struct peespi * espi)156*d39a76e7Sxw161283 int t1_espi_intr_handler(struct peespi *espi)
157*d39a76e7Sxw161283 {
158*d39a76e7Sxw161283 u32 status = t1_read_reg_4(espi->adapter, A_ESPI_INTR_STATUS);
159*d39a76e7Sxw161283
160*d39a76e7Sxw161283 if (status & F_DIP4ERR)
161*d39a76e7Sxw161283 espi->intr_cnt.DIP4_err++;
162*d39a76e7Sxw161283 if (status & F_RXDROP)
163*d39a76e7Sxw161283 espi->intr_cnt.rx_drops++;
164*d39a76e7Sxw161283 if (status & F_TXDROP)
165*d39a76e7Sxw161283 espi->intr_cnt.tx_drops++;
166*d39a76e7Sxw161283 if (status & F_RXOVERFLOW)
167*d39a76e7Sxw161283 espi->intr_cnt.rx_ovflw++;
168*d39a76e7Sxw161283 if (status & F_RAMPARITYERR)
169*d39a76e7Sxw161283 espi->intr_cnt.parity_err++;
170*d39a76e7Sxw161283 if (status & F_DIP2PARITYERR) {
171*d39a76e7Sxw161283 espi->intr_cnt.DIP2_parity_err++;
172*d39a76e7Sxw161283 (void) t1_read_reg_4(espi->adapter, A_ESPI_DIP2_ERR_COUNT);
173*d39a76e7Sxw161283 }
174*d39a76e7Sxw161283
175*d39a76e7Sxw161283 /*
176*d39a76e7Sxw161283 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we
177*d39a76e7Sxw161283 * write the status as is.
178*d39a76e7Sxw161283 */
179*d39a76e7Sxw161283 if (status && t1_is_T1B(espi->adapter))
180*d39a76e7Sxw161283 status = 1;
181*d39a76e7Sxw161283 t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, status);
182*d39a76e7Sxw161283 return 0;
183*d39a76e7Sxw161283 }
184*d39a76e7Sxw161283
t1_espi_get_intr_counts(struct peespi * espi)185*d39a76e7Sxw161283 const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi)
186*d39a76e7Sxw161283 {
187*d39a76e7Sxw161283 return &espi->intr_cnt;
188*d39a76e7Sxw161283 }
189*d39a76e7Sxw161283
espi_setup_for_pm3393(adapter_t * adapter)190*d39a76e7Sxw161283 static void espi_setup_for_pm3393(adapter_t *adapter)
191*d39a76e7Sxw161283 {
192*d39a76e7Sxw161283 u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
193*d39a76e7Sxw161283
194*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4);
195*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f4);
196*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4);
197*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN3, 0x1f4);
198*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x100);
199*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, wmark);
200*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 3);
201*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_TRAIN, 0x08000008);
202*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_PORT_CONFIG,
203*d39a76e7Sxw161283 V_RX_NPORTS(1) | V_TX_NPORTS(1));
204*d39a76e7Sxw161283 }
205*d39a76e7Sxw161283
espi_setup_for_vsc7321(adapter_t * adapter)206*d39a76e7Sxw161283 static void espi_setup_for_vsc7321(adapter_t *adapter)
207*d39a76e7Sxw161283 {
208*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_COUGAR
209*d39a76e7Sxw161283 u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
210*d39a76e7Sxw161283
211*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4);
212*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f4);
213*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4);
214*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN3, 0x1f4);
215*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x100);
216*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, wmark);
217*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 3);
218*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_PORT_CONFIG,
219*d39a76e7Sxw161283 V_RX_NPORTS(1) | V_TX_NPORTS(1));
220*d39a76e7Sxw161283 #else
221*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4);
222*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f401f4);
223*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4);
224*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, 0xa00);
225*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x1ff);
226*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 1);
227*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_PORT_CONFIG,
228*d39a76e7Sxw161283 V_RX_NPORTS(4) | V_TX_NPORTS(4));
229*d39a76e7Sxw161283 #endif
230*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_TRAIN, 0x08000008);
231*d39a76e7Sxw161283 }
232*d39a76e7Sxw161283
233*d39a76e7Sxw161283 /*
234*d39a76e7Sxw161283 * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug.
235*d39a76e7Sxw161283 */
espi_setup_for_ixf1010(adapter_t * adapter,int nports)236*d39a76e7Sxw161283 static void espi_setup_for_ixf1010(adapter_t *adapter, int nports)
237*d39a76e7Sxw161283 {
238*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 1);
239*d39a76e7Sxw161283 if (nports == 4) {
240*d39a76e7Sxw161283 if (is_T2(adapter)) {
241*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK,
242*d39a76e7Sxw161283 0xf00);
243*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK,
244*d39a76e7Sxw161283 0x3c0);
245*d39a76e7Sxw161283 } else {
246*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK,
247*d39a76e7Sxw161283 0x7ff);
248*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK,
249*d39a76e7Sxw161283 0x1ff);
250*d39a76e7Sxw161283 }
251*d39a76e7Sxw161283 } else {
252*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK,
253*d39a76e7Sxw161283 0x1fff);
254*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK,
255*d39a76e7Sxw161283 0x7ff);
256*d39a76e7Sxw161283 }
257*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_PORT_CONFIG,
258*d39a76e7Sxw161283 V_RX_NPORTS(nports) | V_TX_NPORTS(nports));
259*d39a76e7Sxw161283 }
260*d39a76e7Sxw161283
t1_espi_init(struct peespi * espi,int mac_type,int nports)261*d39a76e7Sxw161283 int t1_espi_init(struct peespi *espi, int mac_type, int nports)
262*d39a76e7Sxw161283 {
263*d39a76e7Sxw161283 u32 status_enable_extra = 0;
264*d39a76e7Sxw161283 adapter_t *adapter = espi->adapter;
265*d39a76e7Sxw161283
266*d39a76e7Sxw161283 /* Disable ESPI training. MACs that can handle it enable it below. */
267*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_TRAIN, 0);
268*d39a76e7Sxw161283
269*d39a76e7Sxw161283 if (is_T2(adapter)) {
270*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
271*d39a76e7Sxw161283 V_OUT_OF_SYNC_COUNT(4) |
272*d39a76e7Sxw161283 V_DIP2_PARITY_ERR_THRES(3) | V_DIP4_THRES(1));
273*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MAXBURST1_MAXBURST2,
274*d39a76e7Sxw161283 nports == 4 ? 0x200040 : 0x1000080);
275*d39a76e7Sxw161283 } else
276*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MAXBURST1_MAXBURST2, 0x800100);
277*d39a76e7Sxw161283
278*d39a76e7Sxw161283 if (mac_type == CHBT_MAC_PM3393)
279*d39a76e7Sxw161283 espi_setup_for_pm3393(adapter);
280*d39a76e7Sxw161283 else if (mac_type == CHBT_MAC_VSC7321)
281*d39a76e7Sxw161283 espi_setup_for_vsc7321(adapter);
282*d39a76e7Sxw161283 else if (mac_type == CHBT_MAC_IXF1010) {
283*d39a76e7Sxw161283 status_enable_extra = F_INTEL1010MODE;
284*d39a76e7Sxw161283 espi_setup_for_ixf1010(adapter, nports);
285*d39a76e7Sxw161283 } else
286*d39a76e7Sxw161283 return -1;
287*d39a76e7Sxw161283
288*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_FIFO_STATUS_ENABLE,
289*d39a76e7Sxw161283 status_enable_extra | F_RXSTATUSENABLE);
290*d39a76e7Sxw161283
291*d39a76e7Sxw161283 if (is_T2(adapter)) {
292*d39a76e7Sxw161283 (void) tricn_init(adapter);
293*d39a76e7Sxw161283 /*
294*d39a76e7Sxw161283 * Always position the control at the 1st port egress IN
295*d39a76e7Sxw161283 * (sop,eop) counter to reduce PIOs for T/N210 workaround.
296*d39a76e7Sxw161283 */
297*d39a76e7Sxw161283 espi->misc_ctrl = t1_read_reg_4(adapter, A_ESPI_MISC_CONTROL);
298*d39a76e7Sxw161283 espi->misc_ctrl &= ~MON_MASK;
299*d39a76e7Sxw161283 espi->misc_ctrl |= F_MONITORED_DIRECTION;
300*d39a76e7Sxw161283 if (adapter->params.nports == 1)
301*d39a76e7Sxw161283 espi->misc_ctrl |= F_MONITORED_INTERFACE;
302*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl);
303*d39a76e7Sxw161283 SPIN_LOCK_INIT(espi->lock);
304*d39a76e7Sxw161283 }
305*d39a76e7Sxw161283
306*d39a76e7Sxw161283 return 0;
307*d39a76e7Sxw161283 }
308*d39a76e7Sxw161283
t1_espi_destroy(struct peespi * espi)309*d39a76e7Sxw161283 void t1_espi_destroy(struct peespi *espi)
310*d39a76e7Sxw161283 {
311*d39a76e7Sxw161283 if (is_T2(espi->adapter)) {
312*d39a76e7Sxw161283 SPIN_LOCK_DESTROY(espi->lock);
313*d39a76e7Sxw161283 }
314*d39a76e7Sxw161283 t1_os_free((void *)espi, sizeof(*espi));
315*d39a76e7Sxw161283 }
316*d39a76e7Sxw161283
t1_espi_create(adapter_t * adapter)317*d39a76e7Sxw161283 struct peespi *t1_espi_create(adapter_t *adapter)
318*d39a76e7Sxw161283 {
319*d39a76e7Sxw161283 struct peespi *espi = t1_os_malloc_wait_zero(sizeof(*espi));
320*d39a76e7Sxw161283
321*d39a76e7Sxw161283 if (espi)
322*d39a76e7Sxw161283 espi->adapter = adapter;
323*d39a76e7Sxw161283 return espi;
324*d39a76e7Sxw161283 }
325*d39a76e7Sxw161283
t1_espi_set_misc_ctrl(adapter_t * adapter,u32 val)326*d39a76e7Sxw161283 void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
327*d39a76e7Sxw161283 {
328*d39a76e7Sxw161283 struct peespi *espi = adapter->espi;
329*d39a76e7Sxw161283
330*d39a76e7Sxw161283 if (!is_T2(adapter))
331*d39a76e7Sxw161283 return;
332*d39a76e7Sxw161283 SPIN_LOCK(espi->lock);
333*d39a76e7Sxw161283 espi->misc_ctrl = (val & ~MON_MASK) |
334*d39a76e7Sxw161283 (espi->misc_ctrl & MON_MASK);
335*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl);
336*d39a76e7Sxw161283 SPIN_UNLOCK(espi->lock);
337*d39a76e7Sxw161283 }
338*d39a76e7Sxw161283
t1_espi_get_mon(adapter_t * adapter,u32 addr,u8 wait)339*d39a76e7Sxw161283 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
340*d39a76e7Sxw161283 {
341*d39a76e7Sxw161283 struct peespi *espi = adapter->espi;
342*d39a76e7Sxw161283 u32 sel;
343*d39a76e7Sxw161283
344*d39a76e7Sxw161283 if (!is_T2(adapter)) return 0;
345*d39a76e7Sxw161283 sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2);
346*d39a76e7Sxw161283 if (!wait) {
347*d39a76e7Sxw161283 if (!SPIN_TRYLOCK(espi->lock))
348*d39a76e7Sxw161283 return 0;
349*d39a76e7Sxw161283 }
350*d39a76e7Sxw161283 else
351*d39a76e7Sxw161283 SPIN_LOCK(espi->lock);
352*d39a76e7Sxw161283 if ((sel != (espi->misc_ctrl & MON_MASK))) {
353*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
354*d39a76e7Sxw161283 ((espi->misc_ctrl & ~MON_MASK) | sel));
355*d39a76e7Sxw161283 sel = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3);
356*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
357*d39a76e7Sxw161283 espi->misc_ctrl);
358*d39a76e7Sxw161283 }
359*d39a76e7Sxw161283 else
360*d39a76e7Sxw161283 sel = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3);
361*d39a76e7Sxw161283 SPIN_UNLOCK(espi->lock);
362*d39a76e7Sxw161283 return sel;
363*d39a76e7Sxw161283 }
364*d39a76e7Sxw161283
365*d39a76e7Sxw161283 /*
366*d39a76e7Sxw161283 * This function is for T204 only.
367*d39a76e7Sxw161283 * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
368*d39a76e7Sxw161283 * one shot, since there is no per port counter on the out side.
369*d39a76e7Sxw161283 */
370*d39a76e7Sxw161283 int
t1_espi_get_mon_t204(adapter_t * adapter,u32 * valp,u8 wait)371*d39a76e7Sxw161283 t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
372*d39a76e7Sxw161283 {
373*d39a76e7Sxw161283 struct peespi *espi = adapter->espi;
374*d39a76e7Sxw161283 u8 i, nport = (u8)adapter->params.nports;
375*d39a76e7Sxw161283
376*d39a76e7Sxw161283 if (!wait) {
377*d39a76e7Sxw161283 if (!SPIN_TRYLOCK(espi->lock))
378*d39a76e7Sxw161283 return -1;
379*d39a76e7Sxw161283 } else
380*d39a76e7Sxw161283 SPIN_LOCK(espi->lock);
381*d39a76e7Sxw161283 if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
382*d39a76e7Sxw161283 espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
383*d39a76e7Sxw161283 F_MONITORED_DIRECTION;
384*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl);
385*d39a76e7Sxw161283 }
386*d39a76e7Sxw161283 for (i = 0 ; i < nport; i++, valp++) {
387*d39a76e7Sxw161283 if (i) {
388*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
389*d39a76e7Sxw161283 (espi->misc_ctrl | V_MONITORED_PORT_NUM(i)));
390*d39a76e7Sxw161283 }
391*d39a76e7Sxw161283 *valp = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3);
392*d39a76e7Sxw161283 }
393*d39a76e7Sxw161283
394*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl);
395*d39a76e7Sxw161283
396*d39a76e7Sxw161283 SPIN_UNLOCK(espi->lock);
397*d39a76e7Sxw161283 return 0;
398*d39a76e7Sxw161283 }
399