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 <sys/nxge/nxge_impl.h>
27 #include <sys/nxge/nxge_txc.h>
28
29 static nxge_status_t
30 nxge_txc_handle_port_errors(p_nxge_t, uint32_t);
31 static void
32 nxge_txc_inject_port_err(uint8_t, txc_int_stat_dbg_t *,
33 uint8_t istats);
34 extern nxge_status_t nxge_tx_port_fatal_err_recover(p_nxge_t);
35
36 nxge_status_t
nxge_txc_init(p_nxge_t nxgep)37 nxge_txc_init(p_nxge_t nxgep)
38 {
39 uint8_t port;
40 npi_handle_t handle;
41 npi_status_t rs = NPI_SUCCESS;
42
43 handle = NXGE_DEV_NPI_HANDLE(nxgep);
44 port = NXGE_GET_PORT_NUM(nxgep->function_num);
45
46 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txc_init: portn %d", port));
47
48 /*
49 * Enable the TXC controller.
50 */
51 if ((rs = npi_txc_global_enable(handle)) != NPI_SUCCESS) {
52 goto fail;
53 }
54
55 /* Enable this port within the TXC. */
56 if ((rs = npi_txc_port_enable(handle, port)) != NPI_SUCCESS) {
57 goto fail;
58 }
59
60 /* Bind DMA channels to this port. */
61 if ((rs = npi_txc_port_dma_enable(handle, port,
62 TXDMA_PORT_BITMAP(nxgep))) != NPI_SUCCESS) {
63 goto fail;
64 }
65
66 /* Unmask all TXC interrupts */
67 npi_txc_global_imask_set(handle, port, 0);
68
69 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txc_init: portn %d", port));
70
71 return (NXGE_OK);
72 fail:
73 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
74 "nxge_txc_init: Failed to initialize txc on port %d",
75 port));
76
77 return (NXGE_ERROR | rs);
78 }
79
80 nxge_status_t
nxge_txc_uninit(p_nxge_t nxgep)81 nxge_txc_uninit(p_nxge_t nxgep)
82 {
83 uint8_t port;
84 npi_handle_t handle;
85 npi_status_t rs = NPI_SUCCESS;
86
87 handle = NXGE_DEV_NPI_HANDLE(nxgep);
88 port = NXGE_GET_PORT_NUM(nxgep->function_num);
89
90 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txc_uninit: portn %d", port));
91
92 /*
93 * disable the TXC controller.
94 */
95 if ((rs = npi_txc_global_disable(handle)) != NPI_SUCCESS) {
96 goto fail;
97 }
98
99 /* disable this port within the TXC. */
100 if ((rs = npi_txc_port_disable(handle, port)) != NPI_SUCCESS) {
101 goto fail;
102 }
103
104 /* unbind DMA channels to this port. */
105 if ((rs = npi_txc_port_dma_enable(handle, port, 0)) != NPI_SUCCESS) {
106 goto fail;
107 }
108
109 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txc_uninit: portn %d", port));
110
111 return (NXGE_OK);
112 fail:
113 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
114 "nxge_txc_init: Failed to initialize txc on port %d",
115 port));
116
117 return (NXGE_ERROR | rs);
118 }
119
120 /*
121 * nxge_txc_tdc_bind
122 *
123 * Bind a TDC to a port.
124 *
125 * Arguments:
126 * nxgep
127 * channel The channel to bind.
128 *
129 * Notes:
130 *
131 * NPI/NXGE function calls:
132 * npi_txc_control()
133 * npi_txc_global_imask_set()
134 * npi_txc_port_dma_enable()
135 *
136 * Registers accessed:
137 * TXC_CONTROL
138 * TXC_PORT_DMA
139 * TXC_INT_MASK
140 *
141 * Context:
142 * Service domain
143 */
144 nxge_status_t
nxge_txc_tdc_bind(p_nxge_t nxgep,int channel)145 nxge_txc_tdc_bind(
146 p_nxge_t nxgep,
147 int channel)
148 {
149 uint8_t port;
150 uint64_t bitmap;
151 npi_handle_t handle;
152 npi_status_t rs = NPI_SUCCESS;
153 txc_control_t txc_control;
154
155 port = NXGE_GET_PORT_NUM(nxgep->function_num);
156
157 NXGE_DEBUG_MSG((nxgep, TX_CTL,
158 "==> nxge_txc_tdc_bind(port %d, channel %d)", port, channel));
159
160 handle = NXGE_DEV_NPI_HANDLE(nxgep);
161
162 /* Get the current value of TXC_CONTROL. */
163 (void) npi_txc_control(handle, OP_GET, &txc_control);
164
165 /* Mask all TXC interrupts for <port>. */
166 if (txc_control.value & (1 << port)) {
167 npi_txc_global_imask_set(handle, port, TXC_INT_MASK_IVAL);
168 }
169
170 /* Bind <channel> to <port>. */
171 /* Read in the old bitmap. */
172 TXC_FZC_CNTL_REG_READ64(handle, TXC_PORT_DMA_ENABLE_REG, port,
173 &bitmap);
174
175 if (bitmap & (1 << channel)) {
176 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
177 "nxge_txc_tdc_bind: channel %d already bound on port %d",
178 channel, port));
179 } else {
180 /* Bind the new channel. */
181 bitmap |= (1 << channel);
182 NXGE_DEBUG_MSG((nxgep, TX_CTL,
183 "==> nxge_txc_tdc_bind(): bitmap = %lx", bitmap));
184
185 /* Write out the new bitmap. */
186 if ((rs = npi_txc_port_dma_enable(handle, port,
187 (uint32_t)bitmap)) != NPI_SUCCESS) {
188 goto fail;
189 }
190 }
191
192 /* Enable this port, if necessary. */
193 if (!(txc_control.value & (1 << port))) {
194 if ((rs = npi_txc_port_enable(handle, port)) != NPI_SUCCESS) {
195 goto fail;
196 }
197 }
198
199 /*
200 * Enable the TXC controller, if necessary.
201 */
202 if (txc_control.bits.ldw.txc_enabled == 0) {
203 if ((rs = npi_txc_global_enable(handle)) != NPI_SUCCESS) {
204 goto fail;
205 }
206 }
207
208 /* Unmask all TXC interrupts on <port> */
209 npi_txc_global_imask_set(handle, port, 0);
210
211 NXGE_DEBUG_MSG((nxgep, TX_CTL,
212 "<== nxge_txc_tdc_bind(port %d, channel %d)", port, channel));
213
214 return (NXGE_OK);
215 fail:
216 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
217 "nxge_txc_tdc_bind(port %d, channel %d) failed", port, channel));
218
219 return (NXGE_ERROR | rs);
220 }
221
222 /*
223 * nxge_txc_tdc_unbind
224 *
225 * Unbind a TDC from a port.
226 *
227 * Arguments:
228 * nxgep
229 * channel The channel to unbind.
230 *
231 * Notes:
232 *
233 * NPI/NXGE function calls:
234 * npi_txc_control()
235 * npi_txc_global_imask_set()
236 * npi_txc_port_dma_enable()
237 *
238 * Registers accessed:
239 * TXC_CONTROL
240 * TXC_PORT_DMA
241 * TXC_INT_MASK
242 *
243 * Context:
244 * Service domain
245 */
246 nxge_status_t
nxge_txc_tdc_unbind(p_nxge_t nxgep,int channel)247 nxge_txc_tdc_unbind(
248 p_nxge_t nxgep,
249 int channel)
250 {
251 uint8_t port;
252 uint64_t bitmap;
253 npi_handle_t handle;
254 npi_status_t rs = NPI_SUCCESS;
255
256 handle = NXGE_DEV_NPI_HANDLE(nxgep);
257 port = NXGE_GET_PORT_NUM(nxgep->function_num);
258
259 NXGE_DEBUG_MSG((nxgep, TX_CTL,
260 "==> nxge_txc_tdc_unbind(port %d, channel %d)", port, channel));
261
262 /* Mask all TXC interrupts for <port>. */
263 npi_txc_global_imask_set(handle, port, TXC_INT_MASK_IVAL);
264
265 /* Unbind <channel>. */
266 /* Read in the old bitmap. */
267 TXC_FZC_CNTL_REG_READ64(handle, TXC_PORT_DMA_ENABLE_REG, port,
268 &bitmap);
269
270 bitmap &= (~(1 << channel));
271
272 /* Write out the new bitmap. */
273 if ((rs = npi_txc_port_dma_enable(handle, port,
274 (uint32_t)bitmap)) != NPI_SUCCESS) {
275 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
276 "npi_txc_port_dma_enable(%d, %d) failed: %x",
277 port, channel, rs));
278 }
279
280 /* Unmask all TXC interrupts on <port> */
281 if (bitmap)
282 npi_txc_global_imask_set(handle, port, 0);
283
284 NXGE_DEBUG_MSG((nxgep, TX_CTL,
285 "<== nxge_txc_tdc_unbind(port %d, channel %d)", port, channel));
286
287 return (NXGE_OK);
288 fail:
289 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
290 "nxge_txc_tdc_unbind(port %d, channel %d) failed", port, channel));
291
292 return (NXGE_ERROR | rs);
293 }
294
295 void
nxge_txc_regs_dump(p_nxge_t nxgep)296 nxge_txc_regs_dump(p_nxge_t nxgep)
297 {
298 uint32_t cnt1, cnt2;
299 npi_handle_t handle;
300 txc_control_t control;
301 uint32_t bitmap = 0;
302
303 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\nTXC dump: func # %d:\n",
304 nxgep->function_num));
305
306 handle = NXGE_DEV_NPI_HANDLE(nxgep);
307
308 (void) npi_txc_control(handle, OP_GET, &control);
309 (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
310
311 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port control 0x%0llx",
312 (long long)control.value));
313 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port bitmap 0x%x", bitmap));
314
315 (void) npi_txc_pkt_xmt_to_mac_get(handle, nxgep->function_num,
316 &cnt1, &cnt2);
317 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC bytes to MAC %d "
318 "packets to MAC %d",
319 cnt1, cnt2));
320
321 (void) npi_txc_pkt_stuffed_get(handle, nxgep->function_num,
322 &cnt1, &cnt2);
323 NXGE_DEBUG_MSG((nxgep, TX_CTL,
324 "\n\tTXC ass packets %d reorder packets %d",
325 cnt1 & 0xffff, cnt2 & 0xffff));
326
327 (void) npi_txc_reorder_get(handle, nxgep->function_num, &cnt1);
328 NXGE_DEBUG_MSG((nxgep, TX_CTL,
329 "\n\tTXC reorder resource %d", cnt1 & 0xff));
330 }
331
332 nxge_status_t
nxge_txc_handle_sys_errors(p_nxge_t nxgep)333 nxge_txc_handle_sys_errors(p_nxge_t nxgep)
334 {
335 npi_handle_t handle;
336 txc_int_stat_t istatus;
337 uint32_t err_status;
338 uint8_t err_portn;
339 boolean_t my_err = B_FALSE;
340 nxge_status_t status = NXGE_OK;
341
342 handle = nxgep->npi_handle;
343 npi_txc_global_istatus_get(handle, (txc_int_stat_t *)&istatus.value);
344 switch (nxgep->mac.portnum) {
345 case 0:
346 if (istatus.bits.ldw.port0_int_status) {
347 my_err = B_TRUE;
348 err_portn = 0;
349 err_status = istatus.bits.ldw.port0_int_status;
350 }
351 break;
352 case 1:
353 if (istatus.bits.ldw.port1_int_status) {
354 my_err = B_TRUE;
355 err_portn = 1;
356 err_status = istatus.bits.ldw.port1_int_status;
357 }
358 break;
359 case 2:
360 if (istatus.bits.ldw.port2_int_status) {
361 my_err = B_TRUE;
362 err_portn = 2;
363 err_status = istatus.bits.ldw.port2_int_status;
364 }
365 break;
366 case 3:
367 if (istatus.bits.ldw.port3_int_status) {
368 my_err = B_TRUE;
369 err_portn = 3;
370 err_status = istatus.bits.ldw.port3_int_status;
371 }
372 break;
373 default:
374 return (NXGE_ERROR);
375 }
376 if (my_err) {
377 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
378 " nxge_txc_handle_sys_errors: errored port %d",
379 err_portn));
380 status = nxge_txc_handle_port_errors(nxgep, err_status);
381 }
382
383 return (status);
384 }
385
386 static nxge_status_t
nxge_txc_handle_port_errors(p_nxge_t nxgep,uint32_t err_status)387 nxge_txc_handle_port_errors(p_nxge_t nxgep, uint32_t err_status)
388 {
389 npi_handle_t handle;
390 npi_status_t rs = NPI_SUCCESS;
391 p_nxge_txc_stats_t statsp;
392 txc_int_stat_t istatus;
393 boolean_t txport_fatal = B_FALSE;
394 uint8_t portn;
395 nxge_status_t status = NXGE_OK;
396
397 handle = nxgep->npi_handle;
398 statsp = (p_nxge_txc_stats_t)&nxgep->statsp->txc_stats;
399 portn = nxgep->mac.portnum;
400 istatus.value = 0;
401
402 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) ||
403 (err_status & TXC_INT_STAT_RO_CORR_ERR) ||
404 (err_status & TXC_INT_STAT_RO_UNCORR_ERR) ||
405 (err_status & TXC_INT_STAT_REORDER_ERR)) {
406 if ((rs = npi_txc_ro_states_get(handle, portn,
407 &statsp->errlog.ro_st)) != NPI_SUCCESS) {
408 return (NXGE_ERROR | rs);
409 }
410
411 if (err_status & TXC_INT_STAT_RO_CORR_ERR) {
412 statsp->ro_correct_err++;
413 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
414 NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR);
415 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
416 "nxge_txc_err_evnts: "
417 "RO FIFO correctable error"));
418 }
419 if (err_status & TXC_INT_STAT_RO_UNCORR_ERR) {
420 statsp->ro_uncorrect_err++;
421 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
422 NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR);
423 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
424 "nxge_txc_err_evnts: "
425 "RO FIFO uncorrectable error"));
426 }
427 if (err_status & TXC_INT_STAT_REORDER_ERR) {
428 statsp->reorder_err++;
429 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
430 NXGE_FM_EREPORT_TXC_REORDER_ERR);
431 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
432 "nxge_txc_err_evnts: "
433 "fatal error: Reorder error"));
434 txport_fatal = B_TRUE;
435 }
436
437 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) ||
438 (err_status & TXC_INT_STAT_RO_CORR_ERR) ||
439 (err_status & TXC_INT_STAT_RO_UNCORR_ERR)) {
440
441 if ((rs = npi_txc_ro_ecc_state_clr(handle, portn))
442 != NPI_SUCCESS)
443 return (NXGE_ERROR | rs);
444 /*
445 * Making sure that error source is cleared if this is
446 * an injected error.
447 */
448 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_ROECC_CTL_REG,
449 portn, 0);
450 }
451 }
452
453 if ((err_status & TXC_INT_STAT_SF_CORR_ERR) ||
454 (err_status & TXC_INT_STAT_SF_UNCORR_ERR)) {
455 if ((rs = npi_txc_sf_states_get(handle, portn,
456 &statsp->errlog.sf_st)) != NPI_SUCCESS) {
457 return (NXGE_ERROR | rs);
458 }
459 if (err_status & TXC_INT_STAT_SF_CORR_ERR) {
460 statsp->sf_correct_err++;
461 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
462 NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR);
463 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
464 "nxge_txc_err_evnts: "
465 "SF FIFO correctable error"));
466 }
467 if (err_status & TXC_INT_STAT_SF_UNCORR_ERR) {
468 statsp->sf_uncorrect_err++;
469 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
470 NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR);
471 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
472 "nxge_txc_err_evnts: "
473 "SF FIFO uncorrectable error"));
474 }
475 if ((rs = npi_txc_sf_ecc_state_clr(handle, portn))
476 != NPI_SUCCESS)
477 return (NXGE_ERROR | rs);
478 /*
479 * Making sure that error source is cleared if this is
480 * an injected error.
481 */
482 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_SFECC_CTL_REG, portn, 0);
483 }
484
485 /* Clear corresponding errors */
486 switch (portn) {
487 case 0:
488 istatus.bits.ldw.port0_int_status = err_status;
489 break;
490 case 1:
491 istatus.bits.ldw.port1_int_status = err_status;
492 break;
493 case 2:
494 istatus.bits.ldw.port2_int_status = err_status;
495 break;
496 case 3:
497 istatus.bits.ldw.port3_int_status = err_status;
498 break;
499 default:
500 return (NXGE_ERROR);
501 }
502
503 npi_txc_global_istatus_clear(handle, istatus.value);
504
505 if (txport_fatal) {
506 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
507 " nxge_txc_handle_port_errors:"
508 " fatal Error on Port#%d\n",
509 portn));
510 status = nxge_tx_port_fatal_err_recover(nxgep);
511 if (status == NXGE_OK) {
512 FM_SERVICE_RESTORED(nxgep);
513 }
514 }
515
516 return (status);
517 }
518
519 void
nxge_txc_inject_err(p_nxge_t nxgep,uint32_t err_id)520 nxge_txc_inject_err(p_nxge_t nxgep, uint32_t err_id)
521 {
522 txc_int_stat_dbg_t txcs;
523 txc_roecc_ctl_t ro_ecc_ctl;
524 txc_sfecc_ctl_t sf_ecc_ctl;
525 uint8_t portn = nxgep->mac.portnum;
526
527 cmn_err(CE_NOTE, "!TXC error Inject\n");
528 switch (err_id) {
529 case NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR:
530 case NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR:
531 ro_ecc_ctl.value = 0;
532 ro_ecc_ctl.bits.ldw.all_pkts = 1;
533 ro_ecc_ctl.bits.ldw.second_line_pkt = 1;
534 if (err_id == NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR)
535 ro_ecc_ctl.bits.ldw.single_bit_err = 1;
536 else
537 ro_ecc_ctl.bits.ldw.double_bit_err = 1;
538 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_ROECC_CTL_REG\n",
539 ro_ecc_ctl.value);
540 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_ROECC_CTL_REG,
541 portn, ro_ecc_ctl.value);
542 break;
543 case NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR:
544 case NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR:
545 sf_ecc_ctl.value = 0;
546 sf_ecc_ctl.bits.ldw.all_pkts = 1;
547 sf_ecc_ctl.bits.ldw.second_line_pkt = 1;
548 if (err_id == NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR)
549 sf_ecc_ctl.bits.ldw.single_bit_err = 1;
550 else
551 sf_ecc_ctl.bits.ldw.double_bit_err = 1;
552 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_SFECC_CTL_REG\n",
553 sf_ecc_ctl.value);
554 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_SFECC_CTL_REG,
555 portn, sf_ecc_ctl.value);
556 break;
557 case NXGE_FM_EREPORT_TXC_REORDER_ERR:
558 NXGE_REG_RD64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG,
559 &txcs.value);
560 nxge_txc_inject_port_err(portn, &txcs,
561 TXC_INT_STAT_REORDER_ERR);
562 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_INT_STAT_DBG_REG\n",
563 txcs.value);
564 NXGE_REG_WR64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG,
565 txcs.value);
566 break;
567 default:
568 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
569 "nxge_txc_inject_err: Unknown err_id"));
570 }
571 }
572
573 static void
nxge_txc_inject_port_err(uint8_t portn,txc_int_stat_dbg_t * txcs,uint8_t istats)574 nxge_txc_inject_port_err(uint8_t portn, txc_int_stat_dbg_t *txcs,
575 uint8_t istats)
576 {
577 switch (portn) {
578 case 0:
579 txcs->bits.ldw.port0_int_status |= istats;
580 break;
581 case 1:
582 txcs->bits.ldw.port1_int_status |= istats;
583 break;
584 case 2:
585 txcs->bits.ldw.port2_int_status |= istats;
586 break;
587 case 3:
588 txcs->bits.ldw.port3_int_status |= istats;
589 break;
590 default:
591 ;
592 }
593 }
594