nxge_txdma.c revision 56d930ae56e5cfc2442f5214a7b2c47f08a2b920
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
extern uint32_t nxge_tx_ring_size;
extern uint32_t nxge_bcopy_thresh;
extern uint32_t nxge_dvma_thresh;
extern uint32_t nxge_dma_stream_thresh;
extern dma_method_t nxge_force_dma;
/* Device register access attributes for PIO. */
/* Device descriptor access attributes for DMA. */
/* Device buffer access attributes for DMA. */
extern ddi_dma_attr_t nxge_desc_dma_attr;
extern ddi_dma_attr_t nxge_tx_dma_attr;
static void nxge_unmap_txdma(p_nxge_t);
static void nxge_txdma_hw_stop(p_nxge_t);
p_tx_mbox_t *);
p_tx_mbox_t *);
static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
{
"<== nxge_init_txdma_channels: status 0x%x", status));
return (status);
}
return (status);
}
"<== nxge_init_txdma_channels: status 0x%x", status));
return (NXGE_OK);
}
void
{
"<== nxge_uinit_txdma_channels"));
}
void
{
}
{
} else {
channel);
}
if (rs != NPI_SUCCESS) {
}
/*
* Reset the tail (kick) register to 0.
* (Hardware will not reset it. Tx overflow fatal
* error if tail is not set to 0 after reset!
*/
return (status);
}
{
"<== nxge_init_txdma_channel_event_mask"));
if (rs != NPI_SUCCESS) {
}
return (status);
}
{
"<== nxge_init_txdma_channel_cntl_stat"));
if (rs != NPI_SUCCESS) {
}
return (status);
}
{
/*
* Use configuration data composed at init time.
* Write to hardware the transmit ring configurations.
*/
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/* Write to hardware the mailbox */
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
/* Start the DMA engine. */
if (rs != NPI_SUCCESS) {
return (NXGE_ERROR | rs);
}
return (status);
}
void
{
64 + sizeof (uint32_t)];
/*
* Caller should zero out the headers first.
*/
if (fill_len) {
"==> nxge_fill_tx_hdr: pkt_len %d "
goto fill_tx_header_done;
}
/*
* mp is the original data packet (does not include the
* Neptune transmit header).
*/
"mp $%p b_rptr $%p len %d",
tmp = 1ull;
if (*(hdrs_buf + sizeof (struct ether_header))
== LLC_SNAP_SAP) {
sizeof (struct ether_header) + 6)));
"==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
eth_type));
} else {
goto fill_tx_header_done;
}
} else if (eth_type == VLAN_ETHERTYPE) {
tmp = 1ull;
hdrs_buf)->ether_type);
}
if (!is_vlan) {
eth_hdr_size = sizeof (struct ether_header);
} else {
eth_hdr_size = sizeof (struct ether_vlan_header);
}
switch (eth_type) {
case ETHERTYPE_IP:
mblk_len -= eth_hdr_size;
ip_buf += eth_hdr_size;
} else {
}
}
hdrs_size = 0;
sizeof (hdrs_buf))) {
if (mblk_len >=
}
ip_buf += eth_hdr_size;
}
" iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
"tmp 0x%x",
break;
case ETHERTYPE_IPV6:
hdrs_size = 0;
sizeof (hdrs_buf))) {
if (mblk_len >=
}
ip_buf += eth_hdr_size;
tmp = 1ull;
/* byte 6 is the next header protocol */
" iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
ipproto));
break;
default:
goto fill_tx_header_done;
}
switch (ipproto) {
case IPPROTO_TCP:
"==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
if (l4_cksum) {
tmp = 1ull;
"==> nxge_tx_pkt_hdr_init: TCP CKSUM"
}
break;
case IPPROTO_UDP:
if (l4_cksum) {
tmp = 0x2ull;
}
"==> nxge_tx_pkt_hdr_init: UDP"
break;
default:
goto fill_tx_header_done;
}
"==> nxge_fill_tx_hdr: pkt_len %d "
}
/*ARGSUSED*/
{
"<== nxge_tx_pkt_header_reserve: allocb failed"));
return (NULL);
}
"==> nxge_tx_pkt_header_reserve: get new mp"));
"b_rptr $%p b_wptr $%p",
"<== nxge_tx_pkt_header_reserve: use new mp"));
return (newmp);
}
int
{
"==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
nmblks = 0;
pkt_len = 0;
*tot_xfer_len_p = 0;
while (nmp) {
"len %d pkt_len %d nmblks %d tot_xfer_len %d",
*tot_xfer_len_p));
if (len <= 0) {
"==> nxge_tx_pkt_nmblocks: "
"len (0) pkt_len %d nmblks %d",
continue;
}
*tot_xfer_len_p += len;
"len %d pkt_len %d nmblks %d tot_xfer_len %d",
*tot_xfer_len_p));
if (len < nxge_bcopy_thresh) {
"==> nxge_tx_pkt_nmblocks: "
"len %d (< thresh) pkt_len %d nmblks %d",
if (pkt_len == 0)
nmblks++;
if (pkt_len >= nxge_bcopy_thresh) {
pkt_len = 0;
len = 0;
}
} else {
"==> nxge_tx_pkt_nmblocks: "
"len %d (> thresh) pkt_len %d nmblks %d",
pkt_len = 0;
nmblks++;
/*
* Hardware limits the transfer length to 4K.
* If len is more than 4K, we need to break
* it up to at most 2 more blocks.
*/
if (len > TX_MAX_TRANSFER_LENGTH) {
"==> nxge_tx_pkt_nmblocks: "
"len %d pkt_len %d nmblks %d nsegs %d",
nsegs = 1;
++nsegs;
}
do {
return (0);
}
nmblks++;
if (--nsegs) {
}
} while (nsegs);
}
}
/*
* Hardware limits the transmit gather pointers to 15.
*/
"==> nxge_tx_pkt_nmblocks: pull msg - "
"len %d pkt_len %d nmblks %d",
/* Pull all message blocks from b_cont */
return (0);
}
pkt_len = 0;
}
}
"<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
"nmblks %d len %d tot_xfer_len %d",
return (nmblks);
}
{
int rc;
(nmblks != 0));
"==> nxge_txdma_reclaim: pending %d reclaim %d nmblks %d",
nmblks));
if (!status) {
}
"==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
"tail_index %d tail_wrap %d "
"tx_desc_p $%p ($%p) ",
/*
* Read the hardware maintained transmit head
* and wrap around bit.
*/
"==> nxge_txdma_reclaim: "
"tx_rd_index %d tail %d tail_wrap %d "
"head %d wrap %d",
head_index, head_wrap));
if (head_index == tail_index) {
tail_index, tail_wrap) &&
(head_index == tx_rd_index)) {
"==> nxge_txdma_reclaim: EMPTY"));
return (B_TRUE);
}
"==> nxge_txdma_reclaim: Checking "
"if ring full"));
tail_wrap)) {
"==> nxge_txdma_reclaim: full"));
return (B_FALSE);
}
}
"==> nxge_txdma_reclaim: tx_rd_index and head_index"));
tx_desc_pp = &r_tx_desc;
while ((tx_rd_index != head_index) &&
(tx_ring_p->descs_pending != 0)) {
"==> nxge_txdma_reclaim: Checking if pending"));
"==> nxge_txdma_reclaim: "
"descs_pending %d ",
"==> nxge_txdma_reclaim: "
"(tx_rd_index %d head_index %d "
"(tx_desc_p $%p)",
tx_desc_p));
"==> nxge_txdma_reclaim: "
"(tx_rd_index %d head_index %d "
"tx_desc_p $%p (desc value 0x%llx) ",
"==> nxge_txdma_reclaim: dump desc:"));
"==> nxge_txdma_reclaim: pkt_len %d "
"tdc channel %d opackets %d",
tdc,
"tx_desc_p = $%p "
"tx_desc_pp = $%p "
"index = %d",
0, -1);
if (tx_ring_p->dvma_wr_index ==
tx_ring_p->dvma_wr_index = 0;
} else {
}
USE_DMA) {
"==> nxge_txdma_reclaim: "
"USE DMA"));
if (rc = ddi_dma_unbind_handle
(tx_msg_p->dma_handle)) {
"ddi_dma_unbind_handle "
"failed. status %d", rc);
}
}
"==> nxge_txdma_reclaim: count packets"));
/*
* count a chained packet only once.
*/
}
}
TX_FULL_MARK));
if (status) {
}
} else {
TX_FULL_MARK));
}
"<== nxge_txdma_reclaim status = 0x%08x", status));
return (status);
}
{
"<== nxge_tx_intr: nxgep $%p ldvp $%p",
return (DDI_INTR_UNCLAIMED);
}
}
"==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
/*
* This interrupt handler is for a specific
* transmit dma channel.
*/
/* Get the control and status for this channel. */
"==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
"channel %d",
"==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
"==> nxge_tx_intr:channel %d ring index %d "
"status 0x%08x (mk bit set)",
"==> nxge_tx_intr:channel %d ring index %d "
"status 0x%08x (mk bit set, calling reclaim)",
}
/*
* Process other transmit control and status.
* Check the ldv state.
*/
/*
* Rearm this logical group if this is a single device
* group.
*/
"==> nxge_tx_intr: rearm"));
}
}
return (serviced);
}
void
{
}
void
{
(void) nxge_txdma_stop(nxgep);
(void) nxge_fixup_txdma_rings(nxgep);
(void) nxge_tx_mac_enable(nxgep);
(void) nxge_txdma_hw_kick(nxgep);
}
{
int i, ndmas;
"==> nxge_txdma_hw_mode: enable mode %d", enable));
"<== nxge_txdma_mode: not initialized"));
return (NXGE_ERROR);
}
"<== nxge_txdma_hw_mode: NULL global ring pointer"));
return (NXGE_ERROR);
}
if (tx_desc_rings == NULL) {
"<== nxge_txdma_hw_mode: NULL rings pointer"));
return (NXGE_ERROR);
}
if (!ndmas) {
"<== nxge_txdma_hw_mode: no dma channel allocated"));
return (NXGE_ERROR);
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
"==> nxge_txdma_hw_mode: channel %d", channel));
if (enable) {
"==> nxge_txdma_hw_mode: channel %d (enable) "
} else {
/*
* Stop the dma channel and waits for the stop done.
* If the stop done bit is not set, then force
* an error so TXC will stop.
* All channels bound to this port need to be stopped
* and reset after injecting an interrupt error.
*/
"==> nxge_txdma_hw_mode: channel %d (disable) "
{
if (rs != NPI_SUCCESS) {
/* Inject any error */
"==> nxge_txdma_hw_mode: "
"channel %d (stop failed 0x%x) "
(void) npi_txdma_inj_int_error_set(
channel);
"==> nxge_txdma_hw_mode: "
"channel %d (stop again 0x%x) "
"(after inject err)",
}
}
}
}
"<== nxge_txdma_hw_mode: status 0x%x", status));
return (status);
}
void
{
"==> nxge_txdma_enable_channel: channel %d", channel));
/* enable the transmit dma channels */
}
void
{
"==> nxge_txdma_disable_channel: channel %d", channel));
/* stop the transmit dma channels */
}
int
{
int status;
/*
* Stop the dma channel waits for the stop done.
* If the stop done bit is not set, then create
* an error.
*/
"<== nxge_txdma_stop_inj_err (channel %d): "
"stopped OK", channel));
return (status);
}
"==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
/* Inject any error */
/* Stop done bit will be set as a result of error injection */
if (!(rs & NPI_TXDMA_STOP_FAILED)) {
"<== nxge_txdma_stop_inj_err (channel %d): "
"stopped OK ", channel));
return (status);
}
#if defined(NXGE_DEBUG)
#endif
"==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
return (status);
}
void
{
(void) nxge_txdma_hw_start(nxgep);
(void) nxge_tx_mac_enable(nxgep);
}
/*ARGSUSED*/
void
{
/*
* For each transmit channel, reclaim each descriptor and
* free buffers.
*/
"<== nxge_fixup_txdma_rings: NULL ring pointer"));
return;
}
if (!ndmas) {
"<== nxge_fixup_txdma_rings: no channel allocated"));
return;
}
"<== nxge_fixup_txdma_rings: NULL rings pointer"));
return;
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> nxge_fixup_txdma_rings: channel %d", channel));
channel);
}
}
/*ARGSUSED*/
void
{
return;
}
"<== nxge_txdma_fix_channel: channel not matched "
"ring tdc %d passed channel",
return;
}
}
/*ARGSUSED*/
void
{
"<== nxge_txdma_fixup_channel: NULL ring pointer"));
return;
}
"<== nxge_txdma_fixup_channel: channel not matched "
"ring tdc %d passed channel",
return;
}
ring_p->descs_pending = 0;
}
/*ARGSUSED*/
void
{
"<== nxge_txdma_hw_kick: NULL ring pointer"));
return;
}
if (!ndmas) {
"<== nxge_txdma_hw_kick: no channel allocated"));
return;
}
"<== nxge_txdma_hw_kick: NULL rings pointer"));
return;
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> nxge_txdma_hw_kick: channel %d", channel));
channel);
}
}
/*ARGSUSED*/
void
{
" nxge_txdma_kick_channel"));
return;
}
"<== nxge_txdma_kick_channel: channel not matched "
"ring tdc %d passed channel",
return;
}
}
/*ARGSUSED*/
void
{
"<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
return;
}
}
/*ARGSUSED*/
void
{
/*
* Needs inputs from hardware for regs:
* head index had not moved since last timeout.
* packets not transmitted or stuffed registers.
*/
if (nxge_txdma_hung(nxgep)) {
}
}
int
{
"<== nxge_txdma_hung: NULL ring pointer"));
return (B_FALSE);
}
if (!ndmas) {
"<== nxge_txdma_hung: no channel "
"allocated"));
return (B_FALSE);
}
"<== nxge_txdma_hung: NULL rings pointer"));
return (B_FALSE);
}
"==> nxge_txdma_hung: channel %d", channel));
return (B_TRUE);
}
}
return (B_FALSE);
}
int
{
"==> nxge_txdma_channel_hung: channel %d", channel));
"==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
"tail_index %d tail_wrap %d ",
/*
* Read the hardware maintained transmit head
* and wrap around bit.
*/
"==> nxge_txdma_channel_hung: "
"tx_rd_index %d tail %d tail_wrap %d "
"head %d wrap %d",
head_index, head_wrap));
tail_index, tail_wrap) &&
(head_index == tx_rd_index)) {
"==> nxge_txdma_channel_hung: EMPTY"));
return (B_FALSE);
}
"==> nxge_txdma_channel_hung: Checking if ring full"));
tail_wrap)) {
"==> nxge_txdma_channel_hung: full"));
return (B_TRUE);
}
return (B_FALSE);
}
/*ARGSUSED*/
void
{
"<== nxge_fixup_hung_txdma_rings: NULL ring pointer"));
return;
}
if (!ndmas) {
"<== nxge_fixup_hung_txdma_rings: no channel "
"allocated"));
return;
}
"<== nxge_fixup_hung_txdma_rings: NULL rings pointer"));
return;
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> nxge_fixup_hung_txdma_rings: channel %d",
channel));
channel);
}
}
/*ARGSUSED*/
void
{
"<== nxge_txdma_fix_hung_channel"));
return;
}
"<== nxge_txdma_fix_hung_channel: channel not matched "
"ring tdc %d passed channel",
return;
}
}
/*ARGSUSED*/
void
{
"<== nxge_txdma_fixup_channel: NULL ring pointer"));
return;
}
"<== nxge_txdma_fixup_hung_channel: channel "
"not matched "
"ring tdc %d passed channel",
return;
}
/* Reclaim descriptors */
/*
* Stop the dma channel waits for the stop done.
* If the stop done bit is not set, then force
* an error.
*/
if (!(status & NPI_TXDMA_STOP_FAILED)) {
"<== nxge_txdma_fixup_hung_channel: stopped OK "
"ring tdc %d passed channel %d",
return;
}
/* Inject any error */
/* Stop done bit will be set as a result of error injection */
if (!(status & NPI_TXDMA_STOP_FAILED)) {
"<== nxge_txdma_fixup_hung_channel: stopped again"
"ring tdc %d passed channel",
return;
}
"<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
"ring tdc %d passed channel",
}
/*ARGSUSED*/
void
{
"<== nxge_reclain_rimgs: NULL ring pointer"));
return;
}
if (!ndmas) {
"<== nxge_reclain_rimgs: no channel "
"allocated"));
return;
}
"<== nxge_reclain_rimgs: NULL rings pointer"));
return;
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> reclain_rimgs: channel %d",
channel));
}
}
void
{
(void) npi_txdma_dump_fzc_regs(handle);
"<== nxge_txdma_regs_dump_channels: NULL ring"));
return;
}
if (!ndmas) {
"<== nxge_txdma_regs_dump_channels: "
"no channel allocated"));
return;
}
"<== nxge_txdma_regs_dump_channels: NULL rings"));
return;
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> nxge_txdma_regs_dump_channels: channel %d",
channel));
}
/* Dump TXC registers */
(void) npi_txc_dump_fzc_regs(handle);
"==> nxge_txdma_regs_dump_channels: channel %d",
channel));
}
"==> nxge_txdma_regs_dump_channels: channel %d",
channel));
}
}
void
{
printf("\n\tfunc # %d tdc %d ",
printf("\n\tlog page func %d valid page 0 %d",
printf("\n\tlog page func %d valid page 1 %d",
printf("\n\thead value is 0x%0llx",
printf("\n\tkick value is 0x%0llx",
printf("\n\tTXC port control 0x%0llx",
{
}
}
/*
* Static functions start here.
*/
static nxge_status_t
{
int i, ndmas;
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
#endif
"==> nxge_map_txdma: buf not allocated"));
return (NXGE_ERROR);
}
if (!ndmas) {
"<== nxge_map_txdma: no dma allocated"));
return (NXGE_ERROR);
}
tx_rings = (p_tx_rings_t)
"tx_rings $%p tx_desc_rings $%p",
/*
* Map descriptors from the buffer pools for each dma channel.
*/
for (i = 0; i < ndmas; i++) {
/*
* Set up and prepare buffer blocks, descriptors
* and mailbox.
*/
(p_nxge_dma_common_t *)&dma_buf_p[i],
(p_tx_ring_t *)&tx_desc_rings[i],
dma_buf_poolp->num_chunks[i],
(p_nxge_dma_common_t *)&dma_cntl_p[i],
(p_tx_mbox_t *)&tx_mbox_p[i]);
goto nxge_map_txdma_fail1;
}
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
"==> nxge_map_txdma_channel: "
"hv data buf base io $%p "
"size 0x%llx (%d) "
"buf base io $%p "
"orig vatopa base io $%p "
"orig_len 0x%llx (%d)",
"==> nxge_map_txdma_channel: "
"hv cntl base io $%p "
"orig ioaddr_pp ($%p) "
"orig vatopa ($%p) "
"size 0x%llx (%d 0x%x)",
}
#endif
}
"tx_rings $%p rings $%p",
"tx_rings $%p tx_desc_rings $%p",
goto nxge_map_txdma_exit;
"==> nxge_map_txdma: uninit tx desc "
"(status 0x%x channel %d i %d)",
i--;
for (; i >= 0; i--) {
tx_desc_rings[i],
tx_mbox_p[i]);
}
"==> nxge_map_txdma: "
"(status 0x%x channel %d)",
return (status);
}
static void
{
int i, ndmas;
if (!dma_buf_poolp->buf_allocated) {
"==> nxge_unmap_txdma: buf not allocated"));
return;
}
if (!ndmas) {
"<== nxge_unmap_txdma: no dma allocated"));
return;
}
"<== nxge_unmap_txdma: NULL ring pointer"));
return;
}
if (tx_desc_rings == NULL) {
"<== nxge_unmap_txdma: NULL ring pointers"));
return;
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
for (i = 0; i < ndmas; i++) {
(p_tx_ring_t)tx_desc_rings[i],
(p_tx_mbox_t)tx_mbox_p[i]);
}
"<== nxge_unmap_txdma"));
}
static nxge_status_t
{
/*
* Set up and prepare buffer blocks, descriptors
* and mailbox.
*/
"==> nxge_map_txdma_channel (channel %d)", channel));
/*
* Transmit buffer blocks
*/
"==> nxge_map_txdma_channel (channel %d): "
}
/*
* Transmit block ring, and mailbox.
*/
"==> nxge_map_txdma_channel: unmap buf"
"(status 0x%x channel %d)",
"<== nxge_map_txdma_channel: "
"(status 0x%x channel %d)",
return (status);
}
/*ARGSUSED*/
static void
{
"==> nxge_unmap_txdma_channel (channel %d)", channel));
/*
* unmap tx block ring, and mailbox.
*/
/* unmap buffer blocks */
}
/*ARGSUSED*/
static void
{
"==> nxge_map_txdma_channel_cfg_ring"));
cntl_dmap = *dma_cntl_p;
sizeof (tx_desc_t));
/*
* Zero out transmit ring descriptors.
*/
tx_ring_cfig_p->value = 0;
tx_ring_kick_p->value = 0;
tx_evmask_p->value = 0;
"==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
tx_ring_cfig_p->value = 0;
"==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
tx_ring_cfig_p->value));
/* Map in mailbox */
mboxp = (p_tx_mbox_t)
"==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
"==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
"==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
"mbox $%p",
"<== nxge_map_txdma_channel_cfg_ring"));
}
/*ARGSUSED*/
static void
{
"==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
"<== nxge_unmap_txdma_channel_cfg_ring"));
}
static nxge_status_t
{
int ddi_status = DDI_SUCCESS;
int i, j, index;
"==> nxge_map_txdma_channel_buf_ring"));
" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
"chunks bufp $%p",
nmsgs = 0;
for (i = 0; i < num_chunks; i++, tmp_bufp++) {
"==> nxge_map_txdma_channel_buf_ring: channel %d "
"bufp $%p nblocks %d nmsgs %d",
}
if (!nmsgs) {
"<== nxge_map_txdma_channel_buf_ring: channel %d "
"no msg blocks",
channel));
status = NXGE_ERROR;
}
tx_ring_p = (p_tx_ring_t)
(void *)nxgep->interrupt_cookie);
/*
* Allocate transmit message rings and handles for packets
* not to be copied to premapped buffers.
*/
for (i = 0; i < nmsgs; i++) {
DDI_DMA_DONTWAIT, 0,
&tx_msg_ring[i].dma_handle);
if (ddi_status != DDI_SUCCESS) {
break;
}
}
if (i < nmsgs) {
"Allocate handles failed."));
}
if (!nxge_tx_intr_thres) {
}
tx_ring_p->descs_pending = 0;
"==> nxge_map_txdma_channel_buf_ring: channel %d "
"actual tx desc max %d nmsgs %d "
"(config nxge_tx_ring_size %d)",
/*
* Map in buffers from the buffer pool.
*/
index = 0;
"dma_bufp $%p tx_rng_p $%p "
"tx_msg_rng_p $%p bsize %d",
for (i = 0; i < num_chunks; i++, dma_bufp++) {
"==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
"size %d dma_bufp $%p",
i, sizeof (nxge_dma_common_t), dma_bufp));
for (j = 0; j < nblocks; j++) {
#ifdef TX_MEM_DEBUG
"==> nxge_map_txdma_channel_buf_ring: j %d"
"dmap $%p", i, dmap));
#endif
bsize);
}
}
if (i < num_chunks) {
status = NXGE_ERROR;
}
}
index--;
}
}
status = NXGE_ERROR;
"<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
return (status);
}
/*ARGSUSED*/
static void
{
int i;
"==> nxge_unmap_txdma_channel_buf_ring"));
"<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
return;
}
"==> nxge_unmap_txdma_channel_buf_ring: channel %d",
for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
tx_msg_p = &tx_msg_ring[i];
"entry = %d",
i));
0, -1);
if (tx_ring_p->dvma_wr_index ==
tx_ring_p->dvma_wr_index = 0;
} else {
}
USE_DMA) {
(tx_msg_p->dma_handle)) {
"ddi_dma_unbind_handle "
"failed.");
}
}
}
}
for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
}
}
}
"<== nxge_unmap_txdma_channel_buf_ring"));
}
static nxge_status_t
{
int i, ndmas;
"<== nxge_txdma_hw_start: NULL ring pointer"));
return (NXGE_ERROR);
}
if (tx_desc_rings == NULL) {
"<== nxge_txdma_hw_start: NULL ring pointers"));
return (NXGE_ERROR);
}
if (!ndmas) {
"<== nxge_txdma_hw_start: no dma channel allocated"));
return (NXGE_ERROR);
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
for (i = 0; i < ndmas; i++) {
(p_tx_ring_t)tx_desc_rings[i],
(p_tx_mbox_t)tx_mbox_p[i]);
}
}
"tx_rings $%p rings $%p",
"tx_rings $%p tx_desc_rings $%p",
goto nxge_txdma_hw_start_exit;
"==> nxge_txdma_hw_start: disable "
for (; i >= 0; i--) {
(p_tx_ring_t)tx_desc_rings[i],
(p_tx_mbox_t)tx_mbox_p[i]);
}
"==> nxge_txdma_hw_start: (status 0x%x)", status));
return (status);
}
static void
{
int i, ndmas;
"<== nxge_txdma_hw_stop: NULL ring pointer"));
return;
}
if (tx_desc_rings == NULL) {
"<== nxge_txdma_hw_stop: NULL ring pointers"));
return;
}
if (!ndmas) {
"<== nxge_txdma_hw_stop: no dma channel allocated"));
return;
}
"tx_rings $%p tx_desc_rings $%p",
for (i = 0; i < ndmas; i++) {
(p_tx_ring_t)tx_desc_rings[i],
(p_tx_mbox_t)tx_mbox_p[i]);
}
"tx_rings $%p tx_desc_rings $%p",
}
static nxge_status_t
{
"==> nxge_txdma_start_channel (channel %d)", channel));
/*
*/
/*
* Reset TXDMA channel
*/
"==> nxge_txdma_start_channel (channel %d)"
}
/*
* Initialize the TXDMA channel specific FZC control
* configurations. These FZC registers are pertaining
* to each TX channel (i.e. logical pages).
*/
}
/*
* Initialize the event masks.
*/
}
/*
* Load TXDMA descriptors, buffers, mailbox,
* initialise the DMA channels and
* enable each DMA channel.
*/
}
return (status);
}
/*ARGSUSED*/
static nxge_status_t
{
"==> nxge_txdma_stop_channel: channel %d", channel));
/*
* Stop (disable) TXDMA and TXC (if stop bit is set
* and STOP_N_GO bit not set, the TXDMA reset state will
* not be set if reset TXDMA.
*/
/*
* Reset TXDMA channel
*/
}
#ifdef HARDWARE_REQUIRED
/* Set up the interrupt event masks. */
}
/* Initialize the DMA control and status register */
}
/* Disable channel */
}
"==> nxge_txdma_stop_channel: event done"));
#endif
return (status);
}
static p_tx_ring_t
{
"<== nxge_txdma_get_ring: NULL ring pointer"));
return (NULL);
}
if (!ndmas) {
"<== nxge_txdma_get_ring: no channel allocated"));
return (NULL);
}
"<== nxge_txdma_get_ring: NULL rings pointer"));
return (NULL);
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> nxge_fixup_txdma_rings: channel %d", tdc));
"<== nxge_txdma_get_ring: tdc %d "
"ring $%p",
}
}
return (NULL);
}
static p_tx_mbox_t
{
"<== nxge_txdma_get_mbox: NULL ring pointer"));
return (NULL);
}
if (tx_mbox_areas_p == NULL) {
"<== nxge_txdma_get_mbox: NULL mbox pointer"));
return (NULL);
}
if (!ndmas) {
"<== nxge_txdma_get_mbox: no channel allocated"));
return (NULL);
}
"<== nxge_txdma_get_mbox: NULL rings pointer"));
return (NULL);
}
"tx_rings $%p tx_desc_rings $%p ndmas %d",
"==> nxge_txdma_get_mbox: channel %d", tdc));
"<== nxge_txdma_get_mbox: tdc %d "
"ring $%p",
}
}
return (NULL);
}
/*ARGSUSED*/
static nxge_status_t
{
return (NXGE_ERROR | rs);
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: mailbox", channel));
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: pkt_size_err", channel));
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: tx_ring_oflow", channel));
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: pre_buf_par_err", channel));
/* Clear error injection source for parity error */
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: nack_pref", channel));
}
tdc_stats->nack_pkt_rd++;
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: nack_pkt_rd", channel));
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: config_partition_err", channel));
}
"==> nxge_tx_err_evnts(channel %d): "
"fatal error: pkt_prt_err", channel));
}
/* Clear error injection source in case this is an injected error */
if (txchan_fatal) {
" nxge_tx_err_evnts: "
" fatal error on channel %d cs 0x%llx\n",
}
}
return (status);
}
static nxge_status_t
{
"Recovering from TxDMAChannel#%d error...", channel));
/*
* Stop the dma channel waits for the stop done.
* If the stop done bit is not set, then create
* an error.
*/
if (rs != NPI_SUCCESS) {
"==> nxge_txdma_fatal_err_recover (channel %d): "
"stop failed ", channel));
goto fail;
}
/*
* Reset TXDMA channel
*/
NPI_SUCCESS) {
"==> nxge_txdma_fatal_err_recover (channel %d)"
goto fail;
}
/*
* Reset the tail (kick) register to 0.
* (Hardware will not reset it. Tx overflow fatal
* error if tail is not set to 0 after reset!
*/
/* Restart TXDMA channel */
/*
* Initialize the TXDMA channel specific FZC control
* configurations. These FZC registers are pertaining
* to each TX channel (i.e. logical pages).
*/
goto fail;
/*
* Initialize the event masks.
*/
goto fail;
/*
* Load TXDMA descriptors, buffers, mailbox,
* initialise the DMA channels and
* enable each DMA channel.
*/
goto fail;
"Recovery Successful, TxDMAChannel#%d Restored",
channel));
return (NXGE_OK);
fail:
"nxge_txdma_fatal_err_recover (channel %d): "
"failed to recover this txdma channel", channel));
return (status);
}
{
int i, ndmas;
"Recovering from TxPort error..."));
/*
* Stop the dma channel waits for the stop done.
* If the stop done bit is not set, then create
* an error.
*/
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
}
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
if (rs != NPI_SUCCESS) {
"==> nxge_txdma_fatal_err_recover (channel %d): "
"stop failed ", channel));
goto fail;
}
}
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
}
/*
* Reset TXDMA channel
*/
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
channel)) != NPI_SUCCESS) {
"==> nxge_txdma_fatal_err_recover (channel %d)"
goto fail;
}
/*
* Reset the tail (kick) register to 0.
* (Hardware will not reset it. Tx overflow fatal
* error if tail is not set to 0 after reset!
*/
}
/*
* Initialize the TXDMA channel specific FZC control
* configurations. These FZC registers are pertaining
* to each TX channel (i.e. logical pages).
*/
/* Restart TXDMA channels */
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
/*
* Initialize the event masks.
*/
goto fail;
goto fail;
}
/*
* Load TXDMA descriptors, buffers, mailbox,
* initialise the DMA channels and
* enable each DMA channel.
*/
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
goto fail;
}
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
}
"Recovery Successful, TxPort Restored"));
return (NXGE_OK);
fail:
for (i = 0; i < ndmas; i++) {
if (tx_desc_rings[i] == NULL) {
continue;
}
}
"nxge_txdma_fatal_err_recover (channel %d): "
"failed to recover this txdma channel"));
return (status);
}
void
{
switch (err_id) {
/* Clear error injection source for parity error */
break;
else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
break;
}
}