1 /*****************************************************************************
5 * $Date: 2005/05/14 00:59:32 $ *
7 * Ethernet SPI functionality. *
8 * part of the Chelsio 10Gb Ethernet Driver. *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License, version 2, as *
12 * published by the Free Software Foundation. *
14 * You should have received a copy of the GNU General Public License along *
15 * with this program; if not, write to the Free Software Foundation, Inc., *
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED *
19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
22 * http://www.chelsio.com *
24 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *
25 * All rights reserved. *
27 * Maintainers: maintainers@chelsio.com *
29 * Authors: Dimitrios Michailidis <dm@chelsio.com> *
30 * Tina Yang <tainay@chelsio.com> *
31 * Felix Marti <felix@chelsio.com> *
32 * Scott Bardone <sbardone@chelsio.com> *
33 * Kurt Ottaway <kottaway@chelsio.com> *
34 * Frank DiMambro <frank@chelsio.com> *
38 ****************************************************************************/
46 struct espi_intr_counts intr_cnt
;
51 #define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \
52 F_RAMPARITYERR | F_DIP2PARITYERR)
53 #define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \
54 | F_MONITORED_INTERFACE)
57 #define TRICN_CMD_READ 0x11
58 #define TRICN_CMD_WRITE 0x21
59 #define TRICN_CMD_ATTEMPTS 10
61 static int tricn_write(adapter_t
*adapter
, int bundle_addr
, int module_addr
,
62 int ch_addr
, int reg_offset
, u32 wr_data
)
64 int busy
, attempts
= TRICN_CMD_ATTEMPTS
;
66 writel(V_WRITE_DATA(wr_data
) |
67 V_REGISTER_OFFSET(reg_offset
) |
68 V_CHANNEL_ADDR(ch_addr
) | V_MODULE_ADDR(module_addr
) |
69 V_BUNDLE_ADDR(bundle_addr
) |
70 V_SPI4_COMMAND(TRICN_CMD_WRITE
),
71 adapter
->regs
+ A_ESPI_CMD_ADDR
);
72 writel(0, adapter
->regs
+ A_ESPI_GOSTAT
);
75 busy
= readl(adapter
->regs
+ A_ESPI_GOSTAT
) & F_ESPI_CMD_BUSY
;
76 } while (busy
&& --attempts
);
79 CH_ERR("%s: TRICN write timed out\n", adapter
->name
);
84 static int tricn_init(adapter_t
*adapter
)
88 if (!(readl(adapter
->regs
+ A_ESPI_RX_RESET
) & F_RX_CLK_STATUS
)) {
89 CH_ERR("%s: ESPI clock not ready\n", adapter
->name
);
93 writel(F_ESPI_RX_CORE_RST
, adapter
->regs
+ A_ESPI_RX_RESET
);
96 tricn_write(adapter
, 0, 0, 0, TRICN_CNFG
, 0x81);
97 tricn_write(adapter
, 0, 1, 0, TRICN_CNFG
, 0x81);
98 tricn_write(adapter
, 0, 2, 0, TRICN_CNFG
, 0x81);
100 for (i
= 1; i
<= 8; i
++)
101 tricn_write(adapter
, 0, 0, i
, TRICN_CNFG
, 0xf1);
102 for (i
= 1; i
<= 2; i
++)
103 tricn_write(adapter
, 0, 1, i
, TRICN_CNFG
, 0xf1);
104 for (i
= 1; i
<= 3; i
++)
105 tricn_write(adapter
, 0, 2, i
, TRICN_CNFG
, 0xe1);
106 tricn_write(adapter
, 0, 2, 4, TRICN_CNFG
, 0xf1);
107 tricn_write(adapter
, 0, 2, 5, TRICN_CNFG
, 0xe1);
108 tricn_write(adapter
, 0, 2, 6, TRICN_CNFG
, 0xf1);
109 tricn_write(adapter
, 0, 2, 7, TRICN_CNFG
, 0x80);
110 tricn_write(adapter
, 0, 2, 8, TRICN_CNFG
, 0xf1);
112 writel(F_ESPI_RX_CORE_RST
| F_ESPI_RX_LNK_RST
,
113 adapter
->regs
+ A_ESPI_RX_RESET
);
118 void t1_espi_intr_enable(struct peespi
*espi
)
120 u32 enable
, pl_intr
= readl(espi
->adapter
->regs
+ A_PL_ENABLE
);
123 * Cannot enable ESPI interrupts on T1B because HW asserts the
124 * interrupt incorrectly, namely the driver gets ESPI interrupts
125 * but no data is actually dropped (can verify this reading the ESPI
126 * drop registers). Also, once the ESPI interrupt is asserted it
127 * cannot be cleared (HW bug).
129 enable
= t1_is_T1B(espi
->adapter
) ? 0 : ESPI_INTR_MASK
;
130 writel(enable
, espi
->adapter
->regs
+ A_ESPI_INTR_ENABLE
);
131 writel(pl_intr
| F_PL_INTR_ESPI
, espi
->adapter
->regs
+ A_PL_ENABLE
);
134 void t1_espi_intr_clear(struct peespi
*espi
)
136 readl(espi
->adapter
->regs
+ A_ESPI_DIP2_ERR_COUNT
);
137 writel(0xffffffff, espi
->adapter
->regs
+ A_ESPI_INTR_STATUS
);
138 writel(F_PL_INTR_ESPI
, espi
->adapter
->regs
+ A_PL_CAUSE
);
141 void t1_espi_intr_disable(struct peespi
*espi
)
143 u32 pl_intr
= readl(espi
->adapter
->regs
+ A_PL_ENABLE
);
145 writel(0, espi
->adapter
->regs
+ A_ESPI_INTR_ENABLE
);
146 writel(pl_intr
& ~F_PL_INTR_ESPI
, espi
->adapter
->regs
+ A_PL_ENABLE
);
149 int t1_espi_intr_handler(struct peespi
*espi
)
151 u32 status
= readl(espi
->adapter
->regs
+ A_ESPI_INTR_STATUS
);
153 if (status
& F_DIP4ERR
)
154 espi
->intr_cnt
.DIP4_err
++;
155 if (status
& F_RXDROP
)
156 espi
->intr_cnt
.rx_drops
++;
157 if (status
& F_TXDROP
)
158 espi
->intr_cnt
.tx_drops
++;
159 if (status
& F_RXOVERFLOW
)
160 espi
->intr_cnt
.rx_ovflw
++;
161 if (status
& F_RAMPARITYERR
)
162 espi
->intr_cnt
.parity_err
++;
163 if (status
& F_DIP2PARITYERR
) {
164 espi
->intr_cnt
.DIP2_parity_err
++;
167 * Must read the error count to clear the interrupt
170 readl(espi
->adapter
->regs
+ A_ESPI_DIP2_ERR_COUNT
);
174 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we
175 * write the status as is.
177 if (status
&& t1_is_T1B(espi
->adapter
))
179 writel(status
, espi
->adapter
->regs
+ A_ESPI_INTR_STATUS
);
183 const struct espi_intr_counts
*t1_espi_get_intr_counts(struct peespi
*espi
)
185 return &espi
->intr_cnt
;
188 static void espi_setup_for_pm3393(adapter_t
*adapter
)
190 u32 wmark
= t1_is_T1B(adapter
) ? 0x4000 : 0x3200;
192 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN0
);
193 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN1
);
194 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN2
);
195 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
196 writel(0x100, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
197 writel(wmark
, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
198 writel(3, adapter
->regs
+ A_ESPI_CALENDAR_LENGTH
);
199 writel(0x08000008, adapter
->regs
+ A_ESPI_TRAIN
);
200 writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter
->regs
+ A_PORT_CONFIG
);
203 static void espi_setup_for_vsc7321(adapter_t
*adapter
)
205 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN0
);
206 writel(0x1f401f4, adapter
->regs
+ A_ESPI_SCH_TOKEN1
);
207 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN2
);
208 writel(0xa00, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
209 writel(0x1ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
210 writel(1, adapter
->regs
+ A_ESPI_CALENDAR_LENGTH
);
211 writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter
->regs
+ A_PORT_CONFIG
);
213 writel(0x08000008, adapter
->regs
+ A_ESPI_TRAIN
);
217 * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug.
219 static void espi_setup_for_ixf1010(adapter_t
*adapter
, int nports
)
221 writel(1, adapter
->regs
+ A_ESPI_CALENDAR_LENGTH
);
223 if (is_T2(adapter
)) {
224 writel(0xf00, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
225 writel(0x3c0, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
227 writel(0x7ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
228 writel(0x1ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
231 writel(0x1fff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
232 writel(0x7ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
234 writel(V_RX_NPORTS(nports
) | V_TX_NPORTS(nports
), adapter
->regs
+ A_PORT_CONFIG
);
238 int t1_espi_init(struct peespi
*espi
, int mac_type
, int nports
)
240 u32 status_enable_extra
= 0;
241 adapter_t
*adapter
= espi
->adapter
;
243 /* Disable ESPI training. MACs that can handle it enable it below. */
244 writel(0, adapter
->regs
+ A_ESPI_TRAIN
);
246 if (is_T2(adapter
)) {
247 writel(V_OUT_OF_SYNC_COUNT(4) |
248 V_DIP2_PARITY_ERR_THRES(3) |
249 V_DIP4_THRES(1), adapter
->regs
+ A_ESPI_MISC_CONTROL
);
250 writel(nports
== 4 ? 0x200040 : 0x1000080,
251 adapter
->regs
+ A_ESPI_MAXBURST1_MAXBURST2
);
253 writel(0x800100, adapter
->regs
+ A_ESPI_MAXBURST1_MAXBURST2
);
255 if (mac_type
== CHBT_MAC_PM3393
)
256 espi_setup_for_pm3393(adapter
);
257 else if (mac_type
== CHBT_MAC_VSC7321
)
258 espi_setup_for_vsc7321(adapter
);
259 else if (mac_type
== CHBT_MAC_IXF1010
) {
260 status_enable_extra
= F_INTEL1010MODE
;
261 espi_setup_for_ixf1010(adapter
, nports
);
265 writel(status_enable_extra
| F_RXSTATUSENABLE
,
266 adapter
->regs
+ A_ESPI_FIFO_STATUS_ENABLE
);
268 if (is_T2(adapter
)) {
271 * Always position the control at the 1st port egress IN
272 * (sop,eop) counter to reduce PIOs for T/N210 workaround.
274 espi
->misc_ctrl
= readl(adapter
->regs
+ A_ESPI_MISC_CONTROL
);
275 espi
->misc_ctrl
&= ~MON_MASK
;
276 espi
->misc_ctrl
|= F_MONITORED_DIRECTION
;
277 if (adapter
->params
.nports
== 1)
278 espi
->misc_ctrl
|= F_MONITORED_INTERFACE
;
279 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
280 spin_lock_init(&espi
->lock
);
286 void t1_espi_destroy(struct peespi
*espi
)
291 struct peespi
*t1_espi_create(adapter_t
*adapter
)
293 struct peespi
*espi
= kzalloc(sizeof(*espi
), GFP_KERNEL
);
296 espi
->adapter
= adapter
;
301 void t1_espi_set_misc_ctrl(adapter_t
*adapter
, u32 val
)
303 struct peespi
*espi
= adapter
->espi
;
307 spin_lock(&espi
->lock
);
308 espi
->misc_ctrl
= (val
& ~MON_MASK
) |
309 (espi
->misc_ctrl
& MON_MASK
);
310 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
311 spin_unlock(&espi
->lock
);
315 u32
t1_espi_get_mon(adapter_t
*adapter
, u32 addr
, u8 wait
)
317 struct peespi
*espi
= adapter
->espi
;
323 sel
= V_MONITORED_PORT_NUM((addr
& 0x3c) >> 2);
325 if (!spin_trylock(&espi
->lock
))
328 spin_lock(&espi
->lock
);
330 if ((sel
!= (espi
->misc_ctrl
& MON_MASK
))) {
331 writel(((espi
->misc_ctrl
& ~MON_MASK
) | sel
),
332 adapter
->regs
+ A_ESPI_MISC_CONTROL
);
333 sel
= readl(adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
334 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
336 sel
= readl(adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
337 spin_unlock(&espi
->lock
);
342 * This function is for T204 only.
343 * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
344 * one shot, since there is no per port counter on the out side.
346 int t1_espi_get_mon_t204(adapter_t
*adapter
, u32
*valp
, u8 wait
)
348 struct peespi
*espi
= adapter
->espi
;
349 u8 i
, nport
= (u8
)adapter
->params
.nports
;
352 if (!spin_trylock(&espi
->lock
))
355 spin_lock(&espi
->lock
);
357 if ((espi
->misc_ctrl
& MON_MASK
) != F_MONITORED_DIRECTION
) {
358 espi
->misc_ctrl
= (espi
->misc_ctrl
& ~MON_MASK
) |
359 F_MONITORED_DIRECTION
;
360 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
362 for (i
= 0 ; i
< nport
; i
++, valp
++) {
364 writel(espi
->misc_ctrl
| V_MONITORED_PORT_NUM(i
),
365 adapter
->regs
+ A_ESPI_MISC_CONTROL
);
367 *valp
= readl(adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
370 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
371 spin_unlock(&espi
->lock
);