144961713Sgirish /* 244961713Sgirish * CDDL HEADER START 344961713Sgirish * 444961713Sgirish * The contents of this file are subject to the terms of the 544961713Sgirish * Common Development and Distribution License (the "License"). 644961713Sgirish * You may not use this file except in compliance with the License. 744961713Sgirish * 844961713Sgirish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 944961713Sgirish * or http://www.opensolaris.org/os/licensing. 1044961713Sgirish * See the License for the specific language governing permissions 1144961713Sgirish * and limitations under the License. 1244961713Sgirish * 1344961713Sgirish * When distributing Covered Code, include this CDDL HEADER in each 1444961713Sgirish * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1544961713Sgirish * If applicable, add the following below this CDDL HEADER, with the 1644961713Sgirish * fields enclosed by brackets "[]" replaced with your own identifying 1744961713Sgirish * information: Portions Copyright [yyyy] [name of copyright owner] 1844961713Sgirish * 1944961713Sgirish * CDDL HEADER END 2044961713Sgirish */ 2144961713Sgirish /* 22678453a8Sspeer * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2344961713Sgirish * Use is subject to license terms. 2444961713Sgirish */ 2544961713Sgirish 2644961713Sgirish #pragma ident "%Z%%M% %I% %E% SMI" 2744961713Sgirish 2844961713Sgirish #include <sys/nxge/nxge_impl.h> 2944961713Sgirish #include <sys/nxge/nxge_txdma.h> 30678453a8Sspeer #include <sys/nxge/nxge_hio.h> 31678453a8Sspeer #include <npi_tx_rd64.h> 32678453a8Sspeer #include <npi_tx_wr64.h> 3344961713Sgirish #include <sys/llc1.h> 3444961713Sgirish 3544961713Sgirish uint32_t nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT; 3644961713Sgirish uint32_t nxge_tx_minfree = 32; 3744961713Sgirish uint32_t nxge_tx_intr_thres = 0; 3844961713Sgirish uint32_t nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS; 3944961713Sgirish uint32_t nxge_tx_tiny_pack = 1; 4044961713Sgirish uint32_t nxge_tx_use_bcopy = 1; 4144961713Sgirish 4244961713Sgirish extern uint32_t nxge_tx_ring_size; 4344961713Sgirish extern uint32_t nxge_bcopy_thresh; 4444961713Sgirish extern uint32_t nxge_dvma_thresh; 4544961713Sgirish extern uint32_t nxge_dma_stream_thresh; 4644961713Sgirish extern dma_method_t nxge_force_dma; 47b4d05839Sml extern uint32_t nxge_cksum_offload; 4844961713Sgirish 4944961713Sgirish /* Device register access attributes for PIO. */ 5044961713Sgirish extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr; 5144961713Sgirish /* Device descriptor access attributes for DMA. */ 5244961713Sgirish extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr; 5344961713Sgirish /* Device buffer access attributes for DMA. */ 5444961713Sgirish extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr; 5544961713Sgirish extern ddi_dma_attr_t nxge_desc_dma_attr; 5644961713Sgirish extern ddi_dma_attr_t nxge_tx_dma_attr; 5744961713Sgirish 581f8914d5Sml extern int nxge_serial_tx(mblk_t *mp, void *arg); 591f8914d5Sml 60678453a8Sspeer static nxge_status_t nxge_map_txdma(p_nxge_t, int); 6144961713Sgirish 62678453a8Sspeer static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int); 6344961713Sgirish 6444961713Sgirish static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t, 6544961713Sgirish p_nxge_dma_common_t *, p_tx_ring_t *, 6644961713Sgirish uint32_t, p_nxge_dma_common_t *, 6744961713Sgirish p_tx_mbox_t *); 68678453a8Sspeer static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t); 6944961713Sgirish 7044961713Sgirish static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t, 7144961713Sgirish p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t); 7244961713Sgirish static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t); 7344961713Sgirish 7444961713Sgirish static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t, 7544961713Sgirish p_nxge_dma_common_t *, p_tx_ring_t, 7644961713Sgirish p_tx_mbox_t *); 7744961713Sgirish static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t, 7844961713Sgirish p_tx_ring_t, p_tx_mbox_t); 7944961713Sgirish 8044961713Sgirish static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t, 8144961713Sgirish p_tx_ring_t, p_tx_mbox_t); 82678453a8Sspeer static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t); 8344961713Sgirish 8444961713Sgirish static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t); 8544961713Sgirish static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t, 8644961713Sgirish p_nxge_ldv_t, tx_cs_t); 8744961713Sgirish static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t); 8844961713Sgirish static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t, 8944961713Sgirish uint16_t, p_tx_ring_t); 9044961713Sgirish 91678453a8Sspeer static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, 92678453a8Sspeer p_tx_ring_t ring_p, uint16_t channel); 93678453a8Sspeer 9444961713Sgirish nxge_status_t 9544961713Sgirish nxge_init_txdma_channels(p_nxge_t nxgep) 9644961713Sgirish { 97678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 98678453a8Sspeer int i, count; 99678453a8Sspeer 100678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels")); 101678453a8Sspeer 102678453a8Sspeer for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) { 103678453a8Sspeer if ((1 << i) & set->lg.map) { 104678453a8Sspeer int tdc; 105678453a8Sspeer nxge_grp_t *group = set->group[i]; 106678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 107678453a8Sspeer if ((1 << tdc) & group->map) { 108678453a8Sspeer if ((nxge_grp_dc_add(nxgep, 109678453a8Sspeer (vr_handle_t)group, 110678453a8Sspeer VP_BOUND_TX, tdc))) 111678453a8Sspeer return (NXGE_ERROR); 112678453a8Sspeer } 113678453a8Sspeer } 114678453a8Sspeer } 115678453a8Sspeer if (++count == set->lg.count) 116678453a8Sspeer break; 117678453a8Sspeer } 118678453a8Sspeer 119678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels")); 120678453a8Sspeer 121678453a8Sspeer return (NXGE_OK); 122678453a8Sspeer } 123678453a8Sspeer 124678453a8Sspeer nxge_status_t 125678453a8Sspeer nxge_init_txdma_channel( 126678453a8Sspeer p_nxge_t nxge, 127678453a8Sspeer int channel) 128678453a8Sspeer { 129678453a8Sspeer nxge_status_t status; 13044961713Sgirish 131678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel")); 13244961713Sgirish 133678453a8Sspeer status = nxge_map_txdma(nxge, channel); 13444961713Sgirish if (status != NXGE_OK) { 135678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 136678453a8Sspeer "<== nxge_init_txdma_channel: status 0x%x", status)); 137678453a8Sspeer (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel); 13844961713Sgirish return (status); 13944961713Sgirish } 14044961713Sgirish 141678453a8Sspeer status = nxge_txdma_hw_start(nxge, channel); 14244961713Sgirish if (status != NXGE_OK) { 143678453a8Sspeer (void) nxge_unmap_txdma_channel(nxge, channel); 144678453a8Sspeer (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel); 14544961713Sgirish return (status); 14644961713Sgirish } 14744961713Sgirish 148678453a8Sspeer if (!nxge->statsp->tdc_ksp[channel]) 149678453a8Sspeer nxge_setup_tdc_kstats(nxge, channel); 15044961713Sgirish 151678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel")); 152678453a8Sspeer 153678453a8Sspeer return (status); 15444961713Sgirish } 15544961713Sgirish 15644961713Sgirish void 15744961713Sgirish nxge_uninit_txdma_channels(p_nxge_t nxgep) 15844961713Sgirish { 159678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 160678453a8Sspeer int tdc; 161678453a8Sspeer 162678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels")); 163678453a8Sspeer 164678453a8Sspeer if (set->owned.map == 0) { 165678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, 166678453a8Sspeer "nxge_uninit_txdma_channels: no channels")); 167678453a8Sspeer return; 168678453a8Sspeer } 169678453a8Sspeer 170678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 171678453a8Sspeer if ((1 << tdc) & set->owned.map) { 172678453a8Sspeer nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc); 173678453a8Sspeer } 174678453a8Sspeer } 175678453a8Sspeer 176678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels")); 177678453a8Sspeer } 178678453a8Sspeer 179678453a8Sspeer void 180678453a8Sspeer nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel) 181678453a8Sspeer { 182678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel")); 183678453a8Sspeer 184678453a8Sspeer if (nxgep->statsp->tdc_ksp[channel]) { 185678453a8Sspeer kstat_delete(nxgep->statsp->tdc_ksp[channel]); 186678453a8Sspeer nxgep->statsp->tdc_ksp[channel] = 0; 187678453a8Sspeer } 18844961713Sgirish 189678453a8Sspeer (void) nxge_txdma_stop_channel(nxgep, channel); 190678453a8Sspeer nxge_unmap_txdma_channel(nxgep, channel); 19144961713Sgirish 19244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 193678453a8Sspeer "<== nxge_uninit_txdma_channel")); 19444961713Sgirish } 19544961713Sgirish 19644961713Sgirish void 19744961713Sgirish nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p, 19844961713Sgirish uint32_t entries, uint32_t size) 19944961713Sgirish { 20044961713Sgirish size_t tsize; 20144961713Sgirish *dest_p = *src_p; 20244961713Sgirish tsize = size * entries; 20344961713Sgirish dest_p->alength = tsize; 20444961713Sgirish dest_p->nblocks = entries; 20544961713Sgirish dest_p->block_size = size; 20644961713Sgirish dest_p->offset += tsize; 20744961713Sgirish 20844961713Sgirish src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize; 20944961713Sgirish src_p->alength -= tsize; 21044961713Sgirish src_p->dma_cookie.dmac_laddress += tsize; 21144961713Sgirish src_p->dma_cookie.dmac_size -= tsize; 21244961713Sgirish } 21344961713Sgirish 214678453a8Sspeer /* 215678453a8Sspeer * nxge_reset_txdma_channel 216678453a8Sspeer * 217678453a8Sspeer * Reset a TDC. 218678453a8Sspeer * 219678453a8Sspeer * Arguments: 220678453a8Sspeer * nxgep 221678453a8Sspeer * channel The channel to reset. 222678453a8Sspeer * reg_data The current TX_CS. 223678453a8Sspeer * 224678453a8Sspeer * Notes: 225678453a8Sspeer * 226678453a8Sspeer * NPI/NXGE function calls: 227678453a8Sspeer * npi_txdma_channel_reset() 228678453a8Sspeer * npi_txdma_channel_control() 229678453a8Sspeer * 230678453a8Sspeer * Registers accessed: 231678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 232678453a8Sspeer * TX_RING_KICK DMC+0x40018 Transmit Ring Kick 233678453a8Sspeer * 234678453a8Sspeer * Context: 235678453a8Sspeer * Any domain 236678453a8Sspeer */ 23744961713Sgirish nxge_status_t 23844961713Sgirish nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data) 23944961713Sgirish { 24044961713Sgirish npi_status_t rs = NPI_SUCCESS; 24144961713Sgirish nxge_status_t status = NXGE_OK; 24244961713Sgirish npi_handle_t handle; 24344961713Sgirish 24444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel")); 24544961713Sgirish 24644961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 24744961713Sgirish if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) { 24844961713Sgirish rs = npi_txdma_channel_reset(handle, channel); 24944961713Sgirish } else { 25044961713Sgirish rs = npi_txdma_channel_control(handle, TXDMA_RESET, 25144961713Sgirish channel); 25244961713Sgirish } 25344961713Sgirish 25444961713Sgirish if (rs != NPI_SUCCESS) { 25544961713Sgirish status = NXGE_ERROR | rs; 25644961713Sgirish } 25744961713Sgirish 25844961713Sgirish /* 25944961713Sgirish * Reset the tail (kick) register to 0. 26044961713Sgirish * (Hardware will not reset it. Tx overflow fatal 26144961713Sgirish * error if tail is not set to 0 after reset! 26244961713Sgirish */ 26344961713Sgirish TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0); 26444961713Sgirish 26544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel")); 26644961713Sgirish return (status); 26744961713Sgirish } 26844961713Sgirish 269678453a8Sspeer /* 270678453a8Sspeer * nxge_init_txdma_channel_event_mask 271678453a8Sspeer * 272678453a8Sspeer * Enable interrupts for a set of events. 273678453a8Sspeer * 274678453a8Sspeer * Arguments: 275678453a8Sspeer * nxgep 276678453a8Sspeer * channel The channel to map. 277678453a8Sspeer * mask_p The events to enable. 278678453a8Sspeer * 279678453a8Sspeer * Notes: 280678453a8Sspeer * 281678453a8Sspeer * NPI/NXGE function calls: 282678453a8Sspeer * npi_txdma_event_mask() 283678453a8Sspeer * 284678453a8Sspeer * Registers accessed: 285678453a8Sspeer * TX_ENT_MSK DMC+0x40020 Transmit Event Mask 286678453a8Sspeer * 287678453a8Sspeer * Context: 288678453a8Sspeer * Any domain 289678453a8Sspeer */ 29044961713Sgirish nxge_status_t 29144961713Sgirish nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel, 29244961713Sgirish p_tx_dma_ent_msk_t mask_p) 29344961713Sgirish { 29444961713Sgirish npi_handle_t handle; 29544961713Sgirish npi_status_t rs = NPI_SUCCESS; 29644961713Sgirish nxge_status_t status = NXGE_OK; 29744961713Sgirish 29844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 29944961713Sgirish "<== nxge_init_txdma_channel_event_mask")); 30044961713Sgirish 30144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 30244961713Sgirish rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p); 30344961713Sgirish if (rs != NPI_SUCCESS) { 30444961713Sgirish status = NXGE_ERROR | rs; 30544961713Sgirish } 30644961713Sgirish 30744961713Sgirish return (status); 30844961713Sgirish } 30944961713Sgirish 310678453a8Sspeer /* 311678453a8Sspeer * nxge_init_txdma_channel_cntl_stat 312678453a8Sspeer * 313678453a8Sspeer * Stop a TDC. If at first we don't succeed, inject an error. 314678453a8Sspeer * 315678453a8Sspeer * Arguments: 316678453a8Sspeer * nxgep 317678453a8Sspeer * channel The channel to stop. 318678453a8Sspeer * 319678453a8Sspeer * Notes: 320678453a8Sspeer * 321678453a8Sspeer * NPI/NXGE function calls: 322678453a8Sspeer * npi_txdma_control_status() 323678453a8Sspeer * 324678453a8Sspeer * Registers accessed: 325678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 326678453a8Sspeer * 327678453a8Sspeer * Context: 328678453a8Sspeer * Any domain 329678453a8Sspeer */ 33044961713Sgirish nxge_status_t 33144961713Sgirish nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel, 33244961713Sgirish uint64_t reg_data) 33344961713Sgirish { 33444961713Sgirish npi_handle_t handle; 33544961713Sgirish npi_status_t rs = NPI_SUCCESS; 33644961713Sgirish nxge_status_t status = NXGE_OK; 33744961713Sgirish 33844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 33944961713Sgirish "<== nxge_init_txdma_channel_cntl_stat")); 34044961713Sgirish 34144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 34244961713Sgirish rs = npi_txdma_control_status(handle, OP_SET, channel, 34344961713Sgirish (p_tx_cs_t)®_data); 34444961713Sgirish 34544961713Sgirish if (rs != NPI_SUCCESS) { 34644961713Sgirish status = NXGE_ERROR | rs; 34744961713Sgirish } 34844961713Sgirish 34944961713Sgirish return (status); 35044961713Sgirish } 35144961713Sgirish 352678453a8Sspeer /* 353678453a8Sspeer * nxge_enable_txdma_channel 354678453a8Sspeer * 355678453a8Sspeer * Enable a TDC. 356678453a8Sspeer * 357678453a8Sspeer * Arguments: 358678453a8Sspeer * nxgep 359678453a8Sspeer * channel The channel to enable. 360678453a8Sspeer * tx_desc_p channel's transmit descriptor ring. 361678453a8Sspeer * mbox_p channel's mailbox, 362678453a8Sspeer * 363678453a8Sspeer * Notes: 364678453a8Sspeer * 365678453a8Sspeer * NPI/NXGE function calls: 366678453a8Sspeer * npi_txdma_ring_config() 367678453a8Sspeer * npi_txdma_mbox_config() 368678453a8Sspeer * npi_txdma_channel_init_enable() 369678453a8Sspeer * 370678453a8Sspeer * Registers accessed: 371678453a8Sspeer * TX_RNG_CFIG DMC+0x40000 Transmit Ring Configuration 372678453a8Sspeer * TXDMA_MBH DMC+0x40030 TXDMA Mailbox High 373678453a8Sspeer * TXDMA_MBL DMC+0x40038 TXDMA Mailbox Low 374678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 375678453a8Sspeer * 376678453a8Sspeer * Context: 377678453a8Sspeer * Any domain 378678453a8Sspeer */ 37944961713Sgirish nxge_status_t 38044961713Sgirish nxge_enable_txdma_channel(p_nxge_t nxgep, 38144961713Sgirish uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p) 38244961713Sgirish { 38344961713Sgirish npi_handle_t handle; 38444961713Sgirish npi_status_t rs = NPI_SUCCESS; 38544961713Sgirish nxge_status_t status = NXGE_OK; 38644961713Sgirish 38744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel")); 38844961713Sgirish 38944961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 39044961713Sgirish /* 39144961713Sgirish * Use configuration data composed at init time. 39244961713Sgirish * Write to hardware the transmit ring configurations. 39344961713Sgirish */ 39444961713Sgirish rs = npi_txdma_ring_config(handle, OP_SET, channel, 395678453a8Sspeer (uint64_t *)&(tx_desc_p->tx_ring_cfig.value)); 39644961713Sgirish 39744961713Sgirish if (rs != NPI_SUCCESS) { 39844961713Sgirish return (NXGE_ERROR | rs); 39944961713Sgirish } 40044961713Sgirish 401678453a8Sspeer if (isLDOMguest(nxgep)) { 402678453a8Sspeer /* Add interrupt handler for this channel. */ 403678453a8Sspeer if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK) 404678453a8Sspeer return (NXGE_ERROR); 405678453a8Sspeer } 406678453a8Sspeer 40744961713Sgirish /* Write to hardware the mailbox */ 40844961713Sgirish rs = npi_txdma_mbox_config(handle, OP_SET, channel, 40944961713Sgirish (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress); 41044961713Sgirish 41144961713Sgirish if (rs != NPI_SUCCESS) { 41244961713Sgirish return (NXGE_ERROR | rs); 41344961713Sgirish } 41444961713Sgirish 41544961713Sgirish /* Start the DMA engine. */ 41644961713Sgirish rs = npi_txdma_channel_init_enable(handle, channel); 41744961713Sgirish 41844961713Sgirish if (rs != NPI_SUCCESS) { 41944961713Sgirish return (NXGE_ERROR | rs); 42044961713Sgirish } 42144961713Sgirish 42244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel")); 42344961713Sgirish 42444961713Sgirish return (status); 42544961713Sgirish } 42644961713Sgirish 42744961713Sgirish void 42844961713Sgirish nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len, 42944961713Sgirish boolean_t l4_cksum, int pkt_len, uint8_t npads, 430b4d05839Sml p_tx_pkt_hdr_all_t pkthdrp, 431b4d05839Sml t_uscalar_t start_offset, 432b4d05839Sml t_uscalar_t stuff_offset) 43344961713Sgirish { 43444961713Sgirish p_tx_pkt_header_t hdrp; 43544961713Sgirish p_mblk_t nmp; 43644961713Sgirish uint64_t tmp; 43744961713Sgirish size_t mblk_len; 43844961713Sgirish size_t iph_len; 43944961713Sgirish size_t hdrs_size; 44044961713Sgirish uint8_t hdrs_buf[sizeof (struct ether_header) + 44144961713Sgirish 64 + sizeof (uint32_t)]; 442ae2d3f74Smisaki uint8_t *cursor; 44344961713Sgirish uint8_t *ip_buf; 44444961713Sgirish uint16_t eth_type; 44544961713Sgirish uint8_t ipproto; 44644961713Sgirish boolean_t is_vlan = B_FALSE; 44744961713Sgirish size_t eth_hdr_size; 44844961713Sgirish 44944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp)); 45044961713Sgirish 45144961713Sgirish /* 45244961713Sgirish * Caller should zero out the headers first. 45344961713Sgirish */ 45444961713Sgirish hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr; 45544961713Sgirish 45644961713Sgirish if (fill_len) { 45744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 45844961713Sgirish "==> nxge_fill_tx_hdr: pkt_len %d " 45944961713Sgirish "npads %d", pkt_len, npads)); 46044961713Sgirish tmp = (uint64_t)pkt_len; 46144961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT); 46244961713Sgirish goto fill_tx_header_done; 46344961713Sgirish } 46444961713Sgirish 465b4d05839Sml hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT); 46644961713Sgirish 46744961713Sgirish /* 46844961713Sgirish * mp is the original data packet (does not include the 46944961713Sgirish * Neptune transmit header). 47044961713Sgirish */ 47144961713Sgirish nmp = mp; 47244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: " 47344961713Sgirish "mp $%p b_rptr $%p len %d", 474ae2d3f74Smisaki mp, nmp->b_rptr, MBLKL(nmp))); 475ae2d3f74Smisaki /* copy ether_header from mblk to hdrs_buf */ 476ae2d3f74Smisaki cursor = &hdrs_buf[0]; 477ae2d3f74Smisaki tmp = sizeof (struct ether_vlan_header); 478ae2d3f74Smisaki while ((nmp != NULL) && (tmp > 0)) { 479ae2d3f74Smisaki size_t buflen; 480ae2d3f74Smisaki mblk_len = MBLKL(nmp); 4817c29db66Smisaki buflen = min((size_t)tmp, mblk_len); 482ae2d3f74Smisaki bcopy(nmp->b_rptr, cursor, buflen); 483ae2d3f74Smisaki cursor += buflen; 484ae2d3f74Smisaki tmp -= buflen; 485ae2d3f74Smisaki nmp = nmp->b_cont; 486ae2d3f74Smisaki } 487ae2d3f74Smisaki 488ae2d3f74Smisaki nmp = mp; 489ae2d3f74Smisaki mblk_len = MBLKL(nmp); 49044961713Sgirish ip_buf = NULL; 49144961713Sgirish eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type); 49244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) " 49344961713Sgirish "ether type 0x%x", eth_type, hdrp->value)); 49444961713Sgirish 49544961713Sgirish if (eth_type < ETHERMTU) { 49644961713Sgirish tmp = 1ull; 49744961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT); 49844961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC " 49944961713Sgirish "value 0x%llx", hdrp->value)); 50044961713Sgirish if (*(hdrs_buf + sizeof (struct ether_header)) 50144961713Sgirish == LLC_SNAP_SAP) { 50244961713Sgirish eth_type = ntohs(*((uint16_t *)(hdrs_buf + 50344961713Sgirish sizeof (struct ether_header) + 6))); 50444961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 50544961713Sgirish "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x", 50644961713Sgirish eth_type)); 50744961713Sgirish } else { 50844961713Sgirish goto fill_tx_header_done; 50944961713Sgirish } 51044961713Sgirish } else if (eth_type == VLAN_ETHERTYPE) { 51144961713Sgirish tmp = 1ull; 51244961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT); 51344961713Sgirish 51444961713Sgirish eth_type = ntohs(((struct ether_vlan_header *) 51544961713Sgirish hdrs_buf)->ether_type); 51644961713Sgirish is_vlan = B_TRUE; 51744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN " 51844961713Sgirish "value 0x%llx", hdrp->value)); 51944961713Sgirish } 52044961713Sgirish 52144961713Sgirish if (!is_vlan) { 52244961713Sgirish eth_hdr_size = sizeof (struct ether_header); 52344961713Sgirish } else { 52444961713Sgirish eth_hdr_size = sizeof (struct ether_vlan_header); 52544961713Sgirish } 52644961713Sgirish 52744961713Sgirish switch (eth_type) { 52844961713Sgirish case ETHERTYPE_IP: 52944961713Sgirish if (mblk_len > eth_hdr_size + sizeof (uint8_t)) { 53044961713Sgirish ip_buf = nmp->b_rptr + eth_hdr_size; 53144961713Sgirish mblk_len -= eth_hdr_size; 53244961713Sgirish iph_len = ((*ip_buf) & 0x0f); 53344961713Sgirish if (mblk_len > (iph_len + sizeof (uint32_t))) { 53444961713Sgirish ip_buf = nmp->b_rptr; 53544961713Sgirish ip_buf += eth_hdr_size; 53644961713Sgirish } else { 53744961713Sgirish ip_buf = NULL; 53844961713Sgirish } 53944961713Sgirish 54044961713Sgirish } 54144961713Sgirish if (ip_buf == NULL) { 54244961713Sgirish hdrs_size = 0; 54344961713Sgirish ((p_ether_header_t)hdrs_buf)->ether_type = 0; 54444961713Sgirish while ((nmp) && (hdrs_size < 54544961713Sgirish sizeof (hdrs_buf))) { 54644961713Sgirish mblk_len = (size_t)nmp->b_wptr - 54744961713Sgirish (size_t)nmp->b_rptr; 54844961713Sgirish if (mblk_len >= 54944961713Sgirish (sizeof (hdrs_buf) - hdrs_size)) 55044961713Sgirish mblk_len = sizeof (hdrs_buf) - 55144961713Sgirish hdrs_size; 55244961713Sgirish bcopy(nmp->b_rptr, 55344961713Sgirish &hdrs_buf[hdrs_size], mblk_len); 55444961713Sgirish hdrs_size += mblk_len; 55544961713Sgirish nmp = nmp->b_cont; 55644961713Sgirish } 55744961713Sgirish ip_buf = hdrs_buf; 55844961713Sgirish ip_buf += eth_hdr_size; 55944961713Sgirish iph_len = ((*ip_buf) & 0x0f); 56044961713Sgirish } 56144961713Sgirish 56244961713Sgirish ipproto = ip_buf[9]; 56344961713Sgirish 56444961713Sgirish tmp = (uint64_t)iph_len; 56544961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT); 56644961713Sgirish tmp = (uint64_t)(eth_hdr_size >> 1); 56744961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT); 56844961713Sgirish 56944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 " 57044961713Sgirish " iph_len %d l3start %d eth_hdr_size %d proto 0x%x" 57144961713Sgirish "tmp 0x%x", 57244961713Sgirish iph_len, hdrp->bits.hdw.l3start, eth_hdr_size, 57344961713Sgirish ipproto, tmp)); 57444961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP " 57544961713Sgirish "value 0x%llx", hdrp->value)); 57644961713Sgirish 57744961713Sgirish break; 57844961713Sgirish 57944961713Sgirish case ETHERTYPE_IPV6: 58044961713Sgirish hdrs_size = 0; 58144961713Sgirish ((p_ether_header_t)hdrs_buf)->ether_type = 0; 58244961713Sgirish while ((nmp) && (hdrs_size < 58344961713Sgirish sizeof (hdrs_buf))) { 58444961713Sgirish mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr; 58544961713Sgirish if (mblk_len >= 58644961713Sgirish (sizeof (hdrs_buf) - hdrs_size)) 58744961713Sgirish mblk_len = sizeof (hdrs_buf) - 58844961713Sgirish hdrs_size; 58944961713Sgirish bcopy(nmp->b_rptr, 59044961713Sgirish &hdrs_buf[hdrs_size], mblk_len); 59144961713Sgirish hdrs_size += mblk_len; 59244961713Sgirish nmp = nmp->b_cont; 59344961713Sgirish } 59444961713Sgirish ip_buf = hdrs_buf; 59544961713Sgirish ip_buf += eth_hdr_size; 59644961713Sgirish 59744961713Sgirish tmp = 1ull; 59844961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT); 59944961713Sgirish 60044961713Sgirish tmp = (eth_hdr_size >> 1); 60144961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT); 60244961713Sgirish 60344961713Sgirish /* byte 6 is the next header protocol */ 60444961713Sgirish ipproto = ip_buf[6]; 60544961713Sgirish 60644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 " 60744961713Sgirish " iph_len %d l3start %d eth_hdr_size %d proto 0x%x", 60844961713Sgirish iph_len, hdrp->bits.hdw.l3start, eth_hdr_size, 60944961713Sgirish ipproto)); 61044961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 " 61144961713Sgirish "value 0x%llx", hdrp->value)); 61244961713Sgirish 61344961713Sgirish break; 61444961713Sgirish 61544961713Sgirish default: 61644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP")); 61744961713Sgirish goto fill_tx_header_done; 61844961713Sgirish } 61944961713Sgirish 62044961713Sgirish switch (ipproto) { 62144961713Sgirish case IPPROTO_TCP: 62244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 623b4d05839Sml "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum)); 62444961713Sgirish if (l4_cksum) { 625b4d05839Sml hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP; 626b4d05839Sml hdrp->value |= 627b4d05839Sml (((uint64_t)(start_offset >> 1)) << 628b4d05839Sml TX_PKT_HEADER_L4START_SHIFT); 629b4d05839Sml hdrp->value |= 630b4d05839Sml (((uint64_t)(stuff_offset >> 1)) << 631b4d05839Sml TX_PKT_HEADER_L4STUFF_SHIFT); 632b4d05839Sml 63344961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 634b4d05839Sml "==> nxge_tx_pkt_hdr_init: TCP CKSUM " 635b4d05839Sml "value 0x%llx", hdrp->value)); 63644961713Sgirish } 63744961713Sgirish 63844961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP " 639b4d05839Sml "value 0x%llx", hdrp->value)); 64044961713Sgirish break; 64144961713Sgirish 64244961713Sgirish case IPPROTO_UDP: 64344961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP")); 64444961713Sgirish if (l4_cksum) { 645b4d05839Sml if (!nxge_cksum_offload) { 646b4d05839Sml uint16_t *up; 647b4d05839Sml uint16_t cksum; 648b4d05839Sml t_uscalar_t stuff_len; 649b4d05839Sml 650b4d05839Sml /* 651b4d05839Sml * The checksum field has the 652b4d05839Sml * partial checksum. 653b4d05839Sml * IP_CSUM() macro calls ip_cksum() which 654b4d05839Sml * can add in the partial checksum. 655b4d05839Sml */ 656b4d05839Sml cksum = IP_CSUM(mp, start_offset, 0); 657b4d05839Sml stuff_len = stuff_offset; 658b4d05839Sml nmp = mp; 659b4d05839Sml mblk_len = MBLKL(nmp); 660b4d05839Sml while ((nmp != NULL) && 661b4d05839Sml (mblk_len < stuff_len)) { 662b4d05839Sml stuff_len -= mblk_len; 663b4d05839Sml nmp = nmp->b_cont; 664b4d05839Sml } 665b4d05839Sml ASSERT(nmp); 666b4d05839Sml up = (uint16_t *)(nmp->b_rptr + stuff_len); 667b4d05839Sml 668b4d05839Sml *up = cksum; 669b4d05839Sml hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP; 670b4d05839Sml NXGE_DEBUG_MSG((NULL, TX_CTL, 671b4d05839Sml "==> nxge_tx_pkt_hdr_init: UDP offset %d " 672b4d05839Sml "use sw cksum " 673b4d05839Sml "write to $%p cksum 0x%x content up 0x%x", 674b4d05839Sml stuff_len, 675b4d05839Sml up, 676b4d05839Sml cksum, 677b4d05839Sml *up)); 678b4d05839Sml } else { 679b4d05839Sml /* Hardware will compute the full checksum */ 680b4d05839Sml hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP; 681b4d05839Sml hdrp->value |= 682b4d05839Sml (((uint64_t)(start_offset >> 1)) << 683b4d05839Sml TX_PKT_HEADER_L4START_SHIFT); 684b4d05839Sml hdrp->value |= 685b4d05839Sml (((uint64_t)(stuff_offset >> 1)) << 686b4d05839Sml TX_PKT_HEADER_L4STUFF_SHIFT); 687b4d05839Sml 688b4d05839Sml NXGE_DEBUG_MSG((NULL, TX_CTL, 689b4d05839Sml "==> nxge_tx_pkt_hdr_init: UDP offset %d " 690b4d05839Sml " use partial checksum " 691b4d05839Sml "cksum 0x%x ", 692b4d05839Sml "value 0x%llx", 693b4d05839Sml stuff_offset, 694b4d05839Sml IP_CSUM(mp, start_offset, 0), 695b4d05839Sml hdrp->value)); 696b4d05839Sml } 69744961713Sgirish } 698b4d05839Sml 69944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 70044961713Sgirish "==> nxge_tx_pkt_hdr_init: UDP" 70144961713Sgirish "value 0x%llx", hdrp->value)); 70244961713Sgirish break; 70344961713Sgirish 70444961713Sgirish default: 70544961713Sgirish goto fill_tx_header_done; 70644961713Sgirish } 70744961713Sgirish 70844961713Sgirish fill_tx_header_done: 70944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 71044961713Sgirish "==> nxge_fill_tx_hdr: pkt_len %d " 71144961713Sgirish "npads %d value 0x%llx", pkt_len, npads, hdrp->value)); 71244961713Sgirish 71344961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr")); 71444961713Sgirish } 71544961713Sgirish 71644961713Sgirish /*ARGSUSED*/ 71744961713Sgirish p_mblk_t 71844961713Sgirish nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads) 71944961713Sgirish { 72044961713Sgirish p_mblk_t newmp = NULL; 72144961713Sgirish 72244961713Sgirish if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) { 72344961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 72444961713Sgirish "<== nxge_tx_pkt_header_reserve: allocb failed")); 72544961713Sgirish return (NULL); 72644961713Sgirish } 72744961713Sgirish 72844961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 72944961713Sgirish "==> nxge_tx_pkt_header_reserve: get new mp")); 73044961713Sgirish DB_TYPE(newmp) = M_DATA; 73144961713Sgirish newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp); 73244961713Sgirish linkb(newmp, mp); 73344961713Sgirish newmp->b_rptr -= TX_PKT_HEADER_SIZE; 73444961713Sgirish 73544961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: " 73644961713Sgirish "b_rptr $%p b_wptr $%p", 73744961713Sgirish newmp->b_rptr, newmp->b_wptr)); 73844961713Sgirish 73944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 74044961713Sgirish "<== nxge_tx_pkt_header_reserve: use new mp")); 74144961713Sgirish 74244961713Sgirish return (newmp); 74344961713Sgirish } 74444961713Sgirish 74544961713Sgirish int 74644961713Sgirish nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p) 74744961713Sgirish { 74844961713Sgirish uint_t nmblks; 74944961713Sgirish ssize_t len; 75044961713Sgirish uint_t pkt_len; 75144961713Sgirish p_mblk_t nmp, bmp, tmp; 75244961713Sgirish uint8_t *b_wptr; 75344961713Sgirish 75444961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 75544961713Sgirish "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p " 75644961713Sgirish "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp))); 75744961713Sgirish 75844961713Sgirish nmp = mp; 75944961713Sgirish bmp = mp; 76044961713Sgirish nmblks = 0; 76144961713Sgirish pkt_len = 0; 76244961713Sgirish *tot_xfer_len_p = 0; 76344961713Sgirish 76444961713Sgirish while (nmp) { 76544961713Sgirish len = MBLKL(nmp); 76644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: " 76744961713Sgirish "len %d pkt_len %d nmblks %d tot_xfer_len %d", 76844961713Sgirish len, pkt_len, nmblks, 76944961713Sgirish *tot_xfer_len_p)); 77044961713Sgirish 77144961713Sgirish if (len <= 0) { 77244961713Sgirish bmp = nmp; 77344961713Sgirish nmp = nmp->b_cont; 77444961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 77544961713Sgirish "==> nxge_tx_pkt_nmblocks: " 77644961713Sgirish "len (0) pkt_len %d nmblks %d", 77744961713Sgirish pkt_len, nmblks)); 77844961713Sgirish continue; 77944961713Sgirish } 78044961713Sgirish 78144961713Sgirish *tot_xfer_len_p += len; 78244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: " 78344961713Sgirish "len %d pkt_len %d nmblks %d tot_xfer_len %d", 78444961713Sgirish len, pkt_len, nmblks, 78544961713Sgirish *tot_xfer_len_p)); 78644961713Sgirish 78744961713Sgirish if (len < nxge_bcopy_thresh) { 78844961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 78944961713Sgirish "==> nxge_tx_pkt_nmblocks: " 79044961713Sgirish "len %d (< thresh) pkt_len %d nmblks %d", 79144961713Sgirish len, pkt_len, nmblks)); 79244961713Sgirish if (pkt_len == 0) 79344961713Sgirish nmblks++; 79444961713Sgirish pkt_len += len; 79544961713Sgirish if (pkt_len >= nxge_bcopy_thresh) { 79644961713Sgirish pkt_len = 0; 79744961713Sgirish len = 0; 79844961713Sgirish nmp = bmp; 79944961713Sgirish } 80044961713Sgirish } else { 80144961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 80244961713Sgirish "==> nxge_tx_pkt_nmblocks: " 80344961713Sgirish "len %d (> thresh) pkt_len %d nmblks %d", 80444961713Sgirish len, pkt_len, nmblks)); 80544961713Sgirish pkt_len = 0; 80644961713Sgirish nmblks++; 80744961713Sgirish /* 80844961713Sgirish * Hardware limits the transfer length to 4K. 80944961713Sgirish * If len is more than 4K, we need to break 81044961713Sgirish * it up to at most 2 more blocks. 81144961713Sgirish */ 81244961713Sgirish if (len > TX_MAX_TRANSFER_LENGTH) { 81344961713Sgirish uint32_t nsegs; 81444961713Sgirish 815678453a8Sspeer nsegs = 1; 81644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 81744961713Sgirish "==> nxge_tx_pkt_nmblocks: " 81844961713Sgirish "len %d pkt_len %d nmblks %d nsegs %d", 81944961713Sgirish len, pkt_len, nmblks, nsegs)); 82044961713Sgirish if (len % (TX_MAX_TRANSFER_LENGTH * 2)) { 82144961713Sgirish ++nsegs; 82244961713Sgirish } 82344961713Sgirish do { 82444961713Sgirish b_wptr = nmp->b_rptr + 82544961713Sgirish TX_MAX_TRANSFER_LENGTH; 82644961713Sgirish nmp->b_wptr = b_wptr; 82744961713Sgirish if ((tmp = dupb(nmp)) == NULL) { 82844961713Sgirish return (0); 82944961713Sgirish } 83044961713Sgirish tmp->b_rptr = b_wptr; 83144961713Sgirish tmp->b_wptr = nmp->b_wptr; 83244961713Sgirish tmp->b_cont = nmp->b_cont; 83344961713Sgirish nmp->b_cont = tmp; 83444961713Sgirish nmblks++; 83544961713Sgirish if (--nsegs) { 83644961713Sgirish nmp = tmp; 83744961713Sgirish } 83844961713Sgirish } while (nsegs); 83944961713Sgirish nmp = tmp; 84044961713Sgirish } 84144961713Sgirish } 84244961713Sgirish 84344961713Sgirish /* 84444961713Sgirish * Hardware limits the transmit gather pointers to 15. 84544961713Sgirish */ 84644961713Sgirish if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) > 84744961713Sgirish TX_MAX_GATHER_POINTERS) { 84844961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 84944961713Sgirish "==> nxge_tx_pkt_nmblocks: pull msg - " 85044961713Sgirish "len %d pkt_len %d nmblks %d", 85144961713Sgirish len, pkt_len, nmblks)); 85244961713Sgirish /* Pull all message blocks from b_cont */ 85344961713Sgirish if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) { 85444961713Sgirish return (0); 85544961713Sgirish } 85644961713Sgirish freemsg(nmp->b_cont); 85744961713Sgirish nmp->b_cont = tmp; 85844961713Sgirish pkt_len = 0; 85944961713Sgirish } 86044961713Sgirish bmp = nmp; 86144961713Sgirish nmp = nmp->b_cont; 86244961713Sgirish } 86344961713Sgirish 86444961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 86544961713Sgirish "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p " 86644961713Sgirish "nmblks %d len %d tot_xfer_len %d", 86744961713Sgirish mp->b_rptr, mp->b_wptr, nmblks, 86844961713Sgirish MBLKL(mp), *tot_xfer_len_p)); 86944961713Sgirish 87044961713Sgirish return (nmblks); 87144961713Sgirish } 87244961713Sgirish 87344961713Sgirish boolean_t 87444961713Sgirish nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks) 87544961713Sgirish { 87644961713Sgirish boolean_t status = B_TRUE; 87744961713Sgirish p_nxge_dma_common_t tx_desc_dma_p; 87844961713Sgirish nxge_dma_common_t desc_area; 87944961713Sgirish p_tx_desc_t tx_desc_ring_vp; 88044961713Sgirish p_tx_desc_t tx_desc_p; 88144961713Sgirish p_tx_desc_t tx_desc_pp; 88244961713Sgirish tx_desc_t r_tx_desc; 88344961713Sgirish p_tx_msg_t tx_msg_ring; 88444961713Sgirish p_tx_msg_t tx_msg_p; 88544961713Sgirish npi_handle_t handle; 88644961713Sgirish tx_ring_hdl_t tx_head; 88744961713Sgirish uint32_t pkt_len; 88844961713Sgirish uint_t tx_rd_index; 88944961713Sgirish uint16_t head_index, tail_index; 89044961713Sgirish uint8_t tdc; 89144961713Sgirish boolean_t head_wrap, tail_wrap; 89244961713Sgirish p_nxge_tx_ring_stats_t tdc_stats; 89344961713Sgirish int rc; 89444961713Sgirish 89544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim")); 89644961713Sgirish 89744961713Sgirish status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) && 89844961713Sgirish (nmblks != 0)); 89944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 90044961713Sgirish "==> nxge_txdma_reclaim: pending %d reclaim %d nmblks %d", 90144961713Sgirish tx_ring_p->descs_pending, nxge_reclaim_pending, 90244961713Sgirish nmblks)); 90344961713Sgirish if (!status) { 90444961713Sgirish tx_desc_dma_p = &tx_ring_p->tdc_desc; 90544961713Sgirish desc_area = tx_ring_p->tdc_desc; 90644961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 90744961713Sgirish tx_desc_ring_vp = tx_desc_dma_p->kaddrp; 90844961713Sgirish tx_desc_ring_vp = 90944961713Sgirish (p_tx_desc_t)DMA_COMMON_VPTR(desc_area); 91044961713Sgirish tx_rd_index = tx_ring_p->rd_index; 91144961713Sgirish tx_desc_p = &tx_desc_ring_vp[tx_rd_index]; 91244961713Sgirish tx_msg_ring = tx_ring_p->tx_msg_ring; 91344961713Sgirish tx_msg_p = &tx_msg_ring[tx_rd_index]; 91444961713Sgirish tdc = tx_ring_p->tdc; 91544961713Sgirish tdc_stats = tx_ring_p->tdc_stats; 91644961713Sgirish if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) { 91744961713Sgirish tdc_stats->tx_max_pend = tx_ring_p->descs_pending; 91844961713Sgirish } 91944961713Sgirish 92044961713Sgirish tail_index = tx_ring_p->wr_index; 92144961713Sgirish tail_wrap = tx_ring_p->wr_index_wrap; 92244961713Sgirish 92344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 92444961713Sgirish "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d " 92544961713Sgirish "tail_index %d tail_wrap %d " 92644961713Sgirish "tx_desc_p $%p ($%p) ", 92744961713Sgirish tdc, tx_rd_index, tail_index, tail_wrap, 92844961713Sgirish tx_desc_p, (*(uint64_t *)tx_desc_p))); 92944961713Sgirish /* 93044961713Sgirish * Read the hardware maintained transmit head 93144961713Sgirish * and wrap around bit. 93244961713Sgirish */ 93344961713Sgirish TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value); 93444961713Sgirish head_index = tx_head.bits.ldw.head; 93544961713Sgirish head_wrap = tx_head.bits.ldw.wrap; 93644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 93744961713Sgirish "==> nxge_txdma_reclaim: " 93844961713Sgirish "tx_rd_index %d tail %d tail_wrap %d " 93944961713Sgirish "head %d wrap %d", 94044961713Sgirish tx_rd_index, tail_index, tail_wrap, 94144961713Sgirish head_index, head_wrap)); 94244961713Sgirish 94344961713Sgirish if (head_index == tail_index) { 94444961713Sgirish if (TXDMA_RING_EMPTY(head_index, head_wrap, 94544961713Sgirish tail_index, tail_wrap) && 94644961713Sgirish (head_index == tx_rd_index)) { 94744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 94844961713Sgirish "==> nxge_txdma_reclaim: EMPTY")); 94944961713Sgirish return (B_TRUE); 95044961713Sgirish } 95144961713Sgirish 95244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 95344961713Sgirish "==> nxge_txdma_reclaim: Checking " 95444961713Sgirish "if ring full")); 95544961713Sgirish if (TXDMA_RING_FULL(head_index, head_wrap, tail_index, 95644961713Sgirish tail_wrap)) { 95744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 95844961713Sgirish "==> nxge_txdma_reclaim: full")); 95944961713Sgirish return (B_FALSE); 96044961713Sgirish } 96144961713Sgirish } 96244961713Sgirish 96344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 96444961713Sgirish "==> nxge_txdma_reclaim: tx_rd_index and head_index")); 96544961713Sgirish 96644961713Sgirish tx_desc_pp = &r_tx_desc; 96744961713Sgirish while ((tx_rd_index != head_index) && 96844961713Sgirish (tx_ring_p->descs_pending != 0)) { 96944961713Sgirish 97044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 97144961713Sgirish "==> nxge_txdma_reclaim: Checking if pending")); 97244961713Sgirish 97344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 97444961713Sgirish "==> nxge_txdma_reclaim: " 97544961713Sgirish "descs_pending %d ", 97644961713Sgirish tx_ring_p->descs_pending)); 97744961713Sgirish 97844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 97944961713Sgirish "==> nxge_txdma_reclaim: " 98044961713Sgirish "(tx_rd_index %d head_index %d " 98144961713Sgirish "(tx_desc_p $%p)", 98244961713Sgirish tx_rd_index, head_index, 98344961713Sgirish tx_desc_p)); 98444961713Sgirish 98544961713Sgirish tx_desc_pp->value = tx_desc_p->value; 98644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 98744961713Sgirish "==> nxge_txdma_reclaim: " 98844961713Sgirish "(tx_rd_index %d head_index %d " 98944961713Sgirish "tx_desc_p $%p (desc value 0x%llx) ", 99044961713Sgirish tx_rd_index, head_index, 99144961713Sgirish tx_desc_pp, (*(uint64_t *)tx_desc_pp))); 99244961713Sgirish 99344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 99444961713Sgirish "==> nxge_txdma_reclaim: dump desc:")); 99544961713Sgirish 99644961713Sgirish pkt_len = tx_desc_pp->bits.hdw.tr_len; 99744961713Sgirish tdc_stats->obytes += pkt_len; 99844961713Sgirish tdc_stats->opackets += tx_desc_pp->bits.hdw.sop; 99944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 100044961713Sgirish "==> nxge_txdma_reclaim: pkt_len %d " 100144961713Sgirish "tdc channel %d opackets %d", 100244961713Sgirish pkt_len, 100344961713Sgirish tdc, 100444961713Sgirish tdc_stats->opackets)); 100544961713Sgirish 100644961713Sgirish if (tx_msg_p->flags.dma_type == USE_DVMA) { 100744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 100844961713Sgirish "tx_desc_p = $%p " 100944961713Sgirish "tx_desc_pp = $%p " 101044961713Sgirish "index = %d", 101144961713Sgirish tx_desc_p, 101244961713Sgirish tx_desc_pp, 101344961713Sgirish tx_ring_p->rd_index)); 101444961713Sgirish (void) dvma_unload(tx_msg_p->dvma_handle, 101544961713Sgirish 0, -1); 101644961713Sgirish tx_msg_p->dvma_handle = NULL; 101744961713Sgirish if (tx_ring_p->dvma_wr_index == 101844961713Sgirish tx_ring_p->dvma_wrap_mask) { 101944961713Sgirish tx_ring_p->dvma_wr_index = 0; 102044961713Sgirish } else { 102144961713Sgirish tx_ring_p->dvma_wr_index++; 102244961713Sgirish } 102344961713Sgirish tx_ring_p->dvma_pending--; 102444961713Sgirish } else if (tx_msg_p->flags.dma_type == 102544961713Sgirish USE_DMA) { 102644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 102744961713Sgirish "==> nxge_txdma_reclaim: " 102844961713Sgirish "USE DMA")); 102944961713Sgirish if (rc = ddi_dma_unbind_handle 103044961713Sgirish (tx_msg_p->dma_handle)) { 103144961713Sgirish cmn_err(CE_WARN, "!nxge_reclaim: " 103244961713Sgirish "ddi_dma_unbind_handle " 103344961713Sgirish "failed. status %d", rc); 103444961713Sgirish } 103544961713Sgirish } 103644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 103744961713Sgirish "==> nxge_txdma_reclaim: count packets")); 103844961713Sgirish /* 103944961713Sgirish * count a chained packet only once. 104044961713Sgirish */ 104144961713Sgirish if (tx_msg_p->tx_message != NULL) { 104244961713Sgirish freemsg(tx_msg_p->tx_message); 104344961713Sgirish tx_msg_p->tx_message = NULL; 104444961713Sgirish } 104544961713Sgirish 104644961713Sgirish tx_msg_p->flags.dma_type = USE_NONE; 104744961713Sgirish tx_rd_index = tx_ring_p->rd_index; 104844961713Sgirish tx_rd_index = (tx_rd_index + 1) & 104944961713Sgirish tx_ring_p->tx_wrap_mask; 105044961713Sgirish tx_ring_p->rd_index = tx_rd_index; 105144961713Sgirish tx_ring_p->descs_pending--; 105244961713Sgirish tx_desc_p = &tx_desc_ring_vp[tx_rd_index]; 105344961713Sgirish tx_msg_p = &tx_msg_ring[tx_rd_index]; 105444961713Sgirish } 105544961713Sgirish 105644961713Sgirish status = (nmblks <= (tx_ring_p->tx_ring_size - 105744961713Sgirish tx_ring_p->descs_pending - 105844961713Sgirish TX_FULL_MARK)); 105944961713Sgirish if (status) { 106044961713Sgirish cas32((uint32_t *)&tx_ring_p->queueing, 1, 0); 106144961713Sgirish } 106244961713Sgirish } else { 106344961713Sgirish status = (nmblks <= 106444961713Sgirish (tx_ring_p->tx_ring_size - 106544961713Sgirish tx_ring_p->descs_pending - 106644961713Sgirish TX_FULL_MARK)); 106744961713Sgirish } 106844961713Sgirish 106944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 107044961713Sgirish "<== nxge_txdma_reclaim status = 0x%08x", status)); 107144961713Sgirish 107244961713Sgirish return (status); 107344961713Sgirish } 107444961713Sgirish 1075678453a8Sspeer /* 1076678453a8Sspeer * nxge_tx_intr 1077678453a8Sspeer * 1078678453a8Sspeer * Process a TDC interrupt 1079678453a8Sspeer * 1080678453a8Sspeer * Arguments: 1081678453a8Sspeer * arg1 A Logical Device state Vector (LSV) data structure. 1082678453a8Sspeer * arg2 nxge_t * 1083678453a8Sspeer * 1084678453a8Sspeer * Notes: 1085678453a8Sspeer * 1086678453a8Sspeer * NPI/NXGE function calls: 1087678453a8Sspeer * npi_txdma_control_status() 1088678453a8Sspeer * npi_intr_ldg_mgmt_set() 1089678453a8Sspeer * 1090678453a8Sspeer * nxge_tx_err_evnts() 1091678453a8Sspeer * nxge_txdma_reclaim() 1092678453a8Sspeer * 1093678453a8Sspeer * Registers accessed: 1094678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1095678453a8Sspeer * PIO_LDSV 1096678453a8Sspeer * 1097678453a8Sspeer * Context: 1098678453a8Sspeer * Any domain 1099678453a8Sspeer */ 110044961713Sgirish uint_t 110144961713Sgirish nxge_tx_intr(void *arg1, void *arg2) 110244961713Sgirish { 110344961713Sgirish p_nxge_ldv_t ldvp = (p_nxge_ldv_t)arg1; 110444961713Sgirish p_nxge_t nxgep = (p_nxge_t)arg2; 110544961713Sgirish p_nxge_ldg_t ldgp; 110644961713Sgirish uint8_t channel; 110744961713Sgirish uint32_t vindex; 110844961713Sgirish npi_handle_t handle; 110944961713Sgirish tx_cs_t cs; 111044961713Sgirish p_tx_ring_t *tx_rings; 111144961713Sgirish p_tx_ring_t tx_ring_p; 111244961713Sgirish npi_status_t rs = NPI_SUCCESS; 111344961713Sgirish uint_t serviced = DDI_INTR_UNCLAIMED; 111444961713Sgirish nxge_status_t status = NXGE_OK; 111544961713Sgirish 111644961713Sgirish if (ldvp == NULL) { 111744961713Sgirish NXGE_DEBUG_MSG((NULL, INT_CTL, 111844961713Sgirish "<== nxge_tx_intr: nxgep $%p ldvp $%p", 111944961713Sgirish nxgep, ldvp)); 112044961713Sgirish return (DDI_INTR_UNCLAIMED); 112144961713Sgirish } 112244961713Sgirish 112344961713Sgirish if (arg2 == NULL || (void *)ldvp->nxgep != arg2) { 112444961713Sgirish nxgep = ldvp->nxgep; 112544961713Sgirish } 112644961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 112744961713Sgirish "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p", 112844961713Sgirish nxgep, ldvp)); 112922c0d73aSspeer 113022c0d73aSspeer if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) || 113122c0d73aSspeer (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) { 113222c0d73aSspeer NXGE_DEBUG_MSG((nxgep, INT_CTL, 113322c0d73aSspeer "<== nxge_tx_intr: interface not started or intialized")); 113422c0d73aSspeer return (DDI_INTR_CLAIMED); 113522c0d73aSspeer } 113622c0d73aSspeer 113744961713Sgirish /* 113844961713Sgirish * This interrupt handler is for a specific 113944961713Sgirish * transmit dma channel. 114044961713Sgirish */ 114144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 114244961713Sgirish /* Get the control and status for this channel. */ 114344961713Sgirish channel = ldvp->channel; 114444961713Sgirish ldgp = ldvp->ldgp; 114544961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 114644961713Sgirish "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p " 114744961713Sgirish "channel %d", 114844961713Sgirish nxgep, ldvp, channel)); 114944961713Sgirish 115044961713Sgirish rs = npi_txdma_control_status(handle, OP_GET, channel, &cs); 115144961713Sgirish vindex = ldvp->vdma_index; 115244961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 115344961713Sgirish "==> nxge_tx_intr:channel %d ring index %d status 0x%08x", 115444961713Sgirish channel, vindex, rs)); 115544961713Sgirish if (!rs && cs.bits.ldw.mk) { 115644961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 115744961713Sgirish "==> nxge_tx_intr:channel %d ring index %d " 115844961713Sgirish "status 0x%08x (mk bit set)", 115944961713Sgirish channel, vindex, rs)); 116044961713Sgirish tx_rings = nxgep->tx_rings->rings; 116144961713Sgirish tx_ring_p = tx_rings[vindex]; 116244961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 116344961713Sgirish "==> nxge_tx_intr:channel %d ring index %d " 116444961713Sgirish "status 0x%08x (mk bit set, calling reclaim)", 116544961713Sgirish channel, vindex, rs)); 116644961713Sgirish 116744961713Sgirish MUTEX_ENTER(&tx_ring_p->lock); 116844961713Sgirish (void) nxge_txdma_reclaim(nxgep, tx_rings[vindex], 0); 116944961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 117044961713Sgirish mac_tx_update(nxgep->mach); 117144961713Sgirish } 117244961713Sgirish 117344961713Sgirish /* 117444961713Sgirish * Process other transmit control and status. 117544961713Sgirish * Check the ldv state. 117644961713Sgirish */ 117744961713Sgirish status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs); 117844961713Sgirish /* 117944961713Sgirish * Rearm this logical group if this is a single device 118044961713Sgirish * group. 118144961713Sgirish */ 118244961713Sgirish if (ldgp->nldvs == 1) { 118344961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 118444961713Sgirish "==> nxge_tx_intr: rearm")); 118544961713Sgirish if (status == NXGE_OK) { 1186678453a8Sspeer if (isLDOMguest(nxgep)) { 1187678453a8Sspeer nxge_hio_ldgimgn(nxgep, ldgp); 1188678453a8Sspeer } else { 1189678453a8Sspeer (void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg, 1190678453a8Sspeer B_TRUE, ldgp->ldg_timer); 1191678453a8Sspeer } 119244961713Sgirish } 119344961713Sgirish } 119444961713Sgirish 119544961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr")); 119644961713Sgirish serviced = DDI_INTR_CLAIMED; 119744961713Sgirish return (serviced); 119844961713Sgirish } 119944961713Sgirish 120044961713Sgirish void 1201678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep) /* Dead */ 120244961713Sgirish { 120344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop")); 120444961713Sgirish 120544961713Sgirish (void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP); 120644961713Sgirish 120744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop")); 120844961713Sgirish } 120944961713Sgirish 121044961713Sgirish void 1211678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */ 121244961713Sgirish { 121344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start")); 121444961713Sgirish 121544961713Sgirish (void) nxge_txdma_stop(nxgep); 121644961713Sgirish 121744961713Sgirish (void) nxge_fixup_txdma_rings(nxgep); 121844961713Sgirish (void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START); 121944961713Sgirish (void) nxge_tx_mac_enable(nxgep); 122044961713Sgirish (void) nxge_txdma_hw_kick(nxgep); 122144961713Sgirish 122244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start")); 122344961713Sgirish } 122444961713Sgirish 1225678453a8Sspeer npi_status_t 1226678453a8Sspeer nxge_txdma_channel_disable( 1227678453a8Sspeer nxge_t *nxge, 1228678453a8Sspeer int channel) 1229678453a8Sspeer { 1230678453a8Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge); 1231678453a8Sspeer npi_status_t rs; 1232678453a8Sspeer tdmc_intr_dbg_t intr_dbg; 1233678453a8Sspeer 1234678453a8Sspeer /* 1235678453a8Sspeer * Stop the dma channel and wait for the stop-done. 1236678453a8Sspeer * If the stop-done bit is not present, then force 1237678453a8Sspeer * an error so TXC will stop. 1238678453a8Sspeer * All channels bound to this port need to be stopped 1239678453a8Sspeer * and reset after injecting an interrupt error. 1240678453a8Sspeer */ 1241678453a8Sspeer rs = npi_txdma_channel_disable(handle, channel); 1242678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 1243678453a8Sspeer "==> nxge_txdma_channel_disable(%d) " 1244678453a8Sspeer "rs 0x%x", channel, rs)); 1245678453a8Sspeer if (rs != NPI_SUCCESS) { 1246678453a8Sspeer /* Inject any error */ 1247678453a8Sspeer intr_dbg.value = 0; 1248678453a8Sspeer intr_dbg.bits.ldw.nack_pref = 1; 1249678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 1250678453a8Sspeer "==> nxge_txdma_hw_mode: " 1251678453a8Sspeer "channel %d (stop failed 0x%x) " 1252678453a8Sspeer "(inject err)", rs, channel)); 1253678453a8Sspeer (void) npi_txdma_inj_int_error_set( 1254678453a8Sspeer handle, channel, &intr_dbg); 1255678453a8Sspeer rs = npi_txdma_channel_disable(handle, channel); 1256678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 1257678453a8Sspeer "==> nxge_txdma_hw_mode: " 1258678453a8Sspeer "channel %d (stop again 0x%x) " 1259678453a8Sspeer "(after inject err)", 1260678453a8Sspeer rs, channel)); 1261678453a8Sspeer } 1262678453a8Sspeer 1263678453a8Sspeer return (rs); 1264678453a8Sspeer } 1265678453a8Sspeer 1266678453a8Sspeer /* 1267678453a8Sspeer * nxge_txdma_hw_mode 1268678453a8Sspeer * 1269678453a8Sspeer * Toggle all TDCs on (enable) or off (disable). 1270678453a8Sspeer * 1271678453a8Sspeer * Arguments: 1272678453a8Sspeer * nxgep 1273678453a8Sspeer * enable Enable or disable a TDC. 1274678453a8Sspeer * 1275678453a8Sspeer * Notes: 1276678453a8Sspeer * 1277678453a8Sspeer * NPI/NXGE function calls: 1278678453a8Sspeer * npi_txdma_channel_enable(TX_CS) 1279678453a8Sspeer * npi_txdma_channel_disable(TX_CS) 1280678453a8Sspeer * npi_txdma_inj_int_error_set(TDMC_INTR_DBG) 1281678453a8Sspeer * 1282678453a8Sspeer * Registers accessed: 1283678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1284678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1285678453a8Sspeer * 1286678453a8Sspeer * Context: 1287678453a8Sspeer * Any domain 1288678453a8Sspeer */ 128944961713Sgirish nxge_status_t 129044961713Sgirish nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable) 129144961713Sgirish { 1292678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1293678453a8Sspeer 1294678453a8Sspeer npi_handle_t handle; 1295678453a8Sspeer nxge_status_t status; 1296678453a8Sspeer npi_status_t rs; 1297678453a8Sspeer int tdc; 129844961713Sgirish 129944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 130044961713Sgirish "==> nxge_txdma_hw_mode: enable mode %d", enable)); 130144961713Sgirish 130244961713Sgirish if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { 130344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 130444961713Sgirish "<== nxge_txdma_mode: not initialized")); 130544961713Sgirish return (NXGE_ERROR); 130644961713Sgirish } 130744961713Sgirish 1308678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 130944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1310678453a8Sspeer "<== nxge_txdma_hw_mode: NULL ring pointer(s)")); 131144961713Sgirish return (NXGE_ERROR); 131244961713Sgirish } 131344961713Sgirish 1314678453a8Sspeer /* Enable or disable all of the TDCs owned by us. */ 131544961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 1316678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1317678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1318678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1319678453a8Sspeer if (ring) { 1320678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1321678453a8Sspeer "==> nxge_txdma_hw_mode: channel %d", tdc)); 1322678453a8Sspeer if (enable) { 1323678453a8Sspeer rs = npi_txdma_channel_enable 1324678453a8Sspeer (handle, tdc); 132544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1326678453a8Sspeer "==> nxge_txdma_hw_mode: " 1327678453a8Sspeer "channel %d (enable) rs 0x%x", 1328678453a8Sspeer tdc, rs)); 1329678453a8Sspeer } else { 1330678453a8Sspeer rs = nxge_txdma_channel_disable 1331678453a8Sspeer (nxgep, tdc); 133244961713Sgirish } 133344961713Sgirish } 133444961713Sgirish } 133544961713Sgirish } 133644961713Sgirish 133744961713Sgirish status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 133844961713Sgirish 133944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 134044961713Sgirish "<== nxge_txdma_hw_mode: status 0x%x", status)); 134144961713Sgirish 134244961713Sgirish return (status); 134344961713Sgirish } 134444961713Sgirish 134544961713Sgirish void 134644961713Sgirish nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel) 134744961713Sgirish { 134844961713Sgirish npi_handle_t handle; 134944961713Sgirish 135044961713Sgirish NXGE_DEBUG_MSG((nxgep, DMA_CTL, 135144961713Sgirish "==> nxge_txdma_enable_channel: channel %d", channel)); 135244961713Sgirish 135344961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 135444961713Sgirish /* enable the transmit dma channels */ 135544961713Sgirish (void) npi_txdma_channel_enable(handle, channel); 135644961713Sgirish 135744961713Sgirish NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel")); 135844961713Sgirish } 135944961713Sgirish 136044961713Sgirish void 136144961713Sgirish nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel) 136244961713Sgirish { 136344961713Sgirish npi_handle_t handle; 136444961713Sgirish 136544961713Sgirish NXGE_DEBUG_MSG((nxgep, DMA_CTL, 136644961713Sgirish "==> nxge_txdma_disable_channel: channel %d", channel)); 136744961713Sgirish 136844961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 136944961713Sgirish /* stop the transmit dma channels */ 137044961713Sgirish (void) npi_txdma_channel_disable(handle, channel); 137144961713Sgirish 137244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel")); 137344961713Sgirish } 137444961713Sgirish 1375678453a8Sspeer /* 1376678453a8Sspeer * nxge_txdma_stop_inj_err 1377678453a8Sspeer * 1378678453a8Sspeer * Stop a TDC. If at first we don't succeed, inject an error. 1379678453a8Sspeer * 1380678453a8Sspeer * Arguments: 1381678453a8Sspeer * nxgep 1382678453a8Sspeer * channel The channel to stop. 1383678453a8Sspeer * 1384678453a8Sspeer * Notes: 1385678453a8Sspeer * 1386678453a8Sspeer * NPI/NXGE function calls: 1387678453a8Sspeer * npi_txdma_channel_disable() 1388678453a8Sspeer * npi_txdma_inj_int_error_set() 1389678453a8Sspeer * #if defined(NXGE_DEBUG) 1390678453a8Sspeer * nxge_txdma_regs_dump_channels(nxgep); 1391678453a8Sspeer * #endif 1392678453a8Sspeer * 1393678453a8Sspeer * Registers accessed: 1394678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1395678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1396678453a8Sspeer * 1397678453a8Sspeer * Context: 1398678453a8Sspeer * Any domain 1399678453a8Sspeer */ 140044961713Sgirish int 140144961713Sgirish nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel) 140244961713Sgirish { 140344961713Sgirish npi_handle_t handle; 140444961713Sgirish tdmc_intr_dbg_t intr_dbg; 140544961713Sgirish int status; 140644961713Sgirish npi_status_t rs = NPI_SUCCESS; 140744961713Sgirish 140844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err")); 140944961713Sgirish /* 141044961713Sgirish * Stop the dma channel waits for the stop done. 141144961713Sgirish * If the stop done bit is not set, then create 141244961713Sgirish * an error. 141344961713Sgirish */ 141444961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 141544961713Sgirish rs = npi_txdma_channel_disable(handle, channel); 141644961713Sgirish status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 141744961713Sgirish if (status == NXGE_OK) { 141844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 141944961713Sgirish "<== nxge_txdma_stop_inj_err (channel %d): " 142044961713Sgirish "stopped OK", channel)); 142144961713Sgirish return (status); 142244961713Sgirish } 142344961713Sgirish 142444961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 142544961713Sgirish "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) " 142644961713Sgirish "injecting error", channel, rs)); 142744961713Sgirish /* Inject any error */ 142844961713Sgirish intr_dbg.value = 0; 142944961713Sgirish intr_dbg.bits.ldw.nack_pref = 1; 143044961713Sgirish (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg); 143144961713Sgirish 143244961713Sgirish /* Stop done bit will be set as a result of error injection */ 143344961713Sgirish rs = npi_txdma_channel_disable(handle, channel); 143444961713Sgirish status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 143544961713Sgirish if (!(rs & NPI_TXDMA_STOP_FAILED)) { 143644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 143744961713Sgirish "<== nxge_txdma_stop_inj_err (channel %d): " 143844961713Sgirish "stopped OK ", channel)); 143944961713Sgirish return (status); 144044961713Sgirish } 144144961713Sgirish 144244961713Sgirish #if defined(NXGE_DEBUG) 144344961713Sgirish nxge_txdma_regs_dump_channels(nxgep); 144444961713Sgirish #endif 144544961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 144644961713Sgirish "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) " 144744961713Sgirish " (injected error but still not stopped)", channel, rs)); 144844961713Sgirish 144944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err")); 145044961713Sgirish return (status); 145144961713Sgirish } 145244961713Sgirish 145344961713Sgirish /*ARGSUSED*/ 145444961713Sgirish void 145544961713Sgirish nxge_fixup_txdma_rings(p_nxge_t nxgep) 145644961713Sgirish { 1457678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1458678453a8Sspeer int tdc; 145944961713Sgirish 146044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings")); 146144961713Sgirish 1462678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 1463678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1464678453a8Sspeer "<== nxge_fixup_txdma_rings: NULL ring pointer(s)")); 146544961713Sgirish return; 146644961713Sgirish } 146744961713Sgirish 1468678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1469678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1470678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1471678453a8Sspeer if (ring) { 1472678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1473678453a8Sspeer "==> nxge_fixup_txdma_rings: channel %d", 1474678453a8Sspeer tdc)); 1475678453a8Sspeer nxge_txdma_fixup_channel(nxgep, ring, tdc); 1476678453a8Sspeer } 1477678453a8Sspeer } 147844961713Sgirish } 147944961713Sgirish 148044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings")); 148144961713Sgirish } 148244961713Sgirish 148344961713Sgirish /*ARGSUSED*/ 148444961713Sgirish void 148544961713Sgirish nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel) 148644961713Sgirish { 148744961713Sgirish p_tx_ring_t ring_p; 148844961713Sgirish 148944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel")); 149044961713Sgirish ring_p = nxge_txdma_get_ring(nxgep, channel); 149144961713Sgirish if (ring_p == NULL) { 149244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel")); 149344961713Sgirish return; 149444961713Sgirish } 149544961713Sgirish 149644961713Sgirish if (ring_p->tdc != channel) { 149744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 149844961713Sgirish "<== nxge_txdma_fix_channel: channel not matched " 149944961713Sgirish "ring tdc %d passed channel", 150044961713Sgirish ring_p->tdc, channel)); 150144961713Sgirish return; 150244961713Sgirish } 150344961713Sgirish 150444961713Sgirish nxge_txdma_fixup_channel(nxgep, ring_p, channel); 150544961713Sgirish 150644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel")); 150744961713Sgirish } 150844961713Sgirish 150944961713Sgirish /*ARGSUSED*/ 151044961713Sgirish void 151144961713Sgirish nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel) 151244961713Sgirish { 151344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel")); 151444961713Sgirish 151544961713Sgirish if (ring_p == NULL) { 151644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 151744961713Sgirish "<== nxge_txdma_fixup_channel: NULL ring pointer")); 151844961713Sgirish return; 151944961713Sgirish } 152044961713Sgirish 152144961713Sgirish if (ring_p->tdc != channel) { 152244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 152344961713Sgirish "<== nxge_txdma_fixup_channel: channel not matched " 152444961713Sgirish "ring tdc %d passed channel", 152544961713Sgirish ring_p->tdc, channel)); 152644961713Sgirish return; 152744961713Sgirish } 152844961713Sgirish 152944961713Sgirish MUTEX_ENTER(&ring_p->lock); 153044961713Sgirish (void) nxge_txdma_reclaim(nxgep, ring_p, 0); 153144961713Sgirish ring_p->rd_index = 0; 153244961713Sgirish ring_p->wr_index = 0; 153344961713Sgirish ring_p->ring_head.value = 0; 153444961713Sgirish ring_p->ring_kick_tail.value = 0; 153544961713Sgirish ring_p->descs_pending = 0; 153644961713Sgirish MUTEX_EXIT(&ring_p->lock); 153744961713Sgirish 153844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel")); 153944961713Sgirish } 154044961713Sgirish 154144961713Sgirish /*ARGSUSED*/ 154244961713Sgirish void 154344961713Sgirish nxge_txdma_hw_kick(p_nxge_t nxgep) 154444961713Sgirish { 1545678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1546678453a8Sspeer int tdc; 154744961713Sgirish 154844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick")); 154944961713Sgirish 1550678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 155144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1552678453a8Sspeer "<== nxge_txdma_hw_kick: NULL ring pointer(s)")); 155344961713Sgirish return; 155444961713Sgirish } 155544961713Sgirish 1556678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1557678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1558678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1559678453a8Sspeer if (ring) { 1560678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1561678453a8Sspeer "==> nxge_txdma_hw_kick: channel %d", tdc)); 1562678453a8Sspeer nxge_txdma_hw_kick_channel(nxgep, ring, tdc); 1563678453a8Sspeer } 1564678453a8Sspeer } 156544961713Sgirish } 156644961713Sgirish 156744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick")); 156844961713Sgirish } 156944961713Sgirish 157044961713Sgirish /*ARGSUSED*/ 157144961713Sgirish void 157244961713Sgirish nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel) 157344961713Sgirish { 157444961713Sgirish p_tx_ring_t ring_p; 157544961713Sgirish 157644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel")); 157744961713Sgirish 157844961713Sgirish ring_p = nxge_txdma_get_ring(nxgep, channel); 157944961713Sgirish if (ring_p == NULL) { 158044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 158144961713Sgirish " nxge_txdma_kick_channel")); 158244961713Sgirish return; 158344961713Sgirish } 158444961713Sgirish 158544961713Sgirish if (ring_p->tdc != channel) { 158644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 158744961713Sgirish "<== nxge_txdma_kick_channel: channel not matched " 158844961713Sgirish "ring tdc %d passed channel", 158944961713Sgirish ring_p->tdc, channel)); 159044961713Sgirish return; 159144961713Sgirish } 159244961713Sgirish 159344961713Sgirish nxge_txdma_hw_kick_channel(nxgep, ring_p, channel); 159444961713Sgirish 159544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel")); 159644961713Sgirish } 1597a3c5bd6dSspeer 159844961713Sgirish /*ARGSUSED*/ 159944961713Sgirish void 160044961713Sgirish nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel) 160144961713Sgirish { 160244961713Sgirish 160344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel")); 160444961713Sgirish 160544961713Sgirish if (ring_p == NULL) { 160644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 160744961713Sgirish "<== nxge_txdma_hw_kick_channel: NULL ring pointer")); 160844961713Sgirish return; 160944961713Sgirish } 161044961713Sgirish 161144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel")); 161244961713Sgirish } 161344961713Sgirish 1614678453a8Sspeer /* 1615678453a8Sspeer * nxge_check_tx_hang 1616678453a8Sspeer * 1617678453a8Sspeer * Check the state of all TDCs belonging to nxgep. 1618678453a8Sspeer * 1619678453a8Sspeer * Arguments: 1620678453a8Sspeer * nxgep 1621678453a8Sspeer * 1622678453a8Sspeer * Notes: 1623678453a8Sspeer * Called by nxge_hw.c:nxge_check_hw_state(). 1624678453a8Sspeer * 1625678453a8Sspeer * NPI/NXGE function calls: 1626678453a8Sspeer * 1627678453a8Sspeer * Registers accessed: 1628678453a8Sspeer * 1629678453a8Sspeer * Context: 1630678453a8Sspeer * Any domain 1631678453a8Sspeer */ 163244961713Sgirish /*ARGSUSED*/ 163344961713Sgirish void 163444961713Sgirish nxge_check_tx_hang(p_nxge_t nxgep) 163544961713Sgirish { 163644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang")); 163744961713Sgirish 163822c0d73aSspeer if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) || 163922c0d73aSspeer (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) { 164022c0d73aSspeer goto nxge_check_tx_hang_exit; 164122c0d73aSspeer } 164222c0d73aSspeer 164344961713Sgirish /* 164444961713Sgirish * Needs inputs from hardware for regs: 164544961713Sgirish * head index had not moved since last timeout. 164644961713Sgirish * packets not transmitted or stuffed registers. 164744961713Sgirish */ 164844961713Sgirish if (nxge_txdma_hung(nxgep)) { 164944961713Sgirish nxge_fixup_hung_txdma_rings(nxgep); 165044961713Sgirish } 165122c0d73aSspeer 165222c0d73aSspeer nxge_check_tx_hang_exit: 165344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang")); 165444961713Sgirish } 165544961713Sgirish 1656678453a8Sspeer /* 1657678453a8Sspeer * nxge_txdma_hung 1658678453a8Sspeer * 1659678453a8Sspeer * Reset a TDC. 1660678453a8Sspeer * 1661678453a8Sspeer * Arguments: 1662678453a8Sspeer * nxgep 1663678453a8Sspeer * channel The channel to reset. 1664678453a8Sspeer * reg_data The current TX_CS. 1665678453a8Sspeer * 1666678453a8Sspeer * Notes: 1667678453a8Sspeer * Called by nxge_check_tx_hang() 1668678453a8Sspeer * 1669678453a8Sspeer * NPI/NXGE function calls: 1670678453a8Sspeer * nxge_txdma_channel_hung() 1671678453a8Sspeer * 1672678453a8Sspeer * Registers accessed: 1673678453a8Sspeer * 1674678453a8Sspeer * Context: 1675678453a8Sspeer * Any domain 1676678453a8Sspeer */ 167744961713Sgirish int 167844961713Sgirish nxge_txdma_hung(p_nxge_t nxgep) 167944961713Sgirish { 1680678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1681678453a8Sspeer int tdc; 168244961713Sgirish 168344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung")); 168444961713Sgirish 1685678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 168644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1687678453a8Sspeer "<== nxge_txdma_hung: NULL ring pointer(s)")); 168844961713Sgirish return (B_FALSE); 168944961713Sgirish } 169044961713Sgirish 1691678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1692678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1693678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1694678453a8Sspeer if (ring) { 1695678453a8Sspeer if (nxge_txdma_channel_hung(nxgep, ring, tdc)) { 1696678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1697678453a8Sspeer "==> nxge_txdma_hung: TDC %d hung", 1698678453a8Sspeer tdc)); 1699678453a8Sspeer return (B_TRUE); 1700678453a8Sspeer } 1701678453a8Sspeer } 170244961713Sgirish } 170344961713Sgirish } 170444961713Sgirish 170544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung")); 170644961713Sgirish 170744961713Sgirish return (B_FALSE); 170844961713Sgirish } 170944961713Sgirish 1710678453a8Sspeer /* 1711678453a8Sspeer * nxge_txdma_channel_hung 1712678453a8Sspeer * 1713678453a8Sspeer * Reset a TDC. 1714678453a8Sspeer * 1715678453a8Sspeer * Arguments: 1716678453a8Sspeer * nxgep 1717678453a8Sspeer * ring <channel>'s ring. 1718678453a8Sspeer * channel The channel to reset. 1719678453a8Sspeer * 1720678453a8Sspeer * Notes: 1721678453a8Sspeer * Called by nxge_txdma.c:nxge_txdma_hung() 1722678453a8Sspeer * 1723678453a8Sspeer * NPI/NXGE function calls: 1724678453a8Sspeer * npi_txdma_ring_head_get() 1725678453a8Sspeer * 1726678453a8Sspeer * Registers accessed: 1727678453a8Sspeer * TX_RING_HDL DMC+0x40010 Transmit Ring Head Low 1728678453a8Sspeer * 1729678453a8Sspeer * Context: 1730678453a8Sspeer * Any domain 1731678453a8Sspeer */ 173244961713Sgirish int 173344961713Sgirish nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel) 173444961713Sgirish { 173544961713Sgirish uint16_t head_index, tail_index; 173644961713Sgirish boolean_t head_wrap, tail_wrap; 173744961713Sgirish npi_handle_t handle; 173844961713Sgirish tx_ring_hdl_t tx_head; 173944961713Sgirish uint_t tx_rd_index; 174044961713Sgirish 174144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung")); 174244961713Sgirish 174344961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 174444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 174544961713Sgirish "==> nxge_txdma_channel_hung: channel %d", channel)); 174644961713Sgirish MUTEX_ENTER(&tx_ring_p->lock); 174744961713Sgirish (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 174844961713Sgirish 174944961713Sgirish tail_index = tx_ring_p->wr_index; 175044961713Sgirish tail_wrap = tx_ring_p->wr_index_wrap; 175144961713Sgirish tx_rd_index = tx_ring_p->rd_index; 175244961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 175344961713Sgirish 175444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 175544961713Sgirish "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d " 175644961713Sgirish "tail_index %d tail_wrap %d ", 175744961713Sgirish channel, tx_rd_index, tail_index, tail_wrap)); 175844961713Sgirish /* 175944961713Sgirish * Read the hardware maintained transmit head 176044961713Sgirish * and wrap around bit. 176144961713Sgirish */ 176244961713Sgirish (void) npi_txdma_ring_head_get(handle, channel, &tx_head); 176344961713Sgirish head_index = tx_head.bits.ldw.head; 176444961713Sgirish head_wrap = tx_head.bits.ldw.wrap; 176544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 176644961713Sgirish "==> nxge_txdma_channel_hung: " 176744961713Sgirish "tx_rd_index %d tail %d tail_wrap %d " 176844961713Sgirish "head %d wrap %d", 176944961713Sgirish tx_rd_index, tail_index, tail_wrap, 177044961713Sgirish head_index, head_wrap)); 177144961713Sgirish 177244961713Sgirish if (TXDMA_RING_EMPTY(head_index, head_wrap, 177344961713Sgirish tail_index, tail_wrap) && 177444961713Sgirish (head_index == tx_rd_index)) { 177544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 177644961713Sgirish "==> nxge_txdma_channel_hung: EMPTY")); 177744961713Sgirish return (B_FALSE); 177844961713Sgirish } 177944961713Sgirish 178044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 178144961713Sgirish "==> nxge_txdma_channel_hung: Checking if ring full")); 178244961713Sgirish if (TXDMA_RING_FULL(head_index, head_wrap, tail_index, 178344961713Sgirish tail_wrap)) { 178444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 178544961713Sgirish "==> nxge_txdma_channel_hung: full")); 178644961713Sgirish return (B_TRUE); 178744961713Sgirish } 178844961713Sgirish 178944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung")); 179044961713Sgirish 179144961713Sgirish return (B_FALSE); 179244961713Sgirish } 179344961713Sgirish 1794678453a8Sspeer /* 1795678453a8Sspeer * nxge_fixup_hung_txdma_rings 1796678453a8Sspeer * 1797678453a8Sspeer * Disable a TDC. 1798678453a8Sspeer * 1799678453a8Sspeer * Arguments: 1800678453a8Sspeer * nxgep 1801678453a8Sspeer * channel The channel to reset. 1802678453a8Sspeer * reg_data The current TX_CS. 1803678453a8Sspeer * 1804678453a8Sspeer * Notes: 1805678453a8Sspeer * Called by nxge_check_tx_hang() 1806678453a8Sspeer * 1807678453a8Sspeer * NPI/NXGE function calls: 1808678453a8Sspeer * npi_txdma_ring_head_get() 1809678453a8Sspeer * 1810678453a8Sspeer * Registers accessed: 1811678453a8Sspeer * TX_RING_HDL DMC+0x40010 Transmit Ring Head Low 1812678453a8Sspeer * 1813678453a8Sspeer * Context: 1814678453a8Sspeer * Any domain 1815678453a8Sspeer */ 181644961713Sgirish /*ARGSUSED*/ 181744961713Sgirish void 181844961713Sgirish nxge_fixup_hung_txdma_rings(p_nxge_t nxgep) 181944961713Sgirish { 1820678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1821678453a8Sspeer int tdc; 182244961713Sgirish 182344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings")); 182444961713Sgirish 1825678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 182644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1827678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 182844961713Sgirish return; 182944961713Sgirish } 183044961713Sgirish 1831678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1832678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1833678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1834678453a8Sspeer if (ring) { 1835678453a8Sspeer nxge_txdma_fixup_hung_channel(nxgep, ring, tdc); 1836678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1837678453a8Sspeer "==> nxge_fixup_hung_txdma_rings: TDC %d", 1838678453a8Sspeer tdc)); 1839678453a8Sspeer } 1840678453a8Sspeer } 184144961713Sgirish } 184244961713Sgirish 184344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings")); 184444961713Sgirish } 184544961713Sgirish 1846678453a8Sspeer /* 1847678453a8Sspeer * nxge_txdma_fixup_hung_channel 1848678453a8Sspeer * 1849678453a8Sspeer * 'Fix' a hung TDC. 1850678453a8Sspeer * 1851678453a8Sspeer * Arguments: 1852678453a8Sspeer * nxgep 1853678453a8Sspeer * channel The channel to fix. 1854678453a8Sspeer * 1855678453a8Sspeer * Notes: 1856678453a8Sspeer * Called by nxge_fixup_hung_txdma_rings() 1857678453a8Sspeer * 1858678453a8Sspeer * 1. Reclaim the TDC. 1859678453a8Sspeer * 2. Disable the TDC. 1860678453a8Sspeer * 1861678453a8Sspeer * NPI/NXGE function calls: 1862678453a8Sspeer * nxge_txdma_reclaim() 1863678453a8Sspeer * npi_txdma_channel_disable(TX_CS) 1864678453a8Sspeer * npi_txdma_inj_int_error_set(TDMC_INTR_DBG) 1865678453a8Sspeer * 1866678453a8Sspeer * Registers accessed: 1867678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1868678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1869678453a8Sspeer * 1870678453a8Sspeer * Context: 1871678453a8Sspeer * Any domain 1872678453a8Sspeer */ 187344961713Sgirish /*ARGSUSED*/ 187444961713Sgirish void 187544961713Sgirish nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel) 187644961713Sgirish { 187744961713Sgirish p_tx_ring_t ring_p; 187844961713Sgirish 187944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel")); 188044961713Sgirish ring_p = nxge_txdma_get_ring(nxgep, channel); 188144961713Sgirish if (ring_p == NULL) { 188244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 188344961713Sgirish "<== nxge_txdma_fix_hung_channel")); 188444961713Sgirish return; 188544961713Sgirish } 188644961713Sgirish 188744961713Sgirish if (ring_p->tdc != channel) { 188844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 188944961713Sgirish "<== nxge_txdma_fix_hung_channel: channel not matched " 189044961713Sgirish "ring tdc %d passed channel", 189144961713Sgirish ring_p->tdc, channel)); 189244961713Sgirish return; 189344961713Sgirish } 189444961713Sgirish 189544961713Sgirish nxge_txdma_fixup_channel(nxgep, ring_p, channel); 189644961713Sgirish 189744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel")); 189844961713Sgirish } 189944961713Sgirish 190044961713Sgirish /*ARGSUSED*/ 190144961713Sgirish void 190244961713Sgirish nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, 190344961713Sgirish uint16_t channel) 190444961713Sgirish { 190544961713Sgirish npi_handle_t handle; 190644961713Sgirish tdmc_intr_dbg_t intr_dbg; 190744961713Sgirish int status = NXGE_OK; 190844961713Sgirish 190944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel")); 191044961713Sgirish 191144961713Sgirish if (ring_p == NULL) { 191244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 191344961713Sgirish "<== nxge_txdma_fixup_channel: NULL ring pointer")); 191444961713Sgirish return; 191544961713Sgirish } 191644961713Sgirish 191744961713Sgirish if (ring_p->tdc != channel) { 191844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 191944961713Sgirish "<== nxge_txdma_fixup_hung_channel: channel " 192044961713Sgirish "not matched " 192144961713Sgirish "ring tdc %d passed channel", 192244961713Sgirish ring_p->tdc, channel)); 192344961713Sgirish return; 192444961713Sgirish } 192544961713Sgirish 192644961713Sgirish /* Reclaim descriptors */ 192744961713Sgirish MUTEX_ENTER(&ring_p->lock); 192844961713Sgirish (void) nxge_txdma_reclaim(nxgep, ring_p, 0); 192944961713Sgirish MUTEX_EXIT(&ring_p->lock); 193044961713Sgirish 193144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 193244961713Sgirish /* 193344961713Sgirish * Stop the dma channel waits for the stop done. 193444961713Sgirish * If the stop done bit is not set, then force 193544961713Sgirish * an error. 193644961713Sgirish */ 193744961713Sgirish status = npi_txdma_channel_disable(handle, channel); 193844961713Sgirish if (!(status & NPI_TXDMA_STOP_FAILED)) { 193944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 194044961713Sgirish "<== nxge_txdma_fixup_hung_channel: stopped OK " 194144961713Sgirish "ring tdc %d passed channel %d", 194244961713Sgirish ring_p->tdc, channel)); 194344961713Sgirish return; 194444961713Sgirish } 194544961713Sgirish 194644961713Sgirish /* Inject any error */ 194744961713Sgirish intr_dbg.value = 0; 194844961713Sgirish intr_dbg.bits.ldw.nack_pref = 1; 194944961713Sgirish (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg); 195044961713Sgirish 195144961713Sgirish /* Stop done bit will be set as a result of error injection */ 195244961713Sgirish status = npi_txdma_channel_disable(handle, channel); 195344961713Sgirish if (!(status & NPI_TXDMA_STOP_FAILED)) { 195444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 195544961713Sgirish "<== nxge_txdma_fixup_hung_channel: stopped again" 195644961713Sgirish "ring tdc %d passed channel", 195744961713Sgirish ring_p->tdc, channel)); 195844961713Sgirish return; 195944961713Sgirish } 196044961713Sgirish 196144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 196244961713Sgirish "<== nxge_txdma_fixup_hung_channel: stop done still not set!! " 196344961713Sgirish "ring tdc %d passed channel", 196444961713Sgirish ring_p->tdc, channel)); 196544961713Sgirish 196644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel")); 196744961713Sgirish } 196844961713Sgirish 196944961713Sgirish /*ARGSUSED*/ 197044961713Sgirish void 197144961713Sgirish nxge_reclaim_rings(p_nxge_t nxgep) 197244961713Sgirish { 1973678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1974678453a8Sspeer int tdc; 197544961713Sgirish 1976678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings")); 197744961713Sgirish 1978678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 197944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1980678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 198144961713Sgirish return; 198244961713Sgirish } 198344961713Sgirish 1984678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1985678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1986678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1987678453a8Sspeer if (ring) { 1988678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1989678453a8Sspeer "==> nxge_reclaim_rings: TDC %d", tdc)); 1990678453a8Sspeer MUTEX_ENTER(&ring->lock); 1991678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, ring, tdc); 1992678453a8Sspeer MUTEX_EXIT(&ring->lock); 1993678453a8Sspeer } 1994678453a8Sspeer } 199544961713Sgirish } 199644961713Sgirish 199744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings")); 199844961713Sgirish } 199944961713Sgirish 200044961713Sgirish void 200144961713Sgirish nxge_txdma_regs_dump_channels(p_nxge_t nxgep) 200244961713Sgirish { 2003678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 2004678453a8Sspeer npi_handle_t handle; 2005678453a8Sspeer int tdc; 200644961713Sgirish 2007678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels")); 200844961713Sgirish 200944961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 201044961713Sgirish 2011678453a8Sspeer if (!isLDOMguest(nxgep)) { 2012678453a8Sspeer (void) npi_txdma_dump_fzc_regs(handle); 201344961713Sgirish 2014678453a8Sspeer /* Dump TXC registers. */ 2015678453a8Sspeer (void) npi_txc_dump_fzc_regs(handle); 2016678453a8Sspeer (void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num); 201744961713Sgirish } 201844961713Sgirish 2019678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 202044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 2021678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 202244961713Sgirish return; 202344961713Sgirish } 202444961713Sgirish 2025678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 2026678453a8Sspeer if ((1 << tdc) & set->owned.map) { 2027678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 2028678453a8Sspeer if (ring) { 2029678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2030678453a8Sspeer "==> nxge_txdma_regs_dump_channels: " 2031678453a8Sspeer "TDC %d", tdc)); 2032678453a8Sspeer (void) npi_txdma_dump_tdc_regs(handle, tdc); 2033678453a8Sspeer 2034678453a8Sspeer /* Dump TXC registers, if able to. */ 2035678453a8Sspeer if (!isLDOMguest(nxgep)) { 2036678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2037678453a8Sspeer "==> nxge_txdma_regs_dump_channels:" 2038678453a8Sspeer " FZC TDC %d", tdc)); 2039678453a8Sspeer (void) npi_txc_dump_tdc_fzc_regs 2040678453a8Sspeer (handle, tdc); 2041678453a8Sspeer } 2042678453a8Sspeer nxge_txdma_regs_dump(nxgep, tdc); 2043678453a8Sspeer } 2044678453a8Sspeer } 204544961713Sgirish } 204644961713Sgirish 204744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump")); 204844961713Sgirish } 204944961713Sgirish 205044961713Sgirish void 205144961713Sgirish nxge_txdma_regs_dump(p_nxge_t nxgep, int channel) 205244961713Sgirish { 205344961713Sgirish npi_handle_t handle; 205444961713Sgirish tx_ring_hdl_t hdl; 205544961713Sgirish tx_ring_kick_t kick; 205644961713Sgirish tx_cs_t cs; 205744961713Sgirish txc_control_t control; 205844961713Sgirish uint32_t bitmap = 0; 205944961713Sgirish uint32_t burst = 0; 206044961713Sgirish uint32_t bytes = 0; 206144961713Sgirish dma_log_page_t cfg; 206244961713Sgirish 206344961713Sgirish printf("\n\tfunc # %d tdc %d ", 206444961713Sgirish nxgep->function_num, channel); 206544961713Sgirish cfg.page_num = 0; 206644961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 206744961713Sgirish (void) npi_txdma_log_page_get(handle, channel, &cfg); 206844961713Sgirish printf("\n\tlog page func %d valid page 0 %d", 206944961713Sgirish cfg.func_num, cfg.valid); 207044961713Sgirish cfg.page_num = 1; 207144961713Sgirish (void) npi_txdma_log_page_get(handle, channel, &cfg); 207244961713Sgirish printf("\n\tlog page func %d valid page 1 %d", 207344961713Sgirish cfg.func_num, cfg.valid); 207444961713Sgirish 207544961713Sgirish (void) npi_txdma_ring_head_get(handle, channel, &hdl); 207644961713Sgirish (void) npi_txdma_desc_kick_reg_get(handle, channel, &kick); 207744961713Sgirish printf("\n\thead value is 0x%0llx", 207844961713Sgirish (long long)hdl.value); 207944961713Sgirish printf("\n\thead index %d", hdl.bits.ldw.head); 208044961713Sgirish printf("\n\tkick value is 0x%0llx", 208144961713Sgirish (long long)kick.value); 208244961713Sgirish printf("\n\ttail index %d\n", kick.bits.ldw.tail); 208344961713Sgirish 208444961713Sgirish (void) npi_txdma_control_status(handle, OP_GET, channel, &cs); 208544961713Sgirish printf("\n\tControl statue is 0x%0llx", (long long)cs.value); 208644961713Sgirish printf("\n\tControl status RST state %d", cs.bits.ldw.rst); 208744961713Sgirish 208844961713Sgirish (void) npi_txc_control(handle, OP_GET, &control); 208944961713Sgirish (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap); 209044961713Sgirish (void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst); 209144961713Sgirish (void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes); 209244961713Sgirish 209344961713Sgirish printf("\n\tTXC port control 0x%0llx", 209444961713Sgirish (long long)control.value); 209544961713Sgirish printf("\n\tTXC port bitmap 0x%x", bitmap); 209644961713Sgirish printf("\n\tTXC max burst %d", burst); 209744961713Sgirish printf("\n\tTXC bytes xmt %d\n", bytes); 209844961713Sgirish 209944961713Sgirish { 210044961713Sgirish ipp_status_t status; 210144961713Sgirish 210244961713Sgirish (void) npi_ipp_get_status(handle, nxgep->function_num, &status); 2103adfcba55Sjoycey #if defined(__i386) 2104adfcba55Sjoycey printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value); 2105adfcba55Sjoycey #else 210644961713Sgirish printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value); 2107adfcba55Sjoycey #endif 210844961713Sgirish } 210944961713Sgirish } 211044961713Sgirish 211144961713Sgirish /* 2112678453a8Sspeer * nxge_tdc_hvio_setup 2113678453a8Sspeer * 2114678453a8Sspeer * I'm not exactly sure what this code does. 2115678453a8Sspeer * 2116678453a8Sspeer * Arguments: 2117678453a8Sspeer * nxgep 2118678453a8Sspeer * channel The channel to map. 2119678453a8Sspeer * 2120678453a8Sspeer * Notes: 2121678453a8Sspeer * 2122678453a8Sspeer * NPI/NXGE function calls: 2123678453a8Sspeer * na 2124678453a8Sspeer * 2125678453a8Sspeer * Context: 2126678453a8Sspeer * Service domain? 212744961713Sgirish */ 2128678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND) 2129678453a8Sspeer static void 2130678453a8Sspeer nxge_tdc_hvio_setup( 2131678453a8Sspeer nxge_t *nxgep, int channel) 213244961713Sgirish { 2133678453a8Sspeer nxge_dma_common_t *data; 2134678453a8Sspeer nxge_dma_common_t *control; 2135678453a8Sspeer tx_ring_t *ring; 2136678453a8Sspeer 2137678453a8Sspeer ring = nxgep->tx_rings->rings[channel]; 2138678453a8Sspeer data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel]; 2139678453a8Sspeer 2140678453a8Sspeer ring->hv_set = B_FALSE; 2141678453a8Sspeer 2142678453a8Sspeer ring->hv_tx_buf_base_ioaddr_pp = 2143678453a8Sspeer (uint64_t)data->orig_ioaddr_pp; 2144678453a8Sspeer ring->hv_tx_buf_ioaddr_size = 2145678453a8Sspeer (uint64_t)data->orig_alength; 2146678453a8Sspeer 2147678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: " 2148678453a8Sspeer "hv data buf base io $%p size 0x%llx (%d) buf base io $%p " 2149678453a8Sspeer "orig vatopa base io $%p orig_len 0x%llx (%d)", 2150678453a8Sspeer ring->hv_tx_buf_base_ioaddr_pp, 2151678453a8Sspeer ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size, 2152678453a8Sspeer data->ioaddr_pp, data->orig_vatopa, 2153678453a8Sspeer data->orig_alength, data->orig_alength)); 2154678453a8Sspeer 2155678453a8Sspeer control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel]; 2156678453a8Sspeer 2157678453a8Sspeer ring->hv_tx_cntl_base_ioaddr_pp = 2158678453a8Sspeer (uint64_t)control->orig_ioaddr_pp; 2159678453a8Sspeer ring->hv_tx_cntl_ioaddr_size = 2160678453a8Sspeer (uint64_t)control->orig_alength; 2161678453a8Sspeer 2162678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: " 2163678453a8Sspeer "hv cntl base io $%p orig ioaddr_pp ($%p) " 2164678453a8Sspeer "orig vatopa ($%p) size 0x%llx (%d 0x%x)", 2165678453a8Sspeer ring->hv_tx_cntl_base_ioaddr_pp, 2166678453a8Sspeer control->orig_ioaddr_pp, control->orig_vatopa, 2167678453a8Sspeer ring->hv_tx_cntl_ioaddr_size, 2168678453a8Sspeer control->orig_alength, control->orig_alength)); 2169678453a8Sspeer } 217044961713Sgirish #endif 217144961713Sgirish 2172678453a8Sspeer static nxge_status_t 2173678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel) 2174678453a8Sspeer { 2175678453a8Sspeer nxge_dma_common_t **pData; 2176678453a8Sspeer nxge_dma_common_t **pControl; 2177678453a8Sspeer tx_ring_t **pRing, *ring; 2178678453a8Sspeer tx_mbox_t **mailbox; 2179678453a8Sspeer uint32_t num_chunks; 2180678453a8Sspeer 2181678453a8Sspeer nxge_status_t status = NXGE_OK; 218244961713Sgirish 2183678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma")); 218444961713Sgirish 2185678453a8Sspeer if (!nxgep->tx_cntl_pool_p->buf_allocated) { 2186678453a8Sspeer if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) { 2187678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 2188678453a8Sspeer "<== nxge_map_txdma: buf not allocated")); 2189678453a8Sspeer return (NXGE_ERROR); 2190678453a8Sspeer } 219144961713Sgirish } 219244961713Sgirish 2193678453a8Sspeer if (nxge_alloc_txb(nxgep, channel) != NXGE_OK) 219444961713Sgirish return (NXGE_ERROR); 219544961713Sgirish 2196678453a8Sspeer num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel]; 2197678453a8Sspeer pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel]; 2198678453a8Sspeer pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel]; 2199678453a8Sspeer pRing = &nxgep->tx_rings->rings[channel]; 2200678453a8Sspeer mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 220144961713Sgirish 2202678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: " 220344961713Sgirish "tx_rings $%p tx_desc_rings $%p", 2204678453a8Sspeer nxgep->tx_rings, nxgep->tx_rings->rings)); 220544961713Sgirish 220644961713Sgirish /* 2207678453a8Sspeer * Map descriptors from the buffer pools for <channel>. 220844961713Sgirish */ 220944961713Sgirish 2210678453a8Sspeer /* 2211678453a8Sspeer * Set up and prepare buffer blocks, descriptors 2212678453a8Sspeer * and mailbox. 2213678453a8Sspeer */ 2214678453a8Sspeer status = nxge_map_txdma_channel(nxgep, channel, 2215678453a8Sspeer pData, pRing, num_chunks, pControl, mailbox); 2216678453a8Sspeer if (status != NXGE_OK) { 2217678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 2218678453a8Sspeer "==> nxge_map_txdma(%d): nxge_map_txdma_channel() " 2219678453a8Sspeer "returned 0x%x", 2220678453a8Sspeer nxgep, channel, status)); 2221678453a8Sspeer return (status); 222244961713Sgirish } 222344961713Sgirish 2224678453a8Sspeer ring = *pRing; 222544961713Sgirish 2226678453a8Sspeer ring->index = (uint16_t)channel; 2227678453a8Sspeer ring->tdc_stats = &nxgep->statsp->tdc_stats[channel]; 222844961713Sgirish 2229678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND) 2230678453a8Sspeer if (isLDOMguest(nxgep)) { 2231678453a8Sspeer (void) nxge_tdc_lp_conf(nxgep, channel); 2232678453a8Sspeer } else { 2233678453a8Sspeer nxge_tdc_hvio_setup(nxgep, channel); 223444961713Sgirish } 2235678453a8Sspeer #endif 223644961713Sgirish 2237678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: " 2238678453a8Sspeer "(status 0x%x channel %d)", status, channel)); 223944961713Sgirish 2240678453a8Sspeer return (status); 224144961713Sgirish } 224244961713Sgirish 224344961713Sgirish static nxge_status_t 224444961713Sgirish nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel, 224544961713Sgirish p_nxge_dma_common_t *dma_buf_p, 224644961713Sgirish p_tx_ring_t *tx_desc_p, 224744961713Sgirish uint32_t num_chunks, 224844961713Sgirish p_nxge_dma_common_t *dma_cntl_p, 224944961713Sgirish p_tx_mbox_t *tx_mbox_p) 225044961713Sgirish { 225144961713Sgirish int status = NXGE_OK; 225244961713Sgirish 225344961713Sgirish /* 225444961713Sgirish * Set up and prepare buffer blocks, descriptors 225544961713Sgirish * and mailbox. 225644961713Sgirish */ 2257678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 225844961713Sgirish "==> nxge_map_txdma_channel (channel %d)", channel)); 225944961713Sgirish /* 226044961713Sgirish * Transmit buffer blocks 226144961713Sgirish */ 226244961713Sgirish status = nxge_map_txdma_channel_buf_ring(nxgep, channel, 226344961713Sgirish dma_buf_p, tx_desc_p, num_chunks); 226444961713Sgirish if (status != NXGE_OK) { 226544961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 226644961713Sgirish "==> nxge_map_txdma_channel (channel %d): " 226744961713Sgirish "map buffer failed 0x%x", channel, status)); 226844961713Sgirish goto nxge_map_txdma_channel_exit; 226944961713Sgirish } 227044961713Sgirish 227144961713Sgirish /* 227244961713Sgirish * Transmit block ring, and mailbox. 227344961713Sgirish */ 227444961713Sgirish nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p, 227544961713Sgirish tx_mbox_p); 227644961713Sgirish 227744961713Sgirish goto nxge_map_txdma_channel_exit; 227844961713Sgirish 227944961713Sgirish nxge_map_txdma_channel_fail1: 2280678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 228144961713Sgirish "==> nxge_map_txdma_channel: unmap buf" 228244961713Sgirish "(status 0x%x channel %d)", 228344961713Sgirish status, channel)); 228444961713Sgirish nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p); 228544961713Sgirish 228644961713Sgirish nxge_map_txdma_channel_exit: 2287678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 228844961713Sgirish "<== nxge_map_txdma_channel: " 228944961713Sgirish "(status 0x%x channel %d)", 229044961713Sgirish status, channel)); 229144961713Sgirish 229244961713Sgirish return (status); 229344961713Sgirish } 229444961713Sgirish 229544961713Sgirish /*ARGSUSED*/ 229644961713Sgirish static void 2297678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel) 229844961713Sgirish { 2299678453a8Sspeer tx_ring_t *ring; 2300678453a8Sspeer tx_mbox_t *mailbox; 2301678453a8Sspeer 230244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 230344961713Sgirish "==> nxge_unmap_txdma_channel (channel %d)", channel)); 230444961713Sgirish /* 230544961713Sgirish * unmap tx block ring, and mailbox. 230644961713Sgirish */ 2307678453a8Sspeer ring = nxgep->tx_rings->rings[channel]; 2308678453a8Sspeer mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 2309678453a8Sspeer 2310678453a8Sspeer (void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox); 231144961713Sgirish 231244961713Sgirish /* unmap buffer blocks */ 2313678453a8Sspeer (void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring); 2314678453a8Sspeer 2315678453a8Sspeer nxge_free_txb(nxgep, channel); 231644961713Sgirish 231744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel")); 231844961713Sgirish } 231944961713Sgirish 2320678453a8Sspeer /* 2321678453a8Sspeer * nxge_map_txdma_channel_cfg_ring 2322678453a8Sspeer * 2323678453a8Sspeer * Map a TDC into our kernel space. 2324678453a8Sspeer * This function allocates all of the per-channel data structures. 2325678453a8Sspeer * 2326678453a8Sspeer * Arguments: 2327678453a8Sspeer * nxgep 2328678453a8Sspeer * dma_channel The channel to map. 2329678453a8Sspeer * dma_cntl_p 2330678453a8Sspeer * tx_ring_p dma_channel's transmit ring 2331678453a8Sspeer * tx_mbox_p dma_channel's mailbox 2332678453a8Sspeer * 2333678453a8Sspeer * Notes: 2334678453a8Sspeer * 2335678453a8Sspeer * NPI/NXGE function calls: 2336678453a8Sspeer * nxge_setup_dma_common() 2337678453a8Sspeer * 2338678453a8Sspeer * Registers accessed: 2339678453a8Sspeer * none. 2340678453a8Sspeer * 2341678453a8Sspeer * Context: 2342678453a8Sspeer * Any domain 2343678453a8Sspeer */ 234444961713Sgirish /*ARGSUSED*/ 234544961713Sgirish static void 234644961713Sgirish nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel, 234744961713Sgirish p_nxge_dma_common_t *dma_cntl_p, 234844961713Sgirish p_tx_ring_t tx_ring_p, 234944961713Sgirish p_tx_mbox_t *tx_mbox_p) 235044961713Sgirish { 235144961713Sgirish p_tx_mbox_t mboxp; 235244961713Sgirish p_nxge_dma_common_t cntl_dmap; 235344961713Sgirish p_nxge_dma_common_t dmap; 235444961713Sgirish p_tx_rng_cfig_t tx_ring_cfig_p; 235544961713Sgirish p_tx_ring_kick_t tx_ring_kick_p; 235644961713Sgirish p_tx_cs_t tx_cs_p; 235744961713Sgirish p_tx_dma_ent_msk_t tx_evmask_p; 235844961713Sgirish p_txdma_mbh_t mboxh_p; 235944961713Sgirish p_txdma_mbl_t mboxl_p; 236044961713Sgirish uint64_t tx_desc_len; 236144961713Sgirish 236244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 236344961713Sgirish "==> nxge_map_txdma_channel_cfg_ring")); 236444961713Sgirish 236544961713Sgirish cntl_dmap = *dma_cntl_p; 236644961713Sgirish 236744961713Sgirish dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc; 236844961713Sgirish nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size, 236944961713Sgirish sizeof (tx_desc_t)); 237044961713Sgirish /* 237144961713Sgirish * Zero out transmit ring descriptors. 237244961713Sgirish */ 237344961713Sgirish bzero((caddr_t)dmap->kaddrp, dmap->alength); 237444961713Sgirish tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig); 237544961713Sgirish tx_ring_kick_p = &(tx_ring_p->tx_ring_kick); 237644961713Sgirish tx_cs_p = &(tx_ring_p->tx_cs); 237744961713Sgirish tx_evmask_p = &(tx_ring_p->tx_evmask); 237844961713Sgirish tx_ring_cfig_p->value = 0; 237944961713Sgirish tx_ring_kick_p->value = 0; 238044961713Sgirish tx_cs_p->value = 0; 238144961713Sgirish tx_evmask_p->value = 0; 238244961713Sgirish 238344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 238444961713Sgirish "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p", 238544961713Sgirish dma_channel, 238644961713Sgirish dmap->dma_cookie.dmac_laddress)); 238744961713Sgirish 238844961713Sgirish tx_ring_cfig_p->value = 0; 238944961713Sgirish tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3); 239044961713Sgirish tx_ring_cfig_p->value = 239144961713Sgirish (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) | 239244961713Sgirish (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT); 239344961713Sgirish 239444961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 239544961713Sgirish "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx", 239644961713Sgirish dma_channel, 239744961713Sgirish tx_ring_cfig_p->value)); 239844961713Sgirish 239944961713Sgirish tx_cs_p->bits.ldw.rst = 1; 240044961713Sgirish 240144961713Sgirish /* Map in mailbox */ 240244961713Sgirish mboxp = (p_tx_mbox_t) 240344961713Sgirish KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP); 240444961713Sgirish dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox; 240544961713Sgirish nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t)); 240644961713Sgirish mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh; 240744961713Sgirish mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl; 240844961713Sgirish mboxh_p->value = mboxl_p->value = 0; 240944961713Sgirish 241044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 241144961713Sgirish "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx", 241244961713Sgirish dmap->dma_cookie.dmac_laddress)); 241344961713Sgirish 241444961713Sgirish mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >> 241544961713Sgirish TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK); 241644961713Sgirish 241744961713Sgirish mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress & 241844961713Sgirish TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT); 241944961713Sgirish 242044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 242144961713Sgirish "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx", 242244961713Sgirish dmap->dma_cookie.dmac_laddress)); 242344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 242444961713Sgirish "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p " 242544961713Sgirish "mbox $%p", 242644961713Sgirish mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr)); 242744961713Sgirish tx_ring_p->page_valid.value = 0; 242844961713Sgirish tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0; 242944961713Sgirish tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0; 243044961713Sgirish tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0; 243144961713Sgirish tx_ring_p->page_hdl.value = 0; 243244961713Sgirish 243344961713Sgirish tx_ring_p->page_valid.bits.ldw.page0 = 1; 243444961713Sgirish tx_ring_p->page_valid.bits.ldw.page1 = 1; 243544961713Sgirish 243644961713Sgirish tx_ring_p->max_burst.value = 0; 243744961713Sgirish tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT; 243844961713Sgirish 243944961713Sgirish *tx_mbox_p = mboxp; 244044961713Sgirish 244144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 244244961713Sgirish "<== nxge_map_txdma_channel_cfg_ring")); 244344961713Sgirish } 244444961713Sgirish 244544961713Sgirish /*ARGSUSED*/ 244644961713Sgirish static void 244744961713Sgirish nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep, 244844961713Sgirish p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p) 244944961713Sgirish { 245044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 245144961713Sgirish "==> nxge_unmap_txdma_channel_cfg_ring: channel %d", 245244961713Sgirish tx_ring_p->tdc)); 245344961713Sgirish 245444961713Sgirish KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t)); 245544961713Sgirish 245644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 245744961713Sgirish "<== nxge_unmap_txdma_channel_cfg_ring")); 245844961713Sgirish } 245944961713Sgirish 2460678453a8Sspeer /* 2461678453a8Sspeer * nxge_map_txdma_channel_buf_ring 2462678453a8Sspeer * 2463678453a8Sspeer * 2464678453a8Sspeer * Arguments: 2465678453a8Sspeer * nxgep 2466678453a8Sspeer * channel The channel to map. 2467678453a8Sspeer * dma_buf_p 2468678453a8Sspeer * tx_desc_p channel's descriptor ring 2469678453a8Sspeer * num_chunks 2470678453a8Sspeer * 2471678453a8Sspeer * Notes: 2472678453a8Sspeer * 2473678453a8Sspeer * NPI/NXGE function calls: 2474678453a8Sspeer * nxge_setup_dma_common() 2475678453a8Sspeer * 2476678453a8Sspeer * Registers accessed: 2477678453a8Sspeer * none. 2478678453a8Sspeer * 2479678453a8Sspeer * Context: 2480678453a8Sspeer * Any domain 2481678453a8Sspeer */ 248244961713Sgirish static nxge_status_t 248344961713Sgirish nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel, 248444961713Sgirish p_nxge_dma_common_t *dma_buf_p, 248544961713Sgirish p_tx_ring_t *tx_desc_p, uint32_t num_chunks) 248644961713Sgirish { 248744961713Sgirish p_nxge_dma_common_t dma_bufp, tmp_bufp; 248844961713Sgirish p_nxge_dma_common_t dmap; 248944961713Sgirish nxge_os_dma_handle_t tx_buf_dma_handle; 249044961713Sgirish p_tx_ring_t tx_ring_p; 249144961713Sgirish p_tx_msg_t tx_msg_ring; 249244961713Sgirish nxge_status_t status = NXGE_OK; 249344961713Sgirish int ddi_status = DDI_SUCCESS; 249444961713Sgirish int i, j, index; 249544961713Sgirish uint32_t size, bsize; 249644961713Sgirish uint32_t nblocks, nmsgs; 249744961713Sgirish 249844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 249944961713Sgirish "==> nxge_map_txdma_channel_buf_ring")); 250044961713Sgirish 250144961713Sgirish dma_bufp = tmp_bufp = *dma_buf_p; 250244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 250344961713Sgirish " nxge_map_txdma_channel_buf_ring: channel %d to map %d " 250444961713Sgirish "chunks bufp $%p", 250544961713Sgirish channel, num_chunks, dma_bufp)); 250644961713Sgirish 250744961713Sgirish nmsgs = 0; 250844961713Sgirish for (i = 0; i < num_chunks; i++, tmp_bufp++) { 250944961713Sgirish nmsgs += tmp_bufp->nblocks; 251044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 251144961713Sgirish "==> nxge_map_txdma_channel_buf_ring: channel %d " 251244961713Sgirish "bufp $%p nblocks %d nmsgs %d", 251344961713Sgirish channel, tmp_bufp, tmp_bufp->nblocks, nmsgs)); 251444961713Sgirish } 251544961713Sgirish if (!nmsgs) { 251644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 251744961713Sgirish "<== nxge_map_txdma_channel_buf_ring: channel %d " 251844961713Sgirish "no msg blocks", 251944961713Sgirish channel)); 252044961713Sgirish status = NXGE_ERROR; 252144961713Sgirish goto nxge_map_txdma_channel_buf_ring_exit; 252244961713Sgirish } 252344961713Sgirish 252444961713Sgirish tx_ring_p = (p_tx_ring_t) 252544961713Sgirish KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP); 252644961713Sgirish MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER, 252744961713Sgirish (void *)nxgep->interrupt_cookie); 25281f8914d5Sml 252922c0d73aSspeer (void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE); 2530*6895688eSspeer tx_ring_p->tx_ring_busy = B_FALSE; 25311f8914d5Sml tx_ring_p->nxgep = nxgep; 25321f8914d5Sml tx_ring_p->serial = nxge_serialize_create(nmsgs, 25331f8914d5Sml nxge_serial_tx, tx_ring_p); 253444961713Sgirish /* 253544961713Sgirish * Allocate transmit message rings and handles for packets 253644961713Sgirish * not to be copied to premapped buffers. 253744961713Sgirish */ 253844961713Sgirish size = nmsgs * sizeof (tx_msg_t); 253944961713Sgirish tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP); 254044961713Sgirish for (i = 0; i < nmsgs; i++) { 254144961713Sgirish ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr, 254244961713Sgirish DDI_DMA_DONTWAIT, 0, 254344961713Sgirish &tx_msg_ring[i].dma_handle); 254444961713Sgirish if (ddi_status != DDI_SUCCESS) { 254544961713Sgirish status |= NXGE_DDI_FAILED; 254644961713Sgirish break; 254744961713Sgirish } 254844961713Sgirish } 254944961713Sgirish if (i < nmsgs) { 255056d930aeSspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 255156d930aeSspeer "Allocate handles failed.")); 255244961713Sgirish goto nxge_map_txdma_channel_buf_ring_fail1; 255344961713Sgirish } 255444961713Sgirish 255544961713Sgirish tx_ring_p->tdc = channel; 255644961713Sgirish tx_ring_p->tx_msg_ring = tx_msg_ring; 255744961713Sgirish tx_ring_p->tx_ring_size = nmsgs; 255844961713Sgirish tx_ring_p->num_chunks = num_chunks; 255944961713Sgirish if (!nxge_tx_intr_thres) { 256044961713Sgirish nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4; 256144961713Sgirish } 256244961713Sgirish tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1; 256344961713Sgirish tx_ring_p->rd_index = 0; 256444961713Sgirish tx_ring_p->wr_index = 0; 256544961713Sgirish tx_ring_p->ring_head.value = 0; 256644961713Sgirish tx_ring_p->ring_kick_tail.value = 0; 256744961713Sgirish tx_ring_p->descs_pending = 0; 256844961713Sgirish 256944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 257044961713Sgirish "==> nxge_map_txdma_channel_buf_ring: channel %d " 257144961713Sgirish "actual tx desc max %d nmsgs %d " 257244961713Sgirish "(config nxge_tx_ring_size %d)", 257344961713Sgirish channel, tx_ring_p->tx_ring_size, nmsgs, 257444961713Sgirish nxge_tx_ring_size)); 257544961713Sgirish 257644961713Sgirish /* 257744961713Sgirish * Map in buffers from the buffer pool. 257844961713Sgirish */ 257944961713Sgirish index = 0; 258044961713Sgirish bsize = dma_bufp->block_size; 258144961713Sgirish 258244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: " 258344961713Sgirish "dma_bufp $%p tx_rng_p $%p " 258444961713Sgirish "tx_msg_rng_p $%p bsize %d", 258544961713Sgirish dma_bufp, tx_ring_p, tx_msg_ring, bsize)); 258644961713Sgirish 258744961713Sgirish tx_buf_dma_handle = dma_bufp->dma_handle; 258844961713Sgirish for (i = 0; i < num_chunks; i++, dma_bufp++) { 258944961713Sgirish bsize = dma_bufp->block_size; 259044961713Sgirish nblocks = dma_bufp->nblocks; 259144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 259244961713Sgirish "==> nxge_map_txdma_channel_buf_ring: dma chunk %d " 259344961713Sgirish "size %d dma_bufp $%p", 259444961713Sgirish i, sizeof (nxge_dma_common_t), dma_bufp)); 259544961713Sgirish 259644961713Sgirish for (j = 0; j < nblocks; j++) { 259744961713Sgirish tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle; 259844961713Sgirish dmap = &tx_msg_ring[index++].buf_dma; 259944961713Sgirish #ifdef TX_MEM_DEBUG 260044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 260144961713Sgirish "==> nxge_map_txdma_channel_buf_ring: j %d" 260244961713Sgirish "dmap $%p", i, dmap)); 260344961713Sgirish #endif 260444961713Sgirish nxge_setup_dma_common(dmap, dma_bufp, 1, 260544961713Sgirish bsize); 260644961713Sgirish } 260744961713Sgirish } 260844961713Sgirish 260944961713Sgirish if (i < num_chunks) { 261056d930aeSspeer status = NXGE_ERROR; 261144961713Sgirish goto nxge_map_txdma_channel_buf_ring_fail1; 261244961713Sgirish } 261344961713Sgirish 261444961713Sgirish *tx_desc_p = tx_ring_p; 261544961713Sgirish 261644961713Sgirish goto nxge_map_txdma_channel_buf_ring_exit; 261744961713Sgirish 261844961713Sgirish nxge_map_txdma_channel_buf_ring_fail1: 26191f8914d5Sml if (tx_ring_p->serial) { 26201f8914d5Sml nxge_serialize_destroy(tx_ring_p->serial); 26211f8914d5Sml tx_ring_p->serial = NULL; 26221f8914d5Sml } 26231f8914d5Sml 262444961713Sgirish index--; 262544961713Sgirish for (; index >= 0; index--) { 262656d930aeSspeer if (tx_msg_ring[index].dma_handle != NULL) { 262756d930aeSspeer ddi_dma_free_handle(&tx_msg_ring[index].dma_handle); 262844961713Sgirish } 262944961713Sgirish } 263044961713Sgirish MUTEX_DESTROY(&tx_ring_p->lock); 263156d930aeSspeer KMEM_FREE(tx_msg_ring, size); 263244961713Sgirish KMEM_FREE(tx_ring_p, sizeof (tx_ring_t)); 263344961713Sgirish 263456d930aeSspeer status = NXGE_ERROR; 263556d930aeSspeer 263644961713Sgirish nxge_map_txdma_channel_buf_ring_exit: 263744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 263844961713Sgirish "<== nxge_map_txdma_channel_buf_ring status 0x%x", status)); 263944961713Sgirish 264044961713Sgirish return (status); 264144961713Sgirish } 264244961713Sgirish 264344961713Sgirish /*ARGSUSED*/ 264444961713Sgirish static void 264544961713Sgirish nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p) 264644961713Sgirish { 264744961713Sgirish p_tx_msg_t tx_msg_ring; 264844961713Sgirish p_tx_msg_t tx_msg_p; 264944961713Sgirish int i; 265044961713Sgirish 265144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 265244961713Sgirish "==> nxge_unmap_txdma_channel_buf_ring")); 265344961713Sgirish if (tx_ring_p == NULL) { 265444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 265544961713Sgirish "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp")); 265644961713Sgirish return; 265744961713Sgirish } 265844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 265944961713Sgirish "==> nxge_unmap_txdma_channel_buf_ring: channel %d", 266044961713Sgirish tx_ring_p->tdc)); 266144961713Sgirish 266244961713Sgirish tx_msg_ring = tx_ring_p->tx_msg_ring; 2663678453a8Sspeer 2664678453a8Sspeer /* 2665678453a8Sspeer * Since the serialization thread, timer thread and 2666678453a8Sspeer * interrupt thread can all call the transmit reclaim, 2667678453a8Sspeer * the unmapping function needs to acquire the lock 2668678453a8Sspeer * to free those buffers which were transmitted 2669678453a8Sspeer * by the hardware already. 2670678453a8Sspeer */ 2671678453a8Sspeer MUTEX_ENTER(&tx_ring_p->lock); 2672678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2673678453a8Sspeer "==> nxge_unmap_txdma_channel_buf_ring (reclaim): " 2674678453a8Sspeer "channel %d", 2675678453a8Sspeer tx_ring_p->tdc)); 2676678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 2677678453a8Sspeer 267844961713Sgirish for (i = 0; i < tx_ring_p->tx_ring_size; i++) { 267944961713Sgirish tx_msg_p = &tx_msg_ring[i]; 268044961713Sgirish if (tx_msg_p->tx_message != NULL) { 268144961713Sgirish freemsg(tx_msg_p->tx_message); 268244961713Sgirish tx_msg_p->tx_message = NULL; 268344961713Sgirish } 268444961713Sgirish } 268544961713Sgirish 268644961713Sgirish for (i = 0; i < tx_ring_p->tx_ring_size; i++) { 268744961713Sgirish if (tx_msg_ring[i].dma_handle != NULL) { 268844961713Sgirish ddi_dma_free_handle(&tx_msg_ring[i].dma_handle); 268944961713Sgirish } 2690678453a8Sspeer tx_msg_ring[i].dma_handle = NULL; 269144961713Sgirish } 269244961713Sgirish 2693678453a8Sspeer MUTEX_EXIT(&tx_ring_p->lock); 2694678453a8Sspeer 26951f8914d5Sml if (tx_ring_p->serial) { 26961f8914d5Sml nxge_serialize_destroy(tx_ring_p->serial); 26971f8914d5Sml tx_ring_p->serial = NULL; 26981f8914d5Sml } 26991f8914d5Sml 270044961713Sgirish MUTEX_DESTROY(&tx_ring_p->lock); 270144961713Sgirish KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size); 270244961713Sgirish KMEM_FREE(tx_ring_p, sizeof (tx_ring_t)); 270344961713Sgirish 270444961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 270544961713Sgirish "<== nxge_unmap_txdma_channel_buf_ring")); 270644961713Sgirish } 270744961713Sgirish 270844961713Sgirish static nxge_status_t 2709678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel) 271044961713Sgirish { 271144961713Sgirish p_tx_rings_t tx_rings; 271244961713Sgirish p_tx_ring_t *tx_desc_rings; 271344961713Sgirish p_tx_mbox_areas_t tx_mbox_areas_p; 271444961713Sgirish p_tx_mbox_t *tx_mbox_p; 271544961713Sgirish nxge_status_t status = NXGE_OK; 271644961713Sgirish 271744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start")); 271844961713Sgirish 271944961713Sgirish tx_rings = nxgep->tx_rings; 272044961713Sgirish if (tx_rings == NULL) { 272144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 272244961713Sgirish "<== nxge_txdma_hw_start: NULL ring pointer")); 272344961713Sgirish return (NXGE_ERROR); 272444961713Sgirish } 272544961713Sgirish tx_desc_rings = tx_rings->rings; 272644961713Sgirish if (tx_desc_rings == NULL) { 272744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 272844961713Sgirish "<== nxge_txdma_hw_start: NULL ring pointers")); 272944961713Sgirish return (NXGE_ERROR); 273044961713Sgirish } 273144961713Sgirish 2732678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 2733678453a8Sspeer "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings)); 273444961713Sgirish 273544961713Sgirish tx_mbox_areas_p = nxgep->tx_mbox_areas_p; 273644961713Sgirish tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p; 273744961713Sgirish 2738678453a8Sspeer status = nxge_txdma_start_channel(nxgep, channel, 2739678453a8Sspeer (p_tx_ring_t)tx_desc_rings[channel], 2740678453a8Sspeer (p_tx_mbox_t)tx_mbox_p[channel]); 2741678453a8Sspeer if (status != NXGE_OK) { 2742678453a8Sspeer goto nxge_txdma_hw_start_fail1; 274344961713Sgirish } 274444961713Sgirish 274544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 274644961713Sgirish "tx_rings $%p rings $%p", 274744961713Sgirish nxgep->tx_rings, nxgep->tx_rings->rings)); 274844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 274944961713Sgirish "tx_rings $%p tx_desc_rings $%p", 275044961713Sgirish nxgep->tx_rings, tx_desc_rings)); 275144961713Sgirish 275244961713Sgirish goto nxge_txdma_hw_start_exit; 275344961713Sgirish 275444961713Sgirish nxge_txdma_hw_start_fail1: 275544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 275644961713Sgirish "==> nxge_txdma_hw_start: disable " 2757678453a8Sspeer "(status 0x%x channel %d)", status, channel)); 275844961713Sgirish 275944961713Sgirish nxge_txdma_hw_start_exit: 276044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 276144961713Sgirish "==> nxge_txdma_hw_start: (status 0x%x)", status)); 276244961713Sgirish 276344961713Sgirish return (status); 276444961713Sgirish } 276544961713Sgirish 2766678453a8Sspeer /* 2767678453a8Sspeer * nxge_txdma_start_channel 2768678453a8Sspeer * 2769678453a8Sspeer * Start a TDC. 2770678453a8Sspeer * 2771678453a8Sspeer * Arguments: 2772678453a8Sspeer * nxgep 2773678453a8Sspeer * channel The channel to start. 2774678453a8Sspeer * tx_ring_p channel's transmit descriptor ring. 2775678453a8Sspeer * tx_mbox_p channel' smailbox. 2776678453a8Sspeer * 2777678453a8Sspeer * Notes: 2778678453a8Sspeer * 2779678453a8Sspeer * NPI/NXGE function calls: 2780678453a8Sspeer * nxge_reset_txdma_channel() 2781678453a8Sspeer * nxge_init_txdma_channel_event_mask() 2782678453a8Sspeer * nxge_enable_txdma_channel() 2783678453a8Sspeer * 2784678453a8Sspeer * Registers accessed: 2785678453a8Sspeer * none directly (see functions above). 2786678453a8Sspeer * 2787678453a8Sspeer * Context: 2788678453a8Sspeer * Any domain 2789678453a8Sspeer */ 279044961713Sgirish static nxge_status_t 279144961713Sgirish nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel, 279244961713Sgirish p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p) 279344961713Sgirish 279444961713Sgirish { 279544961713Sgirish nxge_status_t status = NXGE_OK; 279644961713Sgirish 279744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 279844961713Sgirish "==> nxge_txdma_start_channel (channel %d)", channel)); 279944961713Sgirish /* 280044961713Sgirish * TXDMA/TXC must be in stopped state. 280144961713Sgirish */ 280244961713Sgirish (void) nxge_txdma_stop_inj_err(nxgep, channel); 280344961713Sgirish 280444961713Sgirish /* 280544961713Sgirish * Reset TXDMA channel 280644961713Sgirish */ 280744961713Sgirish tx_ring_p->tx_cs.value = 0; 280844961713Sgirish tx_ring_p->tx_cs.bits.ldw.rst = 1; 280944961713Sgirish status = nxge_reset_txdma_channel(nxgep, channel, 281044961713Sgirish tx_ring_p->tx_cs.value); 281144961713Sgirish if (status != NXGE_OK) { 281244961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 281344961713Sgirish "==> nxge_txdma_start_channel (channel %d)" 281444961713Sgirish " reset channel failed 0x%x", channel, status)); 281544961713Sgirish goto nxge_txdma_start_channel_exit; 281644961713Sgirish } 281744961713Sgirish 281844961713Sgirish /* 281944961713Sgirish * Initialize the TXDMA channel specific FZC control 282044961713Sgirish * configurations. These FZC registers are pertaining 282144961713Sgirish * to each TX channel (i.e. logical pages). 282244961713Sgirish */ 2823678453a8Sspeer if (!isLDOMguest(nxgep)) { 2824678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, channel, 2825678453a8Sspeer tx_ring_p, tx_mbox_p); 2826678453a8Sspeer if (status != NXGE_OK) { 2827678453a8Sspeer goto nxge_txdma_start_channel_exit; 2828678453a8Sspeer } 282944961713Sgirish } 283044961713Sgirish 283144961713Sgirish /* 283244961713Sgirish * Initialize the event masks. 283344961713Sgirish */ 283444961713Sgirish tx_ring_p->tx_evmask.value = 0; 283544961713Sgirish status = nxge_init_txdma_channel_event_mask(nxgep, 2836678453a8Sspeer channel, &tx_ring_p->tx_evmask); 283744961713Sgirish if (status != NXGE_OK) { 283844961713Sgirish goto nxge_txdma_start_channel_exit; 283944961713Sgirish } 284044961713Sgirish 284144961713Sgirish /* 284244961713Sgirish * Load TXDMA descriptors, buffers, mailbox, 284344961713Sgirish * initialise the DMA channels and 284444961713Sgirish * enable each DMA channel. 284544961713Sgirish */ 284644961713Sgirish status = nxge_enable_txdma_channel(nxgep, channel, 284744961713Sgirish tx_ring_p, tx_mbox_p); 284844961713Sgirish if (status != NXGE_OK) { 284944961713Sgirish goto nxge_txdma_start_channel_exit; 285044961713Sgirish } 285144961713Sgirish 285244961713Sgirish nxge_txdma_start_channel_exit: 285344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel")); 285444961713Sgirish 285544961713Sgirish return (status); 285644961713Sgirish } 285744961713Sgirish 2858678453a8Sspeer /* 2859678453a8Sspeer * nxge_txdma_stop_channel 2860678453a8Sspeer * 2861678453a8Sspeer * Stop a TDC. 2862678453a8Sspeer * 2863678453a8Sspeer * Arguments: 2864678453a8Sspeer * nxgep 2865678453a8Sspeer * channel The channel to stop. 2866678453a8Sspeer * tx_ring_p channel's transmit descriptor ring. 2867678453a8Sspeer * tx_mbox_p channel' smailbox. 2868678453a8Sspeer * 2869678453a8Sspeer * Notes: 2870678453a8Sspeer * 2871678453a8Sspeer * NPI/NXGE function calls: 2872678453a8Sspeer * nxge_txdma_stop_inj_err() 2873678453a8Sspeer * nxge_reset_txdma_channel() 2874678453a8Sspeer * nxge_init_txdma_channel_event_mask() 2875678453a8Sspeer * nxge_init_txdma_channel_cntl_stat() 2876678453a8Sspeer * nxge_disable_txdma_channel() 2877678453a8Sspeer * 2878678453a8Sspeer * Registers accessed: 2879678453a8Sspeer * none directly (see functions above). 2880678453a8Sspeer * 2881678453a8Sspeer * Context: 2882678453a8Sspeer * Any domain 2883678453a8Sspeer */ 288444961713Sgirish /*ARGSUSED*/ 288544961713Sgirish static nxge_status_t 2886678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel) 288744961713Sgirish { 2888678453a8Sspeer p_tx_ring_t tx_ring_p; 2889678453a8Sspeer int status = NXGE_OK; 289044961713Sgirish 289144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 289244961713Sgirish "==> nxge_txdma_stop_channel: channel %d", channel)); 289344961713Sgirish 289444961713Sgirish /* 289544961713Sgirish * Stop (disable) TXDMA and TXC (if stop bit is set 289644961713Sgirish * and STOP_N_GO bit not set, the TXDMA reset state will 289744961713Sgirish * not be set if reset TXDMA. 289844961713Sgirish */ 289944961713Sgirish (void) nxge_txdma_stop_inj_err(nxgep, channel); 290044961713Sgirish 2901678453a8Sspeer tx_ring_p = nxgep->tx_rings->rings[channel]; 2902678453a8Sspeer 290344961713Sgirish /* 290444961713Sgirish * Reset TXDMA channel 290544961713Sgirish */ 290644961713Sgirish tx_ring_p->tx_cs.value = 0; 290744961713Sgirish tx_ring_p->tx_cs.bits.ldw.rst = 1; 290844961713Sgirish status = nxge_reset_txdma_channel(nxgep, channel, 290944961713Sgirish tx_ring_p->tx_cs.value); 291044961713Sgirish if (status != NXGE_OK) { 291144961713Sgirish goto nxge_txdma_stop_channel_exit; 291244961713Sgirish } 291344961713Sgirish 291444961713Sgirish #ifdef HARDWARE_REQUIRED 291544961713Sgirish /* Set up the interrupt event masks. */ 291644961713Sgirish tx_ring_p->tx_evmask.value = 0; 291744961713Sgirish status = nxge_init_txdma_channel_event_mask(nxgep, 291844961713Sgirish channel, &tx_ring_p->tx_evmask); 291944961713Sgirish if (status != NXGE_OK) { 292044961713Sgirish goto nxge_txdma_stop_channel_exit; 292144961713Sgirish } 292244961713Sgirish 292344961713Sgirish /* Initialize the DMA control and status register */ 292444961713Sgirish tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL; 292544961713Sgirish status = nxge_init_txdma_channel_cntl_stat(nxgep, channel, 292644961713Sgirish tx_ring_p->tx_cs.value); 292744961713Sgirish if (status != NXGE_OK) { 292844961713Sgirish goto nxge_txdma_stop_channel_exit; 292944961713Sgirish } 293044961713Sgirish 2931678453a8Sspeer tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 2932678453a8Sspeer 293344961713Sgirish /* Disable channel */ 293444961713Sgirish status = nxge_disable_txdma_channel(nxgep, channel, 2935678453a8Sspeer tx_ring_p, tx_mbox_p); 293644961713Sgirish if (status != NXGE_OK) { 293744961713Sgirish goto nxge_txdma_start_channel_exit; 293844961713Sgirish } 293944961713Sgirish 294044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 294144961713Sgirish "==> nxge_txdma_stop_channel: event done")); 294244961713Sgirish 294344961713Sgirish #endif 294444961713Sgirish 294544961713Sgirish nxge_txdma_stop_channel_exit: 294644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel")); 294744961713Sgirish return (status); 294844961713Sgirish } 294944961713Sgirish 2950678453a8Sspeer /* 2951678453a8Sspeer * nxge_txdma_get_ring 2952678453a8Sspeer * 2953678453a8Sspeer * Get the ring for a TDC. 2954678453a8Sspeer * 2955678453a8Sspeer * Arguments: 2956678453a8Sspeer * nxgep 2957678453a8Sspeer * channel 2958678453a8Sspeer * 2959678453a8Sspeer * Notes: 2960678453a8Sspeer * 2961678453a8Sspeer * NPI/NXGE function calls: 2962678453a8Sspeer * 2963678453a8Sspeer * Registers accessed: 2964678453a8Sspeer * 2965678453a8Sspeer * Context: 2966678453a8Sspeer * Any domain 2967678453a8Sspeer */ 296844961713Sgirish static p_tx_ring_t 296944961713Sgirish nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel) 297044961713Sgirish { 2971678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 2972678453a8Sspeer int tdc; 297344961713Sgirish 297444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring")); 297544961713Sgirish 2976678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 297744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 2978678453a8Sspeer "<== nxge_txdma_get_ring: NULL ring pointer(s)")); 2979678453a8Sspeer goto return_null; 2980678453a8Sspeer } 2981678453a8Sspeer 2982678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 2983678453a8Sspeer if ((1 << tdc) & set->owned.map) { 2984678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 2985678453a8Sspeer if (ring) { 2986678453a8Sspeer if (channel == ring->tdc) { 2987678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2988678453a8Sspeer "<== nxge_txdma_get_ring: " 2989678453a8Sspeer "tdc %d ring $%p", tdc, ring)); 2990678453a8Sspeer return (ring); 2991678453a8Sspeer } 2992678453a8Sspeer } 299344961713Sgirish } 299444961713Sgirish } 299544961713Sgirish 2996678453a8Sspeer return_null: 2997678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: " 2998678453a8Sspeer "ring not found")); 2999678453a8Sspeer 300044961713Sgirish return (NULL); 300144961713Sgirish } 300244961713Sgirish 3003678453a8Sspeer /* 3004678453a8Sspeer * nxge_txdma_get_mbox 3005678453a8Sspeer * 3006678453a8Sspeer * Get the mailbox for a TDC. 3007678453a8Sspeer * 3008678453a8Sspeer * Arguments: 3009678453a8Sspeer * nxgep 3010678453a8Sspeer * channel 3011678453a8Sspeer * 3012678453a8Sspeer * Notes: 3013678453a8Sspeer * 3014678453a8Sspeer * NPI/NXGE function calls: 3015678453a8Sspeer * 3016678453a8Sspeer * Registers accessed: 3017678453a8Sspeer * 3018678453a8Sspeer * Context: 3019678453a8Sspeer * Any domain 3020678453a8Sspeer */ 302144961713Sgirish static p_tx_mbox_t 302244961713Sgirish nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel) 302344961713Sgirish { 3024678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3025678453a8Sspeer int tdc; 302644961713Sgirish 302744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox")); 302844961713Sgirish 3029678453a8Sspeer if (nxgep->tx_mbox_areas_p == 0 || 3030678453a8Sspeer nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) { 3031678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3032678453a8Sspeer "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)")); 3033678453a8Sspeer goto return_null; 303444961713Sgirish } 303544961713Sgirish 3036678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 3037678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3038678453a8Sspeer "<== nxge_txdma_get_mbox: NULL ring pointer(s)")); 3039678453a8Sspeer goto return_null; 3040678453a8Sspeer } 3041678453a8Sspeer 3042678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3043678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3044678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3045678453a8Sspeer if (ring) { 3046678453a8Sspeer if (channel == ring->tdc) { 3047678453a8Sspeer tx_mbox_t *mailbox = nxgep-> 3048678453a8Sspeer tx_mbox_areas_p-> 3049678453a8Sspeer txmbox_areas_p[tdc]; 3050678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3051678453a8Sspeer "<== nxge_txdma_get_mbox: tdc %d " 3052678453a8Sspeer "ring $%p", tdc, mailbox)); 3053678453a8Sspeer return (mailbox); 3054678453a8Sspeer } 3055678453a8Sspeer } 305644961713Sgirish } 305744961713Sgirish } 305844961713Sgirish 3059678453a8Sspeer return_null: 3060678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: " 3061678453a8Sspeer "mailbox not found")); 3062678453a8Sspeer 306344961713Sgirish return (NULL); 306444961713Sgirish } 306544961713Sgirish 3066678453a8Sspeer /* 3067678453a8Sspeer * nxge_tx_err_evnts 3068678453a8Sspeer * 3069678453a8Sspeer * Recover a TDC. 3070678453a8Sspeer * 3071678453a8Sspeer * Arguments: 3072678453a8Sspeer * nxgep 3073678453a8Sspeer * index The index to the TDC ring. 3074678453a8Sspeer * ldvp Used to get the channel number ONLY. 3075678453a8Sspeer * cs A copy of the bits from TX_CS. 3076678453a8Sspeer * 3077678453a8Sspeer * Notes: 3078678453a8Sspeer * Calling tree: 3079678453a8Sspeer * nxge_tx_intr() 3080678453a8Sspeer * 3081678453a8Sspeer * NPI/NXGE function calls: 3082678453a8Sspeer * npi_txdma_ring_error_get() 3083678453a8Sspeer * npi_txdma_inj_par_error_get() 3084678453a8Sspeer * nxge_txdma_fatal_err_recover() 3085678453a8Sspeer * 3086678453a8Sspeer * Registers accessed: 3087678453a8Sspeer * TX_RNG_ERR_LOGH DMC+0x40048 Transmit Ring Error Log High 3088678453a8Sspeer * TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low 3089678453a8Sspeer * TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error 3090678453a8Sspeer * 3091678453a8Sspeer * Context: 3092678453a8Sspeer * Any domain XXX Remove code which accesses TDMC_INJ_PAR_ERR. 3093678453a8Sspeer */ 309444961713Sgirish /*ARGSUSED*/ 309544961713Sgirish static nxge_status_t 309644961713Sgirish nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs) 309744961713Sgirish { 309844961713Sgirish npi_handle_t handle; 309944961713Sgirish npi_status_t rs; 310044961713Sgirish uint8_t channel; 310144961713Sgirish p_tx_ring_t *tx_rings; 310244961713Sgirish p_tx_ring_t tx_ring_p; 310344961713Sgirish p_nxge_tx_ring_stats_t tdc_stats; 310444961713Sgirish boolean_t txchan_fatal = B_FALSE; 310544961713Sgirish nxge_status_t status = NXGE_OK; 310644961713Sgirish tdmc_inj_par_err_t par_err; 310744961713Sgirish uint32_t value; 310844961713Sgirish 3109678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts")); 311044961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 311144961713Sgirish channel = ldvp->channel; 311244961713Sgirish 311344961713Sgirish tx_rings = nxgep->tx_rings->rings; 311444961713Sgirish tx_ring_p = tx_rings[index]; 311544961713Sgirish tdc_stats = tx_ring_p->tdc_stats; 311644961713Sgirish if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) || 311744961713Sgirish (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) || 311844961713Sgirish (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) { 311944961713Sgirish if ((rs = npi_txdma_ring_error_get(handle, channel, 312044961713Sgirish &tdc_stats->errlog)) != NPI_SUCCESS) 312144961713Sgirish return (NXGE_ERROR | rs); 312244961713Sgirish } 312344961713Sgirish 312444961713Sgirish if (cs.bits.ldw.mbox_err) { 312544961713Sgirish tdc_stats->mbox_err++; 312644961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 312744961713Sgirish NXGE_FM_EREPORT_TDMC_MBOX_ERR); 312844961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 312944961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 313044961713Sgirish "fatal error: mailbox", channel)); 313144961713Sgirish txchan_fatal = B_TRUE; 313244961713Sgirish } 313344961713Sgirish if (cs.bits.ldw.pkt_size_err) { 313444961713Sgirish tdc_stats->pkt_size_err++; 313544961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 313644961713Sgirish NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR); 313744961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 313844961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 313944961713Sgirish "fatal error: pkt_size_err", channel)); 314044961713Sgirish txchan_fatal = B_TRUE; 314144961713Sgirish } 314244961713Sgirish if (cs.bits.ldw.tx_ring_oflow) { 314344961713Sgirish tdc_stats->tx_ring_oflow++; 314444961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 314544961713Sgirish NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW); 314644961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 314744961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 314844961713Sgirish "fatal error: tx_ring_oflow", channel)); 314944961713Sgirish txchan_fatal = B_TRUE; 315044961713Sgirish } 315144961713Sgirish if (cs.bits.ldw.pref_buf_par_err) { 315244961713Sgirish tdc_stats->pre_buf_par_err++; 315344961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 315444961713Sgirish NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR); 315544961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 315644961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 315744961713Sgirish "fatal error: pre_buf_par_err", channel)); 315844961713Sgirish /* Clear error injection source for parity error */ 315944961713Sgirish (void) npi_txdma_inj_par_error_get(handle, &value); 316044961713Sgirish par_err.value = value; 316144961713Sgirish par_err.bits.ldw.inject_parity_error &= ~(1 << channel); 316244961713Sgirish (void) npi_txdma_inj_par_error_set(handle, par_err.value); 316344961713Sgirish txchan_fatal = B_TRUE; 316444961713Sgirish } 316544961713Sgirish if (cs.bits.ldw.nack_pref) { 316644961713Sgirish tdc_stats->nack_pref++; 316744961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 316844961713Sgirish NXGE_FM_EREPORT_TDMC_NACK_PREF); 316944961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 317044961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 317144961713Sgirish "fatal error: nack_pref", channel)); 317244961713Sgirish txchan_fatal = B_TRUE; 317344961713Sgirish } 317444961713Sgirish if (cs.bits.ldw.nack_pkt_rd) { 317544961713Sgirish tdc_stats->nack_pkt_rd++; 317644961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 317744961713Sgirish NXGE_FM_EREPORT_TDMC_NACK_PKT_RD); 317844961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 317944961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 318044961713Sgirish "fatal error: nack_pkt_rd", channel)); 318144961713Sgirish txchan_fatal = B_TRUE; 318244961713Sgirish } 318344961713Sgirish if (cs.bits.ldw.conf_part_err) { 318444961713Sgirish tdc_stats->conf_part_err++; 318544961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 318644961713Sgirish NXGE_FM_EREPORT_TDMC_CONF_PART_ERR); 318744961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 318844961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 318944961713Sgirish "fatal error: config_partition_err", channel)); 319044961713Sgirish txchan_fatal = B_TRUE; 319144961713Sgirish } 319244961713Sgirish if (cs.bits.ldw.pkt_prt_err) { 319344961713Sgirish tdc_stats->pkt_part_err++; 319444961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 319544961713Sgirish NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR); 319644961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 319744961713Sgirish "==> nxge_tx_err_evnts(channel %d): " 319844961713Sgirish "fatal error: pkt_prt_err", channel)); 319944961713Sgirish txchan_fatal = B_TRUE; 320044961713Sgirish } 320144961713Sgirish 320244961713Sgirish /* Clear error injection source in case this is an injected error */ 320344961713Sgirish TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0); 320444961713Sgirish 320544961713Sgirish if (txchan_fatal) { 320644961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 320744961713Sgirish " nxge_tx_err_evnts: " 320844961713Sgirish " fatal error on channel %d cs 0x%llx\n", 320944961713Sgirish channel, cs.value)); 321044961713Sgirish status = nxge_txdma_fatal_err_recover(nxgep, channel, 321144961713Sgirish tx_ring_p); 321244961713Sgirish if (status == NXGE_OK) { 321344961713Sgirish FM_SERVICE_RESTORED(nxgep); 321444961713Sgirish } 321544961713Sgirish } 321644961713Sgirish 3217678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts")); 321844961713Sgirish 321944961713Sgirish return (status); 322044961713Sgirish } 322144961713Sgirish 322244961713Sgirish static nxge_status_t 3223678453a8Sspeer nxge_txdma_fatal_err_recover( 3224678453a8Sspeer p_nxge_t nxgep, 3225678453a8Sspeer uint16_t channel, 3226678453a8Sspeer p_tx_ring_t tx_ring_p) 322744961713Sgirish { 322844961713Sgirish npi_handle_t handle; 322944961713Sgirish npi_status_t rs = NPI_SUCCESS; 323044961713Sgirish p_tx_mbox_t tx_mbox_p; 323144961713Sgirish nxge_status_t status = NXGE_OK; 323244961713Sgirish 323344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover")); 323444961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 323544961713Sgirish "Recovering from TxDMAChannel#%d error...", channel)); 323644961713Sgirish 323744961713Sgirish /* 323844961713Sgirish * Stop the dma channel waits for the stop done. 323944961713Sgirish * If the stop done bit is not set, then create 324044961713Sgirish * an error. 324144961713Sgirish */ 324244961713Sgirish 324344961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 324444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop...")); 324544961713Sgirish MUTEX_ENTER(&tx_ring_p->lock); 324644961713Sgirish rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel); 324744961713Sgirish if (rs != NPI_SUCCESS) { 324844961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 324944961713Sgirish "==> nxge_txdma_fatal_err_recover (channel %d): " 325044961713Sgirish "stop failed ", channel)); 325144961713Sgirish goto fail; 325244961713Sgirish } 325344961713Sgirish 325444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim...")); 325544961713Sgirish (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 325644961713Sgirish 325744961713Sgirish /* 325844961713Sgirish * Reset TXDMA channel 325944961713Sgirish */ 326044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset...")); 326144961713Sgirish if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) != 326244961713Sgirish NPI_SUCCESS) { 326344961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 326444961713Sgirish "==> nxge_txdma_fatal_err_recover (channel %d)" 326544961713Sgirish " reset channel failed 0x%x", channel, rs)); 326644961713Sgirish goto fail; 326744961713Sgirish } 326844961713Sgirish 326944961713Sgirish /* 327044961713Sgirish * Reset the tail (kick) register to 0. 327144961713Sgirish * (Hardware will not reset it. Tx overflow fatal 327244961713Sgirish * error if tail is not set to 0 after reset! 327344961713Sgirish */ 327444961713Sgirish TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0); 327544961713Sgirish 327644961713Sgirish /* Restart TXDMA channel */ 327744961713Sgirish 3278678453a8Sspeer if (!isLDOMguest(nxgep)) { 3279678453a8Sspeer tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel); 328044961713Sgirish 3281678453a8Sspeer // XXX This is a problem in HIO! 3282678453a8Sspeer /* 3283678453a8Sspeer * Initialize the TXDMA channel specific FZC control 3284678453a8Sspeer * configurations. These FZC registers are pertaining 3285678453a8Sspeer * to each TX channel (i.e. logical pages). 3286678453a8Sspeer */ 3287678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart...")); 3288678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, channel, 3289678453a8Sspeer tx_ring_p, tx_mbox_p); 3290678453a8Sspeer if (status != NXGE_OK) 3291678453a8Sspeer goto fail; 3292678453a8Sspeer } 329344961713Sgirish 329444961713Sgirish /* 329544961713Sgirish * Initialize the event masks. 329644961713Sgirish */ 329744961713Sgirish tx_ring_p->tx_evmask.value = 0; 329844961713Sgirish status = nxge_init_txdma_channel_event_mask(nxgep, channel, 329944961713Sgirish &tx_ring_p->tx_evmask); 330044961713Sgirish if (status != NXGE_OK) 330144961713Sgirish goto fail; 330244961713Sgirish 330344961713Sgirish tx_ring_p->wr_index_wrap = B_FALSE; 330444961713Sgirish tx_ring_p->wr_index = 0; 330544961713Sgirish tx_ring_p->rd_index = 0; 330644961713Sgirish 330744961713Sgirish /* 330844961713Sgirish * Load TXDMA descriptors, buffers, mailbox, 330944961713Sgirish * initialise the DMA channels and 331044961713Sgirish * enable each DMA channel. 331144961713Sgirish */ 331244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable...")); 331344961713Sgirish status = nxge_enable_txdma_channel(nxgep, channel, 331444961713Sgirish tx_ring_p, tx_mbox_p); 331544961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 331644961713Sgirish if (status != NXGE_OK) 331744961713Sgirish goto fail; 331844961713Sgirish 331944961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 332044961713Sgirish "Recovery Successful, TxDMAChannel#%d Restored", 332144961713Sgirish channel)); 332244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover")); 332344961713Sgirish 332444961713Sgirish return (NXGE_OK); 332544961713Sgirish 332644961713Sgirish fail: 332744961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 332844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 332944961713Sgirish "nxge_txdma_fatal_err_recover (channel %d): " 333044961713Sgirish "failed to recover this txdma channel", channel)); 333144961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed")); 333244961713Sgirish 333344961713Sgirish return (status); 333444961713Sgirish } 333544961713Sgirish 3336678453a8Sspeer /* 3337678453a8Sspeer * nxge_tx_port_fatal_err_recover 3338678453a8Sspeer * 3339678453a8Sspeer * Attempt to recover from a fatal port error. 3340678453a8Sspeer * 3341678453a8Sspeer * Arguments: 3342678453a8Sspeer * nxgep 3343678453a8Sspeer * 3344678453a8Sspeer * Notes: 3345678453a8Sspeer * How would a guest do this? 3346678453a8Sspeer * 3347678453a8Sspeer * NPI/NXGE function calls: 3348678453a8Sspeer * 3349678453a8Sspeer * Registers accessed: 3350678453a8Sspeer * 3351678453a8Sspeer * Context: 3352678453a8Sspeer * Service domain 3353678453a8Sspeer */ 335444961713Sgirish nxge_status_t 335544961713Sgirish nxge_tx_port_fatal_err_recover(p_nxge_t nxgep) 335644961713Sgirish { 3357678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3358678453a8Sspeer nxge_channel_t tdc; 3359678453a8Sspeer 3360678453a8Sspeer tx_ring_t *ring; 3361678453a8Sspeer tx_mbox_t *mailbox; 3362678453a8Sspeer 336344961713Sgirish npi_handle_t handle; 3364678453a8Sspeer nxge_status_t status; 3365678453a8Sspeer npi_status_t rs; 336644961713Sgirish 336744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover")); 336844961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3369678453a8Sspeer "Recovering from TxPort error...")); 337044961713Sgirish 3371678453a8Sspeer if (isLDOMguest(nxgep)) { 3372678453a8Sspeer return (NXGE_OK); 337344961713Sgirish } 337444961713Sgirish 3375678453a8Sspeer if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { 3376678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3377678453a8Sspeer "<== nxge_tx_port_fatal_err_recover: not initialized")); 3378678453a8Sspeer return (NXGE_ERROR); 337944961713Sgirish } 338044961713Sgirish 3381678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 3382678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3383678453a8Sspeer "<== nxge_tx_port_fatal_err_recover: " 3384678453a8Sspeer "NULL ring pointer(s)")); 3385678453a8Sspeer return (NXGE_ERROR); 3386678453a8Sspeer } 338744961713Sgirish 3388678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3389678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3390678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3391678453a8Sspeer if (ring) 3392678453a8Sspeer MUTEX_ENTER(&ring->lock); 339344961713Sgirish } 339444961713Sgirish } 339544961713Sgirish 3396678453a8Sspeer handle = NXGE_DEV_NPI_HANDLE(nxgep); 3397678453a8Sspeer 339844961713Sgirish /* 3399678453a8Sspeer * Stop all the TDCs owned by us. 3400678453a8Sspeer * (The shared TDCs will have been stopped by their owners.) 340144961713Sgirish */ 3402678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3403678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3404678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3405678453a8Sspeer if (ring) { 3406678453a8Sspeer rs = npi_txdma_channel_control 3407678453a8Sspeer (handle, TXDMA_STOP, tdc); 3408678453a8Sspeer if (rs != NPI_SUCCESS) { 3409678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3410678453a8Sspeer "nxge_tx_port_fatal_err_recover " 3411678453a8Sspeer "(channel %d): stop failed ", tdc)); 3412678453a8Sspeer goto fail; 3413678453a8Sspeer } 3414678453a8Sspeer } 341544961713Sgirish } 3416678453a8Sspeer } 341744961713Sgirish 3418678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs...")); 341944961713Sgirish 3420678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3421678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3422678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3423678453a8Sspeer if (ring) 3424678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, ring, 0); 3425678453a8Sspeer } 342644961713Sgirish } 342744961713Sgirish 342844961713Sgirish /* 3429678453a8Sspeer * Reset all the TDCs. 343044961713Sgirish */ 3431678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs...")); 3432678453a8Sspeer 3433678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3434678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3435678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3436678453a8Sspeer if (ring) { 3437678453a8Sspeer if ((rs = npi_txdma_channel_control 3438678453a8Sspeer (handle, TXDMA_RESET, tdc)) 3439678453a8Sspeer != NPI_SUCCESS) { 3440678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3441678453a8Sspeer "nxge_tx_port_fatal_err_recover " 3442678453a8Sspeer "(channel %d) reset channel " 3443678453a8Sspeer "failed 0x%x", tdc, rs)); 3444678453a8Sspeer goto fail; 3445678453a8Sspeer } 3446678453a8Sspeer } 3447678453a8Sspeer /* 3448678453a8Sspeer * Reset the tail (kick) register to 0. 3449678453a8Sspeer * (Hardware will not reset it. Tx overflow fatal 3450678453a8Sspeer * error if tail is not set to 0 after reset! 3451678453a8Sspeer */ 3452678453a8Sspeer TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0); 345344961713Sgirish } 3454678453a8Sspeer } 345544961713Sgirish 3456678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs...")); 3457678453a8Sspeer 3458678453a8Sspeer /* Restart all the TDCs */ 3459678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3460678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3461678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3462678453a8Sspeer if (ring) { 3463678453a8Sspeer mailbox = nxge_txdma_get_mbox(nxgep, tdc); 3464678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, tdc, 3465678453a8Sspeer ring, mailbox); 3466678453a8Sspeer ring->tx_evmask.value = 0; 3467678453a8Sspeer /* 3468678453a8Sspeer * Initialize the event masks. 3469678453a8Sspeer */ 3470678453a8Sspeer status = nxge_init_txdma_channel_event_mask 3471678453a8Sspeer (nxgep, tdc, &ring->tx_evmask); 3472678453a8Sspeer 3473678453a8Sspeer ring->wr_index_wrap = B_FALSE; 3474678453a8Sspeer ring->wr_index = 0; 3475678453a8Sspeer ring->rd_index = 0; 3476678453a8Sspeer 3477678453a8Sspeer if (status != NXGE_OK) 3478678453a8Sspeer goto fail; 3479678453a8Sspeer if (status != NXGE_OK) 3480678453a8Sspeer goto fail; 3481678453a8Sspeer } 3482678453a8Sspeer } 348344961713Sgirish } 348444961713Sgirish 3485678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs...")); 348644961713Sgirish 3487678453a8Sspeer /* Re-enable all the TDCs */ 3488678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3489678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3490678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3491678453a8Sspeer if (ring) { 3492678453a8Sspeer mailbox = nxge_txdma_get_mbox(nxgep, tdc); 3493678453a8Sspeer status = nxge_enable_txdma_channel(nxgep, tdc, 3494678453a8Sspeer ring, mailbox); 3495678453a8Sspeer if (status != NXGE_OK) 3496678453a8Sspeer goto fail; 3497678453a8Sspeer } 349844961713Sgirish } 349944961713Sgirish } 350044961713Sgirish 3501678453a8Sspeer /* 3502678453a8Sspeer * Unlock all the TDCs. 3503678453a8Sspeer */ 3504678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3505678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3506678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3507678453a8Sspeer if (ring) 3508678453a8Sspeer MUTEX_EXIT(&ring->lock); 350944961713Sgirish } 351044961713Sgirish } 351144961713Sgirish 3512678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded")); 351344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover")); 351444961713Sgirish 351544961713Sgirish return (NXGE_OK); 351644961713Sgirish 351744961713Sgirish fail: 3518678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3519678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3520678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3521678453a8Sspeer if (ring) 3522678453a8Sspeer MUTEX_EXIT(&ring->lock); 352344961713Sgirish } 352444961713Sgirish } 352544961713Sgirish 3526678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed")); 3527678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover")); 352844961713Sgirish 352944961713Sgirish return (status); 353044961713Sgirish } 353144961713Sgirish 3532678453a8Sspeer /* 3533678453a8Sspeer * nxge_txdma_inject_err 3534678453a8Sspeer * 3535678453a8Sspeer * Inject an error into a TDC. 3536678453a8Sspeer * 3537678453a8Sspeer * Arguments: 3538678453a8Sspeer * nxgep 3539678453a8Sspeer * err_id The error to inject. 3540678453a8Sspeer * chan The channel to inject into. 3541678453a8Sspeer * 3542678453a8Sspeer * Notes: 3543678453a8Sspeer * This is called from nxge_main.c:nxge_err_inject() 3544678453a8Sspeer * Has this ioctl ever been used? 3545678453a8Sspeer * 3546678453a8Sspeer * NPI/NXGE function calls: 3547678453a8Sspeer * npi_txdma_inj_par_error_get() 3548678453a8Sspeer * npi_txdma_inj_par_error_set() 3549678453a8Sspeer * 3550678453a8Sspeer * Registers accessed: 3551678453a8Sspeer * TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error 3552678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 3553678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 3554678453a8Sspeer * 3555678453a8Sspeer * Context: 3556678453a8Sspeer * Service domain 3557678453a8Sspeer */ 355844961713Sgirish void 355944961713Sgirish nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan) 356044961713Sgirish { 356144961713Sgirish tdmc_intr_dbg_t tdi; 356244961713Sgirish tdmc_inj_par_err_t par_err; 356344961713Sgirish uint32_t value; 356444961713Sgirish npi_handle_t handle; 356544961713Sgirish 356644961713Sgirish switch (err_id) { 356744961713Sgirish 356844961713Sgirish case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR: 356944961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 357044961713Sgirish /* Clear error injection source for parity error */ 357144961713Sgirish (void) npi_txdma_inj_par_error_get(handle, &value); 357244961713Sgirish par_err.value = value; 357344961713Sgirish par_err.bits.ldw.inject_parity_error &= ~(1 << chan); 357444961713Sgirish (void) npi_txdma_inj_par_error_set(handle, par_err.value); 357544961713Sgirish 357644961713Sgirish par_err.bits.ldw.inject_parity_error = (1 << chan); 357744961713Sgirish (void) npi_txdma_inj_par_error_get(handle, &value); 357844961713Sgirish par_err.value = value; 357944961713Sgirish par_err.bits.ldw.inject_parity_error |= (1 << chan); 358044961713Sgirish cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n", 358144961713Sgirish (unsigned long long)par_err.value); 358244961713Sgirish (void) npi_txdma_inj_par_error_set(handle, par_err.value); 358344961713Sgirish break; 358444961713Sgirish 358544961713Sgirish case NXGE_FM_EREPORT_TDMC_MBOX_ERR: 358644961713Sgirish case NXGE_FM_EREPORT_TDMC_NACK_PREF: 358744961713Sgirish case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD: 358844961713Sgirish case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR: 358944961713Sgirish case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW: 359044961713Sgirish case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR: 359144961713Sgirish case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR: 359244961713Sgirish TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG, 359344961713Sgirish chan, &tdi.value); 359444961713Sgirish if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR) 359544961713Sgirish tdi.bits.ldw.pref_buf_par_err = 1; 359644961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR) 359744961713Sgirish tdi.bits.ldw.mbox_err = 1; 359844961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF) 359944961713Sgirish tdi.bits.ldw.nack_pref = 1; 360044961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD) 360144961713Sgirish tdi.bits.ldw.nack_pkt_rd = 1; 360244961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR) 360344961713Sgirish tdi.bits.ldw.pkt_size_err = 1; 360444961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW) 360544961713Sgirish tdi.bits.ldw.tx_ring_oflow = 1; 360644961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR) 360744961713Sgirish tdi.bits.ldw.conf_part_err = 1; 360844961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR) 360944961713Sgirish tdi.bits.ldw.pkt_part_err = 1; 3610adfcba55Sjoycey #if defined(__i386) 3611adfcba55Sjoycey cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n", 3612adfcba55Sjoycey tdi.value); 3613adfcba55Sjoycey #else 361444961713Sgirish cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n", 361544961713Sgirish tdi.value); 3616adfcba55Sjoycey #endif 361744961713Sgirish TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, 361844961713Sgirish chan, tdi.value); 361944961713Sgirish 362044961713Sgirish break; 362144961713Sgirish } 362244961713Sgirish } 3623