]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgb/common/cxgb_mc5.c
This commit was generated by cvs2svn to compensate for changes in r167612,
[FreeBSD/FreeBSD.git] / sys / dev / cxgb / common / cxgb_mc5.c
1 /**************************************************************************
2
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in the
14     documentation and/or other materials provided with the distribution.
15
16  3. Neither the name of the Chelsio Corporation nor the names of its
17     contributors may be used to endorse or promote products derived from
18     this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31
32 ***************************************************************************/
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <dev/cxgb/common/cxgb_common.h>
38 #include <dev/cxgb/common/cxgb_regs.h>
39
40 enum {
41         IDT75P52100 = 4,
42         IDT75N43102 = 5
43 };
44
45 /* DBGI command mode */
46 enum {
47         DBGI_MODE_MBUS = 0,
48         DBGI_MODE_IDT52100 = 5
49 };
50
51 /* IDT 75P52100 commands */
52 #define IDT_CMD_READ   0
53 #define IDT_CMD_WRITE  1
54 #define IDT_CMD_SEARCH 2
55 #define IDT_CMD_LEARN  3
56
57 /* IDT LAR register address and value for 144-bit mode (low 32 bits) */
58 #define IDT_LAR_ADR0    0x180006
59 #define IDT_LAR_MODE144 0xffff0000
60
61 /* IDT SCR and SSR addresses (low 32 bits) */
62 #define IDT_SCR_ADR0  0x180000
63 #define IDT_SSR0_ADR0 0x180002
64 #define IDT_SSR1_ADR0 0x180004
65
66 /* IDT GMR base address (low 32 bits) */
67 #define IDT_GMR_BASE_ADR0 0x180020
68
69 /* IDT data and mask array base addresses (low 32 bits) */
70 #define IDT_DATARY_BASE_ADR0 0
71 #define IDT_MSKARY_BASE_ADR0 0x80000
72
73 /* IDT 75N43102 commands */
74 #define IDT4_CMD_SEARCH144 3
75 #define IDT4_CMD_WRITE     4
76 #define IDT4_CMD_READ      5
77
78 /* IDT 75N43102 SCR address (low 32 bits) */
79 #define IDT4_SCR_ADR0  0x3
80
81 /* IDT 75N43102 GMR base addresses (low 32 bits) */
82 #define IDT4_GMR_BASE0 0x10
83 #define IDT4_GMR_BASE1 0x20
84 #define IDT4_GMR_BASE2 0x30
85
86 /* IDT 75N43102 data and mask array base addresses (low 32 bits) */
87 #define IDT4_DATARY_BASE_ADR0 0x1000000
88 #define IDT4_MSKARY_BASE_ADR0 0x2000000
89
90 #define MAX_WRITE_ATTEMPTS 5
91
92 #define MAX_ROUTES 2048
93
94 /*
95  * Issue a command to the TCAM and wait for its completion.  The address and
96  * any data required by the command must have been setup by the caller.
97  */
98 static int mc5_cmd_write(adapter_t *adapter, u32 cmd)
99 {
100         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
101         return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
102                                F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
103 }
104
105 static inline void dbgi_wr_addr3(adapter_t *adapter, u32 v1, u32 v2, u32 v3)
106 {
107         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
108         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
109         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
110 }
111
112 static inline void dbgi_wr_data3(adapter_t *adapter, u32 v1, u32 v2, u32 v3)
113 {
114         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
115         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
116         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
117 }
118
119 static inline void dbgi_rd_rsp3(adapter_t *adapter, u32 *v1, u32 *v2, u32 *v3)
120 {
121         *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
122         *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
123         *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
124 }
125
126 /*
127  * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
128  * command cmd.  The data to be written must have been set up by the caller.
129  * Returns -1 on failure, 0 on success.
130  */
131 static int mc5_write(adapter_t *adapter, u32 addr_lo, u32 cmd)
132 {
133         t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
134         if (mc5_cmd_write(adapter, cmd) == 0)
135                 return 0;
136         CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", addr_lo);
137         return -1;
138 }
139
140 static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
141                                 u32 data_array_base, u32 write_cmd,
142                                 int addr_shift)
143 {
144         unsigned int i;
145         adapter_t *adap = mc5->adapter;
146
147         /*
148          * We need the size of the TCAM data and mask arrays in terms of
149          * 72-bit entries.
150          */
151         unsigned int size72 = mc5->tcam_size;
152         unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
153
154         if (mc5->mode == MC5_MODE_144_BIT) {
155                 size72 *= 2;      /* 1 144-bit entry is 2 72-bit entries */
156                 server_base *= 2;
157         }
158
159         /* Clear the data array */
160         dbgi_wr_data3(adap, 0, 0, 0);
161         for (i = 0; i < size72; i++)
162                 if (mc5_write(adap, data_array_base + (i << addr_shift),
163                               write_cmd))
164                         return -1;
165
166         /* Initialize the mask array. */
167         dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
168         for (i = 0; i < size72; i++) {
169                 if (i == server_base)   /* entering server or routing region */
170                         t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0,
171                                      mc5->mode == MC5_MODE_144_BIT ?
172                                      0xfffffff9 : 0xfffffffd);
173                 if (mc5_write(adap, mask_array_base + (i << addr_shift),
174                               write_cmd))
175                         return -1;
176         }
177         return 0;
178 }
179
180 static int init_idt52100(struct mc5 *mc5)
181 {
182         int i;
183         adapter_t *adap = mc5->adapter;
184
185         t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
186                      V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
187         t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
188
189         /*
190          * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
191          * GMRs 8-9 for ACK- and AOPEN searches.
192          */
193         t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
194         t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
195         t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
196         t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
197         t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
198         t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
199         t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
200         t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
201         t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
202         t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
203         t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
204         t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
205
206         /* Set DBGI command mode for IDT TCAM. */
207         t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
208
209         /* Set up LAR */
210         dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
211         if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
212                 goto err;
213
214         /* Set up SSRs */
215         dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
216         if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
217             mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
218                 goto err;
219
220         /* Set up GMRs */
221         for (i = 0; i < 32; ++i) {
222                 if (i >= 12 && i < 15)
223                         dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
224                 else if (i == 15)
225                         dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
226                 else
227                         dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
228
229                 if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
230                         goto err;
231         }
232
233         /* Set up SCR */
234         dbgi_wr_data3(adap, 1, 0, 0);
235         if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
236                 goto err;
237
238         return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
239                                     IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
240  err:
241         return -EIO;
242 }
243
244 static int init_idt43102(struct mc5 *mc5)
245 {
246         int i;
247         adapter_t *adap = mc5->adapter;
248
249         t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
250                      adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
251                                              V_RDLAT(0xd) | V_SRCHLAT(0x12));
252
253         /*
254          * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
255          * for ACK- and AOPEN searches.
256          */
257         t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
258         t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
259         t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
260                      IDT4_CMD_SEARCH144 | 0x3800);
261         t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
262         t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
263         t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
264         t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
265         t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
266         t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
267
268         t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
269
270         /* Set DBGI command mode for IDT TCAM. */
271         t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
272
273         /* Set up GMRs */
274         dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
275         for (i = 0; i < 7; ++i)
276                 if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
277                         goto err;
278
279         for (i = 0; i < 4; ++i)
280                 if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
281                         goto err;
282
283         dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
284         if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
285             mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
286             mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
287                 goto err;
288
289         dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
290         if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
291                 goto err;
292
293         /* Set up SCR */
294         dbgi_wr_data3(adap, 0xf0000000, 0, 0);
295         if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
296                 goto err;
297
298         return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
299                                     IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
300  err:
301         return -EIO;
302 }
303
304 /* Put MC5 in DBGI mode. */
305 static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
306 {
307         t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
308                      V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN);
309 }
310
311 /* Put MC5 in M-Bus mode. */
312 static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
313 {
314         t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
315                      V_TMMODE(mc5->mode == MC5_MODE_72_BIT) |
316                      V_COMPEN(mc5->mode == MC5_MODE_72_BIT) |
317                      V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
318 }
319
320 /*
321  * Initialization that requires the OS and protocol layers to already
322  * be intialized goes here.
323  */
324 int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
325                 unsigned int nroutes)
326 {
327         u32 cfg;
328         int err;
329         unsigned int tcam_size = mc5->tcam_size;
330         adapter_t *adap = mc5->adapter;
331
332         if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
333                 return -EINVAL;
334
335         /* Reset the TCAM */
336         cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE;
337         cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST;
338         t3_write_reg(adap, A_MC5_DB_CONFIG, cfg);
339         if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
340                 CH_ERR(adap, "TCAM reset timed out\n");
341                 return -1;
342         }
343
344         t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
345         t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
346                      tcam_size - nroutes - nfilters);
347         t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
348                      tcam_size - nroutes - nfilters - nservers);
349
350         mc5->parity_enabled = 1;
351
352         /* All the TCAM addresses we access have only the low 32 bits non 0 */
353         t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
354         t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
355
356         mc5_dbgi_mode_enable(mc5);
357
358         switch (mc5->part_type) {
359         case IDT75P52100:
360                 err = init_idt52100(mc5);
361                 break;
362         case IDT75N43102:
363                 err = init_idt43102(mc5);
364                 break;
365         default:
366                 CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
367                 err = -EINVAL;
368                 break;
369         }
370
371         mc5_dbgi_mode_disable(mc5);
372         return err;
373 }
374
375 /*
376  *      read_mc5_range - dump a part of the memory managed by MC5
377  *      @mc5: the MC5 handle
378  *      @start: the start address for the dump
379  *      @n: number of 72-bit words to read
380  *      @buf: result buffer
381  *
382  *      Read n 72-bit words from MC5 memory from the given start location.
383  */
384 int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
385                       unsigned int n, u32 *buf)
386 {
387         u32 read_cmd;
388         int err = 0;
389         adapter_t *adap = mc5->adapter;
390
391         if (mc5->part_type == IDT75P52100)
392                 read_cmd = IDT_CMD_READ;
393         else if (mc5->part_type == IDT75N43102)
394                 read_cmd = IDT4_CMD_READ;
395         else
396                 return -EINVAL;
397
398         mc5_dbgi_mode_enable(mc5);
399
400         while (n--) {
401                 t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
402                 if (mc5_cmd_write(adap, read_cmd)) {
403                         err = -EIO;
404                         break;
405                 }
406                 dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
407                 buf += 3;
408         }
409
410         mc5_dbgi_mode_disable(mc5);
411         return 0;
412 }
413
414 #define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
415
416 /*
417  * MC5 interrupt handler
418  */
419 void t3_mc5_intr_handler(struct mc5 *mc5)
420 {
421         adapter_t *adap = mc5->adapter;
422         u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
423
424         if ((cause & F_PARITYERR) && mc5->parity_enabled) {
425                 CH_ALERT(adap, "MC5 parity error\n");
426                 mc5->stats.parity_err++;
427         }
428
429         if (cause & F_REQQPARERR) {
430                 CH_ALERT(adap, "MC5 request queue parity error\n");
431                 mc5->stats.reqq_parity_err++;
432         }
433
434         if (cause & F_DISPQPARERR) {
435                 CH_ALERT(adap, "MC5 dispatch queue parity error\n");
436                 mc5->stats.dispq_parity_err++;
437         }
438
439         if (cause & F_ACTRGNFULL)
440                 mc5->stats.active_rgn_full++;
441         if (cause & F_NFASRCHFAIL)
442                 mc5->stats.nfa_srch_err++;
443         if (cause & F_UNKNOWNCMD)
444                 mc5->stats.unknown_cmd++;
445         if (cause & F_DELACTEMPTY)
446                 mc5->stats.del_act_empty++;
447         if (cause & MC5_INT_FATAL)
448                 t3_fatal_err(adap);
449
450         t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
451 }
452
453 void __devinit t3_mc5_prep(adapter_t *adapter, struct mc5 *mc5, int mode)
454 {
455 #define K * 1024
456
457         static unsigned int tcam_part_size[] = {  /* in K 72-bit entries */
458                 64 K, 128 K, 256 K, 32 K
459         };
460
461 #undef K
462
463         u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
464
465         mc5->adapter = adapter;
466         mc5->mode = (unsigned char) mode;
467         mc5->part_type = (unsigned char) G_TMTYPE(cfg);
468         if (cfg & F_TMTYPEHI)
469                 mc5->part_type |= 4;
470
471         mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
472         if (mode == MC5_MODE_144_BIT)
473                 mc5->tcam_size /= 2;
474 }