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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/nxge/nxge_impl.h>
  28 #include <sys/nxge/nxge_txdma.h>
  29 #include <sys/nxge/nxge_hio.h>
  30 #include <npi_tx_rd64.h>
  31 #include <npi_tx_wr64.h>
  32 #include <sys/llc1.h>
  33 
  34 uint32_t        nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
  35 uint32_t        nxge_tx_minfree = 64;
  36 uint32_t        nxge_tx_intr_thres = 0;
  37 uint32_t        nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
  38 uint32_t        nxge_tx_tiny_pack = 1;
  39 uint32_t        nxge_tx_use_bcopy = 1;
  40 
  41 extern uint32_t         nxge_tx_ring_size;
  42 extern uint32_t         nxge_bcopy_thresh;
  43 extern uint32_t         nxge_dvma_thresh;
  44 extern uint32_t         nxge_dma_stream_thresh;
  45 extern dma_method_t     nxge_force_dma;
  46 extern uint32_t         nxge_cksum_offload;
  47 
  48 /* Device register access attributes for PIO.  */
  49 extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
  50 /* Device descriptor access attributes for DMA.  */
  51 extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
  52 /* Device buffer access attributes for DMA.  */
  53 extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
  54 extern ddi_dma_attr_t nxge_desc_dma_attr;
  55 extern ddi_dma_attr_t nxge_tx_dma_attr;
  56 
  57 extern void nxge_tx_ring_task(void *arg);
  58 
  59 static nxge_status_t nxge_map_txdma(p_nxge_t, int);
  60 
  61 static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int);
  62 
  63 static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t,
  64         p_nxge_dma_common_t *, p_tx_ring_t *,
  65         uint32_t, p_nxge_dma_common_t *,
  66         p_tx_mbox_t *);
  67 static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t);
  68 
  69 static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t,
  70         p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t);
  71 static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t);
  72 
  73 static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t,
  74         p_nxge_dma_common_t *, p_tx_ring_t,
  75         p_tx_mbox_t *);
  76 static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
  77         p_tx_ring_t, p_tx_mbox_t);
  78 
  79 static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t,
  80     p_tx_ring_t, p_tx_mbox_t);
  81 static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t);
  82 
  83 static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t);
  84 static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t,
  85         p_nxge_ldv_t, tx_cs_t);
  86 static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t);
  87 static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t,
  88         uint16_t, p_tx_ring_t);
  89 
  90 static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep,
  91     p_tx_ring_t ring_p, uint16_t channel);
  92 
  93 nxge_status_t
  94 nxge_init_txdma_channels(p_nxge_t nxgep)
  95 {
  96         nxge_grp_set_t  *set = &nxgep->tx_set;
  97         int             i, tdc, count;
  98         nxge_grp_t      *group;
  99         dc_map_t        map;
 100         int             dev_gindex;
 101 
 102         NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels"));
 103 
 104         for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
 105                 if ((1 << i) & set->lg.map) {
 106                         group = set->group[i];
 107                         dev_gindex =
 108                             nxgep->pt_config.hw_config.def_mac_txdma_grpid + i;
 109                         map = nxgep->pt_config.tdc_grps[dev_gindex].map;
 110                         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
 111                                 if ((1 << tdc) & map) {
 112                                         if ((nxge_grp_dc_add(nxgep,
 113                                             group, VP_BOUND_TX, tdc)))
 114                                                 goto init_txdma_channels_exit;
 115                                 }
 116                         }
 117                 }
 118                 if (++count == set->lg.count)
 119                         break;
 120         }
 121 
 122         NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels"));
 123         return (NXGE_OK);
 124 
 125 init_txdma_channels_exit:
 126         for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
 127                 if ((1 << i) & set->lg.map) {
 128                         group = set->group[i];
 129                         dev_gindex =
 130                             nxgep->pt_config.hw_config.def_mac_txdma_grpid + i;
 131                         map = nxgep->pt_config.tdc_grps[dev_gindex].map;
 132                         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
 133                                 if ((1 << tdc) & map) {
 134                                         nxge_grp_dc_remove(nxgep,
 135                                             VP_BOUND_TX, tdc);
 136                                 }
 137                         }
 138                 }
 139                 if (++count == set->lg.count)
 140                         break;
 141         }
 142 
 143         return (NXGE_ERROR);
 144 
 145 }
 146 
 147 nxge_status_t
 148 nxge_init_txdma_channel(
 149         p_nxge_t nxge,
 150         int channel)
 151 {
 152         nxge_status_t status;
 153 
 154         NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel"));
 155 
 156         status = nxge_map_txdma(nxge, channel);
 157         if (status != NXGE_OK) {
 158                 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
 159                     "<== nxge_init_txdma_channel: status 0x%x", status));
 160                 (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
 161                 return (status);
 162         }
 163 
 164         status = nxge_txdma_hw_start(nxge, channel);
 165         if (status != NXGE_OK) {
 166                 (void) nxge_unmap_txdma_channel(nxge, channel);
 167                 (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
 168                 return (status);
 169         }
 170 
 171         if (!nxge->statsp->tdc_ksp[channel])
 172                 nxge_setup_tdc_kstats(nxge, channel);
 173 
 174         NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel"));
 175 
 176         return (status);
 177 }
 178 
 179 void
 180 nxge_uninit_txdma_channels(p_nxge_t nxgep)
 181 {
 182         nxge_grp_set_t *set = &nxgep->tx_set;
 183         int tdc;
 184 
 185         NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels"));
 186 
 187         if (set->owned.map == 0) {
 188                 NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
 189                     "nxge_uninit_txdma_channels: no channels"));
 190                 return;
 191         }
 192 
 193         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
 194                 if ((1 << tdc) & set->owned.map) {
 195                         nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc);
 196                 }
 197         }
 198 
 199         NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels"));
 200 }
 201 
 202 void
 203 nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel)
 204 {
 205         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel"));
 206 
 207         if (nxgep->statsp->tdc_ksp[channel]) {
 208                 kstat_delete(nxgep->statsp->tdc_ksp[channel]);
 209                 nxgep->statsp->tdc_ksp[channel] = 0;
 210         }
 211 
 212         if (nxge_txdma_stop_channel(nxgep, channel) != NXGE_OK)
 213                 goto nxge_uninit_txdma_channel_exit;
 214 
 215         nxge_unmap_txdma_channel(nxgep, channel);
 216 
 217 nxge_uninit_txdma_channel_exit:
 218         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_uninit_txdma_channel"));
 219 }
 220 
 221 void
 222 nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
 223         uint32_t entries, uint32_t size)
 224 {
 225         size_t          tsize;
 226         *dest_p = *src_p;
 227         tsize = size * entries;
 228         dest_p->alength = tsize;
 229         dest_p->nblocks = entries;
 230         dest_p->block_size = size;
 231         dest_p->offset += tsize;
 232 
 233         src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
 234         src_p->alength -= tsize;
 235         src_p->dma_cookie.dmac_laddress += tsize;
 236         src_p->dma_cookie.dmac_size -= tsize;
 237 }
 238 
 239 /*
 240  * nxge_reset_txdma_channel
 241  *
 242  *      Reset a TDC.
 243  *
 244  * Arguments:
 245  *      nxgep
 246  *      channel         The channel to reset.
 247  *      reg_data        The current TX_CS.
 248  *
 249  * Notes:
 250  *
 251  * NPI/NXGE function calls:
 252  *      npi_txdma_channel_reset()
 253  *      npi_txdma_channel_control()
 254  *
 255  * Registers accessed:
 256  *      TX_CS           DMC+0x40028 Transmit Control And Status
 257  *      TX_RING_KICK    DMC+0x40018 Transmit Ring Kick
 258  *
 259  * Context:
 260  *      Any domain
 261  */
 262 nxge_status_t
 263 nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
 264 {
 265         npi_status_t            rs = NPI_SUCCESS;
 266         nxge_status_t           status = NXGE_OK;
 267         npi_handle_t            handle;
 268 
 269         NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
 270 
 271         handle = NXGE_DEV_NPI_HANDLE(nxgep);
 272         if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
 273                 rs = npi_txdma_channel_reset(handle, channel);
 274         } else {
 275                 rs = npi_txdma_channel_control(handle, TXDMA_RESET,
 276                     channel);
 277         }
 278 
 279         if (rs != NPI_SUCCESS) {
 280                 status = NXGE_ERROR | rs;
 281         }
 282 
 283         /*
 284          * Reset the tail (kick) register to 0.
 285          * (Hardware will not reset it. Tx overflow fatal
 286          * error if tail is not set to 0 after reset!
 287          */
 288         TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
 289 
 290         NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
 291         return (status);
 292 }
 293 
 294 /*
 295  * nxge_init_txdma_channel_event_mask
 296  *
 297  *      Enable interrupts for a set of events.
 298  *
 299  * Arguments:
 300  *      nxgep
 301  *      channel The channel to map.
 302  *      mask_p  The events to enable.
 303  *
 304  * Notes:
 305  *
 306  * NPI/NXGE function calls:
 307  *      npi_txdma_event_mask()
 308  *
 309  * Registers accessed:
 310  *      TX_ENT_MSK      DMC+0x40020 Transmit Event Mask
 311  *
 312  * Context:
 313  *      Any domain
 314  */
 315 nxge_status_t
 316 nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
 317                 p_tx_dma_ent_msk_t mask_p)
 318 {
 319         npi_handle_t            handle;
 320         npi_status_t            rs = NPI_SUCCESS;
 321         nxge_status_t           status = NXGE_OK;
 322 
 323         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
 324             "<== nxge_init_txdma_channel_event_mask"));
 325 
 326         handle = NXGE_DEV_NPI_HANDLE(nxgep);
 327         rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
 328         if (rs != NPI_SUCCESS) {
 329                 status = NXGE_ERROR | rs;
 330         }
 331 
 332         return (status);
 333 }
 334 
 335 /*
 336  * nxge_init_txdma_channel_cntl_stat
 337  *
 338  *      Stop a TDC.  If at first we don't succeed, inject an error.
 339  *
 340  * Arguments:
 341  *      nxgep
 342  *      channel         The channel to stop.
 343  *
 344  * Notes:
 345  *
 346  * NPI/NXGE function calls:
 347  *      npi_txdma_control_status()
 348  *
 349  * Registers accessed:
 350  *      TX_CS           DMC+0x40028 Transmit Control And Status
 351  *
 352  * Context:
 353  *      Any domain
 354  */
 355 nxge_status_t
 356 nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
 357         uint64_t reg_data)
 358 {
 359         npi_handle_t            handle;
 360         npi_status_t            rs = NPI_SUCCESS;
 361         nxge_status_t           status = NXGE_OK;
 362 
 363         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
 364             "<== nxge_init_txdma_channel_cntl_stat"));
 365 
 366         handle = NXGE_DEV_NPI_HANDLE(nxgep);
 367         rs = npi_txdma_control_status(handle, OP_SET, channel,
 368             (p_tx_cs_t)&reg_data);
 369 
 370         if (rs != NPI_SUCCESS) {
 371                 status = NXGE_ERROR | rs;
 372         }
 373 
 374         return (status);
 375 }
 376 
 377 /*
 378  * nxge_enable_txdma_channel
 379  *
 380  *      Enable a TDC.
 381  *
 382  * Arguments:
 383  *      nxgep
 384  *      channel         The channel to enable.
 385  *      tx_desc_p       channel's transmit descriptor ring.
 386  *      mbox_p          channel's mailbox,
 387  *
 388  * Notes:
 389  *
 390  * NPI/NXGE function calls:
 391  *      npi_txdma_ring_config()
 392  *      npi_txdma_mbox_config()
 393  *      npi_txdma_channel_init_enable()
 394  *
 395  * Registers accessed:
 396  *      TX_RNG_CFIG     DMC+0x40000 Transmit Ring Configuration
 397  *      TXDMA_MBH       DMC+0x40030 TXDMA Mailbox High
 398  *      TXDMA_MBL       DMC+0x40038 TXDMA Mailbox Low
 399  *      TX_CS           DMC+0x40028 Transmit Control And Status
 400  *
 401  * Context:
 402  *      Any domain
 403  */
 404 nxge_status_t
 405 nxge_enable_txdma_channel(p_nxge_t nxgep,
 406         uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
 407 {
 408         npi_handle_t            handle;
 409         npi_status_t            rs = NPI_SUCCESS;
 410         nxge_status_t           status = NXGE_OK;
 411 
 412         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
 413 
 414         handle = NXGE_DEV_NPI_HANDLE(nxgep);
 415         /*
 416          * Use configuration data composed at init time.
 417          * Write to hardware the transmit ring configurations.
 418          */
 419         rs = npi_txdma_ring_config(handle, OP_SET, channel,
 420             (uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
 421 
 422         if (rs != NPI_SUCCESS) {
 423                 return (NXGE_ERROR | rs);
 424         }
 425 
 426         if (isLDOMguest(nxgep)) {
 427                 /* Add interrupt handler for this channel. */
 428                 if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK)
 429                         return (NXGE_ERROR);
 430         }
 431 
 432         /* Write to hardware the mailbox */
 433         rs = npi_txdma_mbox_config(handle, OP_SET, channel,
 434             (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
 435 
 436         if (rs != NPI_SUCCESS) {
 437                 return (NXGE_ERROR | rs);
 438         }
 439 
 440         /* Start the DMA engine. */
 441         rs = npi_txdma_channel_init_enable(handle, channel);
 442 
 443         if (rs != NPI_SUCCESS) {
 444                 return (NXGE_ERROR | rs);
 445         }
 446 
 447         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
 448 
 449         return (status);
 450 }
 451 
 452 void
 453 nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
 454                 boolean_t l4_cksum, int pkt_len, uint8_t npads,
 455                 p_tx_pkt_hdr_all_t pkthdrp,
 456                 t_uscalar_t start_offset,
 457                 t_uscalar_t stuff_offset)
 458 {
 459         p_tx_pkt_header_t       hdrp;
 460         p_mblk_t                nmp;
 461         uint64_t                tmp;
 462         size_t                  mblk_len;
 463         size_t                  iph_len;
 464         size_t                  hdrs_size;
 465         uint8_t                 hdrs_buf[sizeof (struct ether_header) +
 466             64 + sizeof (uint32_t)];
 467         uint8_t                 *cursor;
 468         uint8_t                 *ip_buf;
 469         uint16_t                eth_type;
 470         uint8_t                 ipproto;
 471         boolean_t               is_vlan = B_FALSE;
 472         size_t                  eth_hdr_size;
 473 
 474         NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
 475 
 476         /*
 477          * Caller should zero out the headers first.
 478          */
 479         hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
 480 
 481         if (fill_len) {
 482                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 483                     "==> nxge_fill_tx_hdr: pkt_len %d "
 484                     "npads %d", pkt_len, npads));
 485                 tmp = (uint64_t)pkt_len;
 486                 hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
 487                 goto fill_tx_header_done;
 488         }
 489 
 490         hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT);
 491 
 492         /*
 493          * mp is the original data packet (does not include the
 494          * Neptune transmit header).
 495          */
 496         nmp = mp;
 497         NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
 498             "mp $%p b_rptr $%p len %d",
 499             mp, nmp->b_rptr, MBLKL(nmp)));
 500         /* copy ether_header from mblk to hdrs_buf */
 501         cursor = &hdrs_buf[0];
 502         tmp = sizeof (struct ether_vlan_header);
 503         while ((nmp != NULL) && (tmp > 0)) {
 504                 size_t buflen;
 505                 mblk_len = MBLKL(nmp);
 506                 buflen = min((size_t)tmp, mblk_len);
 507                 bcopy(nmp->b_rptr, cursor, buflen);
 508                 cursor += buflen;
 509                 tmp -= buflen;
 510                 nmp = nmp->b_cont;
 511         }
 512 
 513         nmp = mp;
 514         mblk_len = MBLKL(nmp);
 515         ip_buf = NULL;
 516         eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
 517         NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
 518             "ether type 0x%x", eth_type, hdrp->value));
 519 
 520         if (eth_type < ETHERMTU) {
 521                 tmp = 1ull;
 522                 hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
 523                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
 524                     "value 0x%llx", hdrp->value));
 525                 if (*(hdrs_buf + sizeof (struct ether_header))
 526                     == LLC_SNAP_SAP) {
 527                         eth_type = ntohs(*((uint16_t *)(hdrs_buf +
 528                             sizeof (struct ether_header) + 6)));
 529                         NXGE_DEBUG_MSG((NULL, TX_CTL,
 530                             "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
 531                             eth_type));
 532                 } else {
 533                         goto fill_tx_header_done;
 534                 }
 535         } else if (eth_type == VLAN_ETHERTYPE) {
 536                 tmp = 1ull;
 537                 hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
 538 
 539                 eth_type = ntohs(((struct ether_vlan_header *)
 540                     hdrs_buf)->ether_type);
 541                 is_vlan = B_TRUE;
 542                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
 543                     "value 0x%llx", hdrp->value));
 544         }
 545 
 546         if (!is_vlan) {
 547                 eth_hdr_size = sizeof (struct ether_header);
 548         } else {
 549                 eth_hdr_size = sizeof (struct ether_vlan_header);
 550         }
 551 
 552         switch (eth_type) {
 553         case ETHERTYPE_IP:
 554                 if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
 555                         ip_buf = nmp->b_rptr + eth_hdr_size;
 556                         mblk_len -= eth_hdr_size;
 557                         iph_len = ((*ip_buf) & 0x0f);
 558                         if (mblk_len > (iph_len + sizeof (uint32_t))) {
 559                                 ip_buf = nmp->b_rptr;
 560                                 ip_buf += eth_hdr_size;
 561                         } else {
 562                                 ip_buf = NULL;
 563                         }
 564 
 565                 }
 566                 if (ip_buf == NULL) {
 567                         hdrs_size = 0;
 568                         ((p_ether_header_t)hdrs_buf)->ether_type = 0;
 569                         while ((nmp) && (hdrs_size <
 570                             sizeof (hdrs_buf))) {
 571                                 mblk_len = (size_t)nmp->b_wptr -
 572                                     (size_t)nmp->b_rptr;
 573                                 if (mblk_len >=
 574                                     (sizeof (hdrs_buf) - hdrs_size))
 575                                         mblk_len = sizeof (hdrs_buf) -
 576                                             hdrs_size;
 577                                 bcopy(nmp->b_rptr,
 578                                     &hdrs_buf[hdrs_size], mblk_len);
 579                                 hdrs_size += mblk_len;
 580                                 nmp = nmp->b_cont;
 581                         }
 582                         ip_buf = hdrs_buf;
 583                         ip_buf += eth_hdr_size;
 584                         iph_len = ((*ip_buf) & 0x0f);
 585                 }
 586 
 587                 ipproto = ip_buf[9];
 588 
 589                 tmp = (uint64_t)iph_len;
 590                 hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
 591                 tmp = (uint64_t)(eth_hdr_size >> 1);
 592                 hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
 593 
 594                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
 595                     " iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
 596                     "tmp 0x%x",
 597                     iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
 598                     ipproto, tmp));
 599                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
 600                     "value 0x%llx", hdrp->value));
 601 
 602                 break;
 603 
 604         case ETHERTYPE_IPV6:
 605                 hdrs_size = 0;
 606                 ((p_ether_header_t)hdrs_buf)->ether_type = 0;
 607                 while ((nmp) && (hdrs_size <
 608                     sizeof (hdrs_buf))) {
 609                         mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
 610                         if (mblk_len >=
 611                             (sizeof (hdrs_buf) - hdrs_size))
 612                                 mblk_len = sizeof (hdrs_buf) -
 613                                     hdrs_size;
 614                         bcopy(nmp->b_rptr,
 615                             &hdrs_buf[hdrs_size], mblk_len);
 616                         hdrs_size += mblk_len;
 617                         nmp = nmp->b_cont;
 618                 }
 619                 ip_buf = hdrs_buf;
 620                 ip_buf += eth_hdr_size;
 621 
 622                 tmp = 1ull;
 623                 hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
 624 
 625                 tmp = (eth_hdr_size >> 1);
 626                 hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
 627 
 628                 /* byte 6 is the next header protocol */
 629                 ipproto = ip_buf[6];
 630 
 631                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
 632                     " iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
 633                     iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
 634                     ipproto));
 635                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
 636                     "value 0x%llx", hdrp->value));
 637 
 638                 break;
 639 
 640         default:
 641                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
 642                 goto fill_tx_header_done;
 643         }
 644 
 645         switch (ipproto) {
 646         case IPPROTO_TCP:
 647                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 648                     "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
 649                 if (l4_cksum) {
 650                         hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP;
 651                         hdrp->value |=
 652                             (((uint64_t)(start_offset >> 1)) <<
 653                             TX_PKT_HEADER_L4START_SHIFT);
 654                         hdrp->value |=
 655                             (((uint64_t)(stuff_offset >> 1)) <<
 656                             TX_PKT_HEADER_L4STUFF_SHIFT);
 657 
 658                         NXGE_DEBUG_MSG((NULL, TX_CTL,
 659                             "==> nxge_tx_pkt_hdr_init: TCP CKSUM "
 660                             "value 0x%llx", hdrp->value));
 661                 }
 662 
 663                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
 664                     "value 0x%llx", hdrp->value));
 665                 break;
 666 
 667         case IPPROTO_UDP:
 668                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
 669                 if (l4_cksum) {
 670                         if (!nxge_cksum_offload) {
 671                                 uint16_t        *up;
 672                                 uint16_t        cksum;
 673                                 t_uscalar_t     stuff_len;
 674 
 675                                 /*
 676                                  * The checksum field has the
 677                                  * partial checksum.
 678                                  * IP_CSUM() macro calls ip_cksum() which
 679                                  * can add in the partial checksum.
 680                                  */
 681                                 cksum = IP_CSUM(mp, start_offset, 0);
 682                                 stuff_len = stuff_offset;
 683                                 nmp = mp;
 684                                 mblk_len = MBLKL(nmp);
 685                                 while ((nmp != NULL) &&
 686                                     (mblk_len < stuff_len)) {
 687                                         stuff_len -= mblk_len;
 688                                         nmp = nmp->b_cont;
 689                                         if (nmp)
 690                                                 mblk_len = MBLKL(nmp);
 691                                 }
 692                                 ASSERT(nmp);
 693                                 up = (uint16_t *)(nmp->b_rptr + stuff_len);
 694 
 695                                 *up = cksum;
 696                                 hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP;
 697                                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 698                                     "==> nxge_tx_pkt_hdr_init: UDP offset %d "
 699                                     "use sw cksum "
 700                                     "write to $%p cksum 0x%x content up 0x%x",
 701                                     stuff_len,
 702                                     up,
 703                                     cksum,
 704                                     *up));
 705                         } else {
 706                                 /* Hardware will compute the full checksum */
 707                                 hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP;
 708                                 hdrp->value |=
 709                                     (((uint64_t)(start_offset >> 1)) <<
 710                                     TX_PKT_HEADER_L4START_SHIFT);
 711                                 hdrp->value |=
 712                                     (((uint64_t)(stuff_offset >> 1)) <<
 713                                     TX_PKT_HEADER_L4STUFF_SHIFT);
 714 
 715                                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 716                                     "==> nxge_tx_pkt_hdr_init: UDP offset %d "
 717                                     " use partial checksum "
 718                                     "cksum 0x%x ",
 719                                     "value 0x%llx",
 720                                     stuff_offset,
 721                                     IP_CSUM(mp, start_offset, 0),
 722                                     hdrp->value));
 723                         }
 724                 }
 725 
 726                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 727                     "==> nxge_tx_pkt_hdr_init: UDP"
 728                     "value 0x%llx", hdrp->value));
 729                 break;
 730 
 731         default:
 732                 goto fill_tx_header_done;
 733         }
 734 
 735 fill_tx_header_done:
 736         NXGE_DEBUG_MSG((NULL, TX_CTL,
 737             "==> nxge_fill_tx_hdr: pkt_len %d  "
 738             "npads %d value 0x%llx", pkt_len, npads, hdrp->value));
 739 
 740         NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
 741 }
 742 
 743 /*ARGSUSED*/
 744 p_mblk_t
 745 nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
 746 {
 747         p_mblk_t                newmp = NULL;
 748 
 749         if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
 750                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 751                     "<== nxge_tx_pkt_header_reserve: allocb failed"));
 752                 return (NULL);
 753         }
 754 
 755         NXGE_DEBUG_MSG((NULL, TX_CTL,
 756             "==> nxge_tx_pkt_header_reserve: get new mp"));
 757         DB_TYPE(newmp) = M_DATA;
 758         newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
 759         linkb(newmp, mp);
 760         newmp->b_rptr -= TX_PKT_HEADER_SIZE;
 761 
 762         NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
 763             "b_rptr $%p b_wptr $%p",
 764             newmp->b_rptr, newmp->b_wptr));
 765 
 766         NXGE_DEBUG_MSG((NULL, TX_CTL,
 767             "<== nxge_tx_pkt_header_reserve: use new mp"));
 768 
 769         return (newmp);
 770 }
 771 
 772 int
 773 nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
 774 {
 775         uint_t                  nmblks;
 776         ssize_t                 len;
 777         uint_t                  pkt_len;
 778         p_mblk_t                nmp, bmp, tmp;
 779         uint8_t                 *b_wptr;
 780 
 781         NXGE_DEBUG_MSG((NULL, TX_CTL,
 782             "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
 783             "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
 784 
 785         nmp = mp;
 786         bmp = mp;
 787         nmblks = 0;
 788         pkt_len = 0;
 789         *tot_xfer_len_p = 0;
 790 
 791         while (nmp) {
 792                 len = MBLKL(nmp);
 793                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
 794                     "len %d pkt_len %d nmblks %d tot_xfer_len %d",
 795                     len, pkt_len, nmblks,
 796                     *tot_xfer_len_p));
 797 
 798                 if (len <= 0) {
 799                         bmp = nmp;
 800                         nmp = nmp->b_cont;
 801                         NXGE_DEBUG_MSG((NULL, TX_CTL,
 802                             "==> nxge_tx_pkt_nmblocks: "
 803                             "len (0) pkt_len %d nmblks %d",
 804                             pkt_len, nmblks));
 805                         continue;
 806                 }
 807 
 808                 *tot_xfer_len_p += len;
 809                 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
 810                     "len %d pkt_len %d nmblks %d tot_xfer_len %d",
 811                     len, pkt_len, nmblks,
 812                     *tot_xfer_len_p));
 813 
 814                 if (len < nxge_bcopy_thresh) {
 815                         NXGE_DEBUG_MSG((NULL, TX_CTL,
 816                             "==> nxge_tx_pkt_nmblocks: "
 817                             "len %d (< thresh) pkt_len %d nmblks %d",
 818                             len, pkt_len, nmblks));
 819                         if (pkt_len == 0)
 820                                 nmblks++;
 821                         pkt_len += len;
 822                         if (pkt_len >= nxge_bcopy_thresh) {
 823                                 pkt_len = 0;
 824                                 len = 0;
 825                                 nmp = bmp;
 826                         }
 827                 } else {
 828                         NXGE_DEBUG_MSG((NULL, TX_CTL,
 829                             "==> nxge_tx_pkt_nmblocks: "
 830                             "len %d (> thresh) pkt_len %d nmblks %d",
 831                             len, pkt_len, nmblks));
 832                         pkt_len = 0;
 833                         nmblks++;
 834                         /*
 835                          * Hardware limits the transfer length to 4K.
 836                          * If len is more than 4K, we need to break
 837                          * it up to at most 2 more blocks.
 838                          */
 839                         if (len > TX_MAX_TRANSFER_LENGTH) {
 840                                 uint32_t        nsegs;
 841 
 842                                 nsegs = 1;
 843                                 NXGE_DEBUG_MSG((NULL, TX_CTL,
 844                                     "==> nxge_tx_pkt_nmblocks: "
 845                                     "len %d pkt_len %d nmblks %d nsegs %d",
 846                                     len, pkt_len, nmblks, nsegs));
 847                                 if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
 848                                         ++nsegs;
 849                                 }
 850                                 do {
 851                                         b_wptr = nmp->b_rptr +
 852                                             TX_MAX_TRANSFER_LENGTH;
 853                                         nmp->b_wptr = b_wptr;
 854                                         if ((tmp = dupb(nmp)) == NULL) {
 855                                                 return (0);
 856                                         }
 857                                         tmp->b_rptr = b_wptr;
 858                                         tmp->b_wptr = nmp->b_wptr;
 859                                         tmp->b_cont = nmp->b_cont;
 860                                         nmp->b_cont = tmp;
 861                                         nmblks++;
 862                                         if (--nsegs) {
 863                                                 nmp = tmp;
 864                                         }
 865                                 } while (nsegs);
 866                                 nmp = tmp;
 867                         }
 868                 }
 869 
 870                 /*
 871                  * Hardware limits the transmit gather pointers to 15.
 872                  */
 873                 if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
 874                     TX_MAX_GATHER_POINTERS) {
 875                         NXGE_DEBUG_MSG((NULL, TX_CTL,
 876                             "==> nxge_tx_pkt_nmblocks: pull msg - "
 877                             "len %d pkt_len %d nmblks %d",
 878                             len, pkt_len, nmblks));
 879                         /* Pull all message blocks from b_cont */
 880                         if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
 881                                 return (0);
 882                         }
 883                         freemsg(nmp->b_cont);
 884                         nmp->b_cont = tmp;
 885                         pkt_len = 0;
 886                 }
 887                 bmp = nmp;
 888                 nmp = nmp->b_cont;
 889         }
 890 
 891         NXGE_DEBUG_MSG((NULL, TX_CTL,
 892             "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
 893             "nmblks %d len %d tot_xfer_len %d",
 894             mp->b_rptr, mp->b_wptr, nmblks,
 895             MBLKL(mp), *tot_xfer_len_p));
 896 
 897         return (nmblks);
 898 }
 899 
 900 boolean_t
 901 nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
 902 {
 903         boolean_t               status = B_TRUE;
 904         p_nxge_dma_common_t     tx_desc_dma_p;
 905         nxge_dma_common_t       desc_area;
 906         p_tx_desc_t             tx_desc_ring_vp;
 907         p_tx_desc_t             tx_desc_p;
 908         p_tx_desc_t             tx_desc_pp;
 909         tx_desc_t               r_tx_desc;
 910         p_tx_msg_t              tx_msg_ring;
 911         p_tx_msg_t              tx_msg_p;
 912         npi_handle_t            handle;
 913         tx_ring_hdl_t           tx_head;
 914         uint32_t                pkt_len;
 915         uint_t                  tx_rd_index;
 916         uint16_t                head_index, tail_index;
 917         uint8_t                 tdc;
 918         boolean_t               head_wrap, tail_wrap;
 919         p_nxge_tx_ring_stats_t tdc_stats;
 920         int                     rc;
 921 
 922         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
 923 
 924         status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
 925             (nmblks != 0));
 926         NXGE_DEBUG_MSG((nxgep, TX_CTL,
 927             "==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
 928             tx_ring_p->descs_pending, nxge_reclaim_pending,
 929             nmblks));
 930         if (!status) {
 931                 tx_desc_dma_p = &tx_ring_p->tdc_desc;
 932                 desc_area = tx_ring_p->tdc_desc;
 933                 handle = NXGE_DEV_NPI_HANDLE(nxgep);
 934                 tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
 935                 tx_desc_ring_vp =
 936                     (p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
 937                 tx_rd_index = tx_ring_p->rd_index;
 938                 tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
 939                 tx_msg_ring = tx_ring_p->tx_msg_ring;
 940                 tx_msg_p = &tx_msg_ring[tx_rd_index];
 941                 tdc = tx_ring_p->tdc;
 942                 tdc_stats = tx_ring_p->tdc_stats;
 943                 if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
 944                         tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
 945                 }
 946 
 947                 tail_index = tx_ring_p->wr_index;
 948                 tail_wrap = tx_ring_p->wr_index_wrap;
 949 
 950                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
 951                     "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
 952                     "tail_index %d tail_wrap %d "
 953                     "tx_desc_p $%p ($%p) ",
 954                     tdc, tx_rd_index, tail_index, tail_wrap,
 955                     tx_desc_p, (*(uint64_t *)tx_desc_p)));
 956                 /*
 957                  * Read the hardware maintained transmit head
 958                  * and wrap around bit.
 959                  */
 960                 TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
 961                 head_index =  tx_head.bits.ldw.head;
 962                 head_wrap = tx_head.bits.ldw.wrap;
 963                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
 964                     "==> nxge_txdma_reclaim: "
 965                     "tx_rd_index %d tail %d tail_wrap %d "
 966                     "head %d wrap %d",
 967                     tx_rd_index, tail_index, tail_wrap,
 968                     head_index, head_wrap));
 969 
 970                 if (head_index == tail_index) {
 971                         if (TXDMA_RING_EMPTY(head_index, head_wrap,
 972                             tail_index, tail_wrap) &&
 973                             (head_index == tx_rd_index)) {
 974                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
 975                                     "==> nxge_txdma_reclaim: EMPTY"));
 976                                 return (B_TRUE);
 977                         }
 978 
 979                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
 980                             "==> nxge_txdma_reclaim: Checking "
 981                             "if ring full"));
 982                         if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
 983                             tail_wrap)) {
 984                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
 985                                     "==> nxge_txdma_reclaim: full"));
 986                                 return (B_FALSE);
 987                         }
 988                 }
 989 
 990                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
 991                     "==> nxge_txdma_reclaim: tx_rd_index and head_index"));
 992 
 993                 tx_desc_pp = &r_tx_desc;
 994                 while ((tx_rd_index != head_index) &&
 995                     (tx_ring_p->descs_pending != 0)) {
 996 
 997                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
 998                             "==> nxge_txdma_reclaim: Checking if pending"));
 999 
