[PATCH] A new 10GB Ethernet Driver by Chelsio Communications
[linux-2.6] / drivers / net / chelsio / espi.c
1 /*****************************************************************************
2  *                                                                           *
3  * File: espi.c                                                              *
4  * $Revision: 1.9 $                                                          *
5  * $Date: 2005/03/23 07:41:27 $                                              *
6  * Description:                                                              *
7  *  Ethernet SPI functionality.                                              *
8  *  part of the Chelsio 10Gb Ethernet Driver.                                *
9  *                                                                           *
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.                                *
13  *                                                                           *
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.                 *
17  *                                                                           *
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.                     *
21  *                                                                           *
22  * http://www.chelsio.com                                                    *
23  *                                                                           *
24  * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    *
25  * All rights reserved.                                                      *
26  *                                                                           *
27  * Maintainers: maintainers@chelsio.com                                      *
28  *                                                                           *
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>                      *
35  *                                                                           *
36  * History:                                                                  *
37  *                                                                           *
38  ****************************************************************************/
39
40 #include "common.h"
41 #include "regs.h"
42 #include "espi.h"
43
44 struct peespi {
45         adapter_t *adapter;
46         struct espi_intr_counts intr_cnt;
47         u32 misc_ctrl;
48         spinlock_t lock;
49 };
50
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)
55
56 #define TRICN_CNFG 14
57 #define TRICN_CMD_READ  0x11
58 #define TRICN_CMD_WRITE 0x21
59 #define TRICN_CMD_ATTEMPTS 10
60
61 static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr,
62                        int ch_addr, int reg_offset, u32 wr_data)
63 {
64         int busy, attempts = TRICN_CMD_ATTEMPTS;
65
66         t1_write_reg_4(adapter, A_ESPI_CMD_ADDR, 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         t1_write_reg_4(adapter, A_ESPI_GOSTAT, 0);
72
73         do {
74                 busy = t1_read_reg_4(adapter, A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY;
75         } while (busy && --attempts);
76
77         if (busy)
78                 CH_ERR("%s: TRICN write timed out\n", adapter->name);
79
80         return busy;
81 }
82
83 /* 1. Deassert rx_reset_core. */
84 /* 2. Program TRICN_CNFG registers. */
85 /* 3. Deassert rx_reset_link */
86 static int tricn_init(adapter_t *adapter)
87 {
88         int     i               = 0;
89         int     sme             = 1;
90         int     stat            = 0;
91         int     timeout         = 0;
92         int     is_ready        = 0;
93         int     dynamic_deskew  = 0;
94
95         if (dynamic_deskew)
96                 sme = 0;
97
98
99         /* 1 */
100         timeout=1000;
101         do {
102                 stat = t1_read_reg_4(adapter, A_ESPI_RX_RESET);
103                 is_ready = (stat & 0x4);
104                 timeout--;
105                 udelay(5);
106         } while (!is_ready || (timeout==0));
107         t1_write_reg_4(adapter, A_ESPI_RX_RESET, 0x2);
108         if (timeout==0)
109         {
110                 CH_ERR("ESPI : ERROR : Timeout tricn_init() \n");
111                 t1_fatal_err(adapter);
112         }
113
114         /* 2 */
115         if (sme) {
116                 tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81);
117                 tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81);
118                 tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81);
119         }
120         for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1);
121         for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1);
122         for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
123         for (i=4; i<= 4; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
124         for (i=5; i<= 5; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1);
125         for (i=6; i<= 6; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
126         for (i=7; i<= 7; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0x80);
127         for (i=8; i<= 8; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1);
128
129         /* 3 */
130         t1_write_reg_4(adapter, A_ESPI_RX_RESET, 0x3);
131
132         return 0;
133 }
134
135 void t1_espi_intr_enable(struct peespi *espi)
136 {
137         u32 enable, pl_intr = t1_read_reg_4(espi->adapter, A_PL_ENABLE);
138
139         /*
140          * Cannot enable ESPI interrupts on T1B because HW asserts the
141          * interrupt incorrectly, namely the driver gets ESPI interrupts
142          * but no data is actually dropped (can verify this reading the ESPI
143          * drop registers).  Also, once the ESPI interrupt is asserted it
144          * cannot be cleared (HW bug).
145          */
146         enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK;
147         t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, enable);
148         t1_write_reg_4(espi->adapter, A_PL_ENABLE, pl_intr | F_PL_INTR_ESPI);
149 }
150
151 void t1_espi_intr_clear(struct peespi *espi)
152 {
153         t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, 0xffffffff);
154         t1_write_reg_4(espi->adapter, A_PL_CAUSE, F_PL_INTR_ESPI);
155 }
156
157 void t1_espi_intr_disable(struct peespi *espi)
158 {
159         u32 pl_intr = t1_read_reg_4(espi->adapter, A_PL_ENABLE);
160
161         t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, 0);
162         t1_write_reg_4(espi->adapter, A_PL_ENABLE, pl_intr & ~F_PL_INTR_ESPI);
163 }
164
165 int t1_espi_intr_handler(struct peespi *espi)
166 {
167         u32 cnt;
168         u32 status = t1_read_reg_4(espi->adapter, A_ESPI_INTR_STATUS);
169
170         if (status & F_DIP4ERR)
171                 espi->intr_cnt.DIP4_err++;
172         if (status & F_RXDROP)
173                 espi->intr_cnt.rx_drops++;
174         if (status & F_TXDROP)
175                 espi->intr_cnt.tx_drops++;
176         if (status & F_RXOVERFLOW)
177                 espi->intr_cnt.rx_ovflw++;
178         if (status & F_RAMPARITYERR)
179                 espi->intr_cnt.parity_err++;
180         if (status & F_DIP2PARITYERR) {
181                 espi->intr_cnt.DIP2_parity_err++;
182
183                 /*
184                  * Must read the error count to clear the interrupt
185                  * that it causes.
186                  */
187                 cnt = t1_read_reg_4(espi->adapter, A_ESPI_DIP2_ERR_COUNT);
188         }
189
190         /*
191          * For T1B we need to write 1 to clear ESPI interrupts.  For T2+ we
192          * write the status as is.
193          */
194         if (status && t1_is_T1B(espi->adapter))
195                 status = 1;
196         t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, status);
197         return 0;
198 }
199
200 static void espi_setup_for_pm3393(adapter_t *adapter)
201 {
202         u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
203
204         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4);
205         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f4);
206         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4);
207         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN3, 0x1f4);
208         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x100);
209         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, wmark);
210         t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 3);
211         t1_write_reg_4(adapter, A_ESPI_TRAIN, 0x08000008);
212         t1_write_reg_4(adapter, A_PORT_CONFIG,
213                        V_RX_NPORTS(1) | V_TX_NPORTS(1));
214 }
215
216 static void espi_setup_for_vsc7321(adapter_t *adapter)
217 {
218         u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200;
219
220         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4);
221         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f4);
222         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4);
223         t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN3, 0x1f4);
224         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x100);
225         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, wmark);
226         t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 3);
227         t1_write_reg_4(adapter, A_ESPI_TRAIN, 0x08000008);
228         t1_write_reg_4(adapter, A_PORT_CONFIG,
229                        V_RX_NPORTS(1) | V_TX_NPORTS(1));
230 }
231
232 /*
233  * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug.
234  */
235 static void espi_setup_for_ixf1010(adapter_t *adapter, int nports)
236 {
237         t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 1);
238         if (nports == 4) {
239                 if (is_T2(adapter)) {
240                         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK,
241                                 0xf00);
242                         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK,
243                                 0x3c0);
244                 } else {
245                         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK,
246                                0x7ff);
247                         t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK,
248                                0x1ff);
249                 }
250         } else {
251                 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK,
252                                0x1fff);
253                 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK,
254                                0x7ff);
255         }
256         t1_write_reg_4(adapter, A_PORT_CONFIG,
257                        V_RX_NPORTS(nports) | V_TX_NPORTS(nports));
258 }
259
260 /* T2 Init part --  */
261 /* 1. Set T_ESPI_MISCCTRL_ADDR */
262 /* 2. Init ESPI registers. */
263 /* 3. Init TriCN Hard Macro */
264 int t1_espi_init(struct peespi *espi, int mac_type, int nports)
265 {
266         u32 status_enable_extra = 0;
267         adapter_t *adapter = espi->adapter;
268         u32 cnt;
269         u32 status, burstval = 0x800100;
270
271         /* Disable ESPI training.  MACs that can handle it enable it below. */
272         t1_write_reg_4(adapter, A_ESPI_TRAIN, 0);
273
274         if (is_T2(adapter)) {
275                 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
276                                V_OUT_OF_SYNC_COUNT(4) |
277                                V_DIP2_PARITY_ERR_THRES(3) | V_DIP4_THRES(1));
278                 if (nports == 4) {
279                         /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */
280                         burstval = 0x200040;
281                 }
282         }
283         t1_write_reg_4(adapter, A_ESPI_MAXBURST1_MAXBURST2, burstval);
284
285         if (mac_type == CHBT_MAC_PM3393)
286                 espi_setup_for_pm3393(adapter);
287         else if (mac_type == CHBT_MAC_VSC7321)
288                 espi_setup_for_vsc7321(adapter);
289         else if (mac_type == CHBT_MAC_IXF1010) {
290                 status_enable_extra = F_INTEL1010MODE;
291                 espi_setup_for_ixf1010(adapter, nports);
292         } else
293                 return -1;
294
295         /*
296          * Make sure any pending interrupts from the SPI are
297          * Cleared before enabling the interrupt.
298          */
299         t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, ESPI_INTR_MASK);
300         status = t1_read_reg_4(espi->adapter, A_ESPI_INTR_STATUS);
301         if (status & F_DIP2PARITYERR) {
302                 cnt = t1_read_reg_4(espi->adapter, A_ESPI_DIP2_ERR_COUNT);
303         }
304
305         /*
306          * For T1B we need to write 1 to clear ESPI interrupts.  For T2+ we
307          * write the status as is.
308          */
309         if (status && t1_is_T1B(espi->adapter))
310                 status = 1;
311         t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, status);
312
313         t1_write_reg_4(adapter, A_ESPI_FIFO_STATUS_ENABLE,
314                        status_enable_extra | F_RXSTATUSENABLE);
315
316         if (is_T2(adapter)) {
317                 tricn_init(adapter);
318                 /*
319                  * Always position the control at the 1st port egress IN
320                  * (sop,eop) counter to reduce PIOs for T/N210 workaround.
321                  */
322                 espi->misc_ctrl = (t1_read_reg_4(adapter, A_ESPI_MISC_CONTROL)
323                                    & ~MON_MASK) | (F_MONITORED_DIRECTION
324                                    | F_MONITORED_INTERFACE);
325                 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl);
326                 spin_lock_init(&espi->lock);
327         }
328
329         return 0;
330 }
331
332 void t1_espi_destroy(struct peespi *espi)
333 {
334         kfree(espi);
335 }
336
337 struct peespi *t1_espi_create(adapter_t *adapter)
338 {
339         struct peespi *espi = kmalloc(sizeof(*espi), GFP_KERNEL);
340
341         memset(espi, 0, sizeof(*espi));
342
343         if (espi)
344                 espi->adapter = adapter;
345         return espi;
346 }
347
348 void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
349 {
350         struct peespi *espi = adapter->espi;
351
352         if (!is_T2(adapter))
353                 return;
354         spin_lock(&espi->lock);
355         espi->misc_ctrl = (val & ~MON_MASK) |
356                           (espi->misc_ctrl & MON_MASK);
357         t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl);
358         spin_unlock(&espi->lock);
359 }
360
361 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
362 {
363         struct peespi *espi = adapter->espi;
364         u32 sel;
365
366         if (!is_T2(adapter))
367                 return 0;
368         sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2);
369         if (!wait) {
370                 if (!spin_trylock(&espi->lock))
371                         return 0;
372         }
373         else
374                 spin_lock(&espi->lock);
375         if ((sel != (espi->misc_ctrl & MON_MASK))) {
376                 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
377                                ((espi->misc_ctrl & ~MON_MASK) | sel));
378                 sel = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3);
379                 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL,
380                                espi->misc_ctrl);
381         }
382         else
383                 sel = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3);
384         spin_unlock(&espi->lock);
385         return sel;
386 }