16f45ec7bSml29623 /* 26f45ec7bSml29623 * CDDL HEADER START 36f45ec7bSml29623 * 46f45ec7bSml29623 * The contents of this file are subject to the terms of the 56f45ec7bSml29623 * Common Development and Distribution License (the "License"). 66f45ec7bSml29623 * You may not use this file except in compliance with the License. 76f45ec7bSml29623 * 86f45ec7bSml29623 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96f45ec7bSml29623 * or http://www.opensolaris.org/os/licensing. 106f45ec7bSml29623 * See the License for the specific language governing permissions 116f45ec7bSml29623 * and limitations under the License. 126f45ec7bSml29623 * 136f45ec7bSml29623 * When distributing Covered Code, include this CDDL HEADER in each 146f45ec7bSml29623 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156f45ec7bSml29623 * If applicable, add the following below this CDDL HEADER, with the 166f45ec7bSml29623 * fields enclosed by brackets "[]" replaced with your own identifying 176f45ec7bSml29623 * information: Portions Copyright [yyyy] [name of copyright owner] 186f45ec7bSml29623 * 196f45ec7bSml29623 * CDDL HEADER END 206f45ec7bSml29623 */ 21952a2464SMichael Speer 226f45ec7bSml29623 /* 230dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 246f45ec7bSml29623 * Use is subject to license terms. 256f45ec7bSml29623 */ 266f45ec7bSml29623 276f45ec7bSml29623 #include <sys/nxge/nxge_impl.h> 286f45ec7bSml29623 #include <sys/nxge/nxge_txdma.h> 29678453a8Sspeer #include <sys/nxge/nxge_hio.h> 30678453a8Sspeer #include <npi_tx_rd64.h> 31678453a8Sspeer #include <npi_tx_wr64.h> 326f45ec7bSml29623 #include <sys/llc1.h> 336f45ec7bSml29623 346f45ec7bSml29623 uint32_t nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT; 35da14cebeSEric Cheng uint32_t nxge_tx_minfree = 64; 366f45ec7bSml29623 uint32_t nxge_tx_intr_thres = 0; 376f45ec7bSml29623 uint32_t nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS; 386f45ec7bSml29623 uint32_t nxge_tx_tiny_pack = 1; 396f45ec7bSml29623 uint32_t nxge_tx_use_bcopy = 1; 406f45ec7bSml29623 416f45ec7bSml29623 extern uint32_t nxge_tx_ring_size; 426f45ec7bSml29623 extern uint32_t nxge_bcopy_thresh; 436f45ec7bSml29623 extern uint32_t nxge_dvma_thresh; 446f45ec7bSml29623 extern uint32_t nxge_dma_stream_thresh; 456f45ec7bSml29623 extern dma_method_t nxge_force_dma; 46b4d05839Sml29623 extern uint32_t nxge_cksum_offload; 476f45ec7bSml29623 486f45ec7bSml29623 /* Device register access attributes for PIO. */ 496f45ec7bSml29623 extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr; 506f45ec7bSml29623 /* Device descriptor access attributes for DMA. */ 516f45ec7bSml29623 extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr; 526f45ec7bSml29623 /* Device buffer access attributes for DMA. */ 536f45ec7bSml29623 extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr; 546f45ec7bSml29623 extern ddi_dma_attr_t nxge_desc_dma_attr; 556f45ec7bSml29623 extern ddi_dma_attr_t nxge_tx_dma_attr; 566f45ec7bSml29623 57da14cebeSEric Cheng extern void nxge_tx_ring_task(void *arg); 582d99c5d4SMichael Speer 59678453a8Sspeer static nxge_status_t nxge_map_txdma(p_nxge_t, int); 606f45ec7bSml29623 61678453a8Sspeer static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int); 626f45ec7bSml29623 636f45ec7bSml29623 static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t, 646f45ec7bSml29623 p_nxge_dma_common_t *, p_tx_ring_t *, 656f45ec7bSml29623 uint32_t, p_nxge_dma_common_t *, 666f45ec7bSml29623 p_tx_mbox_t *); 67678453a8Sspeer static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t); 686f45ec7bSml29623 696f45ec7bSml29623 static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t, 706f45ec7bSml29623 p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t); 716f45ec7bSml29623 static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t); 726f45ec7bSml29623 736f45ec7bSml29623 static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t, 746f45ec7bSml29623 p_nxge_dma_common_t *, p_tx_ring_t, 756f45ec7bSml29623 p_tx_mbox_t *); 766f45ec7bSml29623 static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t, 776f45ec7bSml29623 p_tx_ring_t, p_tx_mbox_t); 786f45ec7bSml29623 796f45ec7bSml29623 static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t, 806f45ec7bSml29623 p_tx_ring_t, p_tx_mbox_t); 81678453a8Sspeer static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t); 826f45ec7bSml29623 836f45ec7bSml29623 static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t); 846f45ec7bSml29623 static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t, 856f45ec7bSml29623 p_nxge_ldv_t, tx_cs_t); 866f45ec7bSml29623 static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t); 876f45ec7bSml29623 static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t, 886f45ec7bSml29623 uint16_t, p_tx_ring_t); 896f45ec7bSml29623 90678453a8Sspeer static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, 91678453a8Sspeer p_tx_ring_t ring_p, uint16_t channel); 92678453a8Sspeer 936f45ec7bSml29623 nxge_status_t 946f45ec7bSml29623 nxge_init_txdma_channels(p_nxge_t nxgep) 956f45ec7bSml29623 { 96678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 97e11f0814SMichael Speer int i, tdc, count; 98e11f0814SMichael Speer nxge_grp_t *group; 99da14cebeSEric Cheng dc_map_t map; 100da14cebeSEric Cheng int dev_gindex; 1016f45ec7bSml29623 102678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels")); 1036f45ec7bSml29623 104678453a8Sspeer for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) { 105678453a8Sspeer if ((1 << i) & set->lg.map) { 106e11f0814SMichael Speer group = set->group[i]; 107da14cebeSEric Cheng dev_gindex = 108da14cebeSEric Cheng nxgep->pt_config.hw_config.def_mac_txdma_grpid + i; 109da14cebeSEric Cheng map = nxgep->pt_config.tdc_grps[dev_gindex].map; 110678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 111da14cebeSEric Cheng if ((1 << tdc) & map) { 112da14cebeSEric Cheng if ((nxge_grp_dc_add(nxgep, 113da14cebeSEric Cheng group, VP_BOUND_TX, tdc))) 114e11f0814SMichael Speer goto init_txdma_channels_exit; 115678453a8Sspeer } 116678453a8Sspeer } 117678453a8Sspeer } 118678453a8Sspeer if (++count == set->lg.count) 119678453a8Sspeer break; 1206f45ec7bSml29623 } 1216f45ec7bSml29623 122678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels")); 1236f45ec7bSml29623 return (NXGE_OK); 124e11f0814SMichael Speer 125e11f0814SMichael Speer init_txdma_channels_exit: 126e11f0814SMichael Speer for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) { 127e11f0814SMichael Speer if ((1 << i) & set->lg.map) { 128e11f0814SMichael Speer group = set->group[i]; 129da14cebeSEric Cheng dev_gindex = 130da14cebeSEric Cheng nxgep->pt_config.hw_config.def_mac_txdma_grpid + i; 131da14cebeSEric Cheng map = nxgep->pt_config.tdc_grps[dev_gindex].map; 132e11f0814SMichael Speer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 133da14cebeSEric Cheng if ((1 << tdc) & map) { 134e11f0814SMichael Speer nxge_grp_dc_remove(nxgep, 135e11f0814SMichael Speer VP_BOUND_TX, tdc); 136e11f0814SMichael Speer } 137e11f0814SMichael Speer } 138e11f0814SMichael Speer } 139e11f0814SMichael Speer if (++count == set->lg.count) 140e11f0814SMichael Speer break; 141e11f0814SMichael Speer } 142e11f0814SMichael Speer 143e11f0814SMichael Speer return (NXGE_ERROR); 144da14cebeSEric Cheng 1456f45ec7bSml29623 } 1466f45ec7bSml29623 147678453a8Sspeer nxge_status_t 148678453a8Sspeer nxge_init_txdma_channel( 149678453a8Sspeer p_nxge_t nxge, 150678453a8Sspeer int channel) 151678453a8Sspeer { 152678453a8Sspeer nxge_status_t status; 153678453a8Sspeer 154678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel")); 155678453a8Sspeer 156678453a8Sspeer status = nxge_map_txdma(nxge, channel); 157678453a8Sspeer if (status != NXGE_OK) { 158678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 159678453a8Sspeer "<== nxge_init_txdma_channel: status 0x%x", status)); 160678453a8Sspeer (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel); 161678453a8Sspeer return (status); 162678453a8Sspeer } 163678453a8Sspeer 164678453a8Sspeer status = nxge_txdma_hw_start(nxge, channel); 165678453a8Sspeer if (status != NXGE_OK) { 166678453a8Sspeer (void) nxge_unmap_txdma_channel(nxge, channel); 167678453a8Sspeer (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel); 168678453a8Sspeer return (status); 169678453a8Sspeer } 170678453a8Sspeer 171678453a8Sspeer if (!nxge->statsp->tdc_ksp[channel]) 172678453a8Sspeer nxge_setup_tdc_kstats(nxge, channel); 173678453a8Sspeer 174678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel")); 175678453a8Sspeer 176678453a8Sspeer return (status); 177678453a8Sspeer } 178678453a8Sspeer 1796f45ec7bSml29623 void 1806f45ec7bSml29623 nxge_uninit_txdma_channels(p_nxge_t nxgep) 1816f45ec7bSml29623 { 182678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 183678453a8Sspeer int tdc; 1846f45ec7bSml29623 185678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels")); 186678453a8Sspeer 187678453a8Sspeer if (set->owned.map == 0) { 188678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, 189678453a8Sspeer "nxge_uninit_txdma_channels: no channels")); 190678453a8Sspeer return; 191678453a8Sspeer } 192678453a8Sspeer 193678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 194678453a8Sspeer if ((1 << tdc) & set->owned.map) { 195678453a8Sspeer nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc); 196678453a8Sspeer } 197678453a8Sspeer } 198678453a8Sspeer 199678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels")); 200678453a8Sspeer } 201678453a8Sspeer 202678453a8Sspeer void 203678453a8Sspeer nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel) 204678453a8Sspeer { 205678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel")); 206678453a8Sspeer 207678453a8Sspeer if (nxgep->statsp->tdc_ksp[channel]) { 208678453a8Sspeer kstat_delete(nxgep->statsp->tdc_ksp[channel]); 209678453a8Sspeer nxgep->statsp->tdc_ksp[channel] = 0; 210678453a8Sspeer } 211678453a8Sspeer 212ef523517SMichael Speer if (nxge_txdma_stop_channel(nxgep, channel) != NXGE_OK) 213ef523517SMichael Speer goto nxge_uninit_txdma_channel_exit; 214ef523517SMichael Speer 215678453a8Sspeer nxge_unmap_txdma_channel(nxgep, channel); 2166f45ec7bSml29623 217ef523517SMichael Speer nxge_uninit_txdma_channel_exit: 218ef523517SMichael Speer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_uninit_txdma_channel")); 2196f45ec7bSml29623 } 2206f45ec7bSml29623 2216f45ec7bSml29623 void 2226f45ec7bSml29623 nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p, 2236f45ec7bSml29623 uint32_t entries, uint32_t size) 2246f45ec7bSml29623 { 2256f45ec7bSml29623 size_t tsize; 2266f45ec7bSml29623 *dest_p = *src_p; 2276f45ec7bSml29623 tsize = size * entries; 2286f45ec7bSml29623 dest_p->alength = tsize; 2296f45ec7bSml29623 dest_p->nblocks = entries; 2306f45ec7bSml29623 dest_p->block_size = size; 2316f45ec7bSml29623 dest_p->offset += tsize; 2326f45ec7bSml29623 2336f45ec7bSml29623 src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize; 2346f45ec7bSml29623 src_p->alength -= tsize; 2356f45ec7bSml29623 src_p->dma_cookie.dmac_laddress += tsize; 2366f45ec7bSml29623 src_p->dma_cookie.dmac_size -= tsize; 2376f45ec7bSml29623 } 2386f45ec7bSml29623 239678453a8Sspeer /* 240678453a8Sspeer * nxge_reset_txdma_channel 241678453a8Sspeer * 242678453a8Sspeer * Reset a TDC. 243678453a8Sspeer * 244678453a8Sspeer * Arguments: 245678453a8Sspeer * nxgep 246678453a8Sspeer * channel The channel to reset. 247678453a8Sspeer * reg_data The current TX_CS. 248678453a8Sspeer * 249678453a8Sspeer * Notes: 250678453a8Sspeer * 251678453a8Sspeer * NPI/NXGE function calls: 252678453a8Sspeer * npi_txdma_channel_reset() 253678453a8Sspeer * npi_txdma_channel_control() 254678453a8Sspeer * 255678453a8Sspeer * Registers accessed: 256678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 257678453a8Sspeer * TX_RING_KICK DMC+0x40018 Transmit Ring Kick 258678453a8Sspeer * 259678453a8Sspeer * Context: 260678453a8Sspeer * Any domain 261678453a8Sspeer */ 2626f45ec7bSml29623 nxge_status_t 2636f45ec7bSml29623 nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data) 2646f45ec7bSml29623 { 2656f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 2666f45ec7bSml29623 nxge_status_t status = NXGE_OK; 2676f45ec7bSml29623 npi_handle_t handle; 2686f45ec7bSml29623 2696f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel")); 2706f45ec7bSml29623 2716f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 2726f45ec7bSml29623 if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) { 2736f45ec7bSml29623 rs = npi_txdma_channel_reset(handle, channel); 2746f45ec7bSml29623 } else { 2756f45ec7bSml29623 rs = npi_txdma_channel_control(handle, TXDMA_RESET, 2766f45ec7bSml29623 channel); 2776f45ec7bSml29623 } 2786f45ec7bSml29623 2796f45ec7bSml29623 if (rs != NPI_SUCCESS) { 2806f45ec7bSml29623 status = NXGE_ERROR | rs; 2816f45ec7bSml29623 } 2826f45ec7bSml29623 2836f45ec7bSml29623 /* 2846f45ec7bSml29623 * Reset the tail (kick) register to 0. 2856f45ec7bSml29623 * (Hardware will not reset it. Tx overflow fatal 2866f45ec7bSml29623 * error if tail is not set to 0 after reset! 2876f45ec7bSml29623 */ 2886f45ec7bSml29623 TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0); 2896f45ec7bSml29623 2906f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel")); 2916f45ec7bSml29623 return (status); 2926f45ec7bSml29623 } 2936f45ec7bSml29623 294678453a8Sspeer /* 295678453a8Sspeer * nxge_init_txdma_channel_event_mask 296678453a8Sspeer * 297678453a8Sspeer * Enable interrupts for a set of events. 298678453a8Sspeer * 299678453a8Sspeer * Arguments: 300678453a8Sspeer * nxgep 301678453a8Sspeer * channel The channel to map. 302678453a8Sspeer * mask_p The events to enable. 303678453a8Sspeer * 304678453a8Sspeer * Notes: 305678453a8Sspeer * 306678453a8Sspeer * NPI/NXGE function calls: 307678453a8Sspeer * npi_txdma_event_mask() 308678453a8Sspeer * 309678453a8Sspeer * Registers accessed: 310678453a8Sspeer * TX_ENT_MSK DMC+0x40020 Transmit Event Mask 311678453a8Sspeer * 312678453a8Sspeer * Context: 313678453a8Sspeer * Any domain 314678453a8Sspeer */ 3156f45ec7bSml29623 nxge_status_t 3166f45ec7bSml29623 nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel, 3176f45ec7bSml29623 p_tx_dma_ent_msk_t mask_p) 3186f45ec7bSml29623 { 3196f45ec7bSml29623 npi_handle_t handle; 3206f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 3216f45ec7bSml29623 nxge_status_t status = NXGE_OK; 3226f45ec7bSml29623 3236f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 3246f45ec7bSml29623 "<== nxge_init_txdma_channel_event_mask")); 3256f45ec7bSml29623 3266f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 3276f45ec7bSml29623 rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p); 3286f45ec7bSml29623 if (rs != NPI_SUCCESS) { 3296f45ec7bSml29623 status = NXGE_ERROR | rs; 3306f45ec7bSml29623 } 3316f45ec7bSml29623 3326f45ec7bSml29623 return (status); 3336f45ec7bSml29623 } 3346f45ec7bSml29623 335678453a8Sspeer /* 336678453a8Sspeer * nxge_init_txdma_channel_cntl_stat 337678453a8Sspeer * 338678453a8Sspeer * Stop a TDC. If at first we don't succeed, inject an error. 339678453a8Sspeer * 340678453a8Sspeer * Arguments: 341678453a8Sspeer * nxgep 342678453a8Sspeer * channel The channel to stop. 343678453a8Sspeer * 344678453a8Sspeer * Notes: 345678453a8Sspeer * 346678453a8Sspeer * NPI/NXGE function calls: 347678453a8Sspeer * npi_txdma_control_status() 348678453a8Sspeer * 349678453a8Sspeer * Registers accessed: 350678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 351678453a8Sspeer * 352678453a8Sspeer * Context: 353678453a8Sspeer * Any domain 354678453a8Sspeer */ 3556f45ec7bSml29623 nxge_status_t 3566f45ec7bSml29623 nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel, 3576f45ec7bSml29623 uint64_t reg_data) 3586f45ec7bSml29623 { 3596f45ec7bSml29623 npi_handle_t handle; 3606f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 3616f45ec7bSml29623 nxge_status_t status = NXGE_OK; 3626f45ec7bSml29623 3636f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 3646f45ec7bSml29623 "<== nxge_init_txdma_channel_cntl_stat")); 3656f45ec7bSml29623 3666f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 3676f45ec7bSml29623 rs = npi_txdma_control_status(handle, OP_SET, channel, 3686f45ec7bSml29623 (p_tx_cs_t)®_data); 3696f45ec7bSml29623 3706f45ec7bSml29623 if (rs != NPI_SUCCESS) { 3716f45ec7bSml29623 status = NXGE_ERROR | rs; 3726f45ec7bSml29623 } 3736f45ec7bSml29623 3746f45ec7bSml29623 return (status); 3756f45ec7bSml29623 } 3766f45ec7bSml29623 377678453a8Sspeer /* 378678453a8Sspeer * nxge_enable_txdma_channel 379678453a8Sspeer * 380678453a8Sspeer * Enable a TDC. 381678453a8Sspeer * 382678453a8Sspeer * Arguments: 383678453a8Sspeer * nxgep 384678453a8Sspeer * channel The channel to enable. 385678453a8Sspeer * tx_desc_p channel's transmit descriptor ring. 386678453a8Sspeer * mbox_p channel's mailbox, 387678453a8Sspeer * 388678453a8Sspeer * Notes: 389678453a8Sspeer * 390678453a8Sspeer * NPI/NXGE function calls: 391678453a8Sspeer * npi_txdma_ring_config() 392678453a8Sspeer * npi_txdma_mbox_config() 393678453a8Sspeer * npi_txdma_channel_init_enable() 394678453a8Sspeer * 395678453a8Sspeer * Registers accessed: 396678453a8Sspeer * TX_RNG_CFIG DMC+0x40000 Transmit Ring Configuration 397678453a8Sspeer * TXDMA_MBH DMC+0x40030 TXDMA Mailbox High 398678453a8Sspeer * TXDMA_MBL DMC+0x40038 TXDMA Mailbox Low 399678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 400678453a8Sspeer * 401678453a8Sspeer * Context: 402678453a8Sspeer * Any domain 403678453a8Sspeer */ 4046f45ec7bSml29623 nxge_status_t 4056f45ec7bSml29623 nxge_enable_txdma_channel(p_nxge_t nxgep, 4066f45ec7bSml29623 uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p) 4076f45ec7bSml29623 { 4086f45ec7bSml29623 npi_handle_t handle; 4096f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 4106f45ec7bSml29623 nxge_status_t status = NXGE_OK; 4116f45ec7bSml29623 4126f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel")); 4136f45ec7bSml29623 4146f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 4156f45ec7bSml29623 /* 4166f45ec7bSml29623 * Use configuration data composed at init time. 4176f45ec7bSml29623 * Write to hardware the transmit ring configurations. 4186f45ec7bSml29623 */ 4196f45ec7bSml29623 rs = npi_txdma_ring_config(handle, OP_SET, channel, 4206f45ec7bSml29623 (uint64_t *)&(tx_desc_p->tx_ring_cfig.value)); 4216f45ec7bSml29623 4226f45ec7bSml29623 if (rs != NPI_SUCCESS) { 4236f45ec7bSml29623 return (NXGE_ERROR | rs); 4246f45ec7bSml29623 } 4256f45ec7bSml29623 426678453a8Sspeer if (isLDOMguest(nxgep)) { 427678453a8Sspeer /* Add interrupt handler for this channel. */ 428678453a8Sspeer if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK) 429678453a8Sspeer return (NXGE_ERROR); 430678453a8Sspeer } 431678453a8Sspeer 4326f45ec7bSml29623 /* Write to hardware the mailbox */ 4336f45ec7bSml29623 rs = npi_txdma_mbox_config(handle, OP_SET, channel, 4346f45ec7bSml29623 (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress); 4356f45ec7bSml29623 4366f45ec7bSml29623 if (rs != NPI_SUCCESS) { 4376f45ec7bSml29623 return (NXGE_ERROR | rs); 4386f45ec7bSml29623 } 4396f45ec7bSml29623 4406f45ec7bSml29623 /* Start the DMA engine. */ 4416f45ec7bSml29623 rs = npi_txdma_channel_init_enable(handle, channel); 4426f45ec7bSml29623 4436f45ec7bSml29623 if (rs != NPI_SUCCESS) { 4446f45ec7bSml29623 return (NXGE_ERROR | rs); 4456f45ec7bSml29623 } 4466f45ec7bSml29623 4476f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel")); 4486f45ec7bSml29623 4496f45ec7bSml29623 return (status); 4506f45ec7bSml29623 } 4516f45ec7bSml29623 4526f45ec7bSml29623 void 4536f45ec7bSml29623 nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len, 4546f45ec7bSml29623 boolean_t l4_cksum, int pkt_len, uint8_t npads, 455b4d05839Sml29623 p_tx_pkt_hdr_all_t pkthdrp, 456b4d05839Sml29623 t_uscalar_t start_offset, 457b4d05839Sml29623 t_uscalar_t stuff_offset) 4586f45ec7bSml29623 { 4596f45ec7bSml29623 p_tx_pkt_header_t hdrp; 4606f45ec7bSml29623 p_mblk_t nmp; 4616f45ec7bSml29623 uint64_t tmp; 4626f45ec7bSml29623 size_t mblk_len; 4636f45ec7bSml29623 size_t iph_len; 4646f45ec7bSml29623 size_t hdrs_size; 4656f45ec7bSml29623 uint8_t hdrs_buf[sizeof (struct ether_header) + 4666f45ec7bSml29623 64 + sizeof (uint32_t)]; 467ae2d3f74Smisaki uint8_t *cursor; 4686f45ec7bSml29623 uint8_t *ip_buf; 4696f45ec7bSml29623 uint16_t eth_type; 4706f45ec7bSml29623 uint8_t ipproto; 4716f45ec7bSml29623 boolean_t is_vlan = B_FALSE; 4726f45ec7bSml29623 size_t eth_hdr_size; 4736f45ec7bSml29623 4746f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp)); 4756f45ec7bSml29623 4766f45ec7bSml29623 /* 4776f45ec7bSml29623 * Caller should zero out the headers first. 4786f45ec7bSml29623 */ 4796f45ec7bSml29623 hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr; 4806f45ec7bSml29623 4816f45ec7bSml29623 if (fill_len) { 4826f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 4836f45ec7bSml29623 "==> nxge_fill_tx_hdr: pkt_len %d " 4846f45ec7bSml29623 "npads %d", pkt_len, npads)); 4856f45ec7bSml29623 tmp = (uint64_t)pkt_len; 4866f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT); 4876f45ec7bSml29623 goto fill_tx_header_done; 4886f45ec7bSml29623 } 4896f45ec7bSml29623 490b4d05839Sml29623 hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT); 4916f45ec7bSml29623 4926f45ec7bSml29623 /* 4936f45ec7bSml29623 * mp is the original data packet (does not include the 4946f45ec7bSml29623 * Neptune transmit header). 4956f45ec7bSml29623 */ 4966f45ec7bSml29623 nmp = mp; 4976f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: " 4986f45ec7bSml29623 "mp $%p b_rptr $%p len %d", 499ae2d3f74Smisaki mp, nmp->b_rptr, MBLKL(nmp))); 500ae2d3f74Smisaki /* copy ether_header from mblk to hdrs_buf */ 501ae2d3f74Smisaki cursor = &hdrs_buf[0]; 502ae2d3f74Smisaki tmp = sizeof (struct ether_vlan_header); 503ae2d3f74Smisaki while ((nmp != NULL) && (tmp > 0)) { 504ae2d3f74Smisaki size_t buflen; 505ae2d3f74Smisaki mblk_len = MBLKL(nmp); 5067c29db66Smisaki buflen = min((size_t)tmp, mblk_len); 507ae2d3f74Smisaki bcopy(nmp->b_rptr, cursor, buflen); 508ae2d3f74Smisaki cursor += buflen; 509ae2d3f74Smisaki tmp -= buflen; 510ae2d3f74Smisaki nmp = nmp->b_cont; 511ae2d3f74Smisaki } 512ae2d3f74Smisaki 513ae2d3f74Smisaki nmp = mp; 514ae2d3f74Smisaki mblk_len = MBLKL(nmp); 5156f45ec7bSml29623 ip_buf = NULL; 5166f45ec7bSml29623 eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type); 5176f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) " 5186f45ec7bSml29623 "ether type 0x%x", eth_type, hdrp->value)); 5196f45ec7bSml29623 5206f45ec7bSml29623 if (eth_type < ETHERMTU) { 5216f45ec7bSml29623 tmp = 1ull; 5226f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT); 5236f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC " 5246f45ec7bSml29623 "value 0x%llx", hdrp->value)); 5256f45ec7bSml29623 if (*(hdrs_buf + sizeof (struct ether_header)) 5266f45ec7bSml29623 == LLC_SNAP_SAP) { 5276f45ec7bSml29623 eth_type = ntohs(*((uint16_t *)(hdrs_buf + 5286f45ec7bSml29623 sizeof (struct ether_header) + 6))); 5296f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 5306f45ec7bSml29623 "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x", 5316f45ec7bSml29623 eth_type)); 5326f45ec7bSml29623 } else { 5336f45ec7bSml29623 goto fill_tx_header_done; 5346f45ec7bSml29623 } 5356f45ec7bSml29623 } else if (eth_type == VLAN_ETHERTYPE) { 5366f45ec7bSml29623 tmp = 1ull; 5376f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT); 5386f45ec7bSml29623 5396f45ec7bSml29623 eth_type = ntohs(((struct ether_vlan_header *) 5406f45ec7bSml29623 hdrs_buf)->ether_type); 5416f45ec7bSml29623 is_vlan = B_TRUE; 5426f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN " 5436f45ec7bSml29623 "value 0x%llx", hdrp->value)); 5446f45ec7bSml29623 } 5456f45ec7bSml29623 5466f45ec7bSml29623 if (!is_vlan) { 5476f45ec7bSml29623 eth_hdr_size = sizeof (struct ether_header); 5486f45ec7bSml29623 } else { 5496f45ec7bSml29623 eth_hdr_size = sizeof (struct ether_vlan_header); 5506f45ec7bSml29623 } 5516f45ec7bSml29623 5526f45ec7bSml29623 switch (eth_type) { 5536f45ec7bSml29623 case ETHERTYPE_IP: 5546f45ec7bSml29623 if (mblk_len > eth_hdr_size + sizeof (uint8_t)) { 5556f45ec7bSml29623 ip_buf = nmp->b_rptr + eth_hdr_size; 5566f45ec7bSml29623 mblk_len -= eth_hdr_size; 5576f45ec7bSml29623 iph_len = ((*ip_buf) & 0x0f); 5586f45ec7bSml29623 if (mblk_len > (iph_len + sizeof (uint32_t))) { 5596f45ec7bSml29623 ip_buf = nmp->b_rptr; 5606f45ec7bSml29623 ip_buf += eth_hdr_size; 5616f45ec7bSml29623 } else { 5626f45ec7bSml29623 ip_buf = NULL; 5636f45ec7bSml29623 } 5646f45ec7bSml29623 5656f45ec7bSml29623 } 5666f45ec7bSml29623 if (ip_buf == NULL) { 5676f45ec7bSml29623 hdrs_size = 0; 5686f45ec7bSml29623 ((p_ether_header_t)hdrs_buf)->ether_type = 0; 5696f45ec7bSml29623 while ((nmp) && (hdrs_size < 5706f45ec7bSml29623 sizeof (hdrs_buf))) { 5716f45ec7bSml29623 mblk_len = (size_t)nmp->b_wptr - 5726f45ec7bSml29623 (size_t)nmp->b_rptr; 5736f45ec7bSml29623 if (mblk_len >= 5746f45ec7bSml29623 (sizeof (hdrs_buf) - hdrs_size)) 5756f45ec7bSml29623 mblk_len = sizeof (hdrs_buf) - 5766f45ec7bSml29623 hdrs_size; 5776f45ec7bSml29623 bcopy(nmp->b_rptr, 5786f45ec7bSml29623 &hdrs_buf[hdrs_size], mblk_len); 5796f45ec7bSml29623 hdrs_size += mblk_len; 5806f45ec7bSml29623 nmp = nmp->b_cont; 5816f45ec7bSml29623 } 5826f45ec7bSml29623 ip_buf = hdrs_buf; 5836f45ec7bSml29623 ip_buf += eth_hdr_size; 5846f45ec7bSml29623 iph_len = ((*ip_buf) & 0x0f); 5856f45ec7bSml29623 } 5866f45ec7bSml29623 5876f45ec7bSml29623 ipproto = ip_buf[9]; 5886f45ec7bSml29623 5896f45ec7bSml29623 tmp = (uint64_t)iph_len; 5906f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT); 5916f45ec7bSml29623 tmp = (uint64_t)(eth_hdr_size >> 1); 5926f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT); 5936f45ec7bSml29623 5946f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 " 5956f45ec7bSml29623 " iph_len %d l3start %d eth_hdr_size %d proto 0x%x" 5966f45ec7bSml29623 "tmp 0x%x", 5976f45ec7bSml29623 iph_len, hdrp->bits.hdw.l3start, eth_hdr_size, 5986f45ec7bSml29623 ipproto, tmp)); 5996f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP " 6006f45ec7bSml29623 "value 0x%llx", hdrp->value)); 6016f45ec7bSml29623 6026f45ec7bSml29623 break; 6036f45ec7bSml29623 6046f45ec7bSml29623 case ETHERTYPE_IPV6: 6056f45ec7bSml29623 hdrs_size = 0; 6066f45ec7bSml29623 ((p_ether_header_t)hdrs_buf)->ether_type = 0; 6076f45ec7bSml29623 while ((nmp) && (hdrs_size < 6086f45ec7bSml29623 sizeof (hdrs_buf))) { 6096f45ec7bSml29623 mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr; 6106f45ec7bSml29623 if (mblk_len >= 6116f45ec7bSml29623 (sizeof (hdrs_buf) - hdrs_size)) 6126f45ec7bSml29623 mblk_len = sizeof (hdrs_buf) - 6136f45ec7bSml29623 hdrs_size; 6146f45ec7bSml29623 bcopy(nmp->b_rptr, 6156f45ec7bSml29623 &hdrs_buf[hdrs_size], mblk_len); 6166f45ec7bSml29623 hdrs_size += mblk_len; 6176f45ec7bSml29623 nmp = nmp->b_cont; 6186f45ec7bSml29623 } 6196f45ec7bSml29623 ip_buf = hdrs_buf; 6206f45ec7bSml29623 ip_buf += eth_hdr_size; 6216f45ec7bSml29623 6226f45ec7bSml29623 tmp = 1ull; 6236f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT); 6246f45ec7bSml29623 6256f45ec7bSml29623 tmp = (eth_hdr_size >> 1); 6266f45ec7bSml29623 hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT); 6276f45ec7bSml29623 6286f45ec7bSml29623 /* byte 6 is the next header protocol */ 6296f45ec7bSml29623 ipproto = ip_buf[6]; 6306f45ec7bSml29623 6316f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 " 6326f45ec7bSml29623 " iph_len %d l3start %d eth_hdr_size %d proto 0x%x", 6336f45ec7bSml29623 iph_len, hdrp->bits.hdw.l3start, eth_hdr_size, 6346f45ec7bSml29623 ipproto)); 6356f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 " 6366f45ec7bSml29623 "value 0x%llx", hdrp->value)); 6376f45ec7bSml29623 6386f45ec7bSml29623 break; 6396f45ec7bSml29623 6406f45ec7bSml29623 default: 6416f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP")); 6426f45ec7bSml29623 goto fill_tx_header_done; 6436f45ec7bSml29623 } 6446f45ec7bSml29623 6456f45ec7bSml29623 switch (ipproto) { 6466f45ec7bSml29623 case IPPROTO_TCP: 6476f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 6486f45ec7bSml29623 "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum)); 6496f45ec7bSml29623 if (l4_cksum) { 650b4d05839Sml29623 hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP; 651b4d05839Sml29623 hdrp->value |= 652b4d05839Sml29623 (((uint64_t)(start_offset >> 1)) << 653b4d05839Sml29623 TX_PKT_HEADER_L4START_SHIFT); 654b4d05839Sml29623 hdrp->value |= 655b4d05839Sml29623 (((uint64_t)(stuff_offset >> 1)) << 656b4d05839Sml29623 TX_PKT_HEADER_L4STUFF_SHIFT); 657b4d05839Sml29623 6586f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 6596f45ec7bSml29623 "==> nxge_tx_pkt_hdr_init: TCP CKSUM " 6606f45ec7bSml29623 "value 0x%llx", hdrp->value)); 6616f45ec7bSml29623 } 6626f45ec7bSml29623 6636f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP " 6646f45ec7bSml29623 "value 0x%llx", hdrp->value)); 6656f45ec7bSml29623 break; 6666f45ec7bSml29623 6676f45ec7bSml29623 case IPPROTO_UDP: 6686f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP")); 6696f45ec7bSml29623 if (l4_cksum) { 670b4d05839Sml29623 if (!nxge_cksum_offload) { 671b4d05839Sml29623 uint16_t *up; 672b4d05839Sml29623 uint16_t cksum; 673b4d05839Sml29623 t_uscalar_t stuff_len; 674b4d05839Sml29623 675b4d05839Sml29623 /* 676b4d05839Sml29623 * The checksum field has the 677b4d05839Sml29623 * partial checksum. 678b4d05839Sml29623 * IP_CSUM() macro calls ip_cksum() which 679b4d05839Sml29623 * can add in the partial checksum. 680b4d05839Sml29623 */ 681b4d05839Sml29623 cksum = IP_CSUM(mp, start_offset, 0); 682b4d05839Sml29623 stuff_len = stuff_offset; 683b4d05839Sml29623 nmp = mp; 684b4d05839Sml29623 mblk_len = MBLKL(nmp); 685b4d05839Sml29623 while ((nmp != NULL) && 686b4d05839Sml29623 (mblk_len < stuff_len)) { 687b4d05839Sml29623 stuff_len -= mblk_len; 688b4d05839Sml29623 nmp = nmp->b_cont; 689ef523517SMichael Speer if (nmp) 690ef523517SMichael Speer mblk_len = MBLKL(nmp); 6916f45ec7bSml29623 } 692b4d05839Sml29623 ASSERT(nmp); 693b4d05839Sml29623 up = (uint16_t *)(nmp->b_rptr + stuff_len); 694b4d05839Sml29623 695b4d05839Sml29623 *up = cksum; 696b4d05839Sml29623 hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP; 697b4d05839Sml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 698b4d05839Sml29623 "==> nxge_tx_pkt_hdr_init: UDP offset %d " 699b4d05839Sml29623 "use sw cksum " 700b4d05839Sml29623 "write to $%p cksum 0x%x content up 0x%x", 701b4d05839Sml29623 stuff_len, 702b4d05839Sml29623 up, 703b4d05839Sml29623 cksum, 704b4d05839Sml29623 *up)); 705b4d05839Sml29623 } else { 706b4d05839Sml29623 /* Hardware will compute the full checksum */ 707b4d05839Sml29623 hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP; 708b4d05839Sml29623 hdrp->value |= 709b4d05839Sml29623 (((uint64_t)(start_offset >> 1)) << 710b4d05839Sml29623 TX_PKT_HEADER_L4START_SHIFT); 711b4d05839Sml29623 hdrp->value |= 712b4d05839Sml29623 (((uint64_t)(stuff_offset >> 1)) << 713b4d05839Sml29623 TX_PKT_HEADER_L4STUFF_SHIFT); 714b4d05839Sml29623 715b4d05839Sml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 716b4d05839Sml29623 "==> nxge_tx_pkt_hdr_init: UDP offset %d " 717b4d05839Sml29623 " use partial checksum " 718b4d05839Sml29623 "cksum 0x%x ", 719b4d05839Sml29623 "value 0x%llx", 720b4d05839Sml29623 stuff_offset, 721b4d05839Sml29623 IP_CSUM(mp, start_offset, 0), 722b4d05839Sml29623 hdrp->value)); 723b4d05839Sml29623 } 724b4d05839Sml29623 } 725b4d05839Sml29623 7266f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 7276f45ec7bSml29623 "==> nxge_tx_pkt_hdr_init: UDP" 7286f45ec7bSml29623 "value 0x%llx", hdrp->value)); 7296f45ec7bSml29623 break; 7306f45ec7bSml29623 7316f45ec7bSml29623 default: 7326f45ec7bSml29623 goto fill_tx_header_done; 7336f45ec7bSml29623 } 7346f45ec7bSml29623 7356f45ec7bSml29623 fill_tx_header_done: 7366f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 7376f45ec7bSml29623 "==> nxge_fill_tx_hdr: pkt_len %d " 7386f45ec7bSml29623 "npads %d value 0x%llx", pkt_len, npads, hdrp->value)); 7396f45ec7bSml29623 7406f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr")); 7416f45ec7bSml29623 } 7426f45ec7bSml29623 7436f45ec7bSml29623 /*ARGSUSED*/ 7446f45ec7bSml29623 p_mblk_t 7456f45ec7bSml29623 nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads) 7466f45ec7bSml29623 { 7476f45ec7bSml29623 p_mblk_t newmp = NULL; 7486f45ec7bSml29623 7496f45ec7bSml29623 if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) { 7506f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 7516f45ec7bSml29623 "<== nxge_tx_pkt_header_reserve: allocb failed")); 7526f45ec7bSml29623 return (NULL); 7536f45ec7bSml29623 } 7546f45ec7bSml29623 7556f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 7566f45ec7bSml29623 "==> nxge_tx_pkt_header_reserve: get new mp")); 7576f45ec7bSml29623 DB_TYPE(newmp) = M_DATA; 7586f45ec7bSml29623 newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp); 7596f45ec7bSml29623 linkb(newmp, mp); 7606f45ec7bSml29623 newmp->b_rptr -= TX_PKT_HEADER_SIZE; 7616f45ec7bSml29623 7626f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: " 7636f45ec7bSml29623 "b_rptr $%p b_wptr $%p", 7646f45ec7bSml29623 newmp->b_rptr, newmp->b_wptr)); 7656f45ec7bSml29623 7666f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 7676f45ec7bSml29623 "<== nxge_tx_pkt_header_reserve: use new mp")); 7686f45ec7bSml29623 7696f45ec7bSml29623 return (newmp); 7706f45ec7bSml29623 } 7716f45ec7bSml29623 7726f45ec7bSml29623 int 7736f45ec7bSml29623 nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p) 7746f45ec7bSml29623 { 7756f45ec7bSml29623 uint_t nmblks; 7766f45ec7bSml29623 ssize_t len; 7776f45ec7bSml29623 uint_t pkt_len; 7786f45ec7bSml29623 p_mblk_t nmp, bmp, tmp; 7796f45ec7bSml29623 uint8_t *b_wptr; 7806f45ec7bSml29623 7816f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 7826f45ec7bSml29623 "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p " 7836f45ec7bSml29623 "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp))); 7846f45ec7bSml29623 7856f45ec7bSml29623 nmp = mp; 7866f45ec7bSml29623 bmp = mp; 7876f45ec7bSml29623 nmblks = 0; 7886f45ec7bSml29623 pkt_len = 0; 7896f45ec7bSml29623 *tot_xfer_len_p = 0; 7906f45ec7bSml29623 7916f45ec7bSml29623 while (nmp) { 7926f45ec7bSml29623 len = MBLKL(nmp); 7936f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: " 7946f45ec7bSml29623 "len %d pkt_len %d nmblks %d tot_xfer_len %d", 7956f45ec7bSml29623 len, pkt_len, nmblks, 7966f45ec7bSml29623 *tot_xfer_len_p)); 7976f45ec7bSml29623 7986f45ec7bSml29623 if (len <= 0) { 7996f45ec7bSml29623 bmp = nmp; 8006f45ec7bSml29623 nmp = nmp->b_cont; 8016f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 8026f45ec7bSml29623 "==> nxge_tx_pkt_nmblocks: " 8036f45ec7bSml29623 "len (0) pkt_len %d nmblks %d", 8046f45ec7bSml29623 pkt_len, nmblks)); 8056f45ec7bSml29623 continue; 8066f45ec7bSml29623 } 8076f45ec7bSml29623 8086f45ec7bSml29623 *tot_xfer_len_p += len; 8096f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: " 8106f45ec7bSml29623 "len %d pkt_len %d nmblks %d tot_xfer_len %d", 8116f45ec7bSml29623 len, pkt_len, nmblks, 8126f45ec7bSml29623 *tot_xfer_len_p)); 8136f45ec7bSml29623 8146f45ec7bSml29623 if (len < nxge_bcopy_thresh) { 8156f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 8166f45ec7bSml29623 "==> nxge_tx_pkt_nmblocks: " 8176f45ec7bSml29623 "len %d (< thresh) pkt_len %d nmblks %d", 8186f45ec7bSml29623 len, pkt_len, nmblks)); 8196f45ec7bSml29623 if (pkt_len == 0) 8206f45ec7bSml29623 nmblks++; 8216f45ec7bSml29623 pkt_len += len; 8226f45ec7bSml29623 if (pkt_len >= nxge_bcopy_thresh) { 8236f45ec7bSml29623 pkt_len = 0; 8246f45ec7bSml29623 len = 0; 8256f45ec7bSml29623 nmp = bmp; 8266f45ec7bSml29623 } 8276f45ec7bSml29623 } else { 8286f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 8296f45ec7bSml29623 "==> nxge_tx_pkt_nmblocks: " 8306f45ec7bSml29623 "len %d (> thresh) pkt_len %d nmblks %d", 8316f45ec7bSml29623 len, pkt_len, nmblks)); 8326f45ec7bSml29623 pkt_len = 0; 8336f45ec7bSml29623 nmblks++; 8346f45ec7bSml29623 /* 8356f45ec7bSml29623 * Hardware limits the transfer length to 4K. 8366f45ec7bSml29623 * If len is more than 4K, we need to break 8376f45ec7bSml29623 * it up to at most 2 more blocks. 8386f45ec7bSml29623 */ 8396f45ec7bSml29623 if (len > TX_MAX_TRANSFER_LENGTH) { 8406f45ec7bSml29623 uint32_t nsegs; 8416f45ec7bSml29623 842678453a8Sspeer nsegs = 1; 8436f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 8446f45ec7bSml29623 "==> nxge_tx_pkt_nmblocks: " 8456f45ec7bSml29623 "len %d pkt_len %d nmblks %d nsegs %d", 8466f45ec7bSml29623 len, pkt_len, nmblks, nsegs)); 8476f45ec7bSml29623 if (len % (TX_MAX_TRANSFER_LENGTH * 2)) { 8486f45ec7bSml29623 ++nsegs; 8496f45ec7bSml29623 } 8506f45ec7bSml29623 do { 8516f45ec7bSml29623 b_wptr = nmp->b_rptr + 8526f45ec7bSml29623 TX_MAX_TRANSFER_LENGTH; 8536f45ec7bSml29623 nmp->b_wptr = b_wptr; 8546f45ec7bSml29623 if ((tmp = dupb(nmp)) == NULL) { 8556f45ec7bSml29623 return (0); 8566f45ec7bSml29623 } 8576f45ec7bSml29623 tmp->b_rptr = b_wptr; 8586f45ec7bSml29623 tmp->b_wptr = nmp->b_wptr; 8596f45ec7bSml29623 tmp->b_cont = nmp->b_cont; 8606f45ec7bSml29623 nmp->b_cont = tmp; 8616f45ec7bSml29623 nmblks++; 8626f45ec7bSml29623 if (--nsegs) { 8636f45ec7bSml29623 nmp = tmp; 8646f45ec7bSml29623 } 8656f45ec7bSml29623 } while (nsegs); 8666f45ec7bSml29623 nmp = tmp; 8676f45ec7bSml29623 } 8686f45ec7bSml29623 } 8696f45ec7bSml29623 8706f45ec7bSml29623 /* 8716f45ec7bSml29623 * Hardware limits the transmit gather pointers to 15. 8726f45ec7bSml29623 */ 8736f45ec7bSml29623 if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) > 8746f45ec7bSml29623 TX_MAX_GATHER_POINTERS) { 8756f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 8766f45ec7bSml29623 "==> nxge_tx_pkt_nmblocks: pull msg - " 8776f45ec7bSml29623 "len %d pkt_len %d nmblks %d", 8786f45ec7bSml29623 len, pkt_len, nmblks)); 8796f45ec7bSml29623 /* Pull all message blocks from b_cont */ 8806f45ec7bSml29623 if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) { 8816f45ec7bSml29623 return (0); 8826f45ec7bSml29623 } 8836f45ec7bSml29623 freemsg(nmp->b_cont); 8846f45ec7bSml29623 nmp->b_cont = tmp; 8856f45ec7bSml29623 pkt_len = 0; 8866f45ec7bSml29623 } 8876f45ec7bSml29623 bmp = nmp; 8886f45ec7bSml29623 nmp = nmp->b_cont; 8896f45ec7bSml29623 } 8906f45ec7bSml29623 8916f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, TX_CTL, 8926f45ec7bSml29623 "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p " 8936f45ec7bSml29623 "nmblks %d len %d tot_xfer_len %d", 8946f45ec7bSml29623 mp->b_rptr, mp->b_wptr, nmblks, 8956f45ec7bSml29623 MBLKL(mp), *tot_xfer_len_p)); 8966f45ec7bSml29623 8976f45ec7bSml29623 return (nmblks); 8986f45ec7bSml29623 } 8996f45ec7bSml29623 9006f45ec7bSml29623 boolean_t 9016f45ec7bSml29623 nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks) 9026f45ec7bSml29623 { 9036f45ec7bSml29623 boolean_t status = B_TRUE; 9046f45ec7bSml29623 p_nxge_dma_common_t tx_desc_dma_p; 9056f45ec7bSml29623 nxge_dma_common_t desc_area; 9066f45ec7bSml29623 p_tx_desc_t tx_desc_ring_vp; 9076f45ec7bSml29623 p_tx_desc_t tx_desc_p; 9086f45ec7bSml29623 p_tx_desc_t tx_desc_pp; 9096f45ec7bSml29623 tx_desc_t r_tx_desc; 9106f45ec7bSml29623 p_tx_msg_t tx_msg_ring; 9116f45ec7bSml29623 p_tx_msg_t tx_msg_p; 9126f45ec7bSml29623 npi_handle_t handle; 9136f45ec7bSml29623 tx_ring_hdl_t tx_head; 9146f45ec7bSml29623 uint32_t pkt_len; 9156f45ec7bSml29623 uint_t tx_rd_index; 9166f45ec7bSml29623 uint16_t head_index, tail_index; 9176f45ec7bSml29623 uint8_t tdc; 9186f45ec7bSml29623 boolean_t head_wrap, tail_wrap; 9196f45ec7bSml29623 p_nxge_tx_ring_stats_t tdc_stats; 9206f45ec7bSml29623 int rc; 9216f45ec7bSml29623 9226f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim")); 9236f45ec7bSml29623 9246f45ec7bSml29623 status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) && 9256f45ec7bSml29623 (nmblks != 0)); 9266f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9276f45ec7bSml29623 "==> nxge_txdma_reclaim: pending %d reclaim %d nmblks %d", 9286f45ec7bSml29623 tx_ring_p->descs_pending, nxge_reclaim_pending, 9296f45ec7bSml29623 nmblks)); 9306f45ec7bSml29623 if (!status) { 9316f45ec7bSml29623 tx_desc_dma_p = &tx_ring_p->tdc_desc; 9326f45ec7bSml29623 desc_area = tx_ring_p->tdc_desc; 9336f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 9346f45ec7bSml29623 tx_desc_ring_vp = tx_desc_dma_p->kaddrp; 9356f45ec7bSml29623 tx_desc_ring_vp = 9366f45ec7bSml29623 (p_tx_desc_t)DMA_COMMON_VPTR(desc_area); 9376f45ec7bSml29623 tx_rd_index = tx_ring_p->rd_index; 9386f45ec7bSml29623 tx_desc_p = &tx_desc_ring_vp[tx_rd_index]; 9396f45ec7bSml29623 tx_msg_ring = tx_ring_p->tx_msg_ring; 9406f45ec7bSml29623 tx_msg_p = &tx_msg_ring[tx_rd_index]; 9416f45ec7bSml29623 tdc = tx_ring_p->tdc; 9426f45ec7bSml29623 tdc_stats = tx_ring_p->tdc_stats; 9436f45ec7bSml29623 if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) { 9446f45ec7bSml29623 tdc_stats->tx_max_pend = tx_ring_p->descs_pending; 9456f45ec7bSml29623 } 9466f45ec7bSml29623 9476f45ec7bSml29623 tail_index = tx_ring_p->wr_index; 9486f45ec7bSml29623 tail_wrap = tx_ring_p->wr_index_wrap; 9496f45ec7bSml29623 9506f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9516f45ec7bSml29623 "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d " 9526f45ec7bSml29623 "tail_index %d tail_wrap %d " 9536f45ec7bSml29623 "tx_desc_p $%p ($%p) ", 9546f45ec7bSml29623 tdc, tx_rd_index, tail_index, tail_wrap, 9556f45ec7bSml29623 tx_desc_p, (*(uint64_t *)tx_desc_p))); 9566f45ec7bSml29623 /* 9576f45ec7bSml29623 * Read the hardware maintained transmit head 9586f45ec7bSml29623 * and wrap around bit. 9596f45ec7bSml29623 */ 9606f45ec7bSml29623 TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value); 9616f45ec7bSml29623 head_index = tx_head.bits.ldw.head; 9626f45ec7bSml29623 head_wrap = tx_head.bits.ldw.wrap; 9636f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9646f45ec7bSml29623 "==> nxge_txdma_reclaim: " 9656f45ec7bSml29623 "tx_rd_index %d tail %d tail_wrap %d " 9666f45ec7bSml29623 "head %d wrap %d", 9676f45ec7bSml29623 tx_rd_index, tail_index, tail_wrap, 9686f45ec7bSml29623 head_index, head_wrap)); 9696f45ec7bSml29623 9706f45ec7bSml29623 if (head_index == tail_index) { 9716f45ec7bSml29623 if (TXDMA_RING_EMPTY(head_index, head_wrap, 9726f45ec7bSml29623 tail_index, tail_wrap) && 9736f45ec7bSml29623 (head_index == tx_rd_index)) { 9746f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9756f45ec7bSml29623 "==> nxge_txdma_reclaim: EMPTY")); 9766f45ec7bSml29623 return (B_TRUE); 9776f45ec7bSml29623 } 9786f45ec7bSml29623 9796f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9806f45ec7bSml29623 "==> nxge_txdma_reclaim: Checking " 9816f45ec7bSml29623 "if ring full")); 9826f45ec7bSml29623 if (TXDMA_RING_FULL(head_index, head_wrap, tail_index, 9836f45ec7bSml29623 tail_wrap)) { 9846f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9856f45ec7bSml29623 "==> nxge_txdma_reclaim: full")); 9866f45ec7bSml29623 return (B_FALSE); 9876f45ec7bSml29623 } 9886f45ec7bSml29623 } 9896f45ec7bSml29623 9906f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9916f45ec7bSml29623 "==> nxge_txdma_reclaim: tx_rd_index and head_index")); 9926f45ec7bSml29623 9936f45ec7bSml29623 tx_desc_pp = &r_tx_desc; 9946f45ec7bSml29623 while ((tx_rd_index != head_index) && 9956f45ec7bSml29623 (tx_ring_p->descs_pending != 0)) { 9966f45ec7bSml29623 9976f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 9986f45ec7bSml29623 "==> nxge_txdma_reclaim: Checking if pending")); 9996f45ec7bSml29623 10006f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10016f45ec7bSml29623 "==> nxge_txdma_reclaim: " 10026f45ec7bSml29623 "descs_pending %d ", 10036f45ec7bSml29623 tx_ring_p->descs_pending)); 10046f45ec7bSml29623 10056f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10066f45ec7bSml29623 "==> nxge_txdma_reclaim: " 10076f45ec7bSml29623 "(tx_rd_index %d head_index %d " 10086f45ec7bSml29623 "(tx_desc_p $%p)", 10096f45ec7bSml29623 tx_rd_index, head_index, 10106f45ec7bSml29623 tx_desc_p)); 10116f45ec7bSml29623 10126f45ec7bSml29623 tx_desc_pp->value = tx_desc_p->value; 10136f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10146f45ec7bSml29623 "==> nxge_txdma_reclaim: " 10156f45ec7bSml29623 "(tx_rd_index %d head_index %d " 10166f45ec7bSml29623 "tx_desc_p $%p (desc value 0x%llx) ", 10176f45ec7bSml29623 tx_rd_index, head_index, 10186f45ec7bSml29623 tx_desc_pp, (*(uint64_t *)tx_desc_pp))); 10196f45ec7bSml29623 10206f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10216f45ec7bSml29623 "==> nxge_txdma_reclaim: dump desc:")); 10226f45ec7bSml29623 10236f45ec7bSml29623 pkt_len = tx_desc_pp->bits.hdw.tr_len; 10240dc2366fSVenugopal Iyer tdc_stats->obytes += (pkt_len - TX_PKT_HEADER_SIZE); 10256f45ec7bSml29623 tdc_stats->opackets += tx_desc_pp->bits.hdw.sop; 10266f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10276f45ec7bSml29623 "==> nxge_txdma_reclaim: pkt_len %d " 10286f45ec7bSml29623 "tdc channel %d opackets %d", 10296f45ec7bSml29623 pkt_len, 10306f45ec7bSml29623 tdc, 10316f45ec7bSml29623 tdc_stats->opackets)); 10326f45ec7bSml29623 10336f45ec7bSml29623 if (tx_msg_p->flags.dma_type == USE_DVMA) { 10346f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10356f45ec7bSml29623 "tx_desc_p = $%p " 10366f45ec7bSml29623 "tx_desc_pp = $%p " 10376f45ec7bSml29623 "index = %d", 10386f45ec7bSml29623 tx_desc_p, 10396f45ec7bSml29623 tx_desc_pp, 10406f45ec7bSml29623 tx_ring_p->rd_index)); 10416f45ec7bSml29623 (void) dvma_unload(tx_msg_p->dvma_handle, 10426f45ec7bSml29623 0, -1); 10436f45ec7bSml29623 tx_msg_p->dvma_handle = NULL; 10446f45ec7bSml29623 if (tx_ring_p->dvma_wr_index == 10456f45ec7bSml29623 tx_ring_p->dvma_wrap_mask) { 10466f45ec7bSml29623 tx_ring_p->dvma_wr_index = 0; 10476f45ec7bSml29623 } else { 10486f45ec7bSml29623 tx_ring_p->dvma_wr_index++; 10496f45ec7bSml29623 } 10506f45ec7bSml29623 tx_ring_p->dvma_pending--; 10516f45ec7bSml29623 } else if (tx_msg_p->flags.dma_type == 10526f45ec7bSml29623 USE_DMA) { 10536f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10546f45ec7bSml29623 "==> nxge_txdma_reclaim: " 10556f45ec7bSml29623 "USE DMA")); 10566f45ec7bSml29623 if (rc = ddi_dma_unbind_handle 10576f45ec7bSml29623 (tx_msg_p->dma_handle)) { 10586f45ec7bSml29623 cmn_err(CE_WARN, "!nxge_reclaim: " 10596f45ec7bSml29623 "ddi_dma_unbind_handle " 10606f45ec7bSml29623 "failed. status %d", rc); 10616f45ec7bSml29623 } 10626f45ec7bSml29623 } 10636f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10646f45ec7bSml29623 "==> nxge_txdma_reclaim: count packets")); 10656f45ec7bSml29623 /* 10666f45ec7bSml29623 * count a chained packet only once. 10676f45ec7bSml29623 */ 10686f45ec7bSml29623 if (tx_msg_p->tx_message != NULL) { 1069da14cebeSEric Cheng freemsg(tx_msg_p->tx_message); 1070da14cebeSEric Cheng tx_msg_p->tx_message = NULL; 10716f45ec7bSml29623 } 10726f45ec7bSml29623 10736f45ec7bSml29623 tx_msg_p->flags.dma_type = USE_NONE; 10746f45ec7bSml29623 tx_rd_index = tx_ring_p->rd_index; 10756f45ec7bSml29623 tx_rd_index = (tx_rd_index + 1) & 10766f45ec7bSml29623 tx_ring_p->tx_wrap_mask; 10776f45ec7bSml29623 tx_ring_p->rd_index = tx_rd_index; 10786f45ec7bSml29623 tx_ring_p->descs_pending--; 10796f45ec7bSml29623 tx_desc_p = &tx_desc_ring_vp[tx_rd_index]; 10806f45ec7bSml29623 tx_msg_p = &tx_msg_ring[tx_rd_index]; 10816f45ec7bSml29623 } 10826f45ec7bSml29623 1083257bdc55SMichael Speer status = (nmblks <= ((int)tx_ring_p->tx_ring_size - 1084257bdc55SMichael Speer (int)tx_ring_p->descs_pending - TX_FULL_MARK)); 10856f45ec7bSml29623 if (status) { 1086*75d94465SJosef 'Jeff' Sipek (void) atomic_cas_32((uint32_t *)&tx_ring_p->queueing, 1087*75d94465SJosef 'Jeff' Sipek 1, 0); 10886f45ec7bSml29623 } 10896f45ec7bSml29623 } else { 1090257bdc55SMichael Speer status = (nmblks <= ((int)tx_ring_p->tx_ring_size - 1091257bdc55SMichael Speer (int)tx_ring_p->descs_pending - TX_FULL_MARK)); 10926f45ec7bSml29623 } 10936f45ec7bSml29623 10946f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 10956f45ec7bSml29623 "<== nxge_txdma_reclaim status = 0x%08x", status)); 10966f45ec7bSml29623 10976f45ec7bSml29623 return (status); 10986f45ec7bSml29623 } 10996f45ec7bSml29623 1100678453a8Sspeer /* 1101678453a8Sspeer * nxge_tx_intr 1102678453a8Sspeer * 1103678453a8Sspeer * Process a TDC interrupt 1104678453a8Sspeer * 1105678453a8Sspeer * Arguments: 1106678453a8Sspeer * arg1 A Logical Device state Vector (LSV) data structure. 1107678453a8Sspeer * arg2 nxge_t * 1108678453a8Sspeer * 1109678453a8Sspeer * Notes: 1110678453a8Sspeer * 1111678453a8Sspeer * NPI/NXGE function calls: 1112678453a8Sspeer * npi_txdma_control_status() 1113678453a8Sspeer * npi_intr_ldg_mgmt_set() 1114678453a8Sspeer * 1115678453a8Sspeer * nxge_tx_err_evnts() 1116678453a8Sspeer * nxge_txdma_reclaim() 1117678453a8Sspeer * 1118678453a8Sspeer * Registers accessed: 1119678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1120678453a8Sspeer * PIO_LDSV 1121678453a8Sspeer * 1122678453a8Sspeer * Context: 1123678453a8Sspeer * Any domain 1124678453a8Sspeer */ 11256f45ec7bSml29623 uint_t 11266f45ec7bSml29623 nxge_tx_intr(void *arg1, void *arg2) 11276f45ec7bSml29623 { 11286f45ec7bSml29623 p_nxge_ldv_t ldvp = (p_nxge_ldv_t)arg1; 11296f45ec7bSml29623 p_nxge_t nxgep = (p_nxge_t)arg2; 11306f45ec7bSml29623 p_nxge_ldg_t ldgp; 11316f45ec7bSml29623 uint8_t channel; 11326f45ec7bSml29623 uint32_t vindex; 11336f45ec7bSml29623 npi_handle_t handle; 11346f45ec7bSml29623 tx_cs_t cs; 11356f45ec7bSml29623 p_tx_ring_t *tx_rings; 11366f45ec7bSml29623 p_tx_ring_t tx_ring_p; 11376f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 11386f45ec7bSml29623 uint_t serviced = DDI_INTR_UNCLAIMED; 11396f45ec7bSml29623 nxge_status_t status = NXGE_OK; 11406f45ec7bSml29623 11416f45ec7bSml29623 if (ldvp == NULL) { 11426f45ec7bSml29623 NXGE_DEBUG_MSG((NULL, INT_CTL, 11436f45ec7bSml29623 "<== nxge_tx_intr: nxgep $%p ldvp $%p", 11446f45ec7bSml29623 nxgep, ldvp)); 11456f45ec7bSml29623 return (DDI_INTR_UNCLAIMED); 11466f45ec7bSml29623 } 11476f45ec7bSml29623 11486f45ec7bSml29623 if (arg2 == NULL || (void *)ldvp->nxgep != arg2) { 11496f45ec7bSml29623 nxgep = ldvp->nxgep; 11506f45ec7bSml29623 } 11516f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, 11526f45ec7bSml29623 "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p", 11536f45ec7bSml29623 nxgep, ldvp)); 115422c0d73aSspeer 115522c0d73aSspeer if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) || 115622c0d73aSspeer (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) { 115722c0d73aSspeer NXGE_DEBUG_MSG((nxgep, INT_CTL, 115822c0d73aSspeer "<== nxge_tx_intr: interface not started or intialized")); 115922c0d73aSspeer return (DDI_INTR_CLAIMED); 116022c0d73aSspeer } 116122c0d73aSspeer 11626f45ec7bSml29623 /* 11636f45ec7bSml29623 * This interrupt handler is for a specific 11646f45ec7bSml29623 * transmit dma channel. 11656f45ec7bSml29623 */ 11666f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 11676f45ec7bSml29623 /* Get the control and status for this channel. */ 11686f45ec7bSml29623 channel = ldvp->channel; 11696f45ec7bSml29623 ldgp = ldvp->ldgp; 11706f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, 11716f45ec7bSml29623 "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p " 11726f45ec7bSml29623 "channel %d", 11736f45ec7bSml29623 nxgep, ldvp, channel)); 11746f45ec7bSml29623 11756f45ec7bSml29623 rs = npi_txdma_control_status(handle, OP_GET, channel, &cs); 11766f45ec7bSml29623 vindex = ldvp->vdma_index; 11776f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, 11786f45ec7bSml29623 "==> nxge_tx_intr:channel %d ring index %d status 0x%08x", 11796f45ec7bSml29623 channel, vindex, rs)); 11806f45ec7bSml29623 if (!rs && cs.bits.ldw.mk) { 11816f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, 11826f45ec7bSml29623 "==> nxge_tx_intr:channel %d ring index %d " 11836f45ec7bSml29623 "status 0x%08x (mk bit set)", 11846f45ec7bSml29623 channel, vindex, rs)); 11856f45ec7bSml29623 tx_rings = nxgep->tx_rings->rings; 11866f45ec7bSml29623 tx_ring_p = tx_rings[vindex]; 11876f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, 11886f45ec7bSml29623 "==> nxge_tx_intr:channel %d ring index %d " 11896f45ec7bSml29623 "status 0x%08x (mk bit set, calling reclaim)", 11906f45ec7bSml29623 channel, vindex, rs)); 11916f45ec7bSml29623 1192da14cebeSEric Cheng nxge_tx_ring_task((void *)tx_ring_p); 11936f45ec7bSml29623 } 11946f45ec7bSml29623 11956f45ec7bSml29623 /* 11966f45ec7bSml29623 * Process other transmit control and status. 11976f45ec7bSml29623 * Check the ldv state. 11986f45ec7bSml29623 */ 11996f45ec7bSml29623 status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs); 12006f45ec7bSml29623 /* 12016f45ec7bSml29623 * Rearm this logical group if this is a single device 12026f45ec7bSml29623 * group. 12036f45ec7bSml29623 */ 12046f45ec7bSml29623 if (ldgp->nldvs == 1) { 12056f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, 12066f45ec7bSml29623 "==> nxge_tx_intr: rearm")); 12076f45ec7bSml29623 if (status == NXGE_OK) { 1208678453a8Sspeer if (isLDOMguest(nxgep)) { 1209678453a8Sspeer nxge_hio_ldgimgn(nxgep, ldgp); 1210678453a8Sspeer } else { 12116f45ec7bSml29623 (void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg, 12126f45ec7bSml29623 B_TRUE, ldgp->ldg_timer); 12136f45ec7bSml29623 } 12146f45ec7bSml29623 } 1215678453a8Sspeer } 12166f45ec7bSml29623 12176f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr")); 12186f45ec7bSml29623 serviced = DDI_INTR_CLAIMED; 12196f45ec7bSml29623 return (serviced); 12206f45ec7bSml29623 } 12216f45ec7bSml29623 12226f45ec7bSml29623 void 1223678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep) /* Dead */ 12246f45ec7bSml29623 { 12256f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop")); 12266f45ec7bSml29623 12276f45ec7bSml29623 (void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP); 12286f45ec7bSml29623 12296f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop")); 12306f45ec7bSml29623 } 12316f45ec7bSml29623 12326f45ec7bSml29623 void 1233678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */ 12346f45ec7bSml29623 { 12356f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start")); 12366f45ec7bSml29623 12376f45ec7bSml29623 (void) nxge_txdma_stop(nxgep); 12386f45ec7bSml29623 12396f45ec7bSml29623 (void) nxge_fixup_txdma_rings(nxgep); 12406f45ec7bSml29623 (void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START); 12416f45ec7bSml29623 (void) nxge_tx_mac_enable(nxgep); 12426f45ec7bSml29623 (void) nxge_txdma_hw_kick(nxgep); 12436f45ec7bSml29623 12446f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start")); 12456f45ec7bSml29623 } 12466f45ec7bSml29623 1247678453a8Sspeer npi_status_t 1248678453a8Sspeer nxge_txdma_channel_disable( 1249678453a8Sspeer nxge_t *nxge, 1250678453a8Sspeer int channel) 1251678453a8Sspeer { 1252678453a8Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge); 1253678453a8Sspeer npi_status_t rs; 1254678453a8Sspeer tdmc_intr_dbg_t intr_dbg; 1255678453a8Sspeer 1256678453a8Sspeer /* 1257678453a8Sspeer * Stop the dma channel and wait for the stop-done. 1258678453a8Sspeer * If the stop-done bit is not present, then force 1259678453a8Sspeer * an error so TXC will stop. 1260678453a8Sspeer * All channels bound to this port need to be stopped 1261678453a8Sspeer * and reset after injecting an interrupt error. 1262678453a8Sspeer */ 1263678453a8Sspeer rs = npi_txdma_channel_disable(handle, channel); 1264678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 1265678453a8Sspeer "==> nxge_txdma_channel_disable(%d) " 1266678453a8Sspeer "rs 0x%x", channel, rs)); 1267678453a8Sspeer if (rs != NPI_SUCCESS) { 1268678453a8Sspeer /* Inject any error */ 1269678453a8Sspeer intr_dbg.value = 0; 1270678453a8Sspeer intr_dbg.bits.ldw.nack_pref = 1; 1271678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 1272678453a8Sspeer "==> nxge_txdma_hw_mode: " 1273678453a8Sspeer "channel %d (stop failed 0x%x) " 1274678453a8Sspeer "(inject err)", rs, channel)); 1275678453a8Sspeer (void) npi_txdma_inj_int_error_set( 1276678453a8Sspeer handle, channel, &intr_dbg); 1277678453a8Sspeer rs = npi_txdma_channel_disable(handle, channel); 1278678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 1279678453a8Sspeer "==> nxge_txdma_hw_mode: " 1280678453a8Sspeer "channel %d (stop again 0x%x) " 1281678453a8Sspeer "(after inject err)", 1282678453a8Sspeer rs, channel)); 1283678453a8Sspeer } 1284678453a8Sspeer 1285678453a8Sspeer return (rs); 1286678453a8Sspeer } 1287678453a8Sspeer 1288678453a8Sspeer /* 1289678453a8Sspeer * nxge_txdma_hw_mode 1290678453a8Sspeer * 1291678453a8Sspeer * Toggle all TDCs on (enable) or off (disable). 1292678453a8Sspeer * 1293678453a8Sspeer * Arguments: 1294678453a8Sspeer * nxgep 1295678453a8Sspeer * enable Enable or disable a TDC. 1296678453a8Sspeer * 1297678453a8Sspeer * Notes: 1298678453a8Sspeer * 1299678453a8Sspeer * NPI/NXGE function calls: 1300678453a8Sspeer * npi_txdma_channel_enable(TX_CS) 1301678453a8Sspeer * npi_txdma_channel_disable(TX_CS) 1302678453a8Sspeer * npi_txdma_inj_int_error_set(TDMC_INTR_DBG) 1303678453a8Sspeer * 1304678453a8Sspeer * Registers accessed: 1305678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1306678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1307678453a8Sspeer * 1308678453a8Sspeer * Context: 1309678453a8Sspeer * Any domain 1310678453a8Sspeer */ 13116f45ec7bSml29623 nxge_status_t 13126f45ec7bSml29623 nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable) 13136f45ec7bSml29623 { 1314678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1315678453a8Sspeer 13166f45ec7bSml29623 npi_handle_t handle; 1317678453a8Sspeer nxge_status_t status; 1318678453a8Sspeer npi_status_t rs; 1319678453a8Sspeer int tdc; 13206f45ec7bSml29623 13216f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 13226f45ec7bSml29623 "==> nxge_txdma_hw_mode: enable mode %d", enable)); 13236f45ec7bSml29623 13246f45ec7bSml29623 if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { 13256f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 13266f45ec7bSml29623 "<== nxge_txdma_mode: not initialized")); 13276f45ec7bSml29623 return (NXGE_ERROR); 13286f45ec7bSml29623 } 13296f45ec7bSml29623 1330678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 13316f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 1332678453a8Sspeer "<== nxge_txdma_hw_mode: NULL ring pointer(s)")); 13336f45ec7bSml29623 return (NXGE_ERROR); 13346f45ec7bSml29623 } 13356f45ec7bSml29623 1336678453a8Sspeer /* Enable or disable all of the TDCs owned by us. */ 13376f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 1338678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1339678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1340678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1341678453a8Sspeer if (ring) { 13426f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1343678453a8Sspeer "==> nxge_txdma_hw_mode: channel %d", tdc)); 13446f45ec7bSml29623 if (enable) { 1345678453a8Sspeer rs = npi_txdma_channel_enable 1346678453a8Sspeer (handle, tdc); 13476f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1348678453a8Sspeer "==> nxge_txdma_hw_mode: " 1349678453a8Sspeer "channel %d (enable) rs 0x%x", 1350678453a8Sspeer tdc, rs)); 13516f45ec7bSml29623 } else { 1352678453a8Sspeer rs = nxge_txdma_channel_disable 1353678453a8Sspeer (nxgep, tdc); 13546f45ec7bSml29623 } 13556f45ec7bSml29623 } 13566f45ec7bSml29623 } 13576f45ec7bSml29623 } 13586f45ec7bSml29623 13596f45ec7bSml29623 status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 13606f45ec7bSml29623 13616f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 13626f45ec7bSml29623 "<== nxge_txdma_hw_mode: status 0x%x", status)); 13636f45ec7bSml29623 13646f45ec7bSml29623 return (status); 13656f45ec7bSml29623 } 13666f45ec7bSml29623 13676f45ec7bSml29623 void 13686f45ec7bSml29623 nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel) 13696f45ec7bSml29623 { 13706f45ec7bSml29623 npi_handle_t handle; 13716f45ec7bSml29623 13726f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, DMA_CTL, 13736f45ec7bSml29623 "==> nxge_txdma_enable_channel: channel %d", channel)); 13746f45ec7bSml29623 13756f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 13766f45ec7bSml29623 /* enable the transmit dma channels */ 13776f45ec7bSml29623 (void) npi_txdma_channel_enable(handle, channel); 13786f45ec7bSml29623 13796f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel")); 13806f45ec7bSml29623 } 13816f45ec7bSml29623 13826f45ec7bSml29623 void 13836f45ec7bSml29623 nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel) 13846f45ec7bSml29623 { 13856f45ec7bSml29623 npi_handle_t handle; 13866f45ec7bSml29623 13876f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, DMA_CTL, 13886f45ec7bSml29623 "==> nxge_txdma_disable_channel: channel %d", channel)); 13896f45ec7bSml29623 13906f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 13916f45ec7bSml29623 /* stop the transmit dma channels */ 13926f45ec7bSml29623 (void) npi_txdma_channel_disable(handle, channel); 13936f45ec7bSml29623 13946f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel")); 13956f45ec7bSml29623 } 13966f45ec7bSml29623 1397678453a8Sspeer /* 1398678453a8Sspeer * nxge_txdma_stop_inj_err 1399678453a8Sspeer * 1400678453a8Sspeer * Stop a TDC. If at first we don't succeed, inject an error. 1401678453a8Sspeer * 1402678453a8Sspeer * Arguments: 1403678453a8Sspeer * nxgep 1404678453a8Sspeer * channel The channel to stop. 1405678453a8Sspeer * 1406678453a8Sspeer * Notes: 1407678453a8Sspeer * 1408678453a8Sspeer * NPI/NXGE function calls: 1409678453a8Sspeer * npi_txdma_channel_disable() 1410678453a8Sspeer * npi_txdma_inj_int_error_set() 1411678453a8Sspeer * #if defined(NXGE_DEBUG) 1412678453a8Sspeer * nxge_txdma_regs_dump_channels(nxgep); 1413678453a8Sspeer * #endif 1414678453a8Sspeer * 1415678453a8Sspeer * Registers accessed: 1416678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1417678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1418678453a8Sspeer * 1419678453a8Sspeer * Context: 1420678453a8Sspeer * Any domain 1421678453a8Sspeer */ 14226f45ec7bSml29623 int 14236f45ec7bSml29623 nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel) 14246f45ec7bSml29623 { 14256f45ec7bSml29623 npi_handle_t handle; 14266f45ec7bSml29623 tdmc_intr_dbg_t intr_dbg; 14276f45ec7bSml29623 int status; 14286f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 14296f45ec7bSml29623 14306f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err")); 14316f45ec7bSml29623 /* 14326f45ec7bSml29623 * Stop the dma channel waits for the stop done. 14336f45ec7bSml29623 * If the stop done bit is not set, then create 14346f45ec7bSml29623 * an error. 14356f45ec7bSml29623 */ 14366f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 14376f45ec7bSml29623 rs = npi_txdma_channel_disable(handle, channel); 14386f45ec7bSml29623 status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 14396f45ec7bSml29623 if (status == NXGE_OK) { 14406f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 14416f45ec7bSml29623 "<== nxge_txdma_stop_inj_err (channel %d): " 14426f45ec7bSml29623 "stopped OK", channel)); 14436f45ec7bSml29623 return (status); 14446f45ec7bSml29623 } 14456f45ec7bSml29623 14466f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 14476f45ec7bSml29623 "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) " 14486f45ec7bSml29623 "injecting error", channel, rs)); 14496f45ec7bSml29623 /* Inject any error */ 14506f45ec7bSml29623 intr_dbg.value = 0; 14516f45ec7bSml29623 intr_dbg.bits.ldw.nack_pref = 1; 14526f45ec7bSml29623 (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg); 14536f45ec7bSml29623 14546f45ec7bSml29623 /* Stop done bit will be set as a result of error injection */ 14556f45ec7bSml29623 rs = npi_txdma_channel_disable(handle, channel); 14566f45ec7bSml29623 status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 14576f45ec7bSml29623 if (!(rs & NPI_TXDMA_STOP_FAILED)) { 14586f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 14596f45ec7bSml29623 "<== nxge_txdma_stop_inj_err (channel %d): " 14606f45ec7bSml29623 "stopped OK ", channel)); 14616f45ec7bSml29623 return (status); 14626f45ec7bSml29623 } 14636f45ec7bSml29623 14646f45ec7bSml29623 #if defined(NXGE_DEBUG) 14656f45ec7bSml29623 nxge_txdma_regs_dump_channels(nxgep); 14666f45ec7bSml29623 #endif 14676f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 14686f45ec7bSml29623 "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) " 14696f45ec7bSml29623 " (injected error but still not stopped)", channel, rs)); 14706f45ec7bSml29623 14716f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err")); 14726f45ec7bSml29623 return (status); 14736f45ec7bSml29623 } 14746f45ec7bSml29623 14756f45ec7bSml29623 /*ARGSUSED*/ 14766f45ec7bSml29623 void 14776f45ec7bSml29623 nxge_fixup_txdma_rings(p_nxge_t nxgep) 14786f45ec7bSml29623 { 1479678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1480678453a8Sspeer int tdc; 14816f45ec7bSml29623 14826f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings")); 14836f45ec7bSml29623 1484678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 1485678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1486678453a8Sspeer "<== nxge_fixup_txdma_rings: NULL ring pointer(s)")); 14876f45ec7bSml29623 return; 14886f45ec7bSml29623 } 14896f45ec7bSml29623 1490678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1491678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1492678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1493678453a8Sspeer if (ring) { 14946f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1495678453a8Sspeer "==> nxge_fixup_txdma_rings: channel %d", 1496678453a8Sspeer tdc)); 1497678453a8Sspeer nxge_txdma_fixup_channel(nxgep, ring, tdc); 14986f45ec7bSml29623 } 14996f45ec7bSml29623 } 15006f45ec7bSml29623 } 15016f45ec7bSml29623 15026f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings")); 15036f45ec7bSml29623 } 15046f45ec7bSml29623 15056f45ec7bSml29623 /*ARGSUSED*/ 15066f45ec7bSml29623 void 15076f45ec7bSml29623 nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel) 15086f45ec7bSml29623 { 15096f45ec7bSml29623 p_tx_ring_t ring_p; 15106f45ec7bSml29623 15116f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel")); 15126f45ec7bSml29623 ring_p = nxge_txdma_get_ring(nxgep, channel); 15136f45ec7bSml29623 if (ring_p == NULL) { 15146f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel")); 15156f45ec7bSml29623 return; 15166f45ec7bSml29623 } 15176f45ec7bSml29623 15186f45ec7bSml29623 if (ring_p->tdc != channel) { 15196f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 15206f45ec7bSml29623 "<== nxge_txdma_fix_channel: channel not matched " 15216f45ec7bSml29623 "ring tdc %d passed channel", 15226f45ec7bSml29623 ring_p->tdc, channel)); 15236f45ec7bSml29623 return; 15246f45ec7bSml29623 } 15256f45ec7bSml29623 15266f45ec7bSml29623 nxge_txdma_fixup_channel(nxgep, ring_p, channel); 15276f45ec7bSml29623 15286f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel")); 15296f45ec7bSml29623 } 15306f45ec7bSml29623 15316f45ec7bSml29623 /*ARGSUSED*/ 15326f45ec7bSml29623 void 15336f45ec7bSml29623 nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel) 15346f45ec7bSml29623 { 15356f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel")); 15366f45ec7bSml29623 15376f45ec7bSml29623 if (ring_p == NULL) { 15386f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 15396f45ec7bSml29623 "<== nxge_txdma_fixup_channel: NULL ring pointer")); 15406f45ec7bSml29623 return; 15416f45ec7bSml29623 } 15426f45ec7bSml29623 15436f45ec7bSml29623 if (ring_p->tdc != channel) { 15446f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 15456f45ec7bSml29623 "<== nxge_txdma_fixup_channel: channel not matched " 15466f45ec7bSml29623 "ring tdc %d passed channel", 15476f45ec7bSml29623 ring_p->tdc, channel)); 15486f45ec7bSml29623 return; 15496f45ec7bSml29623 } 15506f45ec7bSml29623 15516f45ec7bSml29623 MUTEX_ENTER(&ring_p->lock); 15526f45ec7bSml29623 (void) nxge_txdma_reclaim(nxgep, ring_p, 0); 15536f45ec7bSml29623 ring_p->rd_index = 0; 15546f45ec7bSml29623 ring_p->wr_index = 0; 15556f45ec7bSml29623 ring_p->ring_head.value = 0; 15566f45ec7bSml29623 ring_p->ring_kick_tail.value = 0; 15576f45ec7bSml29623 ring_p->descs_pending = 0; 15586f45ec7bSml29623 MUTEX_EXIT(&ring_p->lock); 15596f45ec7bSml29623 15606f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel")); 15616f45ec7bSml29623 } 15626f45ec7bSml29623 15636f45ec7bSml29623 /*ARGSUSED*/ 15646f45ec7bSml29623 void 15656f45ec7bSml29623 nxge_txdma_hw_kick(p_nxge_t nxgep) 15666f45ec7bSml29623 { 1567678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1568678453a8Sspeer int tdc; 15696f45ec7bSml29623 15706f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick")); 15716f45ec7bSml29623 1572678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 15736f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 1574678453a8Sspeer "<== nxge_txdma_hw_kick: NULL ring pointer(s)")); 15756f45ec7bSml29623 return; 15766f45ec7bSml29623 } 15776f45ec7bSml29623 1578678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1579678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1580678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1581678453a8Sspeer if (ring) { 15826f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1583678453a8Sspeer "==> nxge_txdma_hw_kick: channel %d", tdc)); 1584678453a8Sspeer nxge_txdma_hw_kick_channel(nxgep, ring, tdc); 1585678453a8Sspeer } 1586678453a8Sspeer } 15876f45ec7bSml29623 } 15886f45ec7bSml29623 15896f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick")); 15906f45ec7bSml29623 } 15916f45ec7bSml29623 15926f45ec7bSml29623 /*ARGSUSED*/ 15936f45ec7bSml29623 void 15946f45ec7bSml29623 nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel) 15956f45ec7bSml29623 { 15966f45ec7bSml29623 p_tx_ring_t ring_p; 15976f45ec7bSml29623 15986f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel")); 15996f45ec7bSml29623 16006f45ec7bSml29623 ring_p = nxge_txdma_get_ring(nxgep, channel); 16016f45ec7bSml29623 if (ring_p == NULL) { 16026f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 16036f45ec7bSml29623 " nxge_txdma_kick_channel")); 16046f45ec7bSml29623 return; 16056f45ec7bSml29623 } 16066f45ec7bSml29623 16076f45ec7bSml29623 if (ring_p->tdc != channel) { 16086f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 16096f45ec7bSml29623 "<== nxge_txdma_kick_channel: channel not matched " 16106f45ec7bSml29623 "ring tdc %d passed channel", 16116f45ec7bSml29623 ring_p->tdc, channel)); 16126f45ec7bSml29623 return; 16136f45ec7bSml29623 } 16146f45ec7bSml29623 16156f45ec7bSml29623 nxge_txdma_hw_kick_channel(nxgep, ring_p, channel); 16166f45ec7bSml29623 16176f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel")); 16186f45ec7bSml29623 } 16196f45ec7bSml29623 16206f45ec7bSml29623 /*ARGSUSED*/ 16216f45ec7bSml29623 void 16226f45ec7bSml29623 nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel) 16236f45ec7bSml29623 { 16246f45ec7bSml29623 16256f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel")); 16266f45ec7bSml29623 16276f45ec7bSml29623 if (ring_p == NULL) { 16286f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 16296f45ec7bSml29623 "<== nxge_txdma_hw_kick_channel: NULL ring pointer")); 16306f45ec7bSml29623 return; 16316f45ec7bSml29623 } 16326f45ec7bSml29623 16336f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel")); 16346f45ec7bSml29623 } 16356f45ec7bSml29623 1636678453a8Sspeer /* 1637678453a8Sspeer * nxge_check_tx_hang 1638678453a8Sspeer * 1639678453a8Sspeer * Check the state of all TDCs belonging to nxgep. 1640678453a8Sspeer * 1641678453a8Sspeer * Arguments: 1642678453a8Sspeer * nxgep 1643678453a8Sspeer * 1644678453a8Sspeer * Notes: 1645678453a8Sspeer * Called by nxge_hw.c:nxge_check_hw_state(). 1646678453a8Sspeer * 1647678453a8Sspeer * NPI/NXGE function calls: 1648678453a8Sspeer * 1649678453a8Sspeer * Registers accessed: 1650678453a8Sspeer * 1651678453a8Sspeer * Context: 1652678453a8Sspeer * Any domain 1653678453a8Sspeer */ 16546f45ec7bSml29623 /*ARGSUSED*/ 16556f45ec7bSml29623 void 16566f45ec7bSml29623 nxge_check_tx_hang(p_nxge_t nxgep) 16576f45ec7bSml29623 { 16586f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang")); 16596f45ec7bSml29623 166022c0d73aSspeer if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) || 166122c0d73aSspeer (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) { 166222c0d73aSspeer goto nxge_check_tx_hang_exit; 166322c0d73aSspeer } 166422c0d73aSspeer 16656f45ec7bSml29623 /* 16666f45ec7bSml29623 * Needs inputs from hardware for regs: 16676f45ec7bSml29623 * head index had not moved since last timeout. 16686f45ec7bSml29623 * packets not transmitted or stuffed registers. 16696f45ec7bSml29623 */ 16706f45ec7bSml29623 if (nxge_txdma_hung(nxgep)) { 16716f45ec7bSml29623 nxge_fixup_hung_txdma_rings(nxgep); 16726f45ec7bSml29623 } 167322c0d73aSspeer 167422c0d73aSspeer nxge_check_tx_hang_exit: 16756f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang")); 16766f45ec7bSml29623 } 16776f45ec7bSml29623 1678678453a8Sspeer /* 1679678453a8Sspeer * nxge_txdma_hung 1680678453a8Sspeer * 1681678453a8Sspeer * Reset a TDC. 1682678453a8Sspeer * 1683678453a8Sspeer * Arguments: 1684678453a8Sspeer * nxgep 1685678453a8Sspeer * channel The channel to reset. 1686678453a8Sspeer * reg_data The current TX_CS. 1687678453a8Sspeer * 1688678453a8Sspeer * Notes: 1689678453a8Sspeer * Called by nxge_check_tx_hang() 1690678453a8Sspeer * 1691678453a8Sspeer * NPI/NXGE function calls: 1692678453a8Sspeer * nxge_txdma_channel_hung() 1693678453a8Sspeer * 1694678453a8Sspeer * Registers accessed: 1695678453a8Sspeer * 1696678453a8Sspeer * Context: 1697678453a8Sspeer * Any domain 1698678453a8Sspeer */ 16996f45ec7bSml29623 int 17006f45ec7bSml29623 nxge_txdma_hung(p_nxge_t nxgep) 17016f45ec7bSml29623 { 1702678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1703678453a8Sspeer int tdc; 1704330cd344SMichael Speer boolean_t shared; 17056f45ec7bSml29623 17066f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung")); 1707678453a8Sspeer 1708678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 17096f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 1710678453a8Sspeer "<== nxge_txdma_hung: NULL ring pointer(s)")); 17116f45ec7bSml29623 return (B_FALSE); 17126f45ec7bSml29623 } 17136f45ec7bSml29623 1714678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1715330cd344SMichael Speer /* 1716330cd344SMichael Speer * Grab the shared state of the TDC. 1717330cd344SMichael Speer */ 1718330cd344SMichael Speer if (isLDOMservice(nxgep)) { 1719330cd344SMichael Speer nxge_hio_data_t *nhd = 1720330cd344SMichael Speer (nxge_hio_data_t *)nxgep->nxge_hw_p->hio; 1721330cd344SMichael Speer 1722330cd344SMichael Speer MUTEX_ENTER(&nhd->lock); 1723330cd344SMichael Speer shared = nxgep->tdc_is_shared[tdc]; 1724330cd344SMichael Speer MUTEX_EXIT(&nhd->lock); 1725330cd344SMichael Speer } else { 1726330cd344SMichael Speer shared = B_FALSE; 1727330cd344SMichael Speer } 1728330cd344SMichael Speer 1729330cd344SMichael Speer /* 1730330cd344SMichael Speer * Now, process continue to process. 1731330cd344SMichael Speer */ 1732330cd344SMichael Speer if (((1 << tdc) & set->owned.map) && !shared) { 1733678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1734678453a8Sspeer if (ring) { 1735678453a8Sspeer if (nxge_txdma_channel_hung(nxgep, ring, tdc)) { 17366f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 1737678453a8Sspeer "==> nxge_txdma_hung: TDC %d hung", 1738678453a8Sspeer tdc)); 17396f45ec7bSml29623 return (B_TRUE); 17406f45ec7bSml29623 } 17416f45ec7bSml29623 } 1742678453a8Sspeer } 1743678453a8Sspeer } 17446f45ec7bSml29623 17456f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung")); 17466f45ec7bSml29623 17476f45ec7bSml29623 return (B_FALSE); 17486f45ec7bSml29623 } 17496f45ec7bSml29623 1750678453a8Sspeer /* 1751678453a8Sspeer * nxge_txdma_channel_hung 1752678453a8Sspeer * 1753678453a8Sspeer * Reset a TDC. 1754678453a8Sspeer * 1755678453a8Sspeer * Arguments: 1756678453a8Sspeer * nxgep 1757678453a8Sspeer * ring <channel>'s ring. 1758678453a8Sspeer * channel The channel to reset. 1759678453a8Sspeer * 1760678453a8Sspeer * Notes: 1761678453a8Sspeer * Called by nxge_txdma.c:nxge_txdma_hung() 1762678453a8Sspeer * 1763678453a8Sspeer * NPI/NXGE function calls: 1764678453a8Sspeer * npi_txdma_ring_head_get() 1765678453a8Sspeer * 1766678453a8Sspeer * Registers accessed: 1767678453a8Sspeer * TX_RING_HDL DMC+0x40010 Transmit Ring Head Low 1768678453a8Sspeer * 1769678453a8Sspeer * Context: 1770678453a8Sspeer * Any domain 1771678453a8Sspeer */ 17726f45ec7bSml29623 int 17736f45ec7bSml29623 nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel) 17746f45ec7bSml29623 { 17756f45ec7bSml29623 uint16_t head_index, tail_index; 17766f45ec7bSml29623 boolean_t head_wrap, tail_wrap; 17776f45ec7bSml29623 npi_handle_t handle; 17786f45ec7bSml29623 tx_ring_hdl_t tx_head; 17796f45ec7bSml29623 uint_t tx_rd_index; 17806f45ec7bSml29623 17816f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung")); 17826f45ec7bSml29623 17836f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 17846f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 17856f45ec7bSml29623 "==> nxge_txdma_channel_hung: channel %d", channel)); 17866f45ec7bSml29623 MUTEX_ENTER(&tx_ring_p->lock); 17876f45ec7bSml29623 (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 17886f45ec7bSml29623 17896f45ec7bSml29623 tail_index = tx_ring_p->wr_index; 17906f45ec7bSml29623 tail_wrap = tx_ring_p->wr_index_wrap; 17916f45ec7bSml29623 tx_rd_index = tx_ring_p->rd_index; 17926f45ec7bSml29623 MUTEX_EXIT(&tx_ring_p->lock); 17936f45ec7bSml29623 17946f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 17956f45ec7bSml29623 "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d " 17966f45ec7bSml29623 "tail_index %d tail_wrap %d ", 17976f45ec7bSml29623 channel, tx_rd_index, tail_index, tail_wrap)); 17986f45ec7bSml29623 /* 17996f45ec7bSml29623 * Read the hardware maintained transmit head 18006f45ec7bSml29623 * and wrap around bit. 18016f45ec7bSml29623 */ 18026f45ec7bSml29623 (void) npi_txdma_ring_head_get(handle, channel, &tx_head); 18036f45ec7bSml29623 head_index = tx_head.bits.ldw.head; 18046f45ec7bSml29623 head_wrap = tx_head.bits.ldw.wrap; 18056f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 18066f45ec7bSml29623 "==> nxge_txdma_channel_hung: " 18076f45ec7bSml29623 "tx_rd_index %d tail %d tail_wrap %d " 18086f45ec7bSml29623 "head %d wrap %d", 18096f45ec7bSml29623 tx_rd_index, tail_index, tail_wrap, 18106f45ec7bSml29623 head_index, head_wrap)); 18116f45ec7bSml29623 18126f45ec7bSml29623 if (TXDMA_RING_EMPTY(head_index, head_wrap, 18136f45ec7bSml29623 tail_index, tail_wrap) && 18146f45ec7bSml29623 (head_index == tx_rd_index)) { 18156f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 18166f45ec7bSml29623 "==> nxge_txdma_channel_hung: EMPTY")); 18176f45ec7bSml29623 return (B_FALSE); 18186f45ec7bSml29623 } 18196f45ec7bSml29623 18206f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 18216f45ec7bSml29623 "==> nxge_txdma_channel_hung: Checking if ring full")); 18226f45ec7bSml29623 if (TXDMA_RING_FULL(head_index, head_wrap, tail_index, 18236f45ec7bSml29623 tail_wrap)) { 18246f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 18256f45ec7bSml29623 "==> nxge_txdma_channel_hung: full")); 18266f45ec7bSml29623 return (B_TRUE); 18276f45ec7bSml29623 } 18286f45ec7bSml29623 18296f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung")); 18306f45ec7bSml29623 18316f45ec7bSml29623 return (B_FALSE); 18326f45ec7bSml29623 } 18336f45ec7bSml29623 1834678453a8Sspeer /* 1835678453a8Sspeer * nxge_fixup_hung_txdma_rings 1836678453a8Sspeer * 1837678453a8Sspeer * Disable a TDC. 1838678453a8Sspeer * 1839678453a8Sspeer * Arguments: 1840678453a8Sspeer * nxgep 1841678453a8Sspeer * channel The channel to reset. 1842678453a8Sspeer * reg_data The current TX_CS. 1843678453a8Sspeer * 1844678453a8Sspeer * Notes: 1845678453a8Sspeer * Called by nxge_check_tx_hang() 1846678453a8Sspeer * 1847678453a8Sspeer * NPI/NXGE function calls: 1848678453a8Sspeer * npi_txdma_ring_head_get() 1849678453a8Sspeer * 1850678453a8Sspeer * Registers accessed: 1851678453a8Sspeer * TX_RING_HDL DMC+0x40010 Transmit Ring Head Low 1852678453a8Sspeer * 1853678453a8Sspeer * Context: 1854678453a8Sspeer * Any domain 1855678453a8Sspeer */ 18566f45ec7bSml29623 /*ARGSUSED*/ 18576f45ec7bSml29623 void 18586f45ec7bSml29623 nxge_fixup_hung_txdma_rings(p_nxge_t nxgep) 18596f45ec7bSml29623 { 1860678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1861678453a8Sspeer int tdc; 18626f45ec7bSml29623 18636f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings")); 1864678453a8Sspeer 1865678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 18666f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 1867678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 18686f45ec7bSml29623 return; 18696f45ec7bSml29623 } 18706f45ec7bSml29623 1871678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1872678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1873678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1874678453a8Sspeer if (ring) { 1875678453a8Sspeer nxge_txdma_fixup_hung_channel(nxgep, ring, tdc); 18766f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 1877678453a8Sspeer "==> nxge_fixup_hung_txdma_rings: TDC %d", 1878678453a8Sspeer tdc)); 18796f45ec7bSml29623 } 18806f45ec7bSml29623 } 18816f45ec7bSml29623 } 18826f45ec7bSml29623 18836f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings")); 18846f45ec7bSml29623 } 18856f45ec7bSml29623 1886678453a8Sspeer /* 1887678453a8Sspeer * nxge_txdma_fixup_hung_channel 1888678453a8Sspeer * 1889678453a8Sspeer * 'Fix' a hung TDC. 1890678453a8Sspeer * 1891678453a8Sspeer * Arguments: 1892678453a8Sspeer * nxgep 1893678453a8Sspeer * channel The channel to fix. 1894678453a8Sspeer * 1895678453a8Sspeer * Notes: 1896678453a8Sspeer * Called by nxge_fixup_hung_txdma_rings() 1897678453a8Sspeer * 1898678453a8Sspeer * 1. Reclaim the TDC. 1899678453a8Sspeer * 2. Disable the TDC. 1900678453a8Sspeer * 1901678453a8Sspeer * NPI/NXGE function calls: 1902678453a8Sspeer * nxge_txdma_reclaim() 1903678453a8Sspeer * npi_txdma_channel_disable(TX_CS) 1904678453a8Sspeer * npi_txdma_inj_int_error_set(TDMC_INTR_DBG) 1905678453a8Sspeer * 1906678453a8Sspeer * Registers accessed: 1907678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1908678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1909678453a8Sspeer * 1910678453a8Sspeer * Context: 1911678453a8Sspeer * Any domain 1912678453a8Sspeer */ 19136f45ec7bSml29623 /*ARGSUSED*/ 19146f45ec7bSml29623 void 19156f45ec7bSml29623 nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel) 19166f45ec7bSml29623 { 19176f45ec7bSml29623 p_tx_ring_t ring_p; 19186f45ec7bSml29623 19196f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel")); 19206f45ec7bSml29623 ring_p = nxge_txdma_get_ring(nxgep, channel); 19216f45ec7bSml29623 if (ring_p == NULL) { 19226f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 19236f45ec7bSml29623 "<== nxge_txdma_fix_hung_channel")); 19246f45ec7bSml29623 return; 19256f45ec7bSml29623 } 19266f45ec7bSml29623 19276f45ec7bSml29623 if (ring_p->tdc != channel) { 19286f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 19296f45ec7bSml29623 "<== nxge_txdma_fix_hung_channel: channel not matched " 19306f45ec7bSml29623 "ring tdc %d passed channel", 19316f45ec7bSml29623 ring_p->tdc, channel)); 19326f45ec7bSml29623 return; 19336f45ec7bSml29623 } 19346f45ec7bSml29623 19356f45ec7bSml29623 nxge_txdma_fixup_channel(nxgep, ring_p, channel); 19366f45ec7bSml29623 19376f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel")); 19386f45ec7bSml29623 } 19396f45ec7bSml29623 19406f45ec7bSml29623 /*ARGSUSED*/ 19416f45ec7bSml29623 void 19426f45ec7bSml29623 nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, 19436f45ec7bSml29623 uint16_t channel) 19446f45ec7bSml29623 { 19456f45ec7bSml29623 npi_handle_t handle; 19466f45ec7bSml29623 tdmc_intr_dbg_t intr_dbg; 19476f45ec7bSml29623 int status = NXGE_OK; 19486f45ec7bSml29623 19496f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel")); 19506f45ec7bSml29623 19516f45ec7bSml29623 if (ring_p == NULL) { 19526f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 19536f45ec7bSml29623 "<== nxge_txdma_fixup_channel: NULL ring pointer")); 19546f45ec7bSml29623 return; 19556f45ec7bSml29623 } 19566f45ec7bSml29623 19576f45ec7bSml29623 if (ring_p->tdc != channel) { 19586f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 19596f45ec7bSml29623 "<== nxge_txdma_fixup_hung_channel: channel " 19606f45ec7bSml29623 "not matched " 19616f45ec7bSml29623 "ring tdc %d passed channel", 19626f45ec7bSml29623 ring_p->tdc, channel)); 19636f45ec7bSml29623 return; 19646f45ec7bSml29623 } 19656f45ec7bSml29623 19666f45ec7bSml29623 /* Reclaim descriptors */ 19676f45ec7bSml29623 MUTEX_ENTER(&ring_p->lock); 19686f45ec7bSml29623 (void) nxge_txdma_reclaim(nxgep, ring_p, 0); 19696f45ec7bSml29623 MUTEX_EXIT(&ring_p->lock); 19706f45ec7bSml29623 19716f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 19726f45ec7bSml29623 /* 19736f45ec7bSml29623 * Stop the dma channel waits for the stop done. 19746f45ec7bSml29623 * If the stop done bit is not set, then force 19756f45ec7bSml29623 * an error. 19766f45ec7bSml29623 */ 19776f45ec7bSml29623 status = npi_txdma_channel_disable(handle, channel); 19786f45ec7bSml29623 if (!(status & NPI_TXDMA_STOP_FAILED)) { 19796f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 19806f45ec7bSml29623 "<== nxge_txdma_fixup_hung_channel: stopped OK " 19816f45ec7bSml29623 "ring tdc %d passed channel %d", 19826f45ec7bSml29623 ring_p->tdc, channel)); 19836f45ec7bSml29623 return; 19846f45ec7bSml29623 } 19856f45ec7bSml29623 19866f45ec7bSml29623 /* Inject any error */ 19876f45ec7bSml29623 intr_dbg.value = 0; 19886f45ec7bSml29623 intr_dbg.bits.ldw.nack_pref = 1; 19896f45ec7bSml29623 (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg); 19906f45ec7bSml29623 19916f45ec7bSml29623 /* Stop done bit will be set as a result of error injection */ 19926f45ec7bSml29623 status = npi_txdma_channel_disable(handle, channel); 19936f45ec7bSml29623 if (!(status & NPI_TXDMA_STOP_FAILED)) { 19946f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 19956f45ec7bSml29623 "<== nxge_txdma_fixup_hung_channel: stopped again" 19966f45ec7bSml29623 "ring tdc %d passed channel", 19976f45ec7bSml29623 ring_p->tdc, channel)); 19986f45ec7bSml29623 return; 19996f45ec7bSml29623 } 20006f45ec7bSml29623 20016f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 20026f45ec7bSml29623 "<== nxge_txdma_fixup_hung_channel: stop done still not set!! " 20036f45ec7bSml29623 "ring tdc %d passed channel", 20046f45ec7bSml29623 ring_p->tdc, channel)); 20056f45ec7bSml29623 20066f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel")); 20076f45ec7bSml29623 } 20086f45ec7bSml29623 20096f45ec7bSml29623 /*ARGSUSED*/ 20106f45ec7bSml29623 void 20116f45ec7bSml29623 nxge_reclaim_rings(p_nxge_t nxgep) 20126f45ec7bSml29623 { 2013678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 2014678453a8Sspeer int tdc; 20156f45ec7bSml29623 2016678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings")); 2017678453a8Sspeer 2018678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 20196f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 2020678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 20216f45ec7bSml29623 return; 20226f45ec7bSml29623 } 20236f45ec7bSml29623 2024678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 2025678453a8Sspeer if ((1 << tdc) & set->owned.map) { 2026678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 2027678453a8Sspeer if (ring) { 20286f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 2029678453a8Sspeer "==> nxge_reclaim_rings: TDC %d", tdc)); 2030678453a8Sspeer MUTEX_ENTER(&ring->lock); 2031da14cebeSEric Cheng (void) nxge_txdma_reclaim(nxgep, ring, 0); 2032678453a8Sspeer MUTEX_EXIT(&ring->lock); 20336f45ec7bSml29623 } 20346f45ec7bSml29623 } 20356f45ec7bSml29623 } 20366f45ec7bSml29623 20376f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings")); 20386f45ec7bSml29623 } 20396f45ec7bSml29623 20406f45ec7bSml29623 void 20416f45ec7bSml29623 nxge_txdma_regs_dump_channels(p_nxge_t nxgep) 20426f45ec7bSml29623 { 2043678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 20446f45ec7bSml29623 npi_handle_t handle; 2045678453a8Sspeer int tdc; 20466f45ec7bSml29623 2047678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels")); 20486f45ec7bSml29623 20496f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 2050678453a8Sspeer 2051678453a8Sspeer if (!isLDOMguest(nxgep)) { 20526f45ec7bSml29623 (void) npi_txdma_dump_fzc_regs(handle); 20536f45ec7bSml29623 2054678453a8Sspeer /* Dump TXC registers. */ 20556f45ec7bSml29623 (void) npi_txc_dump_fzc_regs(handle); 20566f45ec7bSml29623 (void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num); 20576f45ec7bSml29623 } 20586f45ec7bSml29623 2059678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 20606f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 2061678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 2062678453a8Sspeer return; 2063678453a8Sspeer } 2064678453a8Sspeer 2065678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 2066678453a8Sspeer if ((1 << tdc) & set->owned.map) { 2067678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 2068678453a8Sspeer if (ring) { 2069678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2070678453a8Sspeer "==> nxge_txdma_regs_dump_channels: " 2071678453a8Sspeer "TDC %d", tdc)); 2072678453a8Sspeer (void) npi_txdma_dump_tdc_regs(handle, tdc); 2073678453a8Sspeer 2074678453a8Sspeer /* Dump TXC registers, if able to. */ 2075678453a8Sspeer if (!isLDOMguest(nxgep)) { 2076678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2077678453a8Sspeer "==> nxge_txdma_regs_dump_channels:" 2078678453a8Sspeer " FZC TDC %d", tdc)); 2079678453a8Sspeer (void) npi_txc_dump_tdc_fzc_regs 2080678453a8Sspeer (handle, tdc); 2081678453a8Sspeer } 2082678453a8Sspeer nxge_txdma_regs_dump(nxgep, tdc); 2083678453a8Sspeer } 2084678453a8Sspeer } 20856f45ec7bSml29623 } 20866f45ec7bSml29623 20876f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump")); 20886f45ec7bSml29623 } 20896f45ec7bSml29623 20906f45ec7bSml29623 void 20916f45ec7bSml29623 nxge_txdma_regs_dump(p_nxge_t nxgep, int channel) 20926f45ec7bSml29623 { 20936f45ec7bSml29623 npi_handle_t handle; 20946f45ec7bSml29623 tx_ring_hdl_t hdl; 20956f45ec7bSml29623 tx_ring_kick_t kick; 20966f45ec7bSml29623 tx_cs_t cs; 20976f45ec7bSml29623 txc_control_t control; 20986f45ec7bSml29623 uint32_t bitmap = 0; 20996f45ec7bSml29623 uint32_t burst = 0; 21006f45ec7bSml29623 uint32_t bytes = 0; 21016f45ec7bSml29623 dma_log_page_t cfg; 21026f45ec7bSml29623 21036f45ec7bSml29623 printf("\n\tfunc # %d tdc %d ", 21046f45ec7bSml29623 nxgep->function_num, channel); 21056f45ec7bSml29623 cfg.page_num = 0; 21066f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 21076f45ec7bSml29623 (void) npi_txdma_log_page_get(handle, channel, &cfg); 21086f45ec7bSml29623 printf("\n\tlog page func %d valid page 0 %d", 21096f45ec7bSml29623 cfg.func_num, cfg.valid); 21106f45ec7bSml29623 cfg.page_num = 1; 21116f45ec7bSml29623 (void) npi_txdma_log_page_get(handle, channel, &cfg); 21126f45ec7bSml29623 printf("\n\tlog page func %d valid page 1 %d", 21136f45ec7bSml29623 cfg.func_num, cfg.valid); 21146f45ec7bSml29623 21156f45ec7bSml29623 (void) npi_txdma_ring_head_get(handle, channel, &hdl); 21166f45ec7bSml29623 (void) npi_txdma_desc_kick_reg_get(handle, channel, &kick); 21176f45ec7bSml29623 printf("\n\thead value is 0x%0llx", 21186f45ec7bSml29623 (long long)hdl.value); 21196f45ec7bSml29623 printf("\n\thead index %d", hdl.bits.ldw.head); 21206f45ec7bSml29623 printf("\n\tkick value is 0x%0llx", 21216f45ec7bSml29623 (long long)kick.value); 21226f45ec7bSml29623 printf("\n\ttail index %d\n", kick.bits.ldw.tail); 21236f45ec7bSml29623 21246f45ec7bSml29623 (void) npi_txdma_control_status(handle, OP_GET, channel, &cs); 21256f45ec7bSml29623 printf("\n\tControl statue is 0x%0llx", (long long)cs.value); 21266f45ec7bSml29623 printf("\n\tControl status RST state %d", cs.bits.ldw.rst); 21276f45ec7bSml29623 21286f45ec7bSml29623 (void) npi_txc_control(handle, OP_GET, &control); 21296f45ec7bSml29623 (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap); 21306f45ec7bSml29623 (void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst); 21316f45ec7bSml29623 (void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes); 21326f45ec7bSml29623 21336f45ec7bSml29623 printf("\n\tTXC port control 0x%0llx", 21346f45ec7bSml29623 (long long)control.value); 21356f45ec7bSml29623 printf("\n\tTXC port bitmap 0x%x", bitmap); 21366f45ec7bSml29623 printf("\n\tTXC max burst %d", burst); 21376f45ec7bSml29623 printf("\n\tTXC bytes xmt %d\n", bytes); 21386f45ec7bSml29623 21396f45ec7bSml29623 { 21406f45ec7bSml29623 ipp_status_t status; 21416f45ec7bSml29623 21426f45ec7bSml29623 (void) npi_ipp_get_status(handle, nxgep->function_num, &status); 2143adfcba55Sjoycey #if defined(__i386) 2144adfcba55Sjoycey printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value); 2145adfcba55Sjoycey #else 21466f45ec7bSml29623 printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value); 2147adfcba55Sjoycey #endif 21486f45ec7bSml29623 } 21496f45ec7bSml29623 } 21506f45ec7bSml29623 21516f45ec7bSml29623 /* 2152678453a8Sspeer * nxge_tdc_hvio_setup 2153678453a8Sspeer * 2154678453a8Sspeer * I'm not exactly sure what this code does. 2155678453a8Sspeer * 2156678453a8Sspeer * Arguments: 2157678453a8Sspeer * nxgep 2158678453a8Sspeer * channel The channel to map. 2159678453a8Sspeer * 2160678453a8Sspeer * Notes: 2161678453a8Sspeer * 2162678453a8Sspeer * NPI/NXGE function calls: 2163678453a8Sspeer * na 2164678453a8Sspeer * 2165678453a8Sspeer * Context: 2166678453a8Sspeer * Service domain? 21676f45ec7bSml29623 */ 21686f45ec7bSml29623 #if defined(sun4v) && defined(NIU_LP_WORKAROUND) 2169678453a8Sspeer static void 2170678453a8Sspeer nxge_tdc_hvio_setup( 2171678453a8Sspeer nxge_t *nxgep, int channel) 2172678453a8Sspeer { 2173678453a8Sspeer nxge_dma_common_t *data; 2174678453a8Sspeer nxge_dma_common_t *control; 2175678453a8Sspeer tx_ring_t *ring; 2176678453a8Sspeer 2177678453a8Sspeer ring = nxgep->tx_rings->rings[channel]; 2178678453a8Sspeer data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel]; 2179678453a8Sspeer 2180678453a8Sspeer ring->hv_set = B_FALSE; 2181678453a8Sspeer 2182678453a8Sspeer ring->hv_tx_buf_base_ioaddr_pp = 2183678453a8Sspeer (uint64_t)data->orig_ioaddr_pp; 2184678453a8Sspeer ring->hv_tx_buf_ioaddr_size = 2185678453a8Sspeer (uint64_t)data->orig_alength; 2186678453a8Sspeer 2187678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: " 2188678453a8Sspeer "hv data buf base io $%p size 0x%llx (%d) buf base io $%p " 2189678453a8Sspeer "orig vatopa base io $%p orig_len 0x%llx (%d)", 2190678453a8Sspeer ring->hv_tx_buf_base_ioaddr_pp, 2191678453a8Sspeer ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size, 2192678453a8Sspeer data->ioaddr_pp, data->orig_vatopa, 2193678453a8Sspeer data->orig_alength, data->orig_alength)); 2194678453a8Sspeer 2195678453a8Sspeer control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel]; 2196678453a8Sspeer 2197678453a8Sspeer ring->hv_tx_cntl_base_ioaddr_pp = 2198678453a8Sspeer (uint64_t)control->orig_ioaddr_pp; 2199678453a8Sspeer ring->hv_tx_cntl_ioaddr_size = 2200678453a8Sspeer (uint64_t)control->orig_alength; 2201678453a8Sspeer 2202678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: " 2203678453a8Sspeer "hv cntl base io $%p orig ioaddr_pp ($%p) " 2204678453a8Sspeer "orig vatopa ($%p) size 0x%llx (%d 0x%x)", 2205678453a8Sspeer ring->hv_tx_cntl_base_ioaddr_pp, 2206678453a8Sspeer control->orig_ioaddr_pp, control->orig_vatopa, 2207678453a8Sspeer ring->hv_tx_cntl_ioaddr_size, 2208678453a8Sspeer control->orig_alength, control->orig_alength)); 2209678453a8Sspeer } 22106f45ec7bSml29623 #endif 22116f45ec7bSml29623 2212678453a8Sspeer static nxge_status_t 2213678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel) 2214678453a8Sspeer { 2215678453a8Sspeer nxge_dma_common_t **pData; 2216678453a8Sspeer nxge_dma_common_t **pControl; 2217678453a8Sspeer tx_ring_t **pRing, *ring; 2218678453a8Sspeer tx_mbox_t **mailbox; 2219678453a8Sspeer uint32_t num_chunks; 22206f45ec7bSml29623 2221678453a8Sspeer nxge_status_t status = NXGE_OK; 22226f45ec7bSml29623 2223678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma")); 2224678453a8Sspeer 2225678453a8Sspeer if (!nxgep->tx_cntl_pool_p->buf_allocated) { 2226678453a8Sspeer if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) { 2227678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 2228678453a8Sspeer "<== nxge_map_txdma: buf not allocated")); 22296f45ec7bSml29623 return (NXGE_ERROR); 22306f45ec7bSml29623 } 22316f45ec7bSml29623 } 22326f45ec7bSml29623 2233678453a8Sspeer if (nxge_alloc_txb(nxgep, channel) != NXGE_OK) 2234678453a8Sspeer return (NXGE_ERROR); 22356f45ec7bSml29623 2236678453a8Sspeer num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel]; 2237678453a8Sspeer pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel]; 2238678453a8Sspeer pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel]; 2239678453a8Sspeer pRing = &nxgep->tx_rings->rings[channel]; 2240678453a8Sspeer mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 22416f45ec7bSml29623 2242678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: " 22436f45ec7bSml29623 "tx_rings $%p tx_desc_rings $%p", 2244678453a8Sspeer nxgep->tx_rings, nxgep->tx_rings->rings)); 22456f45ec7bSml29623 22466f45ec7bSml29623 /* 2247678453a8Sspeer * Map descriptors from the buffer pools for <channel>. 22486f45ec7bSml29623 */ 2249678453a8Sspeer 22506f45ec7bSml29623 /* 22516f45ec7bSml29623 * Set up and prepare buffer blocks, descriptors 22526f45ec7bSml29623 * and mailbox. 22536f45ec7bSml29623 */ 22546f45ec7bSml29623 status = nxge_map_txdma_channel(nxgep, channel, 2255678453a8Sspeer pData, pRing, num_chunks, pControl, mailbox); 22566f45ec7bSml29623 if (status != NXGE_OK) { 2257678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 2258678453a8Sspeer "==> nxge_map_txdma(%d): nxge_map_txdma_channel() " 2259678453a8Sspeer "returned 0x%x", 2260678453a8Sspeer nxgep, channel, status)); 22616f45ec7bSml29623 return (status); 22626f45ec7bSml29623 } 22636f45ec7bSml29623 2264678453a8Sspeer ring = *pRing; 22656f45ec7bSml29623 2266678453a8Sspeer ring->index = (uint16_t)channel; 2267678453a8Sspeer ring->tdc_stats = &nxgep->statsp->tdc_stats[channel]; 22686f45ec7bSml29623 2269678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND) 2270678453a8Sspeer if (isLDOMguest(nxgep)) { 2271678453a8Sspeer (void) nxge_tdc_lp_conf(nxgep, channel); 2272678453a8Sspeer } else { 2273678453a8Sspeer nxge_tdc_hvio_setup(nxgep, channel); 22746f45ec7bSml29623 } 2275678453a8Sspeer #endif 22766f45ec7bSml29623 2277678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: " 2278678453a8Sspeer "(status 0x%x channel %d)", status, channel)); 22796f45ec7bSml29623 2280678453a8Sspeer return (status); 22816f45ec7bSml29623 } 22826f45ec7bSml29623 22836f45ec7bSml29623 static nxge_status_t 22846f45ec7bSml29623 nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel, 22856f45ec7bSml29623 p_nxge_dma_common_t *dma_buf_p, 22866f45ec7bSml29623 p_tx_ring_t *tx_desc_p, 22876f45ec7bSml29623 uint32_t num_chunks, 22886f45ec7bSml29623 p_nxge_dma_common_t *dma_cntl_p, 22896f45ec7bSml29623 p_tx_mbox_t *tx_mbox_p) 22906f45ec7bSml29623 { 22916f45ec7bSml29623 int status = NXGE_OK; 22926f45ec7bSml29623 22936f45ec7bSml29623 /* 22946f45ec7bSml29623 * Set up and prepare buffer blocks, descriptors 22956f45ec7bSml29623 * and mailbox. 22966f45ec7bSml29623 */ 2297678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 22986f45ec7bSml29623 "==> nxge_map_txdma_channel (channel %d)", channel)); 22996f45ec7bSml29623 /* 23006f45ec7bSml29623 * Transmit buffer blocks 23016f45ec7bSml29623 */ 23026f45ec7bSml29623 status = nxge_map_txdma_channel_buf_ring(nxgep, channel, 23036f45ec7bSml29623 dma_buf_p, tx_desc_p, num_chunks); 23046f45ec7bSml29623 if (status != NXGE_OK) { 23056f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 23066f45ec7bSml29623 "==> nxge_map_txdma_channel (channel %d): " 23076f45ec7bSml29623 "map buffer failed 0x%x", channel, status)); 23086f45ec7bSml29623 goto nxge_map_txdma_channel_exit; 23096f45ec7bSml29623 } 23106f45ec7bSml29623 23116f45ec7bSml29623 /* 23126f45ec7bSml29623 * Transmit block ring, and mailbox. 23136f45ec7bSml29623 */ 23146f45ec7bSml29623 nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p, 23156f45ec7bSml29623 tx_mbox_p); 23166f45ec7bSml29623 23176f45ec7bSml29623 goto nxge_map_txdma_channel_exit; 23186f45ec7bSml29623 23196f45ec7bSml29623 nxge_map_txdma_channel_fail1: 2320678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 23216f45ec7bSml29623 "==> nxge_map_txdma_channel: unmap buf" 23226f45ec7bSml29623 "(status 0x%x channel %d)", 23236f45ec7bSml29623 status, channel)); 23246f45ec7bSml29623 nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p); 23256f45ec7bSml29623 23266f45ec7bSml29623 nxge_map_txdma_channel_exit: 2327678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 23286f45ec7bSml29623 "<== nxge_map_txdma_channel: " 23296f45ec7bSml29623 "(status 0x%x channel %d)", 23306f45ec7bSml29623 status, channel)); 23316f45ec7bSml29623 23326f45ec7bSml29623 return (status); 23336f45ec7bSml29623 } 23346f45ec7bSml29623 23356f45ec7bSml29623 /*ARGSUSED*/ 23366f45ec7bSml29623 static void 2337678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel) 23386f45ec7bSml29623 { 2339678453a8Sspeer tx_ring_t *ring; 2340678453a8Sspeer tx_mbox_t *mailbox; 2341678453a8Sspeer 23426f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 23436f45ec7bSml29623 "==> nxge_unmap_txdma_channel (channel %d)", channel)); 23446f45ec7bSml29623 /* 23456f45ec7bSml29623 * unmap tx block ring, and mailbox. 23466f45ec7bSml29623 */ 2347678453a8Sspeer ring = nxgep->tx_rings->rings[channel]; 2348678453a8Sspeer mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 2349678453a8Sspeer 2350678453a8Sspeer (void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox); 23516f45ec7bSml29623 23526f45ec7bSml29623 /* unmap buffer blocks */ 2353678453a8Sspeer (void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring); 2354678453a8Sspeer 2355678453a8Sspeer nxge_free_txb(nxgep, channel); 23566f45ec7bSml29623 235748056c53SMichael Speer /* 235848056c53SMichael Speer * Cleanup the reference to the ring now that it does not exist. 235948056c53SMichael Speer */ 236048056c53SMichael Speer nxgep->tx_rings->rings[channel] = NULL; 236148056c53SMichael Speer 23626f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel")); 23636f45ec7bSml29623 } 23646f45ec7bSml29623 2365678453a8Sspeer /* 2366678453a8Sspeer * nxge_map_txdma_channel_cfg_ring 2367678453a8Sspeer * 2368678453a8Sspeer * Map a TDC into our kernel space. 2369678453a8Sspeer * This function allocates all of the per-channel data structures. 2370678453a8Sspeer * 2371678453a8Sspeer * Arguments: 2372678453a8Sspeer * nxgep 2373678453a8Sspeer * dma_channel The channel to map. 2374678453a8Sspeer * dma_cntl_p 2375678453a8Sspeer * tx_ring_p dma_channel's transmit ring 2376678453a8Sspeer * tx_mbox_p dma_channel's mailbox 2377678453a8Sspeer * 2378678453a8Sspeer * Notes: 2379678453a8Sspeer * 2380678453a8Sspeer * NPI/NXGE function calls: 2381678453a8Sspeer * nxge_setup_dma_common() 2382678453a8Sspeer * 2383678453a8Sspeer * Registers accessed: 2384678453a8Sspeer * none. 2385678453a8Sspeer * 2386678453a8Sspeer * Context: 2387678453a8Sspeer * Any domain 2388678453a8Sspeer */ 23896f45ec7bSml29623 /*ARGSUSED*/ 23906f45ec7bSml29623 static void 23916f45ec7bSml29623 nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel, 23926f45ec7bSml29623 p_nxge_dma_common_t *dma_cntl_p, 23936f45ec7bSml29623 p_tx_ring_t tx_ring_p, 23946f45ec7bSml29623 p_tx_mbox_t *tx_mbox_p) 23956f45ec7bSml29623 { 23966f45ec7bSml29623 p_tx_mbox_t mboxp; 23976f45ec7bSml29623 p_nxge_dma_common_t cntl_dmap; 23986f45ec7bSml29623 p_nxge_dma_common_t dmap; 23996f45ec7bSml29623 p_tx_rng_cfig_t tx_ring_cfig_p; 24006f45ec7bSml29623 p_tx_ring_kick_t tx_ring_kick_p; 24016f45ec7bSml29623 p_tx_cs_t tx_cs_p; 24026f45ec7bSml29623 p_tx_dma_ent_msk_t tx_evmask_p; 24036f45ec7bSml29623 p_txdma_mbh_t mboxh_p; 24046f45ec7bSml29623 p_txdma_mbl_t mboxl_p; 24056f45ec7bSml29623 uint64_t tx_desc_len; 24066f45ec7bSml29623 24076f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24086f45ec7bSml29623 "==> nxge_map_txdma_channel_cfg_ring")); 24096f45ec7bSml29623 24106f45ec7bSml29623 cntl_dmap = *dma_cntl_p; 24116f45ec7bSml29623 24126f45ec7bSml29623 dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc; 24136f45ec7bSml29623 nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size, 24146f45ec7bSml29623 sizeof (tx_desc_t)); 24156f45ec7bSml29623 /* 24166f45ec7bSml29623 * Zero out transmit ring descriptors. 24176f45ec7bSml29623 */ 24186f45ec7bSml29623 bzero((caddr_t)dmap->kaddrp, dmap->alength); 24196f45ec7bSml29623 tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig); 24206f45ec7bSml29623 tx_ring_kick_p = &(tx_ring_p->tx_ring_kick); 24216f45ec7bSml29623 tx_cs_p = &(tx_ring_p->tx_cs); 24226f45ec7bSml29623 tx_evmask_p = &(tx_ring_p->tx_evmask); 24236f45ec7bSml29623 tx_ring_cfig_p->value = 0; 24246f45ec7bSml29623 tx_ring_kick_p->value = 0; 24256f45ec7bSml29623 tx_cs_p->value = 0; 24266f45ec7bSml29623 tx_evmask_p->value = 0; 24276f45ec7bSml29623 24286f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24296f45ec7bSml29623 "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p", 24306f45ec7bSml29623 dma_channel, 24316f45ec7bSml29623 dmap->dma_cookie.dmac_laddress)); 24326f45ec7bSml29623 24336f45ec7bSml29623 tx_ring_cfig_p->value = 0; 24346f45ec7bSml29623 tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3); 24356f45ec7bSml29623 tx_ring_cfig_p->value = 24366f45ec7bSml29623 (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) | 24376f45ec7bSml29623 (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT); 24386f45ec7bSml29623 24396f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24406f45ec7bSml29623 "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx", 24416f45ec7bSml29623 dma_channel, 24426f45ec7bSml29623 tx_ring_cfig_p->value)); 24436f45ec7bSml29623 24446f45ec7bSml29623 tx_cs_p->bits.ldw.rst = 1; 24456f45ec7bSml29623 24466f45ec7bSml29623 /* Map in mailbox */ 24476f45ec7bSml29623 mboxp = (p_tx_mbox_t) 24486f45ec7bSml29623 KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP); 24496f45ec7bSml29623 dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox; 24506f45ec7bSml29623 nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t)); 24516f45ec7bSml29623 mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh; 24526f45ec7bSml29623 mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl; 24536f45ec7bSml29623 mboxh_p->value = mboxl_p->value = 0; 24546f45ec7bSml29623 24556f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24566f45ec7bSml29623 "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx", 24576f45ec7bSml29623 dmap->dma_cookie.dmac_laddress)); 24586f45ec7bSml29623 24596f45ec7bSml29623 mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >> 24606f45ec7bSml29623 TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK); 24616f45ec7bSml29623 24626f45ec7bSml29623 mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress & 24636f45ec7bSml29623 TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT); 24646f45ec7bSml29623 24656f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24666f45ec7bSml29623 "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx", 24676f45ec7bSml29623 dmap->dma_cookie.dmac_laddress)); 24686f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24696f45ec7bSml29623 "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p " 24706f45ec7bSml29623 "mbox $%p", 24716f45ec7bSml29623 mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr)); 24726f45ec7bSml29623 tx_ring_p->page_valid.value = 0; 24736f45ec7bSml29623 tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0; 24746f45ec7bSml29623 tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0; 24756f45ec7bSml29623 tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0; 24766f45ec7bSml29623 tx_ring_p->page_hdl.value = 0; 24776f45ec7bSml29623 24786f45ec7bSml29623 tx_ring_p->page_valid.bits.ldw.page0 = 1; 24796f45ec7bSml29623 tx_ring_p->page_valid.bits.ldw.page1 = 1; 24806f45ec7bSml29623 24816f45ec7bSml29623 tx_ring_p->max_burst.value = 0; 24826f45ec7bSml29623 tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT; 24836f45ec7bSml29623 24846f45ec7bSml29623 *tx_mbox_p = mboxp; 24856f45ec7bSml29623 24866f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24876f45ec7bSml29623 "<== nxge_map_txdma_channel_cfg_ring")); 24886f45ec7bSml29623 } 24896f45ec7bSml29623 24906f45ec7bSml29623 /*ARGSUSED*/ 24916f45ec7bSml29623 static void 24926f45ec7bSml29623 nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep, 24936f45ec7bSml29623 p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p) 24946f45ec7bSml29623 { 24956f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 24966f45ec7bSml29623 "==> nxge_unmap_txdma_channel_cfg_ring: channel %d", 24976f45ec7bSml29623 tx_ring_p->tdc)); 24986f45ec7bSml29623 24996f45ec7bSml29623 KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t)); 25006f45ec7bSml29623 25016f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 25026f45ec7bSml29623 "<== nxge_unmap_txdma_channel_cfg_ring")); 25036f45ec7bSml29623 } 25046f45ec7bSml29623 2505678453a8Sspeer /* 2506678453a8Sspeer * nxge_map_txdma_channel_buf_ring 2507678453a8Sspeer * 2508678453a8Sspeer * 2509678453a8Sspeer * Arguments: 2510678453a8Sspeer * nxgep 2511678453a8Sspeer * channel The channel to map. 2512678453a8Sspeer * dma_buf_p 2513678453a8Sspeer * tx_desc_p channel's descriptor ring 2514678453a8Sspeer * num_chunks 2515678453a8Sspeer * 2516678453a8Sspeer * Notes: 2517678453a8Sspeer * 2518678453a8Sspeer * NPI/NXGE function calls: 2519678453a8Sspeer * nxge_setup_dma_common() 2520678453a8Sspeer * 2521678453a8Sspeer * Registers accessed: 2522678453a8Sspeer * none. 2523678453a8Sspeer * 2524678453a8Sspeer * Context: 2525678453a8Sspeer * Any domain 2526678453a8Sspeer */ 25276f45ec7bSml29623 static nxge_status_t 25286f45ec7bSml29623 nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel, 25296f45ec7bSml29623 p_nxge_dma_common_t *dma_buf_p, 25306f45ec7bSml29623 p_tx_ring_t *tx_desc_p, uint32_t num_chunks) 25316f45ec7bSml29623 { 25326f45ec7bSml29623 p_nxge_dma_common_t dma_bufp, tmp_bufp; 25336f45ec7bSml29623 p_nxge_dma_common_t dmap; 25346f45ec7bSml29623 nxge_os_dma_handle_t tx_buf_dma_handle; 25356f45ec7bSml29623 p_tx_ring_t tx_ring_p; 25366f45ec7bSml29623 p_tx_msg_t tx_msg_ring; 25376f45ec7bSml29623 nxge_status_t status = NXGE_OK; 25386f45ec7bSml29623 int ddi_status = DDI_SUCCESS; 25396f45ec7bSml29623 int i, j, index; 25406f45ec7bSml29623 uint32_t size, bsize; 25416f45ec7bSml29623 uint32_t nblocks, nmsgs; 2542da14cebeSEric Cheng char qname[TASKQ_NAMELEN]; 25436f45ec7bSml29623 25446f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 25456f45ec7bSml29623 "==> nxge_map_txdma_channel_buf_ring")); 25466f45ec7bSml29623 25476f45ec7bSml29623 dma_bufp = tmp_bufp = *dma_buf_p; 25486f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 25496f45ec7bSml29623 " nxge_map_txdma_channel_buf_ring: channel %d to map %d " 25506f45ec7bSml29623 "chunks bufp $%p", 25516f45ec7bSml29623 channel, num_chunks, dma_bufp)); 25526f45ec7bSml29623 25536f45ec7bSml29623 nmsgs = 0; 25546f45ec7bSml29623 for (i = 0; i < num_chunks; i++, tmp_bufp++) { 25556f45ec7bSml29623 nmsgs += tmp_bufp->nblocks; 25566f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 25576f45ec7bSml29623 "==> nxge_map_txdma_channel_buf_ring: channel %d " 25586f45ec7bSml29623 "bufp $%p nblocks %d nmsgs %d", 25596f45ec7bSml29623 channel, tmp_bufp, tmp_bufp->nblocks, nmsgs)); 25606f45ec7bSml29623 } 25616f45ec7bSml29623 if (!nmsgs) { 25626f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 25636f45ec7bSml29623 "<== nxge_map_txdma_channel_buf_ring: channel %d " 25646f45ec7bSml29623 "no msg blocks", 25656f45ec7bSml29623 channel)); 25666f45ec7bSml29623 status = NXGE_ERROR; 25676f45ec7bSml29623 goto nxge_map_txdma_channel_buf_ring_exit; 25686f45ec7bSml29623 } 25696f45ec7bSml29623 25706f45ec7bSml29623 tx_ring_p = (p_tx_ring_t) 25716f45ec7bSml29623 KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP); 25726f45ec7bSml29623 MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER, 25736f45ec7bSml29623 (void *)nxgep->interrupt_cookie); 25741f8914d5Sml29623 257522c0d73aSspeer (void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE); 25766895688eSspeer tx_ring_p->tx_ring_busy = B_FALSE; 25771f8914d5Sml29623 tx_ring_p->nxgep = nxgep; 2578da14cebeSEric Cheng tx_ring_p->tx_ring_handle = (mac_ring_handle_t)NULL; 2579da14cebeSEric Cheng (void) snprintf(qname, TASKQ_NAMELEN, "tx_%d_%d", 2580da14cebeSEric Cheng nxgep->instance, channel); 2581da14cebeSEric Cheng tx_ring_p->taskq = ddi_taskq_create(nxgep->dip, qname, 1, 2582da14cebeSEric Cheng TASKQ_DEFAULTPRI, 0); 2583da14cebeSEric Cheng if (tx_ring_p->taskq == NULL) { 2584da14cebeSEric Cheng goto nxge_map_txdma_channel_buf_ring_fail1; 2585da14cebeSEric Cheng } 2586da14cebeSEric Cheng 25876f45ec7bSml29623 /* 25886f45ec7bSml29623 * Allocate transmit message rings and handles for packets 25896f45ec7bSml29623 * not to be copied to premapped buffers. 25906f45ec7bSml29623 */ 25916f45ec7bSml29623 size = nmsgs * sizeof (tx_msg_t); 25926f45ec7bSml29623 tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP); 25936f45ec7bSml29623 for (i = 0; i < nmsgs; i++) { 25946f45ec7bSml29623 ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr, 25956f45ec7bSml29623 DDI_DMA_DONTWAIT, 0, 25966f45ec7bSml29623 &tx_msg_ring[i].dma_handle); 25976f45ec7bSml29623 if (ddi_status != DDI_SUCCESS) { 25986f45ec7bSml29623 status |= NXGE_DDI_FAILED; 25996f45ec7bSml29623 break; 26006f45ec7bSml29623 } 26016f45ec7bSml29623 } 26026f45ec7bSml29623 if (i < nmsgs) { 260356d930aeSspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 260456d930aeSspeer "Allocate handles failed.")); 26056f45ec7bSml29623 goto nxge_map_txdma_channel_buf_ring_fail1; 26066f45ec7bSml29623 } 26076f45ec7bSml29623 26086f45ec7bSml29623 tx_ring_p->tdc = channel; 26096f45ec7bSml29623 tx_ring_p->tx_msg_ring = tx_msg_ring; 26106f45ec7bSml29623 tx_ring_p->tx_ring_size = nmsgs; 26116f45ec7bSml29623 tx_ring_p->num_chunks = num_chunks; 26126f45ec7bSml29623 if (!nxge_tx_intr_thres) { 26136f45ec7bSml29623 nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4; 26146f45ec7bSml29623 } 26156f45ec7bSml29623 tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1; 26166f45ec7bSml29623 tx_ring_p->rd_index = 0; 26176f45ec7bSml29623 tx_ring_p->wr_index = 0; 26186f45ec7bSml29623 tx_ring_p->ring_head.value = 0; 26196f45ec7bSml29623 tx_ring_p->ring_kick_tail.value = 0; 26206f45ec7bSml29623 tx_ring_p->descs_pending = 0; 26216f45ec7bSml29623 26226f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 26236f45ec7bSml29623 "==> nxge_map_txdma_channel_buf_ring: channel %d " 26246f45ec7bSml29623 "actual tx desc max %d nmsgs %d " 26256f45ec7bSml29623 "(config nxge_tx_ring_size %d)", 26266f45ec7bSml29623 channel, tx_ring_p->tx_ring_size, nmsgs, 26276f45ec7bSml29623 nxge_tx_ring_size)); 26286f45ec7bSml29623 26296f45ec7bSml29623 /* 26306f45ec7bSml29623 * Map in buffers from the buffer pool. 26316f45ec7bSml29623 */ 26326f45ec7bSml29623 index = 0; 26336f45ec7bSml29623 bsize = dma_bufp->block_size; 26346f45ec7bSml29623 26356f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: " 26366f45ec7bSml29623 "dma_bufp $%p tx_rng_p $%p " 26376f45ec7bSml29623 "tx_msg_rng_p $%p bsize %d", 26386f45ec7bSml29623 dma_bufp, tx_ring_p, tx_msg_ring, bsize)); 26396f45ec7bSml29623 26406f45ec7bSml29623 tx_buf_dma_handle = dma_bufp->dma_handle; 26416f45ec7bSml29623 for (i = 0; i < num_chunks; i++, dma_bufp++) { 26426f45ec7bSml29623 bsize = dma_bufp->block_size; 26436f45ec7bSml29623 nblocks = dma_bufp->nblocks; 26446f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 26456f45ec7bSml29623 "==> nxge_map_txdma_channel_buf_ring: dma chunk %d " 26466f45ec7bSml29623 "size %d dma_bufp $%p", 26476f45ec7bSml29623 i, sizeof (nxge_dma_common_t), dma_bufp)); 26486f45ec7bSml29623 26496f45ec7bSml29623 for (j = 0; j < nblocks; j++) { 26506f45ec7bSml29623 tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle; 26516f45ec7bSml29623 dmap = &tx_msg_ring[index++].buf_dma; 26526f45ec7bSml29623 #ifdef TX_MEM_DEBUG 26536f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 26546f45ec7bSml29623 "==> nxge_map_txdma_channel_buf_ring: j %d" 26556f45ec7bSml29623 "dmap $%p", i, dmap)); 26566f45ec7bSml29623 #endif 26576f45ec7bSml29623 nxge_setup_dma_common(dmap, dma_bufp, 1, 26586f45ec7bSml29623 bsize); 26596f45ec7bSml29623 } 26606f45ec7bSml29623 } 26616f45ec7bSml29623 26626f45ec7bSml29623 if (i < num_chunks) { 266356d930aeSspeer status = NXGE_ERROR; 26646f45ec7bSml29623 goto nxge_map_txdma_channel_buf_ring_fail1; 26656f45ec7bSml29623 } 26666f45ec7bSml29623 26676f45ec7bSml29623 *tx_desc_p = tx_ring_p; 26686f45ec7bSml29623 26696f45ec7bSml29623 goto nxge_map_txdma_channel_buf_ring_exit; 26706f45ec7bSml29623 26716f45ec7bSml29623 nxge_map_txdma_channel_buf_ring_fail1: 2672da14cebeSEric Cheng if (tx_ring_p->taskq) { 2673da14cebeSEric Cheng ddi_taskq_destroy(tx_ring_p->taskq); 2674da14cebeSEric Cheng tx_ring_p->taskq = NULL; 26751f8914d5Sml29623 } 26761f8914d5Sml29623 26776f45ec7bSml29623 index--; 26786f45ec7bSml29623 for (; index >= 0; index--) { 267956d930aeSspeer if (tx_msg_ring[index].dma_handle != NULL) { 268056d930aeSspeer ddi_dma_free_handle(&tx_msg_ring[index].dma_handle); 26816f45ec7bSml29623 } 26826f45ec7bSml29623 } 26836f45ec7bSml29623 MUTEX_DESTROY(&tx_ring_p->lock); 268456d930aeSspeer KMEM_FREE(tx_msg_ring, size); 26856f45ec7bSml29623 KMEM_FREE(tx_ring_p, sizeof (tx_ring_t)); 26866f45ec7bSml29623 268756d930aeSspeer status = NXGE_ERROR; 268856d930aeSspeer 26896f45ec7bSml29623 nxge_map_txdma_channel_buf_ring_exit: 26906f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 26916f45ec7bSml29623 "<== nxge_map_txdma_channel_buf_ring status 0x%x", status)); 26926f45ec7bSml29623 26936f45ec7bSml29623 return (status); 26946f45ec7bSml29623 } 26956f45ec7bSml29623 26966f45ec7bSml29623 /*ARGSUSED*/ 26976f45ec7bSml29623 static void 26986f45ec7bSml29623 nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p) 26996f45ec7bSml29623 { 27006f45ec7bSml29623 p_tx_msg_t tx_msg_ring; 27016f45ec7bSml29623 p_tx_msg_t tx_msg_p; 27026f45ec7bSml29623 int i; 27036f45ec7bSml29623 27046f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 27056f45ec7bSml29623 "==> nxge_unmap_txdma_channel_buf_ring")); 27066f45ec7bSml29623 if (tx_ring_p == NULL) { 27076f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 27086f45ec7bSml29623 "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp")); 27096f45ec7bSml29623 return; 27106f45ec7bSml29623 } 27116f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 27126f45ec7bSml29623 "==> nxge_unmap_txdma_channel_buf_ring: channel %d", 27136f45ec7bSml29623 tx_ring_p->tdc)); 27146f45ec7bSml29623 27156f45ec7bSml29623 tx_msg_ring = tx_ring_p->tx_msg_ring; 2716678453a8Sspeer 2717678453a8Sspeer /* 2718678453a8Sspeer * Since the serialization thread, timer thread and 2719678453a8Sspeer * interrupt thread can all call the transmit reclaim, 2720678453a8Sspeer * the unmapping function needs to acquire the lock 2721678453a8Sspeer * to free those buffers which were transmitted 2722678453a8Sspeer * by the hardware already. 2723678453a8Sspeer */ 2724678453a8Sspeer MUTEX_ENTER(&tx_ring_p->lock); 2725678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2726678453a8Sspeer "==> nxge_unmap_txdma_channel_buf_ring (reclaim): " 2727678453a8Sspeer "channel %d", 2728678453a8Sspeer tx_ring_p->tdc)); 2729678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 2730678453a8Sspeer 27316f45ec7bSml29623 for (i = 0; i < tx_ring_p->tx_ring_size; i++) { 27326f45ec7bSml29623 tx_msg_p = &tx_msg_ring[i]; 27336f45ec7bSml29623 if (tx_msg_p->tx_message != NULL) { 27346f45ec7bSml29623 freemsg(tx_msg_p->tx_message); 27356f45ec7bSml29623 tx_msg_p->tx_message = NULL; 27366f45ec7bSml29623 } 27376f45ec7bSml29623 } 27386f45ec7bSml29623 27396f45ec7bSml29623 for (i = 0; i < tx_ring_p->tx_ring_size; i++) { 27406f45ec7bSml29623 if (tx_msg_ring[i].dma_handle != NULL) { 27416f45ec7bSml29623 ddi_dma_free_handle(&tx_msg_ring[i].dma_handle); 27426f45ec7bSml29623 } 2743678453a8Sspeer tx_msg_ring[i].dma_handle = NULL; 27446f45ec7bSml29623 } 27456f45ec7bSml29623 2746678453a8Sspeer MUTEX_EXIT(&tx_ring_p->lock); 2747678453a8Sspeer 2748da14cebeSEric Cheng if (tx_ring_p->taskq) { 2749da14cebeSEric Cheng ddi_taskq_destroy(tx_ring_p->taskq); 2750da14cebeSEric Cheng tx_ring_p->taskq = NULL; 27511f8914d5Sml29623 } 27521f8914d5Sml29623 27536f45ec7bSml29623 MUTEX_DESTROY(&tx_ring_p->lock); 27546f45ec7bSml29623 KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size); 27556f45ec7bSml29623 KMEM_FREE(tx_ring_p, sizeof (tx_ring_t)); 27566f45ec7bSml29623 27576f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 27586f45ec7bSml29623 "<== nxge_unmap_txdma_channel_buf_ring")); 27596f45ec7bSml29623 } 27606f45ec7bSml29623 27616f45ec7bSml29623 static nxge_status_t 2762678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel) 27636f45ec7bSml29623 { 27646f45ec7bSml29623 p_tx_rings_t tx_rings; 27656f45ec7bSml29623 p_tx_ring_t *tx_desc_rings; 27666f45ec7bSml29623 p_tx_mbox_areas_t tx_mbox_areas_p; 27676f45ec7bSml29623 p_tx_mbox_t *tx_mbox_p; 27686f45ec7bSml29623 nxge_status_t status = NXGE_OK; 27696f45ec7bSml29623 27706f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start")); 27716f45ec7bSml29623 27726f45ec7bSml29623 tx_rings = nxgep->tx_rings; 27736f45ec7bSml29623 if (tx_rings == NULL) { 27746f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 27756f45ec7bSml29623 "<== nxge_txdma_hw_start: NULL ring pointer")); 27766f45ec7bSml29623 return (NXGE_ERROR); 27776f45ec7bSml29623 } 27786f45ec7bSml29623 tx_desc_rings = tx_rings->rings; 27796f45ec7bSml29623 if (tx_desc_rings == NULL) { 27806f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 27816f45ec7bSml29623 "<== nxge_txdma_hw_start: NULL ring pointers")); 27826f45ec7bSml29623 return (NXGE_ERROR); 27836f45ec7bSml29623 } 27846f45ec7bSml29623 2785678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 2786678453a8Sspeer "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings)); 27876f45ec7bSml29623 27886f45ec7bSml29623 tx_mbox_areas_p = nxgep->tx_mbox_areas_p; 27896f45ec7bSml29623 tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p; 27906f45ec7bSml29623 27916f45ec7bSml29623 status = nxge_txdma_start_channel(nxgep, channel, 2792678453a8Sspeer (p_tx_ring_t)tx_desc_rings[channel], 2793678453a8Sspeer (p_tx_mbox_t)tx_mbox_p[channel]); 27946f45ec7bSml29623 if (status != NXGE_OK) { 27956f45ec7bSml29623 goto nxge_txdma_hw_start_fail1; 27966f45ec7bSml29623 } 27976f45ec7bSml29623 27986f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 27996f45ec7bSml29623 "tx_rings $%p rings $%p", 28006f45ec7bSml29623 nxgep->tx_rings, nxgep->tx_rings->rings)); 28016f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 28026f45ec7bSml29623 "tx_rings $%p tx_desc_rings $%p", 28036f45ec7bSml29623 nxgep->tx_rings, tx_desc_rings)); 28046f45ec7bSml29623 28056f45ec7bSml29623 goto nxge_txdma_hw_start_exit; 28066f45ec7bSml29623 28076f45ec7bSml29623 nxge_txdma_hw_start_fail1: 28086f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 28096f45ec7bSml29623 "==> nxge_txdma_hw_start: disable " 2810678453a8Sspeer "(status 0x%x channel %d)", status, channel)); 28116f45ec7bSml29623 28126f45ec7bSml29623 nxge_txdma_hw_start_exit: 28136f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 28146f45ec7bSml29623 "==> nxge_txdma_hw_start: (status 0x%x)", status)); 28156f45ec7bSml29623 28166f45ec7bSml29623 return (status); 28176f45ec7bSml29623 } 28186f45ec7bSml29623 2819678453a8Sspeer /* 2820678453a8Sspeer * nxge_txdma_start_channel 2821678453a8Sspeer * 2822678453a8Sspeer * Start a TDC. 2823678453a8Sspeer * 2824678453a8Sspeer * Arguments: 2825678453a8Sspeer * nxgep 2826678453a8Sspeer * channel The channel to start. 2827678453a8Sspeer * tx_ring_p channel's transmit descriptor ring. 2828678453a8Sspeer * tx_mbox_p channel' smailbox. 2829678453a8Sspeer * 2830678453a8Sspeer * Notes: 2831678453a8Sspeer * 2832678453a8Sspeer * NPI/NXGE function calls: 2833678453a8Sspeer * nxge_reset_txdma_channel() 2834678453a8Sspeer * nxge_init_txdma_channel_event_mask() 2835678453a8Sspeer * nxge_enable_txdma_channel() 2836678453a8Sspeer * 2837678453a8Sspeer * Registers accessed: 2838678453a8Sspeer * none directly (see functions above). 2839678453a8Sspeer * 2840678453a8Sspeer * Context: 2841678453a8Sspeer * Any domain 2842678453a8Sspeer */ 28436f45ec7bSml29623 static nxge_status_t 28446f45ec7bSml29623 nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel, 28456f45ec7bSml29623 p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p) 28466f45ec7bSml29623 28476f45ec7bSml29623 { 28486f45ec7bSml29623 nxge_status_t status = NXGE_OK; 28496f45ec7bSml29623 28506f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 28516f45ec7bSml29623 "==> nxge_txdma_start_channel (channel %d)", channel)); 28526f45ec7bSml29623 /* 28536f45ec7bSml29623 * TXDMA/TXC must be in stopped state. 28546f45ec7bSml29623 */ 28556f45ec7bSml29623 (void) nxge_txdma_stop_inj_err(nxgep, channel); 28566f45ec7bSml29623 28576f45ec7bSml29623 /* 28586f45ec7bSml29623 * Reset TXDMA channel 28596f45ec7bSml29623 */ 28606f45ec7bSml29623 tx_ring_p->tx_cs.value = 0; 28616f45ec7bSml29623 tx_ring_p->tx_cs.bits.ldw.rst = 1; 28626f45ec7bSml29623 status = nxge_reset_txdma_channel(nxgep, channel, 28636f45ec7bSml29623 tx_ring_p->tx_cs.value); 28646f45ec7bSml29623 if (status != NXGE_OK) { 28656f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 28666f45ec7bSml29623 "==> nxge_txdma_start_channel (channel %d)" 28676f45ec7bSml29623 " reset channel failed 0x%x", channel, status)); 28686f45ec7bSml29623 goto nxge_txdma_start_channel_exit; 28696f45ec7bSml29623 } 28706f45ec7bSml29623 28716f45ec7bSml29623 /* 28726f45ec7bSml29623 * Initialize the TXDMA channel specific FZC control 28736f45ec7bSml29623 * configurations. These FZC registers are pertaining 28746f45ec7bSml29623 * to each TX channel (i.e. logical pages). 28756f45ec7bSml29623 */ 2876678453a8Sspeer if (!isLDOMguest(nxgep)) { 28776f45ec7bSml29623 status = nxge_init_fzc_txdma_channel(nxgep, channel, 28786f45ec7bSml29623 tx_ring_p, tx_mbox_p); 28796f45ec7bSml29623 if (status != NXGE_OK) { 28806f45ec7bSml29623 goto nxge_txdma_start_channel_exit; 28816f45ec7bSml29623 } 2882678453a8Sspeer } 28836f45ec7bSml29623 28846f45ec7bSml29623 /* 28856f45ec7bSml29623 * Initialize the event masks. 28866f45ec7bSml29623 */ 28876f45ec7bSml29623 tx_ring_p->tx_evmask.value = 0; 28886f45ec7bSml29623 status = nxge_init_txdma_channel_event_mask(nxgep, 28896f45ec7bSml29623 channel, &tx_ring_p->tx_evmask); 28906f45ec7bSml29623 if (status != NXGE_OK) { 28916f45ec7bSml29623 goto nxge_txdma_start_channel_exit; 28926f45ec7bSml29623 } 28936f45ec7bSml29623 28946f45ec7bSml29623 /* 28956f45ec7bSml29623 * Load TXDMA descriptors, buffers, mailbox, 28966f45ec7bSml29623 * initialise the DMA channels and 28976f45ec7bSml29623 * enable each DMA channel. 28986f45ec7bSml29623 */ 28996f45ec7bSml29623 status = nxge_enable_txdma_channel(nxgep, channel, 29006f45ec7bSml29623 tx_ring_p, tx_mbox_p); 29016f45ec7bSml29623 if (status != NXGE_OK) { 29026f45ec7bSml29623 goto nxge_txdma_start_channel_exit; 29036f45ec7bSml29623 } 29046f45ec7bSml29623 29056f45ec7bSml29623 nxge_txdma_start_channel_exit: 29066f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel")); 29076f45ec7bSml29623 29086f45ec7bSml29623 return (status); 29096f45ec7bSml29623 } 29106f45ec7bSml29623 2911678453a8Sspeer /* 2912678453a8Sspeer * nxge_txdma_stop_channel 2913678453a8Sspeer * 2914678453a8Sspeer * Stop a TDC. 2915678453a8Sspeer * 2916678453a8Sspeer * Arguments: 2917678453a8Sspeer * nxgep 2918678453a8Sspeer * channel The channel to stop. 2919678453a8Sspeer * tx_ring_p channel's transmit descriptor ring. 2920678453a8Sspeer * tx_mbox_p channel' smailbox. 2921678453a8Sspeer * 2922678453a8Sspeer * Notes: 2923678453a8Sspeer * 2924678453a8Sspeer * NPI/NXGE function calls: 2925678453a8Sspeer * nxge_txdma_stop_inj_err() 2926678453a8Sspeer * nxge_reset_txdma_channel() 2927678453a8Sspeer * nxge_init_txdma_channel_event_mask() 2928678453a8Sspeer * nxge_init_txdma_channel_cntl_stat() 2929678453a8Sspeer * nxge_disable_txdma_channel() 2930678453a8Sspeer * 2931678453a8Sspeer * Registers accessed: 2932678453a8Sspeer * none directly (see functions above). 2933678453a8Sspeer * 2934678453a8Sspeer * Context: 2935678453a8Sspeer * Any domain 2936678453a8Sspeer */ 29376f45ec7bSml29623 /*ARGSUSED*/ 29386f45ec7bSml29623 static nxge_status_t 2939678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel) 29406f45ec7bSml29623 { 2941678453a8Sspeer p_tx_ring_t tx_ring_p; 29426f45ec7bSml29623 int status = NXGE_OK; 29436f45ec7bSml29623 29446f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 29456f45ec7bSml29623 "==> nxge_txdma_stop_channel: channel %d", channel)); 29466f45ec7bSml29623 29476f45ec7bSml29623 /* 29486f45ec7bSml29623 * Stop (disable) TXDMA and TXC (if stop bit is set 29496f45ec7bSml29623 * and STOP_N_GO bit not set, the TXDMA reset state will 29506f45ec7bSml29623 * not be set if reset TXDMA. 29516f45ec7bSml29623 */ 29526f45ec7bSml29623 (void) nxge_txdma_stop_inj_err(nxgep, channel); 29536f45ec7bSml29623 2954ef523517SMichael Speer if (nxgep->tx_rings == NULL) { 2955ef523517SMichael Speer status = NXGE_ERROR; 2956ef523517SMichael Speer goto nxge_txdma_stop_channel_exit; 2957ef523517SMichael Speer } 2958ef523517SMichael Speer 2959678453a8Sspeer tx_ring_p = nxgep->tx_rings->rings[channel]; 2960ef523517SMichael Speer if (tx_ring_p == NULL) { 2961ef523517SMichael Speer status = NXGE_ERROR; 2962ef523517SMichael Speer goto nxge_txdma_stop_channel_exit; 2963ef523517SMichael Speer } 2964678453a8Sspeer 29656f45ec7bSml29623 /* 29666f45ec7bSml29623 * Reset TXDMA channel 29676f45ec7bSml29623 */ 29686f45ec7bSml29623 tx_ring_p->tx_cs.value = 0; 29696f45ec7bSml29623 tx_ring_p->tx_cs.bits.ldw.rst = 1; 29706f45ec7bSml29623 status = nxge_reset_txdma_channel(nxgep, channel, 29716f45ec7bSml29623 tx_ring_p->tx_cs.value); 29726f45ec7bSml29623 if (status != NXGE_OK) { 29736f45ec7bSml29623 goto nxge_txdma_stop_channel_exit; 29746f45ec7bSml29623 } 29756f45ec7bSml29623 29766f45ec7bSml29623 #ifdef HARDWARE_REQUIRED 29776f45ec7bSml29623 /* Set up the interrupt event masks. */ 29786f45ec7bSml29623 tx_ring_p->tx_evmask.value = 0; 29796f45ec7bSml29623 status = nxge_init_txdma_channel_event_mask(nxgep, 29806f45ec7bSml29623 channel, &tx_ring_p->tx_evmask); 29816f45ec7bSml29623 if (status != NXGE_OK) { 29826f45ec7bSml29623 goto nxge_txdma_stop_channel_exit; 29836f45ec7bSml29623 } 29846f45ec7bSml29623 29856f45ec7bSml29623 /* Initialize the DMA control and status register */ 29866f45ec7bSml29623 tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL; 29876f45ec7bSml29623 status = nxge_init_txdma_channel_cntl_stat(nxgep, channel, 29886f45ec7bSml29623 tx_ring_p->tx_cs.value); 29896f45ec7bSml29623 if (status != NXGE_OK) { 29906f45ec7bSml29623 goto nxge_txdma_stop_channel_exit; 29916f45ec7bSml29623 } 29926f45ec7bSml29623 2993678453a8Sspeer tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 2994678453a8Sspeer 29956f45ec7bSml29623 /* Disable channel */ 29966f45ec7bSml29623 status = nxge_disable_txdma_channel(nxgep, channel, 29976f45ec7bSml29623 tx_ring_p, tx_mbox_p); 29986f45ec7bSml29623 if (status != NXGE_OK) { 29996f45ec7bSml29623 goto nxge_txdma_start_channel_exit; 30006f45ec7bSml29623 } 30016f45ec7bSml29623 30026f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 30036f45ec7bSml29623 "==> nxge_txdma_stop_channel: event done")); 30046f45ec7bSml29623 30056f45ec7bSml29623 #endif 30066f45ec7bSml29623 30076f45ec7bSml29623 nxge_txdma_stop_channel_exit: 30086f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel")); 30096f45ec7bSml29623 return (status); 30106f45ec7bSml29623 } 30116f45ec7bSml29623 3012678453a8Sspeer /* 3013678453a8Sspeer * nxge_txdma_get_ring 3014678453a8Sspeer * 3015678453a8Sspeer * Get the ring for a TDC. 3016678453a8Sspeer * 3017678453a8Sspeer * Arguments: 3018678453a8Sspeer * nxgep 3019678453a8Sspeer * channel 3020678453a8Sspeer * 3021678453a8Sspeer * Notes: 3022678453a8Sspeer * 3023678453a8Sspeer * NPI/NXGE function calls: 3024678453a8Sspeer * 3025678453a8Sspeer * Registers accessed: 3026678453a8Sspeer * 3027678453a8Sspeer * Context: 3028678453a8Sspeer * Any domain 3029678453a8Sspeer */ 30306f45ec7bSml29623 static p_tx_ring_t 30316f45ec7bSml29623 nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel) 30326f45ec7bSml29623 { 3033678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3034678453a8Sspeer int tdc; 30356f45ec7bSml29623 30366f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring")); 30376f45ec7bSml29623 3038678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 30396f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 3040678453a8Sspeer "<== nxge_txdma_get_ring: NULL ring pointer(s)")); 3041678453a8Sspeer goto return_null; 3042678453a8Sspeer } 3043678453a8Sspeer 3044678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3045678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3046678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3047678453a8Sspeer if (ring) { 3048678453a8Sspeer if (channel == ring->tdc) { 3049678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3050678453a8Sspeer "<== nxge_txdma_get_ring: " 3051678453a8Sspeer "tdc %d ring $%p", tdc, ring)); 3052678453a8Sspeer return (ring); 3053678453a8Sspeer } 3054678453a8Sspeer } 3055678453a8Sspeer } 3056678453a8Sspeer } 3057678453a8Sspeer 3058678453a8Sspeer return_null: 3059678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: " 3060678453a8Sspeer "ring not found")); 3061678453a8Sspeer 30626f45ec7bSml29623 return (NULL); 30636f45ec7bSml29623 } 30646f45ec7bSml29623 3065678453a8Sspeer /* 3066678453a8Sspeer * nxge_txdma_get_mbox 3067678453a8Sspeer * 3068678453a8Sspeer * Get the mailbox for a TDC. 3069678453a8Sspeer * 3070678453a8Sspeer * Arguments: 3071678453a8Sspeer * nxgep 3072678453a8Sspeer * channel 3073678453a8Sspeer * 3074678453a8Sspeer * Notes: 3075678453a8Sspeer * 3076678453a8Sspeer * NPI/NXGE function calls: 3077678453a8Sspeer * 3078678453a8Sspeer * Registers accessed: 3079678453a8Sspeer * 3080678453a8Sspeer * Context: 3081678453a8Sspeer * Any domain 3082678453a8Sspeer */ 30836f45ec7bSml29623 static p_tx_mbox_t 30846f45ec7bSml29623 nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel) 30856f45ec7bSml29623 { 3086678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3087678453a8Sspeer int tdc; 30886f45ec7bSml29623 30896f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox")); 30906f45ec7bSml29623 3091678453a8Sspeer if (nxgep->tx_mbox_areas_p == 0 || 3092678453a8Sspeer nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) { 3093678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3094678453a8Sspeer "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)")); 3095678453a8Sspeer goto return_null; 30966f45ec7bSml29623 } 30976f45ec7bSml29623 3098678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 3099678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3100678453a8Sspeer "<== nxge_txdma_get_mbox: NULL ring pointer(s)")); 3101678453a8Sspeer goto return_null; 31026f45ec7bSml29623 } 31036f45ec7bSml29623 3104678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3105678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3106678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3107678453a8Sspeer if (ring) { 3108678453a8Sspeer if (channel == ring->tdc) { 3109678453a8Sspeer tx_mbox_t *mailbox = nxgep-> 3110678453a8Sspeer tx_mbox_areas_p-> 3111678453a8Sspeer txmbox_areas_p[tdc]; 31126f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 31136f45ec7bSml29623 "<== nxge_txdma_get_mbox: tdc %d " 3114678453a8Sspeer "ring $%p", tdc, mailbox)); 3115678453a8Sspeer return (mailbox); 3116678453a8Sspeer } 3117678453a8Sspeer } 31186f45ec7bSml29623 } 31196f45ec7bSml29623 } 31206f45ec7bSml29623 3121678453a8Sspeer return_null: 3122678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: " 3123678453a8Sspeer "mailbox not found")); 3124678453a8Sspeer 31256f45ec7bSml29623 return (NULL); 31266f45ec7bSml29623 } 31276f45ec7bSml29623 3128678453a8Sspeer /* 3129678453a8Sspeer * nxge_tx_err_evnts 3130678453a8Sspeer * 3131678453a8Sspeer * Recover a TDC. 3132678453a8Sspeer * 3133678453a8Sspeer * Arguments: 3134678453a8Sspeer * nxgep 3135678453a8Sspeer * index The index to the TDC ring. 3136678453a8Sspeer * ldvp Used to get the channel number ONLY. 3137678453a8Sspeer * cs A copy of the bits from TX_CS. 3138678453a8Sspeer * 3139678453a8Sspeer * Notes: 3140678453a8Sspeer * Calling tree: 3141678453a8Sspeer * nxge_tx_intr() 3142678453a8Sspeer * 3143678453a8Sspeer * NPI/NXGE function calls: 3144678453a8Sspeer * npi_txdma_ring_error_get() 3145678453a8Sspeer * npi_txdma_inj_par_error_get() 3146678453a8Sspeer * nxge_txdma_fatal_err_recover() 3147678453a8Sspeer * 3148678453a8Sspeer * Registers accessed: 3149678453a8Sspeer * TX_RNG_ERR_LOGH DMC+0x40048 Transmit Ring Error Log High 3150678453a8Sspeer * TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low 3151678453a8Sspeer * TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error 3152678453a8Sspeer * 3153678453a8Sspeer * Context: 3154678453a8Sspeer * Any domain XXX Remove code which accesses TDMC_INJ_PAR_ERR. 3155678453a8Sspeer */ 31566f45ec7bSml29623 /*ARGSUSED*/ 31576f45ec7bSml29623 static nxge_status_t 31586f45ec7bSml29623 nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs) 31596f45ec7bSml29623 { 31606f45ec7bSml29623 npi_handle_t handle; 31616f45ec7bSml29623 npi_status_t rs; 31626f45ec7bSml29623 uint8_t channel; 31636f45ec7bSml29623 p_tx_ring_t *tx_rings; 31646f45ec7bSml29623 p_tx_ring_t tx_ring_p; 31656f45ec7bSml29623 p_nxge_tx_ring_stats_t tdc_stats; 31666f45ec7bSml29623 boolean_t txchan_fatal = B_FALSE; 31676f45ec7bSml29623 nxge_status_t status = NXGE_OK; 31686f45ec7bSml29623 tdmc_inj_par_err_t par_err; 31696f45ec7bSml29623 uint32_t value; 31706f45ec7bSml29623 3171678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts")); 31726f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 31736f45ec7bSml29623 channel = ldvp->channel; 31746f45ec7bSml29623 31756f45ec7bSml29623 tx_rings = nxgep->tx_rings->rings; 31766f45ec7bSml29623 tx_ring_p = tx_rings[index]; 31776f45ec7bSml29623 tdc_stats = tx_ring_p->tdc_stats; 31786f45ec7bSml29623 if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) || 31796f45ec7bSml29623 (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) || 31806f45ec7bSml29623 (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) { 31816f45ec7bSml29623 if ((rs = npi_txdma_ring_error_get(handle, channel, 31826f45ec7bSml29623 &tdc_stats->errlog)) != NPI_SUCCESS) 31836f45ec7bSml29623 return (NXGE_ERROR | rs); 31846f45ec7bSml29623 } 31856f45ec7bSml29623 31866f45ec7bSml29623 if (cs.bits.ldw.mbox_err) { 31876f45ec7bSml29623 tdc_stats->mbox_err++; 31886f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 31896f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_MBOX_ERR); 31906f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 31916f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 31926f45ec7bSml29623 "fatal error: mailbox", channel)); 31936f45ec7bSml29623 txchan_fatal = B_TRUE; 31946f45ec7bSml29623 } 31956f45ec7bSml29623 if (cs.bits.ldw.pkt_size_err) { 31966f45ec7bSml29623 tdc_stats->pkt_size_err++; 31976f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 31986f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR); 31996f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32006f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32016f45ec7bSml29623 "fatal error: pkt_size_err", channel)); 32026f45ec7bSml29623 txchan_fatal = B_TRUE; 32036f45ec7bSml29623 } 32046f45ec7bSml29623 if (cs.bits.ldw.tx_ring_oflow) { 32056f45ec7bSml29623 tdc_stats->tx_ring_oflow++; 32066f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 32076f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW); 32086f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32096f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32106f45ec7bSml29623 "fatal error: tx_ring_oflow", channel)); 32116f45ec7bSml29623 txchan_fatal = B_TRUE; 32126f45ec7bSml29623 } 32136f45ec7bSml29623 if (cs.bits.ldw.pref_buf_par_err) { 32146f45ec7bSml29623 tdc_stats->pre_buf_par_err++; 32156f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 32166f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR); 32176f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32186f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32196f45ec7bSml29623 "fatal error: pre_buf_par_err", channel)); 32206f45ec7bSml29623 /* Clear error injection source for parity error */ 32216f45ec7bSml29623 (void) npi_txdma_inj_par_error_get(handle, &value); 32226f45ec7bSml29623 par_err.value = value; 32236f45ec7bSml29623 par_err.bits.ldw.inject_parity_error &= ~(1 << channel); 32246f45ec7bSml29623 (void) npi_txdma_inj_par_error_set(handle, par_err.value); 32256f45ec7bSml29623 txchan_fatal = B_TRUE; 32266f45ec7bSml29623 } 32276f45ec7bSml29623 if (cs.bits.ldw.nack_pref) { 32286f45ec7bSml29623 tdc_stats->nack_pref++; 32296f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 32306f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_NACK_PREF); 32316f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32326f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32336f45ec7bSml29623 "fatal error: nack_pref", channel)); 32346f45ec7bSml29623 txchan_fatal = B_TRUE; 32356f45ec7bSml29623 } 32366f45ec7bSml29623 if (cs.bits.ldw.nack_pkt_rd) { 32376f45ec7bSml29623 tdc_stats->nack_pkt_rd++; 32386f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 32396f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_NACK_PKT_RD); 32406f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32416f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32426f45ec7bSml29623 "fatal error: nack_pkt_rd", channel)); 32436f45ec7bSml29623 txchan_fatal = B_TRUE; 32446f45ec7bSml29623 } 32456f45ec7bSml29623 if (cs.bits.ldw.conf_part_err) { 32466f45ec7bSml29623 tdc_stats->conf_part_err++; 32476f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 32486f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_CONF_PART_ERR); 32496f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32506f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32516f45ec7bSml29623 "fatal error: config_partition_err", channel)); 32526f45ec7bSml29623 txchan_fatal = B_TRUE; 32536f45ec7bSml29623 } 32546f45ec7bSml29623 if (cs.bits.ldw.pkt_prt_err) { 32556f45ec7bSml29623 tdc_stats->pkt_part_err++; 32566f45ec7bSml29623 NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 32576f45ec7bSml29623 NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR); 32586f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32596f45ec7bSml29623 "==> nxge_tx_err_evnts(channel %d): " 32606f45ec7bSml29623 "fatal error: pkt_prt_err", channel)); 32616f45ec7bSml29623 txchan_fatal = B_TRUE; 32626f45ec7bSml29623 } 32636f45ec7bSml29623 32646f45ec7bSml29623 /* Clear error injection source in case this is an injected error */ 32656f45ec7bSml29623 TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0); 32666f45ec7bSml29623 32676f45ec7bSml29623 if (txchan_fatal) { 32686f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32696f45ec7bSml29623 " nxge_tx_err_evnts: " 32706f45ec7bSml29623 " fatal error on channel %d cs 0x%llx\n", 32716f45ec7bSml29623 channel, cs.value)); 32726f45ec7bSml29623 status = nxge_txdma_fatal_err_recover(nxgep, channel, 32736f45ec7bSml29623 tx_ring_p); 32746f45ec7bSml29623 if (status == NXGE_OK) { 32756f45ec7bSml29623 FM_SERVICE_RESTORED(nxgep); 32766f45ec7bSml29623 } 32776f45ec7bSml29623 } 32786f45ec7bSml29623 3279678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts")); 32806f45ec7bSml29623 32816f45ec7bSml29623 return (status); 32826f45ec7bSml29623 } 32836f45ec7bSml29623 32846f45ec7bSml29623 static nxge_status_t 3285678453a8Sspeer nxge_txdma_fatal_err_recover( 3286678453a8Sspeer p_nxge_t nxgep, 3287678453a8Sspeer uint16_t channel, 32886f45ec7bSml29623 p_tx_ring_t tx_ring_p) 32896f45ec7bSml29623 { 32906f45ec7bSml29623 npi_handle_t handle; 32916f45ec7bSml29623 npi_status_t rs = NPI_SUCCESS; 32926f45ec7bSml29623 p_tx_mbox_t tx_mbox_p; 32936f45ec7bSml29623 nxge_status_t status = NXGE_OK; 32946f45ec7bSml29623 32956f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover")); 32966f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 32976f45ec7bSml29623 "Recovering from TxDMAChannel#%d error...", channel)); 32986f45ec7bSml29623 32996f45ec7bSml29623 /* 33006f45ec7bSml29623 * Stop the dma channel waits for the stop done. 33016f45ec7bSml29623 * If the stop done bit is not set, then create 33026f45ec7bSml29623 * an error. 33036f45ec7bSml29623 */ 33046f45ec7bSml29623 33056f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 33066f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop...")); 33076f45ec7bSml29623 MUTEX_ENTER(&tx_ring_p->lock); 33086f45ec7bSml29623 rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel); 33096f45ec7bSml29623 if (rs != NPI_SUCCESS) { 33106f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 33116f45ec7bSml29623 "==> nxge_txdma_fatal_err_recover (channel %d): " 33126f45ec7bSml29623 "stop failed ", channel)); 33136f45ec7bSml29623 goto fail; 33146f45ec7bSml29623 } 33156f45ec7bSml29623 33166f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim...")); 33176f45ec7bSml29623 (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 33186f45ec7bSml29623 33196f45ec7bSml29623 /* 33206f45ec7bSml29623 * Reset TXDMA channel 33216f45ec7bSml29623 */ 33226f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset...")); 33236f45ec7bSml29623 if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) != 33246f45ec7bSml29623 NPI_SUCCESS) { 33256f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 33266f45ec7bSml29623 "==> nxge_txdma_fatal_err_recover (channel %d)" 33276f45ec7bSml29623 " reset channel failed 0x%x", channel, rs)); 33286f45ec7bSml29623 goto fail; 33296f45ec7bSml29623 } 33306f45ec7bSml29623 33316f45ec7bSml29623 /* 33326f45ec7bSml29623 * Reset the tail (kick) register to 0. 33336f45ec7bSml29623 * (Hardware will not reset it. Tx overflow fatal 33346f45ec7bSml29623 * error if tail is not set to 0 after reset! 33356f45ec7bSml29623 */ 33366f45ec7bSml29623 TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0); 33376f45ec7bSml29623 33386f45ec7bSml29623 /* Restart TXDMA channel */ 33396f45ec7bSml29623 3340678453a8Sspeer if (!isLDOMguest(nxgep)) { 3341678453a8Sspeer tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel); 3342678453a8Sspeer 3343678453a8Sspeer // XXX This is a problem in HIO! 33446f45ec7bSml29623 /* 33456f45ec7bSml29623 * Initialize the TXDMA channel specific FZC control 33466f45ec7bSml29623 * configurations. These FZC registers are pertaining 33476f45ec7bSml29623 * to each TX channel (i.e. logical pages). 33486f45ec7bSml29623 */ 33496f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart...")); 33506f45ec7bSml29623 status = nxge_init_fzc_txdma_channel(nxgep, channel, 33516f45ec7bSml29623 tx_ring_p, tx_mbox_p); 33526f45ec7bSml29623 if (status != NXGE_OK) 33536f45ec7bSml29623 goto fail; 3354678453a8Sspeer } 33556f45ec7bSml29623 33566f45ec7bSml29623 /* 33576f45ec7bSml29623 * Initialize the event masks. 33586f45ec7bSml29623 */ 33596f45ec7bSml29623 tx_ring_p->tx_evmask.value = 0; 33606f45ec7bSml29623 status = nxge_init_txdma_channel_event_mask(nxgep, channel, 33616f45ec7bSml29623 &tx_ring_p->tx_evmask); 33626f45ec7bSml29623 if (status != NXGE_OK) 33636f45ec7bSml29623 goto fail; 33646f45ec7bSml29623 33656f45ec7bSml29623 tx_ring_p->wr_index_wrap = B_FALSE; 33666f45ec7bSml29623 tx_ring_p->wr_index = 0; 33676f45ec7bSml29623 tx_ring_p->rd_index = 0; 33686f45ec7bSml29623 33696f45ec7bSml29623 /* 33706f45ec7bSml29623 * Load TXDMA descriptors, buffers, mailbox, 33716f45ec7bSml29623 * initialise the DMA channels and 33726f45ec7bSml29623 * enable each DMA channel. 33736f45ec7bSml29623 */ 33746f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable...")); 33756f45ec7bSml29623 status = nxge_enable_txdma_channel(nxgep, channel, 33766f45ec7bSml29623 tx_ring_p, tx_mbox_p); 33776f45ec7bSml29623 MUTEX_EXIT(&tx_ring_p->lock); 33786f45ec7bSml29623 if (status != NXGE_OK) 33796f45ec7bSml29623 goto fail; 33806f45ec7bSml29623 33816f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 33826f45ec7bSml29623 "Recovery Successful, TxDMAChannel#%d Restored", 33836f45ec7bSml29623 channel)); 33846f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover")); 33856f45ec7bSml29623 33866f45ec7bSml29623 return (NXGE_OK); 33876f45ec7bSml29623 33886f45ec7bSml29623 fail: 33896f45ec7bSml29623 MUTEX_EXIT(&tx_ring_p->lock); 33902d99c5d4SMichael Speer 33916f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, 33926f45ec7bSml29623 "nxge_txdma_fatal_err_recover (channel %d): " 33936f45ec7bSml29623 "failed to recover this txdma channel", channel)); 33946f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed")); 33956f45ec7bSml29623 33966f45ec7bSml29623 return (status); 33976f45ec7bSml29623 } 33986f45ec7bSml29623 3399678453a8Sspeer /* 3400678453a8Sspeer * nxge_tx_port_fatal_err_recover 3401678453a8Sspeer * 3402678453a8Sspeer * Attempt to recover from a fatal port error. 3403678453a8Sspeer * 3404678453a8Sspeer * Arguments: 3405678453a8Sspeer * nxgep 3406678453a8Sspeer * 3407678453a8Sspeer * Notes: 3408678453a8Sspeer * How would a guest do this? 3409678453a8Sspeer * 3410678453a8Sspeer * NPI/NXGE function calls: 3411678453a8Sspeer * 3412678453a8Sspeer * Registers accessed: 3413678453a8Sspeer * 3414678453a8Sspeer * Context: 3415678453a8Sspeer * Service domain 3416678453a8Sspeer */ 34176f45ec7bSml29623 nxge_status_t 34186f45ec7bSml29623 nxge_tx_port_fatal_err_recover(p_nxge_t nxgep) 34196f45ec7bSml29623 { 3420678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3421678453a8Sspeer nxge_channel_t tdc; 3422678453a8Sspeer 3423678453a8Sspeer tx_ring_t *ring; 3424678453a8Sspeer tx_mbox_t *mailbox; 3425678453a8Sspeer 34266f45ec7bSml29623 npi_handle_t handle; 3427678453a8Sspeer nxge_status_t status; 3428678453a8Sspeer npi_status_t rs; 34296f45ec7bSml29623 34306f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover")); 34316f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 34326f45ec7bSml29623 "Recovering from TxPort error...")); 34336f45ec7bSml29623 3434678453a8Sspeer if (isLDOMguest(nxgep)) { 3435678453a8Sspeer return (NXGE_OK); 3436678453a8Sspeer } 3437678453a8Sspeer 3438678453a8Sspeer if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { 3439678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3440678453a8Sspeer "<== nxge_tx_port_fatal_err_recover: not initialized")); 3441678453a8Sspeer return (NXGE_ERROR); 3442678453a8Sspeer } 3443678453a8Sspeer 3444678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 3445678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3446678453a8Sspeer "<== nxge_tx_port_fatal_err_recover: " 3447678453a8Sspeer "NULL ring pointer(s)")); 3448678453a8Sspeer return (NXGE_ERROR); 3449678453a8Sspeer } 3450678453a8Sspeer 3451678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3452678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3453678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3454678453a8Sspeer if (ring) 3455678453a8Sspeer MUTEX_ENTER(&ring->lock); 3456678453a8Sspeer } 3457678453a8Sspeer } 34586f45ec7bSml29623 34596f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 34606f45ec7bSml29623 3461678453a8Sspeer /* 3462678453a8Sspeer * Stop all the TDCs owned by us. 3463678453a8Sspeer * (The shared TDCs will have been stopped by their owners.) 3464678453a8Sspeer */ 3465678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3466678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3467678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3468678453a8Sspeer if (ring) { 3469678453a8Sspeer rs = npi_txdma_channel_control 3470678453a8Sspeer (handle, TXDMA_STOP, tdc); 34716f45ec7bSml29623 if (rs != NPI_SUCCESS) { 34726f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3473678453a8Sspeer "nxge_tx_port_fatal_err_recover " 3474678453a8Sspeer "(channel %d): stop failed ", tdc)); 34756f45ec7bSml29623 goto fail; 34766f45ec7bSml29623 } 34776f45ec7bSml29623 } 34786f45ec7bSml29623 } 3479678453a8Sspeer } 3480678453a8Sspeer 3481678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs...")); 3482678453a8Sspeer 3483678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3484678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3485678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 34862d99c5d4SMichael Speer if (ring) { 3487678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, ring, 0); 34882d99c5d4SMichael Speer } 3489678453a8Sspeer } 34906f45ec7bSml29623 } 34916f45ec7bSml29623 34926f45ec7bSml29623 /* 3493678453a8Sspeer * Reset all the TDCs. 34946f45ec7bSml29623 */ 3495678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs...")); 34966f45ec7bSml29623 3497678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3498678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3499678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3500678453a8Sspeer if (ring) { 3501678453a8Sspeer if ((rs = npi_txdma_channel_control 3502678453a8Sspeer (handle, TXDMA_RESET, tdc)) 3503678453a8Sspeer != NPI_SUCCESS) { 35046f45ec7bSml29623 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3505678453a8Sspeer "nxge_tx_port_fatal_err_recover " 3506678453a8Sspeer "(channel %d) reset channel " 3507678453a8Sspeer "failed 0x%x", tdc, rs)); 35086f45ec7bSml29623 goto fail; 35096f45ec7bSml29623 } 3510678453a8Sspeer } 35116f45ec7bSml29623 /* 35126f45ec7bSml29623 * Reset the tail (kick) register to 0. 35136f45ec7bSml29623 * (Hardware will not reset it. Tx overflow fatal 35146f45ec7bSml29623 * error if tail is not set to 0 after reset! 35156f45ec7bSml29623 */ 3516678453a8Sspeer TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0); 3517678453a8Sspeer } 35186f45ec7bSml29623 } 35196f45ec7bSml29623 3520678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs...")); 35216f45ec7bSml29623 3522678453a8Sspeer /* Restart all the TDCs */ 3523678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3524678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3525678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3526678453a8Sspeer if (ring) { 3527678453a8Sspeer mailbox = nxge_txdma_get_mbox(nxgep, tdc); 3528678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, tdc, 3529678453a8Sspeer ring, mailbox); 3530678453a8Sspeer ring->tx_evmask.value = 0; 35316f45ec7bSml29623 /* 35326f45ec7bSml29623 * Initialize the event masks. 35336f45ec7bSml29623 */ 3534678453a8Sspeer status = nxge_init_txdma_channel_event_mask 3535678453a8Sspeer (nxgep, tdc, &ring->tx_evmask); 35366f45ec7bSml29623 3537678453a8Sspeer ring->wr_index_wrap = B_FALSE; 3538678453a8Sspeer ring->wr_index = 0; 3539678453a8Sspeer ring->rd_index = 0; 35406f45ec7bSml29623 35416f45ec7bSml29623 if (status != NXGE_OK) 35426f45ec7bSml29623 goto fail; 35436f45ec7bSml29623 if (status != NXGE_OK) 35446f45ec7bSml29623 goto fail; 35456f45ec7bSml29623 } 3546678453a8Sspeer } 3547678453a8Sspeer } 3548678453a8Sspeer 3549678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs...")); 3550678453a8Sspeer 3551678453a8Sspeer /* Re-enable all the TDCs */ 3552678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3553678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3554678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3555678453a8Sspeer if (ring) { 3556678453a8Sspeer mailbox = nxge_txdma_get_mbox(nxgep, tdc); 3557678453a8Sspeer status = nxge_enable_txdma_channel(nxgep, tdc, 3558678453a8Sspeer ring, mailbox); 3559678453a8Sspeer if (status != NXGE_OK) 3560678453a8Sspeer goto fail; 3561678453a8Sspeer } 3562678453a8Sspeer } 3563678453a8Sspeer } 35646f45ec7bSml29623 35656f45ec7bSml29623 /* 3566678453a8Sspeer * Unlock all the TDCs. 35676f45ec7bSml29623 */ 3568678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3569678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3570678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3571678453a8Sspeer if (ring) 3572678453a8Sspeer MUTEX_EXIT(&ring->lock); 35736f45ec7bSml29623 } 35746f45ec7bSml29623 } 35756f45ec7bSml29623 3576678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded")); 35776f45ec7bSml29623 NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover")); 35786f45ec7bSml29623 35796f45ec7bSml29623 return (NXGE_OK); 35806f45ec7bSml29623 35816f45ec7bSml29623 fail: 3582678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3583678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3584678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3585678453a8Sspeer if (ring) 3586678453a8Sspeer MUTEX_EXIT(&ring->lock); 35876f45ec7bSml29623 } 35886f45ec7bSml29623 } 35896f45ec7bSml29623 3590678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed")); 3591678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover")); 35926f45ec7bSml29623 35936f45ec7bSml29623 return (status); 35946f45ec7bSml29623 } 35956f45ec7bSml29623 3596678453a8Sspeer /* 3597678453a8Sspeer * nxge_txdma_inject_err 3598678453a8Sspeer * 3599678453a8Sspeer * Inject an error into a TDC. 3600678453a8Sspeer * 3601678453a8Sspeer * Arguments: 3602678453a8Sspeer * nxgep 3603678453a8Sspeer * err_id The error to inject. 3604678453a8Sspeer * chan The channel to inject into. 3605678453a8Sspeer * 3606678453a8Sspeer * Notes: 3607678453a8Sspeer * This is called from nxge_main.c:nxge_err_inject() 3608678453a8Sspeer * Has this ioctl ever been used? 3609678453a8Sspeer * 3610678453a8Sspeer * NPI/NXGE function calls: 3611678453a8Sspeer * npi_txdma_inj_par_error_get() 3612678453a8Sspeer * npi_txdma_inj_par_error_set() 3613678453a8Sspeer * 3614678453a8Sspeer * Registers accessed: 3615678453a8Sspeer * TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error 3616678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 3617678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 3618678453a8Sspeer * 3619678453a8Sspeer * Context: 3620678453a8Sspeer * Service domain 3621678453a8Sspeer */ 36226f45ec7bSml29623 void 36236f45ec7bSml29623 nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan) 36246f45ec7bSml29623 { 36256f45ec7bSml29623 tdmc_intr_dbg_t tdi; 36266f45ec7bSml29623 tdmc_inj_par_err_t par_err; 36276f45ec7bSml29623 uint32_t value; 36286f45ec7bSml29623 npi_handle_t handle; 36296f45ec7bSml29623 36306f45ec7bSml29623 switch (err_id) { 36316f45ec7bSml29623 36326f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR: 36336f45ec7bSml29623 handle = NXGE_DEV_NPI_HANDLE(nxgep); 36346f45ec7bSml29623 /* Clear error injection source for parity error */ 36356f45ec7bSml29623 (void) npi_txdma_inj_par_error_get(handle, &value); 36366f45ec7bSml29623 par_err.value = value; 36376f45ec7bSml29623 par_err.bits.ldw.inject_parity_error &= ~(1 << chan); 36386f45ec7bSml29623 (void) npi_txdma_inj_par_error_set(handle, par_err.value); 36396f45ec7bSml29623 36406f45ec7bSml29623 par_err.bits.ldw.inject_parity_error = (1 << chan); 36416f45ec7bSml29623 (void) npi_txdma_inj_par_error_get(handle, &value); 36426f45ec7bSml29623 par_err.value = value; 36436f45ec7bSml29623 par_err.bits.ldw.inject_parity_error |= (1 << chan); 36446f45ec7bSml29623 cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n", 36456f45ec7bSml29623 (unsigned long long)par_err.value); 36466f45ec7bSml29623 (void) npi_txdma_inj_par_error_set(handle, par_err.value); 36476f45ec7bSml29623 break; 36486f45ec7bSml29623 36496f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_MBOX_ERR: 36506f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_NACK_PREF: 36516f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD: 36526f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR: 36536f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW: 36546f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR: 36556f45ec7bSml29623 case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR: 36566f45ec7bSml29623 TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG, 36576f45ec7bSml29623 chan, &tdi.value); 36586f45ec7bSml29623 if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR) 36596f45ec7bSml29623 tdi.bits.ldw.pref_buf_par_err = 1; 36606f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR) 36616f45ec7bSml29623 tdi.bits.ldw.mbox_err = 1; 36626f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF) 36636f45ec7bSml29623 tdi.bits.ldw.nack_pref = 1; 36646f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD) 36656f45ec7bSml29623 tdi.bits.ldw.nack_pkt_rd = 1; 36666f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR) 36676f45ec7bSml29623 tdi.bits.ldw.pkt_size_err = 1; 36686f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW) 36696f45ec7bSml29623 tdi.bits.ldw.tx_ring_oflow = 1; 36706f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR) 36716f45ec7bSml29623 tdi.bits.ldw.conf_part_err = 1; 36726f45ec7bSml29623 else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR) 36736f45ec7bSml29623 tdi.bits.ldw.pkt_part_err = 1; 3674adfcba55Sjoycey #if defined(__i386) 3675adfcba55Sjoycey cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n", 3676adfcba55Sjoycey tdi.value); 3677adfcba55Sjoycey #else 36786f45ec7bSml29623 cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n", 36796f45ec7bSml29623 tdi.value); 3680adfcba55Sjoycey #endif 36816f45ec7bSml29623 TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, 36826f45ec7bSml29623 chan, tdi.value); 36836f45ec7bSml29623 36846f45ec7bSml29623 break; 36856f45ec7bSml29623 } 36866f45ec7bSml29623 } 3687