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, see <http://www.gnu.org/licenses/>. *
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED *
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
21 * http://www.chelsio.com *
23 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *
24 * All rights reserved. *
26 * Maintainers: maintainers@chelsio.com *
28 * Authors: Dimitrios Michailidis <dm@chelsio.com> *
29 * Tina Yang <tainay@chelsio.com> *
30 * Felix Marti <felix@chelsio.com> *
31 * Scott Bardone <sbardone@chelsio.com> *
32 * Kurt Ottaway <kottaway@chelsio.com> *
33 * Frank DiMambro <frank@chelsio.com> *
37 ****************************************************************************/
45 struct espi_intr_counts intr_cnt
;
50 #define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \
51 F_RAMPARITYERR | F_DIP2PARITYERR)
52 #define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \
53 | F_MONITORED_INTERFACE)
56 #define TRICN_CMD_READ 0x11
57 #define TRICN_CMD_WRITE 0x21
58 #define TRICN_CMD_ATTEMPTS 10
60 static int tricn_write(adapter_t
*adapter
, int bundle_addr
, int module_addr
,
61 int ch_addr
, int reg_offset
, u32 wr_data
)
63 int busy
, attempts
= TRICN_CMD_ATTEMPTS
;
65 writel(V_WRITE_DATA(wr_data
) |
66 V_REGISTER_OFFSET(reg_offset
) |
67 V_CHANNEL_ADDR(ch_addr
) | V_MODULE_ADDR(module_addr
) |
68 V_BUNDLE_ADDR(bundle_addr
) |
69 V_SPI4_COMMAND(TRICN_CMD_WRITE
),
70 adapter
->regs
+ A_ESPI_CMD_ADDR
);
71 writel(0, adapter
->regs
+ A_ESPI_GOSTAT
);
74 busy
= readl(adapter
->regs
+ A_ESPI_GOSTAT
) & F_ESPI_CMD_BUSY
;
75 } while (busy
&& --attempts
);
78 pr_err("%s: TRICN write timed out\n", adapter
->name
);
83 static int tricn_init(adapter_t
*adapter
)
87 if (!(readl(adapter
->regs
+ A_ESPI_RX_RESET
) & F_RX_CLK_STATUS
)) {
88 pr_err("%s: ESPI clock not ready\n", adapter
->name
);
92 writel(F_ESPI_RX_CORE_RST
, adapter
->regs
+ A_ESPI_RX_RESET
);
95 tricn_write(adapter
, 0, 0, 0, TRICN_CNFG
, 0x81);
96 tricn_write(adapter
, 0, 1, 0, TRICN_CNFG
, 0x81);
97 tricn_write(adapter
, 0, 2, 0, TRICN_CNFG
, 0x81);
99 for (i
= 1; i
<= 8; i
++)
100 tricn_write(adapter
, 0, 0, i
, TRICN_CNFG
, 0xf1);
101 for (i
= 1; i
<= 2; i
++)
102 tricn_write(adapter
, 0, 1, i
, TRICN_CNFG
, 0xf1);
103 for (i
= 1; i
<= 3; i
++)
104 tricn_write(adapter
, 0, 2, i
, TRICN_CNFG
, 0xe1);
105 tricn_write(adapter
, 0, 2, 4, TRICN_CNFG
, 0xf1);
106 tricn_write(adapter
, 0, 2, 5, TRICN_CNFG
, 0xe1);
107 tricn_write(adapter
, 0, 2, 6, TRICN_CNFG
, 0xf1);
108 tricn_write(adapter
, 0, 2, 7, TRICN_CNFG
, 0x80);
109 tricn_write(adapter
, 0, 2, 8, TRICN_CNFG
, 0xf1);
111 writel(F_ESPI_RX_CORE_RST
| F_ESPI_RX_LNK_RST
,
112 adapter
->regs
+ A_ESPI_RX_RESET
);
117 void t1_espi_intr_enable(struct peespi
*espi
)
119 u32 enable
, pl_intr
= readl(espi
->adapter
->regs
+ A_PL_ENABLE
);
122 * Cannot enable ESPI interrupts on T1B because HW asserts the
123 * interrupt incorrectly, namely the driver gets ESPI interrupts
124 * but no data is actually dropped (can verify this reading the ESPI
125 * drop registers). Also, once the ESPI interrupt is asserted it
126 * cannot be cleared (HW bug).
128 enable
= t1_is_T1B(espi
->adapter
) ? 0 : ESPI_INTR_MASK
;
129 writel(enable
, espi
->adapter
->regs
+ A_ESPI_INTR_ENABLE
);
130 writel(pl_intr
| F_PL_INTR_ESPI
, espi
->adapter
->regs
+ A_PL_ENABLE
);
133 void t1_espi_intr_clear(struct peespi
*espi
)
135 readl(espi
->adapter
->regs
+ A_ESPI_DIP2_ERR_COUNT
);
136 writel(0xffffffff, espi
->adapter
->regs
+ A_ESPI_INTR_STATUS
);
137 writel(F_PL_INTR_ESPI
, espi
->adapter
->regs
+ A_PL_CAUSE
);
140 void t1_espi_intr_disable(struct peespi
*espi
)
142 u32 pl_intr
= readl(espi
->adapter
->regs
+ A_PL_ENABLE
);
144 writel(0, espi
->adapter
->regs
+ A_ESPI_INTR_ENABLE
);
145 writel(pl_intr
& ~F_PL_INTR_ESPI
, espi
->adapter
->regs
+ A_PL_ENABLE
);
148 int t1_espi_intr_handler(struct peespi
*espi
)
150 u32 status
= readl(espi
->adapter
->regs
+ A_ESPI_INTR_STATUS
);
152 if (status
& F_DIP4ERR
)
153 espi
->intr_cnt
.DIP4_err
++;
154 if (status
& F_RXDROP
)
155 espi
->intr_cnt
.rx_drops
++;
156 if (status
& F_TXDROP
)
157 espi
->intr_cnt
.tx_drops
++;
158 if (status
& F_RXOVERFLOW
)
159 espi
->intr_cnt
.rx_ovflw
++;
160 if (status
& F_RAMPARITYERR
)
161 espi
->intr_cnt
.parity_err
++;
162 if (status
& F_DIP2PARITYERR
) {
163 espi
->intr_cnt
.DIP2_parity_err
++;
166 * Must read the error count to clear the interrupt
169 readl(espi
->adapter
->regs
+ A_ESPI_DIP2_ERR_COUNT
);
173 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we
174 * write the status as is.
176 if (status
&& t1_is_T1B(espi
->adapter
))
178 writel(status
, espi
->adapter
->regs
+ A_ESPI_INTR_STATUS
);
182 const struct espi_intr_counts
*t1_espi_get_intr_counts(struct peespi
*espi
)
184 return &espi
->intr_cnt
;
187 static void espi_setup_for_pm3393(adapter_t
*adapter
)
189 u32 wmark
= t1_is_T1B(adapter
) ? 0x4000 : 0x3200;
191 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN0
);
192 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN1
);
193 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN2
);
194 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
195 writel(0x100, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
196 writel(wmark
, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
197 writel(3, adapter
->regs
+ A_ESPI_CALENDAR_LENGTH
);
198 writel(0x08000008, adapter
->regs
+ A_ESPI_TRAIN
);
199 writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter
->regs
+ A_PORT_CONFIG
);
202 static void espi_setup_for_vsc7321(adapter_t
*adapter
)
204 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN0
);
205 writel(0x1f401f4, adapter
->regs
+ A_ESPI_SCH_TOKEN1
);
206 writel(0x1f4, adapter
->regs
+ A_ESPI_SCH_TOKEN2
);
207 writel(0xa00, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
208 writel(0x1ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
209 writel(1, adapter
->regs
+ A_ESPI_CALENDAR_LENGTH
);
210 writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter
->regs
+ A_PORT_CONFIG
);
212 writel(0x08000008, adapter
->regs
+ A_ESPI_TRAIN
);
216 * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug.
218 static void espi_setup_for_ixf1010(adapter_t
*adapter
, int nports
)
220 writel(1, adapter
->regs
+ A_ESPI_CALENDAR_LENGTH
);
222 if (is_T2(adapter
)) {
223 writel(0xf00, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
224 writel(0x3c0, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
226 writel(0x7ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
227 writel(0x1ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
230 writel(0x1fff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK
);
231 writel(0x7ff, adapter
->regs
+ A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK
);
233 writel(V_RX_NPORTS(nports
) | V_TX_NPORTS(nports
), adapter
->regs
+ A_PORT_CONFIG
);
237 int t1_espi_init(struct peespi
*espi
, int mac_type
, int nports
)
239 u32 status_enable_extra
= 0;
240 adapter_t
*adapter
= espi
->adapter
;
242 /* Disable ESPI training. MACs that can handle it enable it below. */
243 writel(0, adapter
->regs
+ A_ESPI_TRAIN
);
245 if (is_T2(adapter
)) {
246 writel(V_OUT_OF_SYNC_COUNT(4) |
247 V_DIP2_PARITY_ERR_THRES(3) |
248 V_DIP4_THRES(1), adapter
->regs
+ A_ESPI_MISC_CONTROL
);
249 writel(nports
== 4 ? 0x200040 : 0x1000080,
250 adapter
->regs
+ A_ESPI_MAXBURST1_MAXBURST2
);
252 writel(0x800100, adapter
->regs
+ A_ESPI_MAXBURST1_MAXBURST2
);
254 if (mac_type
== CHBT_MAC_PM3393
)
255 espi_setup_for_pm3393(adapter
);
256 else if (mac_type
== CHBT_MAC_VSC7321
)
257 espi_setup_for_vsc7321(adapter
);
258 else if (mac_type
== CHBT_MAC_IXF1010
) {
259 status_enable_extra
= F_INTEL1010MODE
;
260 espi_setup_for_ixf1010(adapter
, nports
);
264 writel(status_enable_extra
| F_RXSTATUSENABLE
,
265 adapter
->regs
+ A_ESPI_FIFO_STATUS_ENABLE
);
267 if (is_T2(adapter
)) {
270 * Always position the control at the 1st port egress IN
271 * (sop,eop) counter to reduce PIOs for T/N210 workaround.
273 espi
->misc_ctrl
= readl(adapter
->regs
+ A_ESPI_MISC_CONTROL
);
274 espi
->misc_ctrl
&= ~MON_MASK
;
275 espi
->misc_ctrl
|= F_MONITORED_DIRECTION
;
276 if (adapter
->params
.nports
== 1)
277 espi
->misc_ctrl
|= F_MONITORED_INTERFACE
;
278 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
279 spin_lock_init(&espi
->lock
);
285 void t1_espi_destroy(struct peespi
*espi
)
290 struct peespi
*t1_espi_create(adapter_t
*adapter
)
292 struct peespi
*espi
= kzalloc(sizeof(*espi
), GFP_KERNEL
);
295 espi
->adapter
= adapter
;
300 void t1_espi_set_misc_ctrl(adapter_t
*adapter
, u32 val
)
302 struct peespi
*espi
= adapter
->espi
;
306 spin_lock(&espi
->lock
);
307 espi
->misc_ctrl
= (val
& ~MON_MASK
) |
308 (espi
->misc_ctrl
& MON_MASK
);
309 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
310 spin_unlock(&espi
->lock
);
314 u32
t1_espi_get_mon(adapter_t
*adapter
, u32 addr
, u8 wait
)
316 struct peespi
*espi
= adapter
->espi
;
322 sel
= V_MONITORED_PORT_NUM((addr
& 0x3c) >> 2);
324 if (!spin_trylock(&espi
->lock
))
327 spin_lock(&espi
->lock
);
329 if ((sel
!= (espi
->misc_ctrl
& MON_MASK
))) {
330 writel(((espi
->misc_ctrl
& ~MON_MASK
) | sel
),
331 adapter
->regs
+ A_ESPI_MISC_CONTROL
);
332 sel
= readl(adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
333 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
335 sel
= readl(adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
336 spin_unlock(&espi
->lock
);
341 * This function is for T204 only.
342 * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
343 * one shot, since there is no per port counter on the out side.
345 int t1_espi_get_mon_t204(adapter_t
*adapter
, u32
*valp
, u8 wait
)
347 struct peespi
*espi
= adapter
->espi
;
348 u8 i
, nport
= (u8
)adapter
->params
.nports
;
351 if (!spin_trylock(&espi
->lock
))
354 spin_lock(&espi
->lock
);
356 if ((espi
->misc_ctrl
& MON_MASK
) != F_MONITORED_DIRECTION
) {
357 espi
->misc_ctrl
= (espi
->misc_ctrl
& ~MON_MASK
) |
358 F_MONITORED_DIRECTION
;
359 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
361 for (i
= 0 ; i
< nport
; i
++, valp
++) {
363 writel(espi
->misc_ctrl
| V_MONITORED_PORT_NUM(i
),
364 adapter
->regs
+ A_ESPI_MISC_CONTROL
);
366 *valp
= readl(adapter
->regs
+ A_ESPI_SCH_TOKEN3
);
369 writel(espi
->misc_ctrl
, adapter
->regs
+ A_ESPI_MISC_CONTROL
);
370 spin_unlock(&espi
->lock
);