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 }
289
290 void
nxge_txc_regs_dump(p_nxge_t nxgep)291 nxge_txc_regs_dump(p_nxge_t nxgep)
292 {
293 uint32_t cnt1, cnt2;
294 npi_handle_t handle;
295 txc_control_t control;
296 uint32_t bitmap = 0;
297
298 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\nTXC dump: func # %d:\n",
299 nxgep->function_num));
300
301 handle = NXGE_DEV_NPI_HANDLE(nxgep);
302
303 (void) npi_txc_control(handle, OP_GET, &control);
304 (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
305
306 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port control 0x%0llx",
307 (long long)control.value));
308 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC port bitmap 0x%x", bitmap));
309
310 (void) npi_txc_pkt_xmt_to_mac_get(handle, nxgep->function_num,
311 &cnt1, &cnt2);
312 NXGE_DEBUG_MSG((nxgep, TX_CTL, "\n\tTXC bytes to MAC %d "
313 "packets to MAC %d",
314 cnt1, cnt2));
315
316 (void) npi_txc_pkt_stuffed_get(handle, nxgep->function_num,
317 &cnt1, &cnt2);
318 NXGE_DEBUG_MSG((nxgep, TX_CTL,
319 "\n\tTXC ass packets %d reorder packets %d",
320 cnt1 & 0xffff, cnt2 & 0xffff));
321
322 (void) npi_txc_reorder_get(handle, nxgep->function_num, &cnt1);
323 NXGE_DEBUG_MSG((nxgep, TX_CTL,
324 "\n\tTXC reorder resource %d", cnt1 & 0xff));
325 }
326
327 nxge_status_t
nxge_txc_handle_sys_errors(p_nxge_t nxgep)328 nxge_txc_handle_sys_errors(p_nxge_t nxgep)
329 {
330 npi_handle_t handle;
331 txc_int_stat_t istatus;
332 uint32_t err_status;
333 uint8_t err_portn;
334 boolean_t my_err = B_FALSE;
335 nxge_status_t status = NXGE_OK;
336
337 handle = nxgep->npi_handle;
338 npi_txc_global_istatus_get(handle, (txc_int_stat_t *)&istatus.value);
339 switch (nxgep->mac.portnum) {
340 case 0:
341 if (istatus.bits.ldw.port0_int_status) {
342 my_err = B_TRUE;
343 err_portn = 0;
344 err_status = istatus.bits.ldw.port0_int_status;
345 }
346 break;
347 case 1:
348 if (istatus.bits.ldw.port1_int_status) {
349 my_err = B_TRUE;
350 err_portn = 1;
351 err_status = istatus.bits.ldw.port1_int_status;
352 }
353 break;
354 case 2:
355 if (istatus.bits.ldw.port2_int_status) {
356 my_err = B_TRUE;
357 err_portn = 2;
358 err_status = istatus.bits.ldw.port2_int_status;
359 }
360 break;
361 case 3:
362 if (istatus.bits.ldw.port3_int_status) {
363 my_err = B_TRUE;
364 err_portn = 3;
365 err_status = istatus.bits.ldw.port3_int_status;
366 }
367 break;
368 default:
369 return (NXGE_ERROR);
370 }
371 if (my_err) {
372 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
373 " nxge_txc_handle_sys_errors: errored port %d",
374 err_portn));
375 status = nxge_txc_handle_port_errors(nxgep, err_status);
376 }
377
378 return (status);
379 }
380
381 static nxge_status_t
nxge_txc_handle_port_errors(p_nxge_t nxgep,uint32_t err_status)382 nxge_txc_handle_port_errors(p_nxge_t nxgep, uint32_t err_status)
383 {
384 npi_handle_t handle;
385 npi_status_t rs = NPI_SUCCESS;
386 p_nxge_txc_stats_t statsp;
387 txc_int_stat_t istatus;
388 boolean_t txport_fatal = B_FALSE;
389 uint8_t portn;
390 nxge_status_t status = NXGE_OK;
391
392 handle = nxgep->npi_handle;
393 statsp = (p_nxge_txc_stats_t)&nxgep->statsp->txc_stats;
394 portn = nxgep->mac.portnum;
395 istatus.value = 0;
396
397 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) ||
398 (err_status & TXC_INT_STAT_RO_CORR_ERR) ||
399 (err_status & TXC_INT_STAT_RO_UNCORR_ERR) ||
400 (err_status & TXC_INT_STAT_REORDER_ERR)) {
401 if ((rs = npi_txc_ro_states_get(handle, portn,
402 &statsp->errlog.ro_st)) != NPI_SUCCESS) {
403 return (NXGE_ERROR | rs);
404 }
405
406 if (err_status & TXC_INT_STAT_RO_CORR_ERR) {
407 statsp->ro_correct_err++;
408 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
409 NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR);
410 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
411 "nxge_txc_err_evnts: "
412 "RO FIFO correctable error"));
413 }
414 if (err_status & TXC_INT_STAT_RO_UNCORR_ERR) {
415 statsp->ro_uncorrect_err++;
416 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
417 NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR);
418 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
419 "nxge_txc_err_evnts: "
420 "RO FIFO uncorrectable error"));
421 }
422 if (err_status & TXC_INT_STAT_REORDER_ERR) {
423 statsp->reorder_err++;
424 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
425 NXGE_FM_EREPORT_TXC_REORDER_ERR);
426 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
427 "nxge_txc_err_evnts: "
428 "fatal error: Reorder error"));
429 txport_fatal = B_TRUE;
430 }
431
432 if ((err_status & TXC_INT_STAT_RO_CORR_ERR) ||
433 (err_status & TXC_INT_STAT_RO_CORR_ERR) ||
434 (err_status & TXC_INT_STAT_RO_UNCORR_ERR)) {
435
436 if ((rs = npi_txc_ro_ecc_state_clr(handle, portn))
437 != NPI_SUCCESS)
438 return (NXGE_ERROR | rs);
439 /*
440 * Making sure that error source is cleared if this is
441 * an injected error.
442 */
443 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_ROECC_CTL_REG,
444 portn, 0);
445 }
446 }
447
448 if ((err_status & TXC_INT_STAT_SF_CORR_ERR) ||
449 (err_status & TXC_INT_STAT_SF_UNCORR_ERR)) {
450 if ((rs = npi_txc_sf_states_get(handle, portn,
451 &statsp->errlog.sf_st)) != NPI_SUCCESS) {
452 return (NXGE_ERROR | rs);
453 }
454 if (err_status & TXC_INT_STAT_SF_CORR_ERR) {
455 statsp->sf_correct_err++;
456 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
457 NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR);
458 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
459 "nxge_txc_err_evnts: "
460 "SF FIFO correctable error"));
461 }
462 if (err_status & TXC_INT_STAT_SF_UNCORR_ERR) {
463 statsp->sf_uncorrect_err++;
464 NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
465 NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR);
466 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
467 "nxge_txc_err_evnts: "
468 "SF FIFO uncorrectable error"));
469 }
470 if ((rs = npi_txc_sf_ecc_state_clr(handle, portn))
471 != NPI_SUCCESS)
472 return (NXGE_ERROR | rs);
473 /*
474 * Making sure that error source is cleared if this is
475 * an injected error.
476 */
477 TXC_FZC_CNTL_REG_WRITE64(handle, TXC_SFECC_CTL_REG, portn, 0);
478 }
479
480 /* Clear corresponding errors */
481 switch (portn) {
482 case 0:
483 istatus.bits.ldw.port0_int_status = err_status;
484 break;
485 case 1:
486 istatus.bits.ldw.port1_int_status = err_status;
487 break;
488 case 2:
489 istatus.bits.ldw.port2_int_status = err_status;
490 break;
491 case 3:
492 istatus.bits.ldw.port3_int_status = err_status;
493 break;
494 default:
495 return (NXGE_ERROR);
496 }
497
498 npi_txc_global_istatus_clear(handle, istatus.value);
499
500 if (txport_fatal) {
501 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
502 " nxge_txc_handle_port_errors:"
503 " fatal Error on Port#%d\n",
504 portn));
505 status = nxge_tx_port_fatal_err_recover(nxgep);
506 if (status == NXGE_OK) {
507 FM_SERVICE_RESTORED(nxgep);
508 }
509 }
510
511 return (status);
512 }
513
514 void
nxge_txc_inject_err(p_nxge_t nxgep,uint32_t err_id)515 nxge_txc_inject_err(p_nxge_t nxgep, uint32_t err_id)
516 {
517 txc_int_stat_dbg_t txcs;
518 txc_roecc_ctl_t ro_ecc_ctl;
519 txc_sfecc_ctl_t sf_ecc_ctl;
520 uint8_t portn = nxgep->mac.portnum;
521
522 cmn_err(CE_NOTE, "!TXC error Inject\n");
523 switch (err_id) {
524 case NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR:
525 case NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR:
526 ro_ecc_ctl.value = 0;
527 ro_ecc_ctl.bits.ldw.all_pkts = 1;
528 ro_ecc_ctl.bits.ldw.second_line_pkt = 1;
529 if (err_id == NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR)
530 ro_ecc_ctl.bits.ldw.single_bit_err = 1;
531 else
532 ro_ecc_ctl.bits.ldw.double_bit_err = 1;
533 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_ROECC_CTL_REG\n",
534 ro_ecc_ctl.value);
535 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_ROECC_CTL_REG,
536 portn, ro_ecc_ctl.value);
537 break;
538 case NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR:
539 case NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR:
540 sf_ecc_ctl.value = 0;
541 sf_ecc_ctl.bits.ldw.all_pkts = 1;
542 sf_ecc_ctl.bits.ldw.second_line_pkt = 1;
543 if (err_id == NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR)
544 sf_ecc_ctl.bits.ldw.single_bit_err = 1;
545 else
546 sf_ecc_ctl.bits.ldw.double_bit_err = 1;
547 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_SFECC_CTL_REG\n",
548 sf_ecc_ctl.value);
549 TXC_FZC_CNTL_REG_WRITE64(nxgep->npi_handle, TXC_SFECC_CTL_REG,
550 portn, sf_ecc_ctl.value);
551 break;
552 case NXGE_FM_EREPORT_TXC_REORDER_ERR:
553 NXGE_REG_RD64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG,
554 &txcs.value);
555 nxge_txc_inject_port_err(portn, &txcs,
556 TXC_INT_STAT_REORDER_ERR);
557 cmn_err(CE_NOTE, "!Write 0x%lx to TXC_INT_STAT_DBG_REG\n",
558 txcs.value);
559 NXGE_REG_WR64(nxgep->npi_handle, TXC_INT_STAT_DBG_REG,
560 txcs.value);
561 break;
562 default:
563 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
564 "nxge_txc_inject_err: Unknown err_id"));
565 }
566 }
567
568 static void
nxge_txc_inject_port_err(uint8_t portn,txc_int_stat_dbg_t * txcs,uint8_t istats)569 nxge_txc_inject_port_err(uint8_t portn, txc_int_stat_dbg_t *txcs,
570 uint8_t istats)
571 {
572 switch (portn) {
573 case 0:
574 txcs->bits.ldw.port0_int_status |= istats;
575 break;
576 case 1:
577 txcs->bits.ldw.port1_int_status |= istats;
578 break;
579 case 2:
580 txcs->bits.ldw.port2_int_status |= istats;
581 break;
582 case 3:
583 txcs->bits.ldw.port3_int_status |= istats;
584 break;
585 default:
586 ;
587 }
588 }
589