1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <nxge_impl.h>
27 #include <nxge_ipp.h>
28
29 #define NXGE_IPP_FIFO_SYNC_TRY_COUNT 100
30
31 /* ARGSUSED */
32 nxge_status_t
nxge_ipp_init(p_nxge_t nxgep)33 nxge_ipp_init(p_nxge_t nxgep)
34 {
35 uint8_t portn;
36 uint32_t config;
37 npi_handle_t handle;
38 uint32_t pkt_size;
39 ipp_status_t istatus;
40 npi_status_t rs = NPI_SUCCESS;
41 uint64_t val;
42 uint32_t d0, d1, d2, d3, d4;
43 int i;
44 uint32_t dfifo_entries;
45
46 handle = nxgep->npi_handle;
47 portn = NXGE_GET_PORT_NUM(nxgep->function_num);
48
49 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn));
50
51 /* Initialize ECC and parity in SRAM of DFIFO and PFIFO */
52 if (nxgep->niu_type == N2_NIU) {
53 dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
54 } else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
55 if (portn < 2)
56 dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
57 else
58 dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
59 } else {
60 goto fail;
61 }
62
63 for (i = 0; i < dfifo_entries; i++) {
64 if ((rs = npi_ipp_write_dfifo(handle,
65 portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
66 goto fail;
67 if ((rs = npi_ipp_read_dfifo(handle, portn,
68 i, &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
69 goto fail;
70 }
71
72 /* Clear PFIFO DFIFO status bits */
73 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
74 goto fail;
75 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
76 goto fail;
77
78 /*
79 * Soft reset to make sure we bring the FIFO pointers back to the
80 * original initial position.
81 */
82 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
83 goto fail;
84
85 /* Clean up ECC counter */
86 IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val);
87 IPP_REG_RD(nxgep->npi_handle, portn, IPP_BAD_CKSUM_ERR_CNT_REG, &val);
88 IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val);
89
90 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
91 goto fail;
92
93 /* Configure IPP port */
94 if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL))
95 != NPI_SUCCESS)
96 goto fail;
97 nxgep->ipp.iconfig = ICFG_IPP_ALL;
98
99 config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
100 CFG_IPP_TCP_UDP_CKSUM;
101 if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
102 goto fail;
103 nxgep->ipp.config = config;
104
105 /* Set max packet size */
106 pkt_size = IPP_MAX_PKT_SIZE;
107 if ((rs = npi_ipp_set_max_pktsize(handle, portn,
108 IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
109 goto fail;
110 nxgep->ipp.max_pkt_size = pkt_size;
111
112 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn));
113
114 return (NXGE_OK);
115 fail:
116 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
117 "nxge_ipp_init: Fail to initialize IPP Port #%d\n",
118 portn));
119 return (NXGE_ERROR | rs);
120 }
121
122 /* ARGSUSED */
123 nxge_status_t
nxge_ipp_disable(p_nxge_t nxgep)124 nxge_ipp_disable(p_nxge_t nxgep)
125 {
126 uint8_t portn;
127 uint32_t config;
128 npi_handle_t handle;
129 npi_status_t rs = NPI_SUCCESS;
130 uint16_t wr_ptr, rd_ptr;
131 uint32_t try_count;
132
133 handle = nxgep->npi_handle;
134 portn = NXGE_GET_PORT_NUM(nxgep->function_num);
135
136 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn));
137 (void) nxge_rx_mac_disable(nxgep);
138
139 /*
140 * Wait until ip read and write fifo pointers are equal
141 */
142 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
143 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
144 try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
145
146 while ((try_count > 0) && (rd_ptr != wr_ptr)) {
147 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
148 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
149 try_count--;
150 }
151
152 if (try_count == 0) {
153 if ((rd_ptr != 0) && (wr_ptr != 1)) {
154 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
155 " nxge_ipp_disable: port%d failed"
156 " rd_fifo != wr_fifo", portn));
157 goto fail;
158 }
159 }
160 /* disable the IPP */
161 config = nxgep->ipp.config;
162 if ((rs = npi_ipp_config(handle, DISABLE,
163 portn, config)) != NPI_SUCCESS)
164 goto fail;
165
166 /* IPP soft reset */
167 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
168 goto fail;
169
170 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn));
171 return (NXGE_OK);
172 fail:
173 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
174 "nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn));
175 return (NXGE_ERROR | rs);
176 }
177
178 /* ARGSUSED */
179 nxge_status_t
nxge_ipp_reset(p_nxge_t nxgep)180 nxge_ipp_reset(p_nxge_t nxgep)
181 {
182 uint8_t portn;
183 uint32_t config;
184 npi_handle_t handle;
185 npi_status_t rs = NPI_SUCCESS;
186 uint16_t wr_ptr, rd_ptr;
187 uint32_t try_count;
188
189 handle = nxgep->npi_handle;
190 portn = NXGE_GET_PORT_NUM(nxgep->function_num);
191
192 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn));
193
194 /* disable the IPP */
195 config = nxgep->ipp.config;
196 if ((rs = npi_ipp_config(handle, DISABLE,
197 portn, config)) != NPI_SUCCESS)
198 goto fail;
199
200 /*
201 * Wait until ip read and write fifo pointers are equal
202 */
203 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
204 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
205 try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
206
207 while ((try_count > 0) && (rd_ptr != wr_ptr)) {
208 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
209 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
210 try_count--;
211 }
212
213 if (try_count == 0) {
214 if ((rd_ptr != 0) && (wr_ptr != 1)) {
215 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
216 " nxge_ipp_disable: port%d failed"
217 " rd_fifo != wr_fifo", portn));
218 goto fail;
219 }
220 }
221
222 /* IPP soft reset */
223 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
224 goto fail;
225 }
226
227 /* to reset control FIFO */
228 if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
229 goto fail;
230
231 /*
232 * Making sure that error source is cleared if this is an injected
233 * error.
234 */
235 IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
236
237 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn));
238 return (NXGE_OK);
239 fail:
240 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
241 "nxge_ipp_init: Fail to Reset IPP Port #%d\n",
242 portn));
243 return (NXGE_ERROR | rs);
244 }
245
246 /* ARGSUSED */
247 nxge_status_t
nxge_ipp_enable(p_nxge_t nxgep)248 nxge_ipp_enable(p_nxge_t nxgep)
249 {
250 uint8_t portn;
251 uint32_t config;
252 npi_handle_t handle;
253 uint32_t pkt_size;
254 npi_status_t rs = NPI_SUCCESS;
255
256 handle = nxgep->npi_handle;
257 portn = NXGE_GET_PORT_NUM(nxgep->function_num);
258
259 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn));
260
261 config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
262 CFG_IPP_TCP_UDP_CKSUM;
263 if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
264 goto fail;
265 nxgep->ipp.config = config;
266
267 /* Set max packet size */
268 pkt_size = IPP_MAX_PKT_SIZE;
269 if ((rs = npi_ipp_set_max_pktsize(handle, portn,
270 IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
271 goto fail;
272 nxgep->ipp.max_pkt_size = pkt_size;
273
274 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn));
275 return (NXGE_OK);
276 fail:
277 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
278 "nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn));
279 return (NXGE_ERROR | rs);
280 }
281
282 /* ARGSUSED */
283 nxge_status_t
nxge_ipp_drain(p_nxge_t nxgep)284 nxge_ipp_drain(p_nxge_t nxgep)
285 {
286 uint8_t portn;
287 npi_handle_t handle;
288 npi_status_t rs = NPI_SUCCESS;
289 uint16_t wr_ptr, rd_ptr;
290 uint32_t try_count;
291
292 handle = nxgep->npi_handle;
293 portn = NXGE_GET_PORT_NUM(nxgep->function_num);
294
295 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_drain: port%d", portn));
296
297 /*
298 * Wait until ip read and write fifo pointers are equal
299 */
300 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
301 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
302 try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
303
304 while ((try_count > 0) && (rd_ptr != wr_ptr)) {
305 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
306 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
307 try_count--;
308 }
309
310 if (try_count == 0) {
311 if ((rd_ptr != 0) && (wr_ptr != 1)) {
312 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
313 " nxge_ipp_drain: port%d failed"
314 " rd_fifo != wr_fifo", portn));
315 goto fail;
316 }
317 }
318
319 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_drain: port%d", portn));
320 return (NXGE_OK);
321 fail:
322 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_ipp_init: "
323 "Fail to Reset IPP Port #%d\n", portn));
324 return (NXGE_ERROR | rs);
325 }
326
327 /* ARGSUSED */
328 nxge_status_t
nxge_ipp_handle_sys_errors(p_nxge_t nxgep)329 nxge_ipp_handle_sys_errors(p_nxge_t nxgep)
330 {
331 npi_handle_t handle;
332 npi_status_t rs = NPI_SUCCESS;
333 p_nxge_ipp_stats_t statsp;
334 ipp_status_t istatus;
335 uint8_t portn;
336 p_ipp_errlog_t errlogp;
337 boolean_t rxport_fatal = B_FALSE;
338 nxge_status_t status = NXGE_OK;
339 uint8_t cnt8;
340 uint16_t cnt16;
341
342 handle = nxgep->npi_handle;
343 statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats;
344 portn = nxgep->mac.portnum;
345
346 errlogp = (p_ipp_errlog_t)&statsp->errlog;
347
348 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
349 return (NXGE_ERROR | rs);
350
351 if (istatus.value == 0) {
352 /*
353 * The error is not initiated from this port, so just exit.
354 */
355 return (NXGE_OK);
356 }
357
358 if (istatus.bits.w0.dfifo_missed_sop) {
359 statsp->sop_miss++;
360 if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
361 &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
362 return (NXGE_ERROR | rs);
363 if ((rs = npi_ipp_get_state_mach(handle, portn,
364 &errlogp->state_mach)) != NPI_SUCCESS)
365 return (NXGE_ERROR | rs);
366 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
367 NXGE_FM_EREPORT_IPP_SOP_MISS);
368 if (statsp->sop_miss < IPP_MAX_ERR_SHOW)
369 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
370 "nxge_ipp_err_evnts: fatal error: sop_miss\n"));
371 rxport_fatal = B_TRUE;
372 }
373 if (istatus.bits.w0.dfifo_missed_eop) {
374 statsp->eop_miss++;
375 if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
376 &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
377 return (NXGE_ERROR | rs);
378 if ((rs = npi_ipp_get_state_mach(handle, portn,
379 &errlogp->state_mach)) != NPI_SUCCESS)
380 return (NXGE_ERROR | rs);
381 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
382 NXGE_FM_EREPORT_IPP_EOP_MISS);
383 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
384 "nxge_ipp_err_evnts: fatal error: eop_miss\n"));
385 rxport_fatal = B_TRUE;
386 }
387 if (istatus.bits.w0.dfifo_uncorr_ecc_err) {
388 boolean_t ue_ecc_valid;
389
390 if ((status = nxge_ipp_eccue_valid_check(nxgep,
391 &ue_ecc_valid)) != NXGE_OK)
392 return (status);
393
394 if (ue_ecc_valid) {
395 statsp->dfifo_ue++;
396 if ((rs = npi_ipp_get_ecc_syndrome(handle, portn,
397 &errlogp->ecc_syndrome)) != NPI_SUCCESS)
398 return (NXGE_ERROR | rs);
399 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
400 NXGE_FM_EREPORT_IPP_DFIFO_UE);
401 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
402 "nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
403 rxport_fatal = B_TRUE;
404 }
405 }
406 if (istatus.bits.w0.pre_fifo_perr) {
407 statsp->pfifo_perr++;
408 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
409 NXGE_FM_EREPORT_IPP_PFIFO_PERR);
410 if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW)
411 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
412 "nxge_ipp_err_evnts: "
413 "fatal error: pre_pifo_perr\n"));
414 rxport_fatal = B_TRUE;
415 }
416 if (istatus.bits.w0.pre_fifo_overrun) {
417 statsp->pfifo_over++;
418 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
419 NXGE_FM_EREPORT_IPP_PFIFO_OVER);
420 if (statsp->pfifo_over < IPP_MAX_ERR_SHOW)
421 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
422 "nxge_ipp_err_evnts: "
423 "fatal error: pfifo_over\n"));
424 rxport_fatal = B_TRUE;
425 }
426 if (istatus.bits.w0.pre_fifo_underrun) {
427 statsp->pfifo_und++;
428 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
429 NXGE_FM_EREPORT_IPP_PFIFO_UND);
430 if (statsp->pfifo_und < IPP_MAX_ERR_SHOW)
431 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
432 "nxge_ipp_err_evnts: "
433 "fatal error: pfifo_und\n"));
434 rxport_fatal = B_TRUE;
435 }
436 if (istatus.bits.w0.bad_cksum_cnt_ovfl) {
437 /*
438 * Do not send FMA ereport or log error message
439 * in /var/adm/messages because this error does not
440 * indicate a HW failure.
441 *
442 * Clear bit BAD_CS_MX of register IPP_INT_STAT
443 * by reading register IPP_BAD_CS_CNT
444 */
445 (void) npi_ipp_get_cs_err_count(handle, portn, &cnt16);
446 statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK;
447 }
448 if (istatus.bits.w0.pkt_discard_cnt_ovfl) {
449 /*
450 * Do not send FMA ereport or log error message
451 * in /var/adm/messages because this error does not
452 * indicate a HW failure.
453 *
454 * Clear bit PKT_DIS_MX of register IPP_INT_STAT
455 * by reading register IPP_PKT_DIS
456 */
457 (void) npi_ipp_get_pkt_dis_count(handle, portn, &cnt16);
458 statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK;
459 }
460 if (istatus.bits.w0.ecc_err_cnt_ovfl) {
461 /*
462 * Clear bit ECC_ERR_MAX of register IPP_INI_STAT
463 * by reading register IPP_ECC
464 */
465 (void) npi_ipp_get_ecc_err_count(handle, portn, &cnt8);
466 statsp->ecc_err_cnt += IPP_ECC_CNT_MASK;
467 /*
468 * A defect in Neptune port2's IPP module could generate
469 * many fake but harmless ECC errors under stress and cause
470 * the ecc-error-counter register IPP_ECC to reach its
471 * maximum value in a few seconds. To avoid false alarm, do
472 * not report the error if it is port2.
473 */
474 if (portn != 2) {
475 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
476 NXGE_FM_EREPORT_IPP_ECC_ERR_MAX);
477 if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW *
478 IPP_ECC_CNT_MASK)) {
479 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
480 "nxge_ipp_err_evnts: pkt_ecc_err_max\n"));
481 }
482 }
483 }
484 /*
485 * Making sure that error source is cleared if this is an injected
486 * error.
487 */
488 IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
489
490 if (rxport_fatal) {
491 NXGE_DEBUG_MSG((nxgep, IPP_CTL,
492 " nxge_ipp_handle_sys_errors:"
493 " fatal Error on Port #%d\n", portn));
494 status = nxge_ipp_fatal_err_recover(nxgep);
495 if (status == NXGE_OK) {
496 FM_SERVICE_RESTORED(nxgep);
497 }
498 }
499 return (status);
500 }
501
502 /* ARGSUSED */
503 void
nxge_ipp_inject_err(p_nxge_t nxgep,uint32_t err_id)504 nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id)
505 {
506 ipp_status_t ipps;
507 ipp_ecc_ctrl_t ecc_ctrl;
508 uint8_t portn = nxgep->mac.portnum;
509
510 switch (err_id) {
511 case NXGE_FM_EREPORT_IPP_DFIFO_UE:
512 ecc_ctrl.value = 0;
513 ecc_ctrl.bits.w0.cor_dbl = 1;
514 ecc_ctrl.bits.w0.cor_1 = 1;
515 ecc_ctrl.bits.w0.cor_lst = 1;
516 cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
517 (unsigned long long) ecc_ctrl.value);
518 IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
519 ecc_ctrl.value);
520 break;
521
522 case NXGE_FM_EREPORT_IPP_DFIFO_CE:
523 ecc_ctrl.value = 0;
524 ecc_ctrl.bits.w0.cor_sng = 1;
525 ecc_ctrl.bits.w0.cor_1 = 1;
526 ecc_ctrl.bits.w0.cor_snd = 1;
527 cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
528 (unsigned long long) ecc_ctrl.value);
529 IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
530 ecc_ctrl.value);
531 break;
532
533 case NXGE_FM_EREPORT_IPP_EOP_MISS:
534 case NXGE_FM_EREPORT_IPP_SOP_MISS:
535 case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
536 case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
537 case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
538 case NXGE_FM_EREPORT_IPP_PFIFO_UND:
539 case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
540 case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
541 case NXGE_FM_EREPORT_IPP_RESET_FAIL:
542 IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
543 &ipps.value);
544 if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
545 ipps.bits.w0.dfifo_missed_eop = 1;
546 else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
547 ipps.bits.w0.dfifo_missed_sop = 1;
548 else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
549 ipps.bits.w0.dfifo_uncorr_ecc_err = 1;
550 else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
551 ipps.bits.w0.dfifo_corr_ecc_err = 1;
552 else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
553 ipps.bits.w0.pre_fifo_perr = 1;
554 else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) {
555 /*
556 * Fill register IPP_ECC with max ECC-error-
557 * counter value (0xff) to set the ECC_ERR_MAX bit
558 * of the IPP_INT_STAT register and trigger an
559 * FMA ereport.
560 */
561 IPP_REG_WR(nxgep->npi_handle, portn,
562 IPP_ECC_ERR_COUNTER_REG, IPP_ECC_CNT_MASK);
563 } else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
564 ipps.bits.w0.pre_fifo_overrun = 1;
565 else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
566 ipps.bits.w0.pre_fifo_underrun = 1;
567 else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) {
568 /*
569 * Fill IPP_BAD_CS_CNT with max bad-checksum-counter
570 * value (0x3fff) to set the BAD_CS_MX bit of
571 * IPP_INT_STAT and trigger an FMA ereport.
572 */
573 IPP_REG_WR(nxgep->npi_handle, portn,
574 IPP_BAD_CKSUM_ERR_CNT_REG, IPP_BAD_CS_CNT_MASK);
575 } else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) {
576 /*
577 * Fill IPP_PKT_DIS with max packet-discard-counter
578 * value (0x3fff) to set the PKT_DIS_MX bit of
579 * IPP_INT_STAT and trigger an FMA ereport.
580 */
581 IPP_REG_WR(nxgep->npi_handle, portn,
582 IPP_DISCARD_PKT_CNT_REG, IPP_PKT_DIS_CNT_MASK);
583 }
584 cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n",
585 (unsigned long long) ipps.value);
586 IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
587 ipps.value);
588 break;
589 }
590 }
591
592 /* ARGSUSED */
593 nxge_status_t
nxge_ipp_fatal_err_recover(p_nxge_t nxgep)594 nxge_ipp_fatal_err_recover(p_nxge_t nxgep)
595 {
596 npi_handle_t handle;
597 npi_status_t rs = NPI_SUCCESS;
598 nxge_status_t status = NXGE_OK;
599 uint8_t portn;
600 uint16_t wr_ptr;
601 uint16_t rd_ptr;
602 uint32_t try_count;
603 uint32_t dfifo_entries;
604 ipp_status_t istatus;
605 uint32_t d0, d1, d2, d3, d4;
606 int i;
607
608 NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover"));
609 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
610 "Recovering from RxPort error..."));
611
612 handle = nxgep->npi_handle;
613 portn = nxgep->mac.portnum;
614
615 /*
616 * Making sure that error source is cleared if this is an injected
617 * error.
618 */
619 IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
620
621 /* Disable RxMAC */
622 if (nxge_rx_mac_disable(nxgep) != NXGE_OK)
623 goto fail;
624
625 /* When recovering from IPP, RxDMA channel resets are not necessary */
626 /* Reset ZCP CFIFO */
627 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn));
628 if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
629 goto fail;
630
631 /*
632 * Wait until ip read and write fifo pointers are equal
633 */
634 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
635 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
636 try_count = 512;
637
638 while ((try_count > 0) && (rd_ptr != wr_ptr)) {
639 (void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
640 (void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
641 try_count--;
642 }
643
644 if (try_count == 0) {
645 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
646 " nxge_ipp_reset: port%d IPP stalled..."
647 " rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
648 portn, rd_ptr, wr_ptr));
649 /*
650 * This means the fatal error occurred on the first line of the
651 * fifo. In this case, just reset the IPP without draining the
652 * PFIFO.
653 */
654 }
655
656 if (nxgep->niu_type == N2_NIU) {
657 dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
658 } else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
659 if (portn < 2)
660 dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
661 else
662 dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
663 } else {
664 goto fail;
665 }
666
667 /* Clean up DFIFO SRAM entries */
668 for (i = 0; i < dfifo_entries; i++) {
669 if ((rs = npi_ipp_write_dfifo(handle, portn,
670 i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
671 goto fail;
672 if ((rs = npi_ipp_read_dfifo(handle, portn, i,
673 &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
674 goto fail;
675 }
676
677 /* Clear PFIFO DFIFO status bits */
678 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
679 goto fail;
680 if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
681 goto fail;
682
683 /* Reset IPP */
684 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn));
685 if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
686 goto fail;
687
688 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn));
689 if (nxge_rx_mac_reset(nxgep) != NXGE_OK)
690 goto fail;
691
692 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn));
693 if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
694 goto fail;
695
696 NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn));
697 if (nxge_rx_mac_enable(nxgep) != NXGE_OK)
698 goto fail;
699
700 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
701 "Recovery successful, RxPort restored"));
702 NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover"));
703
704 return (NXGE_OK);
705 fail:
706 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
707 return (status | rs);
708 }
709
710 /* ARGSUSED */
711 /*
712 * A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error).
713 * This function checks if a ECCUE is real(valid) or not. It is not
714 * real if rd_ptr == wr_ptr.
715 * The hardware module that has the bug is used not only by the IPP
716 * FIFO but also by the ZCP FIFO, therefore this function is also
717 * called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO
718 * error.
719 */
720 nxge_status_t
nxge_ipp_eccue_valid_check(p_nxge_t nxgep,boolean_t * valid)721 nxge_ipp_eccue_valid_check(p_nxge_t nxgep, boolean_t *valid)
722 {
723 npi_handle_t handle;
724 npi_status_t rs = NPI_SUCCESS;
725 uint8_t portn;
726 uint16_t rd_ptr;
727 uint16_t wr_ptr;
728 uint16_t curr_rd_ptr;
729 uint16_t curr_wr_ptr;
730 uint32_t stall_cnt;
731 uint32_t d0, d1, d2, d3, d4;
732
733 handle = nxgep->npi_handle;
734 portn = nxgep->mac.portnum;
735 *valid = B_TRUE;
736
737 if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr))
738 != NPI_SUCCESS)
739 goto fail;
740 if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr))
741 != NPI_SUCCESS)
742 goto fail;
743
744 if (rd_ptr == wr_ptr) {
745 *valid = B_FALSE; /* FIFO not stuck, so it's not a real ECCUE */
746 } else {
747 stall_cnt = 0;
748 /*
749 * Check if the two pointers are moving, the ECCUE is invali
750 * if either pointer is moving, which indicates that the FIFO
751 * is functional.
752 */
753 while (stall_cnt < 16) {
754 if ((rs = npi_ipp_get_dfifo_rd_ptr(handle,
755 portn, &curr_rd_ptr)) != NPI_SUCCESS)
756 goto fail;
757 if ((rs = npi_ipp_get_dfifo_wr_ptr(handle,
758 portn, &curr_wr_ptr)) != NPI_SUCCESS)
759 goto fail;
760
761 if (rd_ptr == curr_rd_ptr && wr_ptr == curr_wr_ptr) {
762 stall_cnt++;
763 } else {
764 *valid = B_FALSE;
765 break;
766 }
767 }
768
769 if (*valid) {
770 /*
771 * Further check to see if the ECCUE is valid. The
772 * error is real if the LSB of d4 is 1, which
773 * indicates that the data that has set the ECC
774 * error flag is the 16-byte internal control word.
775 */
776 if ((rs = npi_ipp_read_dfifo(handle, portn, rd_ptr,
777 &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
778 goto fail;
779 if ((d4 & 0x1) == 0) /* Not the 1st line */
780 *valid = B_FALSE;
781 }
782 }
783 return (NXGE_OK);
784 fail:
785 return (NXGE_ERROR | rs);
786 }
787