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