1000                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1001                             "==> nxge_txdma_reclaim: "
1002                             "descs_pending %d ",
1003                             tx_ring_p->descs_pending));
1004 
1005                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1006                             "==> nxge_txdma_reclaim: "
1007                             "(tx_rd_index %d head_index %d "
1008                             "(tx_desc_p $%p)",
1009                             tx_rd_index, head_index,
1010                             tx_desc_p));
1011 
1012                         tx_desc_pp->value = tx_desc_p->value;
1013                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1014                             "==> nxge_txdma_reclaim: "
1015                             "(tx_rd_index %d head_index %d "
1016                             "tx_desc_p $%p (desc value 0x%llx) ",
1017                             tx_rd_index, head_index,
1018                             tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
1019 
1020                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1021                             "==> nxge_txdma_reclaim: dump desc:"));
1022 
1023                         pkt_len = tx_desc_pp->bits.hdw.tr_len;
1024                         tdc_stats->obytes += (pkt_len - TX_PKT_HEADER_SIZE);
1025                         tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
1026                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1027                             "==> nxge_txdma_reclaim: pkt_len %d "
1028                             "tdc channel %d opackets %d",
1029                             pkt_len,
1030                             tdc,
1031                             tdc_stats->opackets));
1032 
1033                         if (tx_msg_p->flags.dma_type == USE_DVMA) {
1034                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1035                                     "tx_desc_p = $%p "
1036                                     "tx_desc_pp = $%p "
1037                                     "index = %d",
1038                                     tx_desc_p,
1039                                     tx_desc_pp,
1040                                     tx_ring_p->rd_index));
1041                                 (void) dvma_unload(tx_msg_p->dvma_handle,
1042                                     0, -1);
1043                                 tx_msg_p->dvma_handle = NULL;
1044                                 if (tx_ring_p->dvma_wr_index ==
1045                                     tx_ring_p->dvma_wrap_mask) {
1046                                         tx_ring_p->dvma_wr_index = 0;
1047                                 } else {
1048                                         tx_ring_p->dvma_wr_index++;
1049                                 }
1050                                 tx_ring_p->dvma_pending--;
1051                         } else if (tx_msg_p->flags.dma_type ==
1052                             USE_DMA) {
1053                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1054                                     "==> nxge_txdma_reclaim: "
1055                                     "USE DMA"));
1056                                 if (rc = ddi_dma_unbind_handle
1057                                     (tx_msg_p->dma_handle)) {
1058                                         cmn_err(CE_WARN, "!nxge_reclaim: "
1059                                             "ddi_dma_unbind_handle "
1060                                             "failed. status %d", rc);
1061                                 }
1062                         }
1063                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1064                             "==> nxge_txdma_reclaim: count packets"));
1065                         /*
1066                          * count a chained packet only once.
1067                          */
1068                         if (tx_msg_p->tx_message != NULL) {
1069                                 freemsg(tx_msg_p->tx_message);
1070                                 tx_msg_p->tx_message = NULL;
1071                         }
1072 
1073                         tx_msg_p->flags.dma_type = USE_NONE;
1074                         tx_rd_index = tx_ring_p->rd_index;
1075                         tx_rd_index = (tx_rd_index + 1) &
1076                             tx_ring_p->tx_wrap_mask;
1077                         tx_ring_p->rd_index = tx_rd_index;
1078                         tx_ring_p->descs_pending--;
1079                         tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
1080                         tx_msg_p = &tx_msg_ring[tx_rd_index];
1081                 }
1082 
1083                 status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1084                     (int)tx_ring_p->descs_pending - TX_FULL_MARK));
1085                 if (status) {
1086                         (void) cas32((uint32_t *)&tx_ring_p->queueing, 1, 0);
1087                 }
1088         } else {
1089                 status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1090                     (int)tx_ring_p->descs_pending - TX_FULL_MARK));
1091         }
1092 
1093         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1094             "<== nxge_txdma_reclaim status = 0x%08x", status));
1095 
1096         return (status);
1097 }
1098 
1099 /*
1100  * nxge_tx_intr
1101  *
1102  *      Process a TDC interrupt
1103  *
1104  * Arguments:
1105  *      arg1    A Logical Device state Vector (LSV) data structure.
1106  *      arg2    nxge_t *
1107  *
1108  * Notes:
1109  *
1110  * NPI/NXGE function calls:
1111  *      npi_txdma_control_status()
1112  *      npi_intr_ldg_mgmt_set()
1113  *
1114  *      nxge_tx_err_evnts()
1115  *      nxge_txdma_reclaim()
1116  *
1117  * Registers accessed:
1118  *      TX_CS           DMC+0x40028 Transmit Control And Status
1119  *      PIO_LDSV
1120  *
1121  * Context:
1122  *      Any domain
1123  */
1124 uint_t
1125 nxge_tx_intr(void *arg1, void *arg2)
1126 {
1127         p_nxge_ldv_t            ldvp = (p_nxge_ldv_t)arg1;
1128         p_nxge_t                nxgep = (p_nxge_t)arg2;
1129         p_nxge_ldg_t            ldgp;
1130         uint8_t                 channel;
1131         uint32_t                vindex;
1132         npi_handle_t            handle;
1133         tx_cs_t                 cs;
1134         p_tx_ring_t             *tx_rings;
1135         p_tx_ring_t             tx_ring_p;
1136         npi_status_t            rs = NPI_SUCCESS;
1137         uint_t                  serviced = DDI_INTR_UNCLAIMED;
1138         nxge_status_t           status = NXGE_OK;
1139 
1140         if (ldvp == NULL) {
1141                 NXGE_DEBUG_MSG((NULL, INT_CTL,
1142                     "<== nxge_tx_intr: nxgep $%p ldvp $%p",
1143                     nxgep, ldvp));
1144                 return (DDI_INTR_UNCLAIMED);
1145         }
1146 
1147         if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
1148                 nxgep = ldvp->nxgep;
1149         }
1150         NXGE_DEBUG_MSG((nxgep, INT_CTL,
1151             "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
1152             nxgep, ldvp));
1153 
1154         if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
1155             (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
1156                 NXGE_DEBUG_MSG((nxgep, INT_CTL,
1157                     "<== nxge_tx_intr: interface not started or intialized"));
1158                 return (DDI_INTR_CLAIMED);
1159         }
1160 
1161         /*
1162          * This interrupt handler is for a specific
1163          * transmit dma channel.
1164          */
1165         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1166         /* Get the control and status for this channel. */
1167         channel = ldvp->channel;
1168         ldgp = ldvp->ldgp;
1169         NXGE_DEBUG_MSG((nxgep, INT_CTL,
1170             "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
1171             "channel %d",
1172             nxgep, ldvp, channel));
1173 
1174         rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
1175         vindex = ldvp->vdma_index;
1176         NXGE_DEBUG_MSG((nxgep, INT_CTL,
1177             "==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
1178             channel, vindex, rs));
1179         if (!rs && cs.bits.ldw.mk) {
1180                 NXGE_DEBUG_MSG((nxgep, INT_CTL,
1181                     "==> nxge_tx_intr:channel %d ring index %d "
1182                     "status 0x%08x (mk bit set)",
1183                     channel, vindex, rs));
1184                 tx_rings = nxgep->tx_rings->rings;
1185                 tx_ring_p = tx_rings[vindex];
1186                 NXGE_DEBUG_MSG((nxgep, INT_CTL,
1187                     "==> nxge_tx_intr:channel %d ring index %d "
1188                     "status 0x%08x (mk bit set, calling reclaim)",
1189                     channel, vindex, rs));
1190 
1191                 nxge_tx_ring_task((void *)tx_ring_p);
1192         }
1193 
1194         /*
1195          * Process other transmit control and status.
1196          * Check the ldv state.
1197          */
1198         status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
1199         /*
1200          * Rearm this logical group if this is a single device
1201          * group.
1202          */
1203         if (ldgp->nldvs == 1) {
1204                 NXGE_DEBUG_MSG((nxgep, INT_CTL,
1205                     "==> nxge_tx_intr: rearm"));
1206                 if (status == NXGE_OK) {
1207                         if (isLDOMguest(nxgep)) {
1208                                 nxge_hio_ldgimgn(nxgep, ldgp);
1209                         } else {
1210                                 (void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
1211                                     B_TRUE, ldgp->ldg_timer);
1212                         }
1213                 }
1214         }
1215 
1216         NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
1217         serviced = DDI_INTR_CLAIMED;
1218         return (serviced);
1219 }
1220 
1221 void
1222 nxge_txdma_stop(p_nxge_t nxgep) /* Dead */
1223 {
1224         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
1225 
1226         (void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
1227 
1228         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
1229 }
1230 
1231 void
1232 nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */
1233 {
1234         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
1235 
1236         (void) nxge_txdma_stop(nxgep);
1237 
1238         (void) nxge_fixup_txdma_rings(nxgep);
1239         (void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
1240         (void) nxge_tx_mac_enable(nxgep);
1241         (void) nxge_txdma_hw_kick(nxgep);
1242 
1243         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
1244 }
1245 
1246 npi_status_t
1247 nxge_txdma_channel_disable(
1248         nxge_t *nxge,
1249         int channel)
1250 {
1251         npi_handle_t    handle = NXGE_DEV_NPI_HANDLE(nxge);
1252         npi_status_t    rs;
1253         tdmc_intr_dbg_t intr_dbg;
1254 
1255         /*
1256          * Stop the dma channel and wait for the stop-done.
1257          * If the stop-done bit is not present, then force
1258          * an error so TXC will stop.
1259          * All channels bound to this port need to be stopped
1260          * and reset after injecting an interrupt error.
1261          */
1262         rs = npi_txdma_channel_disable(handle, channel);
1263         NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1264             "==> nxge_txdma_channel_disable(%d) "
1265             "rs 0x%x", channel, rs));
1266         if (rs != NPI_SUCCESS) {
1267                 /* Inject any error */
1268                 intr_dbg.value = 0;
1269                 intr_dbg.bits.ldw.nack_pref = 1;
1270                 NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1271                     "==> nxge_txdma_hw_mode: "
1272                     "channel %d (stop failed 0x%x) "
1273                     "(inject err)", rs, channel));
1274                 (void) npi_txdma_inj_int_error_set(
1275                     handle, channel, &intr_dbg);
1276                 rs = npi_txdma_channel_disable(handle, channel);
1277                 NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1278                     "==> nxge_txdma_hw_mode: "
1279                     "channel %d (stop again 0x%x) "
1280                     "(after inject err)",
1281                     rs, channel));
1282         }
1283 
1284         return (rs);
1285 }
1286 
1287 /*
1288  * nxge_txdma_hw_mode
1289  *
1290  *      Toggle all TDCs on (enable) or off (disable).
1291  *
1292  * Arguments:
1293  *      nxgep
1294  *      enable  Enable or disable a TDC.
1295  *
1296  * Notes:
1297  *
1298  * NPI/NXGE function calls:
1299  *      npi_txdma_channel_enable(TX_CS)
1300  *      npi_txdma_channel_disable(TX_CS)
1301  *      npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1302  *
1303  * Registers accessed:
1304  *      TX_CS           DMC+0x40028 Transmit Control And Status
1305  *      TDMC_INTR_DBG   DMC + 0x40060 Transmit DMA Interrupt Debug
1306  *
1307  * Context:
1308  *      Any domain
1309  */
1310 nxge_status_t
1311 nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
1312 {
1313         nxge_grp_set_t *set = &nxgep->tx_set;
1314 
1315         npi_handle_t    handle;
1316         nxge_status_t   status;
1317         npi_status_t    rs;
1318         int             tdc;
1319 
1320         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1321             "==> nxge_txdma_hw_mode: enable mode %d", enable));
1322 
1323         if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
1324                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1325                     "<== nxge_txdma_mode: not initialized"));
1326                 return (NXGE_ERROR);
1327         }
1328 
1329         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1330                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1331                     "<== nxge_txdma_hw_mode: NULL ring pointer(s)"));
1332                 return (NXGE_ERROR);
1333         }
1334 
1335         /* Enable or disable all of the TDCs owned by us. */
1336         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1337         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1338                 if ((1 << tdc) & set->owned.map) {
1339                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1340                         if (ring) {
1341                                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1342                                     "==> nxge_txdma_hw_mode: channel %d", tdc));
1343                                 if (enable) {
1344                                         rs = npi_txdma_channel_enable
1345                                             (handle, tdc);
1346                                         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1347                                             "==> nxge_txdma_hw_mode: "
1348                                             "channel %d (enable) rs 0x%x",
1349                                             tdc, rs));
1350                                 } else {
1351                                         rs = nxge_txdma_channel_disable
1352                                             (nxgep, tdc);
1353                                 }
1354                         }
1355                 }
1356         }
1357 
1358         status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
1359 
1360         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1361             "<== nxge_txdma_hw_mode: status 0x%x", status));
1362 
1363         return (status);
1364 }
1365 
1366 void
1367 nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
1368 {
1369         npi_handle_t            handle;
1370 
1371         NXGE_DEBUG_MSG((nxgep, DMA_CTL,
1372             "==> nxge_txdma_enable_channel: channel %d", channel));
1373 
1374         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1375         /* enable the transmit dma channels */
1376         (void) npi_txdma_channel_enable(handle, channel);
1377 
1378         NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
1379 }
1380 
1381 void
1382 nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
1383 {
1384         npi_handle_t            handle;
1385 
1386         NXGE_DEBUG_MSG((nxgep, DMA_CTL,
1387             "==> nxge_txdma_disable_channel: channel %d", channel));
1388 
1389         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1390         /* stop the transmit dma channels */
1391         (void) npi_txdma_channel_disable(handle, channel);
1392 
1393         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
1394 }
1395 
1396 /*
1397  * nxge_txdma_stop_inj_err
1398  *
1399  *      Stop a TDC.  If at first we don't succeed, inject an error.
1400  *
1401  * Arguments:
1402  *      nxgep
1403  *      channel         The channel to stop.
1404  *
1405  * Notes:
1406  *
1407  * NPI/NXGE function calls:
1408  *      npi_txdma_channel_disable()
1409  *      npi_txdma_inj_int_error_set()
1410  * #if defined(NXGE_DEBUG)
1411  *      nxge_txdma_regs_dump_channels(nxgep);
1412  * #endif
1413  *
1414  * Registers accessed:
1415  *      TX_CS           DMC+0x40028 Transmit Control And Status
1416  *      TDMC_INTR_DBG   DMC + 0x40060 Transmit DMA Interrupt Debug
1417  *
1418  * Context:
1419  *      Any domain
1420  */
1421 int
1422 nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
1423 {
1424         npi_handle_t            handle;
1425         tdmc_intr_dbg_t         intr_dbg;
1426         int                     status;
1427         npi_status_t            rs = NPI_SUCCESS;
1428 
1429         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
1430         /*
1431          * Stop the dma channel waits for the stop done.
1432          * If the stop done bit is not set, then create
1433          * an error.
1434          */
1435         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1436         rs = npi_txdma_channel_disable(handle, channel);
1437         status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
1438         if (status == NXGE_OK) {
1439                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1440                     "<== nxge_txdma_stop_inj_err (channel %d): "
1441                     "stopped OK", channel));
1442                 return (status);
1443         }
1444 
1445         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1446             "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
1447             "injecting error", channel, rs));
1448         /* Inject any error */
1449         intr_dbg.value = 0;
1450         intr_dbg.bits.ldw.nack_pref = 1;
1451         (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
1452 
1453         /* Stop done bit will be set as a result of error injection */
1454         rs = npi_txdma_channel_disable(handle, channel);
1455         status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
1456         if (!(rs & NPI_TXDMA_STOP_FAILED)) {
1457                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1458                     "<== nxge_txdma_stop_inj_err (channel %d): "
1459                     "stopped OK ", channel));
1460                 return (status);
1461         }
1462 
1463 #if     defined(NXGE_DEBUG)
1464         nxge_txdma_regs_dump_channels(nxgep);
1465 #endif
1466         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1467             "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
1468             " (injected error but still not stopped)", channel, rs));
1469 
1470         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
1471         return (status);
1472 }
1473 
1474 /*ARGSUSED*/
1475 void
1476 nxge_fixup_txdma_rings(p_nxge_t nxgep)
1477 {
1478         nxge_grp_set_t *set = &nxgep->tx_set;
1479         int tdc;
1480 
1481         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
1482 
1483         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1484                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1485                     "<== nxge_fixup_txdma_rings: NULL ring pointer(s)"));
1486                 return;
1487         }
1488 
1489         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1490                 if ((1 << tdc) & set->owned.map) {
1491                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1492                         if (ring) {
1493                                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1494                                     "==> nxge_fixup_txdma_rings: channel %d",
1495                                     tdc));
1496                                 nxge_txdma_fixup_channel(nxgep, ring, tdc);
1497                         }
1498                 }
1499         }
1500 
1501         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
1502 }
1503 
1504 /*ARGSUSED*/
1505 void
1506 nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
1507 {
1508         p_tx_ring_t     ring_p;
1509 
1510         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
1511         ring_p = nxge_txdma_get_ring(nxgep, channel);
1512         if (ring_p == NULL) {
1513                 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
1514                 return;
1515         }
1516 
1517         if (ring_p->tdc != channel) {
1518                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1519                     "<== nxge_txdma_fix_channel: channel not matched "
1520                     "ring tdc %d passed channel",
1521                     ring_p->tdc, channel));
1522                 return;
1523         }
1524 
1525         nxge_txdma_fixup_channel(nxgep, ring_p, channel);
1526 
1527         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
1528 }
1529 
1530 /*ARGSUSED*/
1531 void
1532 nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
1533 {
1534         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
1535 
1536         if (ring_p == NULL) {
1537                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1538                     "<== nxge_txdma_fixup_channel: NULL ring pointer"));
1539                 return;
1540         }
1541 
1542         if (ring_p->tdc != channel) {
1543                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1544                     "<== nxge_txdma_fixup_channel: channel not matched "
1545                     "ring tdc %d passed channel",
1546                     ring_p->tdc, channel));
1547                 return;
1548         }
1549 
1550         MUTEX_ENTER(&ring_p->lock);
1551         (void) nxge_txdma_reclaim(nxgep, ring_p, 0);
1552         ring_p->rd_index = 0;
1553         ring_p->wr_index = 0;
1554         ring_p->ring_head.value = 0;
1555         ring_p->ring_kick_tail.value = 0;
1556         ring_p->descs_pending = 0;
1557         MUTEX_EXIT(&ring_p->lock);
1558 
1559         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
1560 }
1561 
1562 /*ARGSUSED*/
1563 void
1564 nxge_txdma_hw_kick(p_nxge_t nxgep)
1565 {
1566         nxge_grp_set_t *set = &nxgep->tx_set;
1567         int tdc;
1568 
1569         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
1570 
1571         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1572                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1573                     "<== nxge_txdma_hw_kick: NULL ring pointer(s)"));
1574                 return;
1575         }
1576 
1577         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1578                 if ((1 << tdc) & set->owned.map) {
1579                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1580                         if (ring) {
1581                                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1582                                     "==> nxge_txdma_hw_kick: channel %d", tdc));
1583                                 nxge_txdma_hw_kick_channel(nxgep, ring, tdc);
1584                         }
1585                 }
1586         }
1587 
1588         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
1589 }
1590 
1591 /*ARGSUSED*/
1592 void
1593 nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
1594 {
1595         p_tx_ring_t     ring_p;
1596 
1597         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
1598 
1599         ring_p = nxge_txdma_get_ring(nxgep, channel);
1600         if (ring_p == NULL) {
1601                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1602                     " nxge_txdma_kick_channel"));
1603                 return;
1604         }
1605 
1606         if (ring_p->tdc != channel) {
1607                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1608                     "<== nxge_txdma_kick_channel: channel not matched "
1609                     "ring tdc %d passed channel",
1610                     ring_p->tdc, channel));
1611                 return;
1612         }
1613 
1614         nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
1615 
1616         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
1617 }
1618 
1619 /*ARGSUSED*/
1620 void
1621 nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
1622 {
1623 
1624         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
1625 
1626         if (ring_p == NULL) {
1627                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1628                     "<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
1629                 return;
1630         }
1631 
1632         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
1633 }
1634 
1635 /*
1636  * nxge_check_tx_hang
1637  *
1638  *      Check the state of all TDCs belonging to nxgep.
1639  *
1640  * Arguments:
1641  *      nxgep
1642  *
1643  * Notes:
1644  *      Called by nxge_hw.c:nxge_check_hw_state().
1645  *
1646  * NPI/NXGE function calls:
1647  *
1648  * Registers accessed:
1649  *
1650  * Context:
1651  *      Any domain
1652  */
1653 /*ARGSUSED*/
1654 void
1655 nxge_check_tx_hang(p_nxge_t nxgep)
1656 {
1657         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
1658 
1659         if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
1660             (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
1661                 goto nxge_check_tx_hang_exit;
1662         }
1663 
1664         /*
1665          * Needs inputs from hardware for regs:
1666          *      head index had not moved since last timeout.
1667          *      packets not transmitted or stuffed registers.
1668          */
1669         if (nxge_txdma_hung(nxgep)) {
1670                 nxge_fixup_hung_txdma_rings(nxgep);
1671         }
1672 
1673 nxge_check_tx_hang_exit:
1674         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
1675 }
1676 
1677 /*
1678  * nxge_txdma_hung
1679  *
1680  *      Reset a TDC.
1681  *
1682  * Arguments:
1683  *      nxgep
1684  *      channel         The channel to reset.
1685  *      reg_data        The current TX_CS.
1686  *
1687  * Notes:
1688  *      Called by nxge_check_tx_hang()
1689  *
1690  * NPI/NXGE function calls:
1691  *      nxge_txdma_channel_hung()
1692  *
1693  * Registers accessed:
1694  *
1695  * Context:
1696  *      Any domain
1697  */
1698 int
1699 nxge_txdma_hung(p_nxge_t nxgep)
1700 {
1701         nxge_grp_set_t  *set = &nxgep->tx_set;
1702         int             tdc;
1703         boolean_t       shared;
1704 
1705         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
1706 
1707         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1708                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1709                     "<== nxge_txdma_hung: NULL ring pointer(s)"));
1710                 return (B_FALSE);
1711         }
1712 
1713         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1714                 /*
1715                  * Grab the shared state of the TDC.
1716                  */
1717                 if (isLDOMservice(nxgep)) {
1718                         nxge_hio_data_t *nhd =
1719                             (nxge_hio_data_t *)nxgep->nxge_hw_p->hio;
1720 
1721                         MUTEX_ENTER(&nhd->lock);
1722                         shared = nxgep->tdc_is_shared[tdc];
1723                         MUTEX_EXIT(&nhd->lock);
1724                 } else {
1725                         shared = B_FALSE;
1726                 }
1727 
1728                 /*
1729                  * Now, process continue to process.
1730                  */
1731                 if (((1 << tdc) & set->owned.map) && !shared) {
1732                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1733                         if (ring) {
1734                                 if (nxge_txdma_channel_hung(nxgep, ring, tdc)) {
1735                                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1736                                             "==> nxge_txdma_hung: TDC %d hung",
1737                                             tdc));
1738                                         return (B_TRUE);
1739                                 }
1740                         }
1741                 }
1742         }
1743 
1744         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
1745 
1746         return (B_FALSE);
1747 }
1748 
1749 /*
1750  * nxge_txdma_channel_hung
1751  *
1752  *      Reset a TDC.
1753  *
1754  * Arguments:
1755  *      nxgep
1756  *      ring            <channel>'s ring.
1757  *      channel         The channel to reset.
1758  *
1759  * Notes:
1760  *      Called by nxge_txdma.c:nxge_txdma_hung()
1761  *
1762  * NPI/NXGE function calls:
1763  *      npi_txdma_ring_head_get()
1764  *
1765  * Registers accessed:
1766  *      TX_RING_HDL     DMC+0x40010 Transmit Ring Head Low
1767  *
1768  * Context:
1769  *      Any domain
1770  */
1771 int
1772 nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
1773 {
1774         uint16_t                head_index, tail_index;
1775         boolean_t               head_wrap, tail_wrap;
1776         npi_handle_t            handle;
1777         tx_ring_hdl_t           tx_head;
1778         uint_t                  tx_rd_index;
1779 
1780         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
1781 
1782         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1783         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1784             "==> nxge_txdma_channel_hung: channel %d", channel));
1785         MUTEX_ENTER(&tx_ring_p->lock);
1786         (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
1787 
1788         tail_index = tx_ring_p->wr_index;
1789         tail_wrap = tx_ring_p->wr_index_wrap;
1790         tx_rd_index = tx_ring_p->rd_index;
1791         MUTEX_EXIT(&tx_ring_p->lock);
1792 
1793         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1794             "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
1795             "tail_index %d tail_wrap %d ",
1796             channel, tx_rd_index, tail_index, tail_wrap));
1797         /*
1798          * Read the hardware maintained transmit head
1799          * and wrap around bit.
1800          */
1801         (void) npi_txdma_ring_head_get(handle, channel, &tx_head);
1802         head_index =  tx_head.bits.ldw.head;
1803         head_wrap = tx_head.bits.ldw.wrap;
1804         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1805             "==> nxge_txdma_channel_hung: "
1806             "tx_rd_index %d tail %d tail_wrap %d "
1807             "head %d wrap %d",
1808             tx_rd_index, tail_index, tail_wrap,
1809             head_index, head_wrap));
1810 
1811         if (TXDMA_RING_EMPTY(head_index, head_wrap,
1812             tail_index, tail_wrap) &&
1813             (head_index == tx_rd_index)) {
1814                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1815                     "==> nxge_txdma_channel_hung: EMPTY"));
1816                 return (B_FALSE);
1817         }
1818 
1819         NXGE_DEBUG_MSG((nxgep, TX_CTL,
1820             "==> nxge_txdma_channel_hung: Checking if ring full"));
1821         if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
1822             tail_wrap)) {
1823                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1824                     "==> nxge_txdma_channel_hung: full"));
1825                 return (B_TRUE);
1826         }
1827 
1828         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
1829 
1830         return (B_FALSE);
1831 }
1832 
1833 /*
1834  * nxge_fixup_hung_txdma_rings
1835  *
1836  *      Disable a TDC.
1837  *
1838  * Arguments:
1839  *      nxgep
1840  *      channel         The channel to reset.
1841  *      reg_data        The current TX_CS.
1842  *
1843  * Notes:
1844  *      Called by nxge_check_tx_hang()
1845  *
1846  * NPI/NXGE function calls:
1847  *      npi_txdma_ring_head_get()
1848  *
1849  * Registers accessed:
1850  *      TX_RING_HDL     DMC+0x40010 Transmit Ring Head Low
1851  *
1852  * Context:
1853  *      Any domain
1854  */
1855 /*ARGSUSED*/
1856 void
1857 nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
1858 {
1859         nxge_grp_set_t *set = &nxgep->tx_set;
1860         int tdc;
1861 
1862         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
1863 
1864         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1865                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1866                     "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
1867                 return;
1868         }
1869 
1870         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1871                 if ((1 << tdc) & set->owned.map) {
1872                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1873                         if (ring) {
1874                                 nxge_txdma_fixup_hung_channel(nxgep, ring, tdc);
1875                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1876                                     "==> nxge_fixup_hung_txdma_rings: TDC %d",
1877                                     tdc));
1878                         }
1879                 }
1880         }
1881 
1882         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
1883 }
1884 
1885 /*
1886  * nxge_txdma_fixup_hung_channel
1887  *
1888  *      'Fix' a hung TDC.
1889  *
1890  * Arguments:
1891  *      nxgep
1892  *      channel         The channel to fix.
1893  *
1894  * Notes:
1895  *      Called by nxge_fixup_hung_txdma_rings()
1896  *
1897  *      1. Reclaim the TDC.
1898  *      2. Disable the TDC.
1899  *
1900  * NPI/NXGE function calls:
1901  *      nxge_txdma_reclaim()
1902  *      npi_txdma_channel_disable(TX_CS)
1903  *      npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1904  *
1905  * Registers accessed:
1906  *      TX_CS           DMC+0x40028 Transmit Control And Status
1907  *      TDMC_INTR_DBG   DMC + 0x40060 Transmit DMA Interrupt Debug
1908  *
1909  * Context:
1910  *      Any domain
1911  */
1912 /*ARGSUSED*/
1913 void
1914 nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
1915 {
1916         p_tx_ring_t     ring_p;
1917 
1918         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
1919         ring_p = nxge_txdma_get_ring(nxgep, channel);
1920         if (ring_p == NULL) {
1921                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1922                     "<== nxge_txdma_fix_hung_channel"));
1923                 return;
1924         }
1925 
1926         if (ring_p->tdc != channel) {
1927                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1928                     "<== nxge_txdma_fix_hung_channel: channel not matched "
1929                     "ring tdc %d passed channel",
1930                     ring_p->tdc, channel));
1931                 return;
1932         }
1933 
1934         nxge_txdma_fixup_channel(nxgep, ring_p, channel);
1935 
1936         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
1937 }
1938 
1939 /*ARGSUSED*/
1940 void
1941 nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
1942         uint16_t channel)
1943 {
1944         npi_handle_t            handle;
1945         tdmc_intr_dbg_t         intr_dbg;
1946         int                     status = NXGE_OK;
1947 
1948         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
1949 
1950         if (ring_p == NULL) {
1951                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1952                     "<== nxge_txdma_fixup_channel: NULL ring pointer"));
1953                 return;
1954         }
1955 
1956         if (ring_p->tdc != channel) {
1957                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1958                     "<== nxge_txdma_fixup_hung_channel: channel "
1959                     "not matched "
1960                     "ring tdc %d passed channel",
1961                     ring_p->tdc, channel));
1962                 return;
1963         }
1964 
1965         /* Reclaim descriptors */
1966         MUTEX_ENTER(&ring_p->lock);
1967         (void) nxge_txdma_reclaim(nxgep, ring_p, 0);
1968         MUTEX_EXIT(&ring_p->lock);
1969 
1970         handle = NXGE_DEV_NPI_HANDLE(nxgep);
1971         /*
1972          * Stop the dma channel waits for the stop done.
1973          * If the stop done bit is not set, then force
1974          * an error.
1975          */
1976         status = npi_txdma_channel_disable(handle, channel);
1977         if (!(status & NPI_TXDMA_STOP_FAILED)) {
1978                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1979                     "<== nxge_txdma_fixup_hung_channel: stopped OK "
1980                     "ring tdc %d passed channel %d",
1981                     ring_p->tdc, channel));
1982                 return;
1983         }
1984 
1985         /* Inject any error */
1986         intr_dbg.value = 0;
1987         intr_dbg.bits.ldw.nack_pref = 1;
1988         (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
1989 
1990         /* Stop done bit will be set as a result of error injection */
1991         status = npi_txdma_channel_disable(handle, channel);
1992         if (!(status & NPI_TXDMA_STOP_FAILED)) {
1993                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
1994                     "<== nxge_txdma_fixup_hung_channel: stopped again"
1995                     "ring tdc %d passed channel",
1996                     ring_p->tdc, channel));
1997                 return;
1998         }
1999 
2000         NXGE_DEBUG_MSG((nxgep, TX_CTL,
2001             "<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
2002             "ring tdc %d passed channel",
2003             ring_p->tdc, channel));
2004 
2005         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
2006 }
2007 
2008 /*ARGSUSED*/
2009 void
2010 nxge_reclaim_rings(p_nxge_t nxgep)
2011 {
2012         nxge_grp_set_t *set = &nxgep->tx_set;
2013         int tdc;
2014 
2015         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings"));
2016 
2017         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
2018                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2019                     "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
2020                 return;
2021         }
2022 
2023         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2024                 if ((1 << tdc) & set->owned.map) {
2025                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2026                         if (ring) {
2027                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2028                                     "==> nxge_reclaim_rings: TDC %d", tdc));
2029                                 MUTEX_ENTER(&ring->lock);
2030                                 (void) nxge_txdma_reclaim(nxgep, ring, 0);
2031                                 MUTEX_EXIT(&ring->lock);
2032                         }
2033                 }
2034         }
2035 
2036         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
2037 }
2038 
2039 void
2040 nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
2041 {
2042         nxge_grp_set_t *set = &nxgep->tx_set;
2043         npi_handle_t handle;
2044         int tdc;
2045 
2046         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels"));
2047 
2048         handle = NXGE_DEV_NPI_HANDLE(nxgep);
2049 
2050         if (!isLDOMguest(nxgep)) {
2051                 (void) npi_txdma_dump_fzc_regs(handle);
2052 
2053                 /* Dump TXC registers. */
2054                 (void) npi_txc_dump_fzc_regs(handle);
2055                 (void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
2056         }
2057 
2058         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
2059                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2060                     "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
2061                 return;
2062         }
2063 
2064         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2065                 if ((1 << tdc) & set->owned.map) {
2066                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2067                         if (ring) {
2068                                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2069                                     "==> nxge_txdma_regs_dump_channels: "
2070                                     "TDC %d", tdc));
2071                                 (void) npi_txdma_dump_tdc_regs(handle, tdc);
2072 
2073                                 /* Dump TXC registers, if able to. */
2074                                 if (!isLDOMguest(nxgep)) {
2075                                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
2076                                             "==> nxge_txdma_regs_dump_channels:"
2077                                             " FZC TDC %d", tdc));
2078                                         (void) npi_txc_dump_tdc_fzc_regs
2079                                             (handle, tdc);
2080                                 }
2081                                 nxge_txdma_regs_dump(nxgep, tdc);
2082                         }
2083                 }
2084         }
2085 
2086         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
2087 }
2088 
2089 void
2090 nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
2091 {
2092         npi_handle_t            handle;
2093         tx_ring_hdl_t           hdl;
2094         tx_ring_kick_t          kick;
2095         tx_cs_t                 cs;
2096         txc_control_t           control;
2097         uint32_t                bitmap = 0;
2098         uint32_t                burst = 0;
2099         uint32_t                bytes = 0;
2100         dma_log_page_t          cfg;
2101 
2102         printf("\n\tfunc # %d tdc %d ",
2103             nxgep->function_num, channel);
2104         cfg.page_num = 0;
2105         handle = NXGE_DEV_NPI_HANDLE(nxgep);
2106         (void) npi_txdma_log_page_get(handle, channel, &cfg);
2107         printf("\n\tlog page func %d valid page 0 %d",
2108             cfg.func_num, cfg.valid);
2109         cfg.page_num = 1;
2110         (void) npi_txdma_log_page_get(handle, channel, &cfg);
2111         printf("\n\tlog page func %d valid page 1 %d",
2112             cfg.func_num, cfg.valid);
2113 
2114         (void) npi_txdma_ring_head_get(handle, channel, &hdl);
2115         (void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
2116         printf("\n\thead value is 0x%0llx",
2117             (long long)hdl.value);
2118         printf("\n\thead index %d", hdl.bits.ldw.head);
2119         printf("\n\tkick value is 0x%0llx",
2120             (long long)kick.value);
2121         printf("\n\ttail index %d\n", kick.bits.ldw.tail);
2122 
2123         (void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
2124         printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
2125         printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
2126 
2127         (void) npi_txc_control(handle, OP_GET, &control);
2128         (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
2129         (void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
2130         (void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
2131 
2132         printf("\n\tTXC port control 0x%0llx",
2133             (long long)control.value);
2134         printf("\n\tTXC port bitmap 0x%x", bitmap);
2135         printf("\n\tTXC max burst %d", burst);
2136         printf("\n\tTXC bytes xmt %d\n", bytes);
2137 
2138         {
2139                 ipp_status_t status;
2140 
2141                 (void) npi_ipp_get_status(handle, nxgep->function_num, &status);
2142 #if defined(__i386)
2143                 printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value);
2144 #else
2145                 printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
2146 #endif
2147         }
2148 }
2149 
2150 /*
2151  * nxge_tdc_hvio_setup
2152  *
2153  *      I'm not exactly sure what this code does.
2154  *
2155  * Arguments:
2156  *      nxgep
2157  *      channel The channel to map.
2158  *
2159  * Notes:
2160  *
2161  * NPI/NXGE function calls:
2162  *      na
2163  *
2164  * Context:
2165  *      Service domain?
2166  */
2167 #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2168 static void
2169 nxge_tdc_hvio_setup(
2170         nxge_t *nxgep, int channel)
2171 {
2172         nxge_dma_common_t       *data;
2173         nxge_dma_common_t       *control;
2174         tx_ring_t               *ring;
2175 
2176         ring = nxgep->tx_rings->rings[channel];
2177         data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2178 
2179         ring->hv_set = B_FALSE;
2180 
2181         ring->hv_tx_buf_base_ioaddr_pp =
2182             (uint64_t)data->orig_ioaddr_pp;
2183         ring->hv_tx_buf_ioaddr_size =
2184             (uint64_t)data->orig_alength;
2185 
2186         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2187             "hv data buf base io $%p size 0x%llx (%d) buf base io $%p "
2188             "orig vatopa base io $%p orig_len 0x%llx (%d)",
2189             ring->hv_tx_buf_base_ioaddr_pp,
2190             ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size,
2191             data->ioaddr_pp, data->orig_vatopa,
2192             data->orig_alength, data->orig_alength));
2193 
2194         control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2195 
2196         ring->hv_tx_cntl_base_ioaddr_pp =
2197             (uint64_t)control->orig_ioaddr_pp;
2198         ring->hv_tx_cntl_ioaddr_size =
2199             (uint64_t)control->orig_alength;
2200 
2201         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2202             "hv cntl base io $%p orig ioaddr_pp ($%p) "
2203             "orig vatopa ($%p) size 0x%llx (%d 0x%x)",
2204             ring->hv_tx_cntl_base_ioaddr_pp,
2205             control->orig_ioaddr_pp, control->orig_vatopa,
2206             ring->hv_tx_cntl_ioaddr_size,
2207             control->orig_alength, control->orig_alength));
2208 }
2209 #endif
2210 
2211 static nxge_status_t
2212 nxge_map_txdma(p_nxge_t nxgep, int channel)
2213 {
2214         nxge_dma_common_t       **pData;
2215         nxge_dma_common_t       **pControl;
2216         tx_ring_t               **pRing, *ring;
2217         tx_mbox_t               **mailbox;
2218         uint32_t                num_chunks;
2219 
2220         nxge_status_t           status = NXGE_OK;
2221 
2222         NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
2223 
2224         if (!nxgep->tx_cntl_pool_p->buf_allocated) {
2225                 if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) {
2226                         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2227                             "<== nxge_map_txdma: buf not allocated"));
2228                         return (NXGE_ERROR);
2229                 }
2230         }
2231 
2232         if (nxge_alloc_txb(nxgep, channel) != NXGE_OK)
2233                 return (NXGE_ERROR);
2234 
2235         num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel];
2236         pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2237         pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2238         pRing = &nxgep->tx_rings->rings[channel];
2239         mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2240 
2241         NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2242             "tx_rings $%p tx_desc_rings $%p",
2243             nxgep->tx_rings, nxgep->tx_rings->rings));
2244 
2245         /*
2246          * Map descriptors from the buffer pools for <channel>.
2247          */
2248 
2249         /*
2250          * Set up and prepare buffer blocks, descriptors
2251          * and mailbox.
2252          */
2253         status = nxge_map_txdma_channel(nxgep, channel,
2254             pData, pRing, num_chunks, pControl, mailbox);
2255         if (status != NXGE_OK) {
2256                 NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2257                     "==> nxge_map_txdma(%d): nxge_map_txdma_channel() "
2258                     "returned 0x%x",
2259                     nxgep, channel, status));
2260                 return (status);
2261         }
2262 
2263         ring = *pRing;
2264 
2265         ring->index = (uint16_t)channel;
2266         ring->tdc_stats = &nxgep->statsp->tdc_stats[channel];
2267 
2268 #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2269         if (isLDOMguest(nxgep)) {
2270                 (void) nxge_tdc_lp_conf(nxgep, channel);
2271         } else {
2272                 nxge_tdc_hvio_setup(nxgep, channel);
2273         }
2274 #endif
2275 
2276         NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2277             "(status 0x%x channel %d)", status, channel));
2278 
2279         return (status);
2280 }
2281 
2282 static nxge_status_t
2283 nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
2284         p_nxge_dma_common_t *dma_buf_p,
2285         p_tx_ring_t *tx_desc_p,
2286         uint32_t num_chunks,
2287         p_nxge_dma_common_t *dma_cntl_p,
2288         p_tx_mbox_t *tx_mbox_p)
2289 {
2290         int     status = NXGE_OK;
2291 
2292         /*
2293          * Set up and prepare buffer blocks, descriptors
2294          * and mailbox.
2295          */
2296         NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2297             "==> nxge_map_txdma_channel (channel %d)", channel));
2298         /*
2299          * Transmit buffer blocks
2300          */
2301         status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
2302             dma_buf_p, tx_desc_p, num_chunks);
2303         if (status != NXGE_OK) {
2304                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2305                     "==> nxge_map_txdma_channel (channel %d): "
2306                     "map buffer failed 0x%x", channel, status));
2307                 goto nxge_map_txdma_channel_exit;
2308         }
2309 
2310         /*
2311          * Transmit block ring, and mailbox.
2312          */
2313         nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
2314             tx_mbox_p);
2315 
2316         goto nxge_map_txdma_channel_exit;
2317 
2318 nxge_map_txdma_channel_fail1:
2319         NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2320             "==> nxge_map_txdma_channel: unmap buf"
2321             "(status 0x%x channel %d)",
2322             status, channel));
2323         nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
2324 
2325 nxge_map_txdma_channel_exit:
2326         NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2327             "<== nxge_map_txdma_channel: "
2328             "(status 0x%x channel %d)",
2329             status, channel));
2330 
2331         return (status);
2332 }
2333 
2334 /*ARGSUSED*/
2335 static void
2336 nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel)
2337 {
2338         tx_ring_t *ring;
2339         tx_mbox_t *mailbox;
2340 
2341         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2342             "==> nxge_unmap_txdma_channel (channel %d)", channel));
2343         /*
2344          * unmap tx block ring, and mailbox.
2345          */
2346         ring = nxgep->tx_rings->rings[channel];
2347         mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2348 
2349         (void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox);
2350 
2351         /* unmap buffer blocks */
2352         (void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring);
2353 
2354         nxge_free_txb(nxgep, channel);
2355 
2356         /*
2357          * Cleanup the reference to the ring now that it does not exist.
2358          */
2359         nxgep->tx_rings->rings[channel] = NULL;
2360 
2361         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
2362 }
2363 
2364 /*
2365  * nxge_map_txdma_channel_cfg_ring
2366  *
2367  *      Map a TDC into our kernel space.
2368  *      This function allocates all of the per-channel data structures.
2369  *
2370  * Arguments:
2371  *      nxgep
2372  *      dma_channel     The channel to map.
2373  *      dma_cntl_p
2374  *      tx_ring_p       dma_channel's transmit ring
2375  *      tx_mbox_p       dma_channel's mailbox
2376  *
2377  * Notes:
2378  *
2379  * NPI/NXGE function calls:
2380  *      nxge_setup_dma_common()
2381  *
2382  * Registers accessed:
2383  *      none.
2384  *
2385  * Context:
2386  *      Any domain
2387  */
2388 /*ARGSUSED*/
2389 static void
2390 nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
2391         p_nxge_dma_common_t *dma_cntl_p,
2392         p_tx_ring_t tx_ring_p,
2393         p_tx_mbox_t *tx_mbox_p)
2394 {
2395         p_tx_mbox_t             mboxp;
2396         p_nxge_dma_common_t     cntl_dmap;
2397         p_nxge_dma_common_t     dmap;
2398         p_tx_rng_cfig_t         tx_ring_cfig_p;
2399         p_tx_ring_kick_t        tx_ring_kick_p;
2400         p_tx_cs_t               tx_cs_p;
2401         p_tx_dma_ent_msk_t      tx_evmask_p;
2402         p_txdma_mbh_t           mboxh_p;
2403         p_txdma_mbl_t           mboxl_p;
2404         uint64_t                tx_desc_len;
2405 
2406         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2407             "==> nxge_map_txdma_channel_cfg_ring"));
2408 
2409         cntl_dmap = *dma_cntl_p;
2410 
2411         dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
2412         nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
2413             sizeof (tx_desc_t));
2414         /*
2415          * Zero out transmit ring descriptors.
2416          */
2417         bzero((caddr_t)dmap->kaddrp, dmap->alength);
2418         tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
2419         tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
2420         tx_cs_p = &(tx_ring_p->tx_cs);
2421         tx_evmask_p = &(tx_ring_p->tx_evmask);
2422         tx_ring_cfig_p->value = 0;
2423         tx_ring_kick_p->value = 0;
2424         tx_cs_p->value = 0;
2425         tx_evmask_p->value = 0;
2426 
2427         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2428             "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
2429             dma_channel,
2430             dmap->dma_cookie.dmac_laddress));
2431 
2432         tx_ring_cfig_p->value = 0;
2433         tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
2434         tx_ring_cfig_p->value =
2435             (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
2436             (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
2437 
2438         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2439             "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
2440             dma_channel,
2441             tx_ring_cfig_p->value));
2442 
2443         tx_cs_p->bits.ldw.rst = 1;
2444 
2445         /* Map in mailbox */
2446         mboxp = (p_tx_mbox_t)
2447             KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
2448         dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
2449         nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
2450         mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
2451         mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
2452         mboxh_p->value = mboxl_p->value = 0;
2453 
2454         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2455             "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
2456             dmap->dma_cookie.dmac_laddress));
2457 
2458         mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
2459             TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
2460 
2461         mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
2462             TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
2463 
2464         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2465             "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
2466             dmap->dma_cookie.dmac_laddress));
2467         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2468             "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
2469             "mbox $%p",
2470             mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
2471         tx_ring_p->page_valid.value = 0;
2472         tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
2473         tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
2474         tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
2475         tx_ring_p->page_hdl.value = 0;
2476 
2477         tx_ring_p->page_valid.bits.ldw.page0 = 1;
2478         tx_ring_p->page_valid.bits.ldw.page1 = 1;
2479 
2480         tx_ring_p->max_burst.value = 0;
2481         tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
2482 
2483         *tx_mbox_p = mboxp;
2484 
2485         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2486             "<== nxge_map_txdma_channel_cfg_ring"));
2487 }
2488 
2489 /*ARGSUSED*/
2490 static void
2491 nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
2492         p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
2493 {
2494         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2495             "==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
2496             tx_ring_p->tdc));
2497 
2498         KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
2499 
2500         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2501             "<== nxge_unmap_txdma_channel_cfg_ring"));
2502 }
2503 
2504 /*
2505  * nxge_map_txdma_channel_buf_ring
2506  *
2507  *
2508  * Arguments:
2509  *      nxgep
2510  *      channel         The channel to map.
2511  *      dma_buf_p
2512  *      tx_desc_p       channel's descriptor ring
2513  *      num_chunks
2514  *
2515  * Notes:
2516  *
2517  * NPI/NXGE function calls:
2518  *      nxge_setup_dma_common()
2519  *
2520  * Registers accessed:
2521  *      none.
2522  *
2523  * Context:
2524  *      Any domain
2525  */
2526 static nxge_status_t
2527 nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
2528         p_nxge_dma_common_t *dma_buf_p,
2529         p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
2530 {
2531         p_nxge_dma_common_t     dma_bufp, tmp_bufp;
2532         p_nxge_dma_common_t     dmap;
2533         nxge_os_dma_handle_t    tx_buf_dma_handle;
2534         p_tx_ring_t             tx_ring_p;
2535         p_tx_msg_t              tx_msg_ring;
2536         nxge_status_t           status = NXGE_OK;
2537         int                     ddi_status = DDI_SUCCESS;
2538         int                     i, j, index;
2539         uint32_t                size, bsize;
2540         uint32_t                nblocks, nmsgs;
2541         char                    qname[TASKQ_NAMELEN];
2542 
2543         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2544             "==> nxge_map_txdma_channel_buf_ring"));
2545 
2546         dma_bufp = tmp_bufp = *dma_buf_p;
2547                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2548                 " nxge_map_txdma_channel_buf_ring: channel %d to map %d "
2549                 "chunks bufp $%p",
2550                     channel, num_chunks, dma_bufp));
2551 
2552         nmsgs = 0;
2553         for (i = 0; i < num_chunks; i++, tmp_bufp++) {
2554                 nmsgs += tmp_bufp->nblocks;
2555                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2556                     "==> nxge_map_txdma_channel_buf_ring: channel %d "
2557                     "bufp $%p nblocks %d nmsgs %d",
2558                     channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
2559         }
2560         if (!nmsgs) {
2561                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2562                     "<== nxge_map_txdma_channel_buf_ring: channel %d "
2563                     "no msg blocks",
2564                     channel));
2565                 status = NXGE_ERROR;
2566                 goto nxge_map_txdma_channel_buf_ring_exit;
2567         }
2568 
2569         tx_ring_p = (p_tx_ring_t)
2570             KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
2571         MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
2572             (void *)nxgep->interrupt_cookie);
2573 
2574         (void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE);
2575         tx_ring_p->tx_ring_busy = B_FALSE;
2576         tx_ring_p->nxgep = nxgep;
2577         tx_ring_p->tx_ring_handle = (mac_ring_handle_t)NULL;
2578         (void) snprintf(qname, TASKQ_NAMELEN, "tx_%d_%d",
2579             nxgep->instance, channel);
2580         tx_ring_p->taskq = ddi_taskq_create(nxgep->dip, qname, 1,
2581             TASKQ_DEFAULTPRI, 0);
2582         if (tx_ring_p->taskq == NULL) {
2583                 goto nxge_map_txdma_channel_buf_ring_fail1;
2584         }
2585 
2586         /*
2587          * Allocate transmit message rings and handles for packets
2588          * not to be copied to premapped buffers.
2589          */
2590         size = nmsgs * sizeof (tx_msg_t);
2591         tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
2592         for (i = 0; i < nmsgs; i++) {
2593                 ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
2594                     DDI_DMA_DONTWAIT, 0,
2595                     &tx_msg_ring[i].dma_handle);
2596                 if (ddi_status != DDI_SUCCESS) {
2597                         status |= NXGE_DDI_FAILED;
2598                         break;
2599                 }
2600         }
2601         if (i < nmsgs) {
2602                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2603                     "Allocate handles failed."));
2604                 goto nxge_map_txdma_channel_buf_ring_fail1;
2605         }
2606 
2607         tx_ring_p->tdc = channel;
2608         tx_ring_p->tx_msg_ring = tx_msg_ring;
2609         tx_ring_p->tx_ring_size = nmsgs;
2610         tx_ring_p->num_chunks = num_chunks;
2611         if (!nxge_tx_intr_thres) {
2612                 nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
2613         }
2614         tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
2615         tx_ring_p->rd_index = 0;
2616         tx_ring_p->wr_index = 0;
2617         tx_ring_p->ring_head.value = 0;
2618         tx_ring_p->ring_kick_tail.value = 0;
2619         tx_ring_p->descs_pending = 0;
2620 
2621         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2622             "==> nxge_map_txdma_channel_buf_ring: channel %d "
2623             "actual tx desc max %d nmsgs %d "
2624             "(config nxge_tx_ring_size %d)",
2625             channel, tx_ring_p->tx_ring_size, nmsgs,
2626             nxge_tx_ring_size));
2627 
2628         /*
2629          * Map in buffers from the buffer pool.
2630          */
2631         index = 0;
2632         bsize = dma_bufp->block_size;
2633 
2634         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
2635             "dma_bufp $%p tx_rng_p $%p "
2636             "tx_msg_rng_p $%p bsize %d",
2637             dma_bufp, tx_ring_p, tx_msg_ring, bsize));
2638 
2639         tx_buf_dma_handle = dma_bufp->dma_handle;
2640         for (i = 0; i < num_chunks; i++, dma_bufp++) {
2641                 bsize = dma_bufp->block_size;
2642                 nblocks = dma_bufp->nblocks;
2643                 NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2644                     "==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
2645                     "size %d dma_bufp $%p",
2646                     i, sizeof (nxge_dma_common_t), dma_bufp));
2647 
2648                 for (j = 0; j < nblocks; j++) {
2649                         tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
2650                         dmap = &tx_msg_ring[index++].buf_dma;
2651 #ifdef TX_MEM_DEBUG
2652                         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2653                             "==> nxge_map_txdma_channel_buf_ring: j %d"
2654                             "dmap $%p", i, dmap));
2655 #endif
2656                         nxge_setup_dma_common(dmap, dma_bufp, 1,
2657                             bsize);
2658                 }
2659         }
2660 
2661         if (i < num_chunks) {
2662                 status = NXGE_ERROR;
2663                 goto nxge_map_txdma_channel_buf_ring_fail1;
2664         }
2665 
2666         *tx_desc_p = tx_ring_p;
2667 
2668         goto nxge_map_txdma_channel_buf_ring_exit;
2669 
2670 nxge_map_txdma_channel_buf_ring_fail1:
2671         if (tx_ring_p->taskq) {
2672                 ddi_taskq_destroy(tx_ring_p->taskq);
2673                 tx_ring_p->taskq = NULL;
2674         }
2675 
2676         index--;
2677         for (; index >= 0; index--) {
2678                 if (tx_msg_ring[index].dma_handle != NULL) {
2679                         ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
2680                 }
2681         }
2682         MUTEX_DESTROY(&tx_ring_p->lock);
2683         KMEM_FREE(tx_msg_ring, size);
2684         KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
2685 
2686         status = NXGE_ERROR;
2687 
2688 nxge_map_txdma_channel_buf_ring_exit:
2689         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2690             "<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
2691 
2692         return (status);
2693 }
2694 
2695 /*ARGSUSED*/
2696 static void
2697 nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
2698 {
2699         p_tx_msg_t              tx_msg_ring;
2700         p_tx_msg_t              tx_msg_p;
2701         int                     i;
2702 
2703         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2704             "==> nxge_unmap_txdma_channel_buf_ring"));
2705         if (tx_ring_p == NULL) {
2706                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2707                     "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
2708                 return;
2709         }
2710         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2711             "==> nxge_unmap_txdma_channel_buf_ring: channel %d",
2712             tx_ring_p->tdc));
2713 
2714         tx_msg_ring = tx_ring_p->tx_msg_ring;
2715 
2716         /*
2717          * Since the serialization thread, timer thread and
2718          * interrupt thread can all call the transmit reclaim,
2719          * the unmapping function needs to acquire the lock
2720          * to free those buffers which were transmitted
2721          * by the hardware already.
2722          */
2723         MUTEX_ENTER(&tx_ring_p->lock);
2724         NXGE_DEBUG_MSG((nxgep, TX_CTL,
2725             "==> nxge_unmap_txdma_channel_buf_ring (reclaim): "
2726             "channel %d",
2727             tx_ring_p->tdc));
2728         (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
2729 
2730         for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
2731                 tx_msg_p = &tx_msg_ring[i];
2732                 if (tx_msg_p->tx_message != NULL) {
2733                         freemsg(tx_msg_p->tx_message);
2734                         tx_msg_p->tx_message = NULL;
2735                 }
2736         }
2737 
2738         for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
2739                 if (tx_msg_ring[i].dma_handle != NULL) {
2740                         ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
2741                 }
2742                 tx_msg_ring[i].dma_handle = NULL;
2743         }
2744 
2745         MUTEX_EXIT(&tx_ring_p->lock);
2746 
2747         if (tx_ring_p->taskq) {
2748                 ddi_taskq_destroy(tx_ring_p->taskq);
2749                 tx_ring_p->taskq = NULL;
2750         }
2751 
2752         MUTEX_DESTROY(&tx_ring_p->lock);
2753         KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
2754         KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
2755 
2756         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2757             "<== nxge_unmap_txdma_channel_buf_ring"));
2758 }
2759 
2760 static nxge_status_t
2761 nxge_txdma_hw_start(p_nxge_t nxgep, int channel)
2762 {
2763         p_tx_rings_t            tx_rings;
2764         p_tx_ring_t             *tx_desc_rings;
2765         p_tx_mbox_areas_t       tx_mbox_areas_p;
2766         p_tx_mbox_t             *tx_mbox_p;
2767         nxge_status_t           status = NXGE_OK;
2768 
2769         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
2770 
2771         tx_rings = nxgep->tx_rings;
2772         if (tx_rings == NULL) {
2773                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2774                     "<== nxge_txdma_hw_start: NULL ring pointer"));
2775                 return (NXGE_ERROR);
2776         }
2777         tx_desc_rings = tx_rings->rings;
2778         if (tx_desc_rings == NULL) {
2779                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
2780                     "<== nxge_txdma_hw_start: NULL ring pointers"));
2781                 return (NXGE_ERROR);
2782         }
2783 
2784         NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2785             "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings));
2786 
2787         tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
2788         tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
2789 
2790         status = nxge_txdma_start_channel(nxgep, channel,
2791             (p_tx_ring_t)tx_desc_rings[channel],
2792             (p_tx_mbox_t)tx_mbox_p[channel]);
2793         if (status != NXGE_OK) {
2794                 goto nxge_txdma_hw_start_fail1;
2795         }
2796 
2797         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2798             "tx_rings $%p rings $%p",
2799             nxgep->tx_rings, nxgep->tx_rings->rings));
2800         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2801             "tx_rings $%p tx_desc_rings $%p",
2802             nxgep->tx_rings, tx_desc_rings));
2803 
2804         goto nxge_txdma_hw_start_exit;
2805 
2806 nxge_txdma_hw_start_fail1:
2807         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2808             "==> nxge_txdma_hw_start: disable "
2809             "(status 0x%x channel %d)", status, channel));
2810 
2811 nxge_txdma_hw_start_exit:
2812         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2813             "==> nxge_txdma_hw_start: (status 0x%x)", status));
2814 
2815         return (status);
2816 }
2817 
2818 /*
2819  * nxge_txdma_start_channel
2820  *
2821  *      Start a TDC.
2822  *
2823  * Arguments:
2824  *      nxgep
2825  *      channel         The channel to start.
2826  *      tx_ring_p       channel's transmit descriptor ring.
2827  *      tx_mbox_p       channel' smailbox.
2828  *
2829  * Notes:
2830  *
2831  * NPI/NXGE function calls:
2832  *      nxge_reset_txdma_channel()
2833  *      nxge_init_txdma_channel_event_mask()
2834  *      nxge_enable_txdma_channel()
2835  *
2836  * Registers accessed:
2837  *      none directly (see functions above).
2838  *
2839  * Context:
2840  *      Any domain
2841  */
2842 static nxge_status_t
2843 nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
2844     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
2845 
2846 {
2847         nxge_status_t           status = NXGE_OK;
2848 
2849         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2850                 "==> nxge_txdma_start_channel (channel %d)", channel));
2851         /*
2852          * TXDMA/TXC must be in stopped state.
2853          */
2854         (void) nxge_txdma_stop_inj_err(nxgep, channel);
2855 
2856         /*
2857          * Reset TXDMA channel
2858          */
2859         tx_ring_p->tx_cs.value = 0;
2860         tx_ring_p->tx_cs.bits.ldw.rst = 1;
2861         status = nxge_reset_txdma_channel(nxgep, channel,
2862                         tx_ring_p->tx_cs.value);
2863         if (status != NXGE_OK) {
2864                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2865                         "==> nxge_txdma_start_channel (channel %d)"
2866                         " reset channel failed 0x%x", channel, status));
2867                 goto nxge_txdma_start_channel_exit;
2868         }
2869 
2870         /*
2871          * Initialize the TXDMA channel specific FZC control
2872          * configurations. These FZC registers are pertaining
2873          * to each TX channel (i.e. logical pages).
2874          */
2875         if (!isLDOMguest(nxgep)) {
2876                 status = nxge_init_fzc_txdma_channel(nxgep, channel,
2877                     tx_ring_p, tx_mbox_p);
2878                 if (status != NXGE_OK) {
2879                         goto nxge_txdma_start_channel_exit;
2880                 }
2881         }
2882 
2883         /*
2884          * Initialize the event masks.
2885          */
2886         tx_ring_p->tx_evmask.value = 0;
2887         status = nxge_init_txdma_channel_event_mask(nxgep,
2888             channel, &tx_ring_p->tx_evmask);
2889         if (status != NXGE_OK) {
2890                 goto nxge_txdma_start_channel_exit;
2891         }
2892 
2893         /*
2894          * Load TXDMA descriptors, buffers, mailbox,
2895          * initialise the DMA channels and
2896          * enable each DMA channel.
2897          */
2898         status = nxge_enable_txdma_channel(nxgep, channel,
2899                         tx_ring_p, tx_mbox_p);
2900         if (status != NXGE_OK) {
2901                 goto nxge_txdma_start_channel_exit;
2902         }
2903 
2904 nxge_txdma_start_channel_exit:
2905         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
2906 
2907         return (status);
2908 }
2909 
2910 /*
2911  * nxge_txdma_stop_channel
2912  *
2913  *      Stop a TDC.
2914  *
2915  * Arguments:
2916  *      nxgep
2917  *      channel         The channel to stop.
2918  *      tx_ring_p       channel's transmit descriptor ring.
2919  *      tx_mbox_p       channel' smailbox.
2920  *
2921  * Notes:
2922  *
2923  * NPI/NXGE function calls:
2924  *      nxge_txdma_stop_inj_err()
2925  *      nxge_reset_txdma_channel()
2926  *      nxge_init_txdma_channel_event_mask()
2927  *      nxge_init_txdma_channel_cntl_stat()
2928  *      nxge_disable_txdma_channel()
2929  *
2930  * Registers accessed:
2931  *      none directly (see functions above).
2932  *
2933  * Context:
2934  *      Any domain
2935  */
2936 /*ARGSUSED*/
2937 static nxge_status_t
2938 nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel)
2939 {
2940         p_tx_ring_t tx_ring_p;
2941         int status = NXGE_OK;
2942 
2943         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2944             "==> nxge_txdma_stop_channel: channel %d", channel));
2945 
2946         /*
2947          * Stop (disable) TXDMA and TXC (if stop bit is set
2948          * and STOP_N_GO bit not set, the TXDMA reset state will
2949          * not be set if reset TXDMA.
2950          */
2951         (void) nxge_txdma_stop_inj_err(nxgep, channel);
2952 
2953         if (nxgep->tx_rings == NULL) {
2954                 status = NXGE_ERROR;
2955                 goto nxge_txdma_stop_channel_exit;
2956         }
2957 
2958         tx_ring_p = nxgep->tx_rings->rings[channel];
2959         if (tx_ring_p == NULL) {
2960                 status = NXGE_ERROR;
2961                 goto nxge_txdma_stop_channel_exit;
2962         }
2963 
2964         /*
2965          * Reset TXDMA channel
2966          */
2967         tx_ring_p->tx_cs.value = 0;
2968         tx_ring_p->tx_cs.bits.ldw.rst = 1;
2969         status = nxge_reset_txdma_channel(nxgep, channel,
2970             tx_ring_p->tx_cs.value);
2971         if (status != NXGE_OK) {
2972                 goto nxge_txdma_stop_channel_exit;
2973         }
2974 
2975 #ifdef HARDWARE_REQUIRED
2976         /* Set up the interrupt event masks. */
2977         tx_ring_p->tx_evmask.value = 0;
2978         status = nxge_init_txdma_channel_event_mask(nxgep,
2979             channel, &tx_ring_p->tx_evmask);
2980         if (status != NXGE_OK) {
2981                 goto nxge_txdma_stop_channel_exit;
2982         }
2983 
2984         /* Initialize the DMA control and status register */
2985         tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
2986         status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
2987             tx_ring_p->tx_cs.value);
2988         if (status != NXGE_OK) {
2989                 goto nxge_txdma_stop_channel_exit;
2990         }
2991 
2992         tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2993 
2994         /* Disable channel */
2995         status = nxge_disable_txdma_channel(nxgep, channel,
2996             tx_ring_p, tx_mbox_p);
2997         if (status != NXGE_OK) {
2998                 goto nxge_txdma_start_channel_exit;
2999         }
3000 
3001         NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
3002             "==> nxge_txdma_stop_channel: event done"));
3003 
3004 #endif
3005 
3006 nxge_txdma_stop_channel_exit:
3007         NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
3008         return (status);
3009 }
3010 
3011 /*
3012  * nxge_txdma_get_ring
3013  *
3014  *      Get the ring for a TDC.
3015  *
3016  * Arguments:
3017  *      nxgep
3018  *      channel
3019  *
3020  * Notes:
3021  *
3022  * NPI/NXGE function calls:
3023  *
3024  * Registers accessed:
3025  *
3026  * Context:
3027  *      Any domain
3028  */
3029 static p_tx_ring_t
3030 nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
3031 {
3032         nxge_grp_set_t *set = &nxgep->tx_set;
3033         int tdc;
3034 
3035         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
3036 
3037         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3038                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
3039                     "<== nxge_txdma_get_ring: NULL ring pointer(s)"));
3040                 goto return_null;
3041         }
3042 
3043         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3044                 if ((1 << tdc) & set->owned.map) {
3045                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3046                         if (ring) {
3047                                 if (channel == ring->tdc) {
3048                                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
3049                                             "<== nxge_txdma_get_ring: "
3050                                             "tdc %d ring $%p", tdc, ring));
3051                                         return (ring);
3052                                 }
3053                         }
3054                 }
3055         }
3056 
3057 return_null:
3058         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: "
3059             "ring not found"));
3060 
3061         return (NULL);
3062 }
3063 
3064 /*
3065  * nxge_txdma_get_mbox
3066  *
3067  *      Get the mailbox for a TDC.
3068  *
3069  * Arguments:
3070  *      nxgep
3071  *      channel
3072  *
3073  * Notes:
3074  *
3075  * NPI/NXGE function calls:
3076  *
3077  * Registers accessed:
3078  *
3079  * Context:
3080  *      Any domain
3081  */
3082 static p_tx_mbox_t
3083 nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
3084 {
3085         nxge_grp_set_t *set = &nxgep->tx_set;
3086         int tdc;
3087 
3088         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
3089 
3090         if (nxgep->tx_mbox_areas_p == 0 ||
3091             nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) {
3092                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
3093                     "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)"));
3094                 goto return_null;
3095         }
3096 
3097         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3098                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
3099                     "<== nxge_txdma_get_mbox: NULL ring pointer(s)"));
3100                 goto return_null;
3101         }
3102 
3103         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3104                 if ((1 << tdc) & set->owned.map) {
3105                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3106                         if (ring) {
3107                                 if (channel == ring->tdc) {
3108                                         tx_mbox_t *mailbox = nxgep->
3109                                             tx_mbox_areas_p->
3110                                             txmbox_areas_p[tdc];
3111                                         NXGE_DEBUG_MSG((nxgep, TX_CTL,
3112                                             "<== nxge_txdma_get_mbox: tdc %d "
3113                                             "ring $%p", tdc, mailbox));
3114                                         return (mailbox);
3115                                 }
3116                         }
3117                 }
3118         }
3119 
3120 return_null:
3121         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: "
3122             "mailbox not found"));
3123 
3124         return (NULL);
3125 }
3126 
3127 /*
3128  * nxge_tx_err_evnts
3129  *
3130  *      Recover a TDC.
3131  *
3132  * Arguments:
3133  *      nxgep
3134  *      index   The index to the TDC ring.
3135  *      ldvp    Used to get the channel number ONLY.
3136  *      cs      A copy of the bits from TX_CS.
3137  *
3138  * Notes:
3139  *      Calling tree:
3140  *       nxge_tx_intr()
3141  *
3142  * NPI/NXGE function calls:
3143  *      npi_txdma_ring_error_get()
3144  *      npi_txdma_inj_par_error_get()
3145  *      nxge_txdma_fatal_err_recover()
3146  *
3147  * Registers accessed:
3148  *      TX_RNG_ERR_LOGH DMC+0x40048 Transmit Ring Error Log High
3149  *      TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low
3150  *      TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3151  *
3152  * Context:
3153  *      Any domain      XXX Remove code which accesses TDMC_INJ_PAR_ERR.
3154  */
3155 /*ARGSUSED*/
3156 static nxge_status_t
3157 nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
3158 {
3159         npi_handle_t            handle;
3160         npi_status_t            rs;
3161         uint8_t                 channel;
3162         p_tx_ring_t             *tx_rings;
3163         p_tx_ring_t             tx_ring_p;
3164         p_nxge_tx_ring_stats_t  tdc_stats;
3165         boolean_t               txchan_fatal = B_FALSE;
3166         nxge_status_t           status = NXGE_OK;
3167         tdmc_inj_par_err_t      par_err;
3168         uint32_t                value;
3169 
3170         NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts"));
3171         handle = NXGE_DEV_NPI_HANDLE(nxgep);
3172         channel = ldvp->channel;
3173 
3174         tx_rings = nxgep->tx_rings->rings;
3175         tx_ring_p = tx_rings[index];
3176         tdc_stats = tx_ring_p->tdc_stats;
3177         if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
3178             (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
3179             (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
3180                 if ((rs = npi_txdma_ring_error_get(handle, channel,
3181                     &tdc_stats->errlog)) != NPI_SUCCESS)
3182                         return (NXGE_ERROR | rs);
3183         }
3184 
3185         if (cs.bits.ldw.mbox_err) {
3186                 tdc_stats->mbox_err++;
3187                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3188                     NXGE_FM_EREPORT_TDMC_MBOX_ERR);
3189                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3190                     "==> nxge_tx_err_evnts(channel %d): "
3191                     "fatal error: mailbox", channel));
3192                 txchan_fatal = B_TRUE;
3193         }
3194         if (cs.bits.ldw.pkt_size_err) {
3195                 tdc_stats->pkt_size_err++;
3196                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3197                     NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
3198                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3199                     "==> nxge_tx_err_evnts(channel %d): "
3200                     "fatal error: pkt_size_err", channel));
3201                 txchan_fatal = B_TRUE;
3202         }
3203         if (cs.bits.ldw.tx_ring_oflow) {
3204                 tdc_stats->tx_ring_oflow++;
3205                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3206                     NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
3207                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3208                     "==> nxge_tx_err_evnts(channel %d): "
3209                     "fatal error: tx_ring_oflow", channel));
3210                 txchan_fatal = B_TRUE;
3211         }
3212         if (cs.bits.ldw.pref_buf_par_err) {
3213                 tdc_stats->pre_buf_par_err++;
3214                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3215                     NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
3216                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3217                     "==> nxge_tx_err_evnts(channel %d): "
3218                     "fatal error: pre_buf_par_err", channel));
3219                 /* Clear error injection source for parity error */
3220                 (void) npi_txdma_inj_par_error_get(handle, &value);
3221                 par_err.value = value;
3222                 par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
3223                 (void) npi_txdma_inj_par_error_set(handle, par_err.value);
3224                 txchan_fatal = B_TRUE;
3225         }
3226         if (cs.bits.ldw.nack_pref) {
3227                 tdc_stats->nack_pref++;
3228                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3229                     NXGE_FM_EREPORT_TDMC_NACK_PREF);
3230                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3231                     "==> nxge_tx_err_evnts(channel %d): "
3232                     "fatal error: nack_pref", channel));
3233                 txchan_fatal = B_TRUE;
3234         }
3235         if (cs.bits.ldw.nack_pkt_rd) {
3236                 tdc_stats->nack_pkt_rd++;
3237                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3238                     NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
3239                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3240                     "==> nxge_tx_err_evnts(channel %d): "
3241                     "fatal error: nack_pkt_rd", channel));
3242                 txchan_fatal = B_TRUE;
3243         }
3244         if (cs.bits.ldw.conf_part_err) {
3245                 tdc_stats->conf_part_err++;
3246                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3247                     NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
3248                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3249                     "==> nxge_tx_err_evnts(channel %d): "
3250                     "fatal error: config_partition_err", channel));
3251                 txchan_fatal = B_TRUE;
3252         }
3253         if (cs.bits.ldw.pkt_prt_err) {
3254                 tdc_stats->pkt_part_err++;
3255                 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3256                     NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
3257                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3258                     "==> nxge_tx_err_evnts(channel %d): "
3259                     "fatal error: pkt_prt_err", channel));
3260                 txchan_fatal = B_TRUE;
3261         }
3262 
3263         /* Clear error injection source in case this is an injected error */
3264         TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
3265 
3266         if (txchan_fatal) {
3267                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3268                     " nxge_tx_err_evnts: "
3269                     " fatal error on channel %d cs 0x%llx\n",
3270                     channel, cs.value));
3271                 status = nxge_txdma_fatal_err_recover(nxgep, channel,
3272                     tx_ring_p);
3273                 if (status == NXGE_OK) {
3274                         FM_SERVICE_RESTORED(nxgep);
3275                 }
3276         }
3277 
3278         NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts"));
3279 
3280         return (status);
3281 }
3282 
3283 static nxge_status_t
3284 nxge_txdma_fatal_err_recover(
3285         p_nxge_t nxgep,
3286         uint16_t channel,
3287         p_tx_ring_t tx_ring_p)
3288 {
3289         npi_handle_t    handle;
3290         npi_status_t    rs = NPI_SUCCESS;
3291         p_tx_mbox_t     tx_mbox_p;
3292         nxge_status_t   status = NXGE_OK;
3293 
3294         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
3295         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3296             "Recovering from TxDMAChannel#%d error...", channel));
3297 
3298         /*
3299          * Stop the dma channel waits for the stop done.
3300          * If the stop done bit is not set, then create
3301          * an error.
3302          */
3303 
3304         handle = NXGE_DEV_NPI_HANDLE(nxgep);
3305         NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
3306         MUTEX_ENTER(&tx_ring_p->lock);
3307         rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
3308         if (rs != NPI_SUCCESS) {
3309                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3310                     "==> nxge_txdma_fatal_err_recover (channel %d): "
3311                     "stop failed ", channel));
3312                 goto fail;
3313         }
3314 
3315         NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
3316         (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
3317 
3318         /*
3319          * Reset TXDMA channel
3320          */
3321         NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
3322         if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
3323             NPI_SUCCESS) {
3324                 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3325                     "==> nxge_txdma_fatal_err_recover (channel %d)"
3326                     " reset channel failed 0x%x", channel, rs));
3327                 goto fail;
3328         }
3329 
3330         /*
3331          * Reset the tail (kick) register to 0.
3332          * (Hardware will not reset it. Tx overflow fatal
3333          * error if tail is not set to 0 after reset!
3334          */
3335         TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
3336 
3337         /* Restart TXDMA channel */
3338 
3339         if (!isLDOMguest(nxgep)) {
3340                 tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
3341 
3342                 // XXX This is a problem in HIO!
3343                 /*
3344                  * Initialize the TXDMA channel specific FZC control
3345                  * configurations. These FZC registers are pertaining
3346                  * to each TX channel (i.e. logical pages).
3347                  */
3348                 NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
3349                 status = nxge_init_fzc_txdma_channel(nxgep, channel,
3350                     tx_ring_p, tx_mbox_p);
3351                 if (status != NXGE_OK)
3352                         goto fail;
3353         }
3354 
3355         /*
3356          * Initialize the event masks.
3357          */
3358         tx_ring_p->tx_evmask.value = 0;
3359         status = nxge_init_txdma_channel_event_mask(nxgep, channel,
3360             &tx_ring_p->tx_evmask);
3361         if (status != NXGE_OK)
3362                 goto fail;
3363 
3364         tx_ring_p->wr_index_wrap = B_FALSE;
3365         tx_ring_p->wr_index = 0;
3366         tx_ring_p->rd_index = 0;
3367 
3368         /*
3369          * Load TXDMA descriptors, buffers, mailbox,
3370          * initialise the DMA channels and
3371          * enable each DMA channel.
3372          */
3373         NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
3374         status = nxge_enable_txdma_channel(nxgep, channel,
3375             tx_ring_p, tx_mbox_p);
3376         MUTEX_EXIT(&tx_ring_p->lock);
3377         if (status != NXGE_OK)
3378                 goto fail;
3379 
3380         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3381             "Recovery Successful, TxDMAChannel#%d Restored",
3382             channel));
3383         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
3384 
3385         return (NXGE_OK);
3386 
3387 fail:
3388         MUTEX_EXIT(&tx_ring_p->lock);
3389 
3390         NXGE_DEBUG_MSG((nxgep, TX_CTL,
3391             "nxge_txdma_fatal_err_recover (channel %d): "
3392             "failed to recover this txdma channel", channel));
3393         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
3394 
3395         return (status);
3396 }
3397 
3398 /*
3399  * nxge_tx_port_fatal_err_recover
3400  *
3401  *      Attempt to recover from a fatal port error.
3402  *
3403  * Arguments:
3404  *      nxgep
3405  *
3406  * Notes:
3407  *      How would a guest do this?
3408  *
3409  * NPI/NXGE function calls:
3410  *
3411  * Registers accessed:
3412  *
3413  * Context:
3414  *      Service domain
3415  */
3416 nxge_status_t
3417 nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
3418 {
3419         nxge_grp_set_t *set = &nxgep->tx_set;
3420         nxge_channel_t tdc;
3421 
3422         tx_ring_t       *ring;
3423         tx_mbox_t       *mailbox;
3424 
3425         npi_handle_t    handle;
3426         nxge_status_t   status;
3427         npi_status_t    rs;
3428 
3429         NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
3430         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3431             "Recovering from TxPort error..."));
3432 
3433         if (isLDOMguest(nxgep)) {
3434                 return (NXGE_OK);
3435         }
3436 
3437         if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
3438                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
3439                     "<== nxge_tx_port_fatal_err_recover: not initialized"));
3440                 return (NXGE_ERROR);
3441         }
3442 
3443         if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3444                 NXGE_DEBUG_MSG((nxgep, TX_CTL,
3445                     "<== nxge_tx_port_fatal_err_recover: "
3446                     "NULL ring pointer(s)"));
3447                 return (NXGE_ERROR);
3448         }
3449 
3450         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3451                 if ((1 << tdc) & set->owned.map) {
3452                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3453                         if (ring)
3454                                 MUTEX_ENTER(&ring->lock);
3455                 }
3456         }
3457 
3458         handle = NXGE_DEV_NPI_HANDLE(nxgep);
3459 
3460         /*
3461          * Stop all the TDCs owned by us.
3462          * (The shared TDCs will have been stopped by their owners.)
3463          */
3464         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3465                 if ((1 << tdc) & set->owned.map) {
3466                         ring = nxgep->tx_rings->rings[tdc];
3467                         if (ring) {
3468                                 rs = npi_txdma_channel_control
3469                                     (handle, TXDMA_STOP, tdc);
3470                                 if (rs != NPI_SUCCESS) {
3471                                         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3472                                             "nxge_tx_port_fatal_err_recover "
3473                                             "(channel %d): stop failed ", tdc));
3474                                         goto fail;
3475                                 }
3476                         }
3477                 }
3478         }
3479 
3480         NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs..."));
3481 
3482         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3483                 if ((1 << tdc) & set->owned.map) {
3484                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3485                         if (ring) {
3486                                 (void) nxge_txdma_reclaim(nxgep, ring, 0);
3487                         }
3488                 }
3489         }
3490 
3491         /*
3492          * Reset all the TDCs.
3493          */
3494         NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs..."));
3495 
3496         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3497                 if ((1 << tdc) & set->owned.map) {
3498                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3499                         if (ring) {
3500                                 if ((rs = npi_txdma_channel_control
3501                                     (handle, TXDMA_RESET, tdc))
3502                                     != NPI_SUCCESS) {
3503                                         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3504                                             "nxge_tx_port_fatal_err_recover "
3505                                             "(channel %d) reset channel "
3506                                             "failed 0x%x", tdc, rs));
3507                                         goto fail;
3508                                 }
3509                         }
3510                         /*
3511                          * Reset the tail (kick) register to 0.
3512                          * (Hardware will not reset it. Tx overflow fatal
3513                          * error if tail is not set to 0 after reset!
3514                          */
3515                         TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0);
3516                 }
3517         }
3518 
3519         NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs..."));
3520 
3521         /* Restart all the TDCs */
3522         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3523                 if ((1 << tdc) & set->owned.map) {
3524                         ring = nxgep->tx_rings->rings[tdc];
3525                         if (ring) {
3526                                 mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3527                                 status = nxge_init_fzc_txdma_channel(nxgep, tdc,
3528                                     ring, mailbox);
3529                                 ring->tx_evmask.value = 0;
3530                                 /*
3531                                  * Initialize the event masks.
3532                                  */
3533                                 status = nxge_init_txdma_channel_event_mask
3534                                     (nxgep, tdc, &ring->tx_evmask);
3535 
3536                                 ring->wr_index_wrap = B_FALSE;
3537                                 ring->wr_index = 0;
3538                                 ring->rd_index = 0;
3539 
3540                                 if (status != NXGE_OK)
3541                                         goto fail;
3542                                 if (status != NXGE_OK)
3543                                         goto fail;
3544                         }
3545                 }
3546         }
3547 
3548         NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs..."));
3549 
3550         /* Re-enable all the TDCs */
3551         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3552                 if ((1 << tdc) & set->owned.map) {
3553                         ring = nxgep->tx_rings->rings[tdc];
3554                         if (ring) {
3555                                 mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3556                                 status = nxge_enable_txdma_channel(nxgep, tdc,
3557                                     ring, mailbox);
3558                                 if (status != NXGE_OK)
3559                                         goto fail;
3560                         }
3561                 }
3562         }
3563 
3564         /*
3565          * Unlock all the TDCs.
3566          */
3567         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3568                 if ((1 << tdc) & set->owned.map) {
3569                         tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3570                         if (ring)
3571                                 MUTEX_EXIT(&ring->lock);
3572                 }
3573         }
3574 
3575         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded"));
3576         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
3577 
3578         return (NXGE_OK);
3579 
3580 fail:
3581         for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3582                 if ((1 << tdc) & set->owned.map) {
3583                         ring = nxgep->tx_rings->rings[tdc];
3584                         if (ring)
3585                                 MUTEX_EXIT(&ring->lock);
3586                 }
3587         }
3588 
3589         NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed"));
3590         NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
3591 
3592         return (status);
3593 }
3594 
3595 /*
3596  * nxge_txdma_inject_err
3597  *
3598  *      Inject an error into a TDC.
3599  *
3600  * Arguments:
3601  *      nxgep
3602  *      err_id  The error to inject.
3603  *      chan    The channel to inject into.
3604  *
3605  * Notes:
3606  *      This is called from nxge_main.c:nxge_err_inject()
3607  *      Has this ioctl ever been used?
3608  *
3609  * NPI/NXGE function calls:
3610  *      npi_txdma_inj_par_error_get()
3611  *      npi_txdma_inj_par_error_set()
3612  *
3613  * Registers accessed:
3614  *      TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3615  *      TDMC_INTR_DBG   DMC + 0x40060 Transmit DMA Interrupt Debug
3616  *      TDMC_INTR_DBG   DMC + 0x40060 Transmit DMA Interrupt Debug
3617  *
3618  * Context:
3619  *      Service domain
3620  */
3621 void
3622 nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
3623 {
3624         tdmc_intr_dbg_t         tdi;
3625         tdmc_inj_par_err_t      par_err;
3626         uint32_t                value;
3627         npi_handle_t            handle;
3628 
3629         switch (err_id) {
3630 
3631         case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
3632                 handle = NXGE_DEV_NPI_HANDLE(nxgep);
3633                 /* Clear error injection source for parity error */
3634                 (void) npi_txdma_inj_par_error_get(handle, &value);
3635                 par_err.value = value;
3636                 par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
3637                 (void) npi_txdma_inj_par_error_set(handle, par_err.value);
3638 
3639                 par_err.bits.ldw.inject_parity_error = (1 << chan);
3640                 (void) npi_txdma_inj_par_error_get(handle, &value);
3641                 par_err.value = value;
3642                 par_err.bits.ldw.inject_parity_error |= (1 << chan);
3643                 cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
3644                     (unsigned long long)par_err.value);
3645                 (void) npi_txdma_inj_par_error_set(handle, par_err.value);
3646                 break;
3647 
3648         case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
3649         case NXGE_FM_EREPORT_TDMC_NACK_PREF:
3650         case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
3651         case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
3652         case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
3653         case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
3654         case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
3655                 TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
3656                     chan, &tdi.value);
3657                 if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
3658                         tdi.bits.ldw.pref_buf_par_err = 1;
3659                 else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
3660                         tdi.bits.ldw.mbox_err = 1;
3661                 else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
3662                         tdi.bits.ldw.nack_pref = 1;
3663                 else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
3664                         tdi.bits.ldw.nack_pkt_rd = 1;
3665                 else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
3666                         tdi.bits.ldw.pkt_size_err = 1;
3667                 else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
3668                         tdi.bits.ldw.tx_ring_oflow = 1;
3669                 else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
3670                         tdi.bits.ldw.conf_part_err = 1;
3671                 else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
3672                         tdi.bits.ldw.pkt_part_err = 1;
3673 #if defined(__i386)
3674                 cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n",
3675                     tdi.value);
3676 #else
3677                 cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
3678                     tdi.value);
3679 #endif
3680                 TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
3681                     chan, tdi.value);
3682 
3683                 break;
3684         }
3685 }