144961713Sgirish /* 244961713Sgirish * CDDL HEADER START 344961713Sgirish * 444961713Sgirish * The contents of this file are subject to the terms of the 544961713Sgirish * Common Development and Distribution License (the "License"). 644961713Sgirish * You may not use this file except in compliance with the License. 744961713Sgirish * 844961713Sgirish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 944961713Sgirish * or http://www.opensolaris.org/os/licensing. 1044961713Sgirish * See the License for the specific language governing permissions 1144961713Sgirish * and limitations under the License. 1244961713Sgirish * 1344961713Sgirish * When distributing Covered Code, include this CDDL HEADER in each 1444961713Sgirish * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1544961713Sgirish * If applicable, add the following below this CDDL HEADER, with the 1644961713Sgirish * fields enclosed by brackets "[]" replaced with your own identifying 1744961713Sgirish * information: Portions Copyright [yyyy] [name of copyright owner] 1844961713Sgirish * 1944961713Sgirish * CDDL HEADER END 2044961713Sgirish */ 21952a2464SMichael Speer 2244961713Sgirish /* 23257bdc55SMichael Speer * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2444961713Sgirish * Use is subject to license terms. 2544961713Sgirish */ 2644961713Sgirish 2744961713Sgirish #include <sys/nxge/nxge_impl.h> 2844961713Sgirish #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> 3244961713Sgirish #include <sys/llc1.h> 3344961713Sgirish 3444961713Sgirish uint32_t nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT; 35da14cebeSEric Cheng uint32_t nxge_tx_minfree = 64; 3644961713Sgirish uint32_t nxge_tx_intr_thres = 0; 3744961713Sgirish uint32_t nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS; 3844961713Sgirish uint32_t nxge_tx_tiny_pack = 1; 3944961713Sgirish uint32_t nxge_tx_use_bcopy = 1; 4044961713Sgirish 4144961713Sgirish extern uint32_t nxge_tx_ring_size; 4244961713Sgirish extern uint32_t nxge_bcopy_thresh; 4344961713Sgirish extern uint32_t nxge_dvma_thresh; 4444961713Sgirish extern uint32_t nxge_dma_stream_thresh; 4544961713Sgirish extern dma_method_t nxge_force_dma; 46b4d05839Sml extern uint32_t nxge_cksum_offload; 4744961713Sgirish 4844961713Sgirish /* Device register access attributes for PIO. */ 4944961713Sgirish extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr; 5044961713Sgirish /* Device descriptor access attributes for DMA. */ 5144961713Sgirish extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr; 5244961713Sgirish /* Device buffer access attributes for DMA. */ 5344961713Sgirish extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr; 5444961713Sgirish extern ddi_dma_attr_t nxge_desc_dma_attr; 5544961713Sgirish extern ddi_dma_attr_t nxge_tx_dma_attr; 5644961713Sgirish 57da14cebeSEric Cheng extern void nxge_tx_ring_task(void *arg); 582d99c5d4SMichael Speer 59678453a8Sspeer static nxge_status_t nxge_map_txdma(p_nxge_t, int); 6044961713Sgirish 61678453a8Sspeer static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int); 6244961713Sgirish 6344961713Sgirish static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t, 6444961713Sgirish p_nxge_dma_common_t *, p_tx_ring_t *, 6544961713Sgirish uint32_t, p_nxge_dma_common_t *, 6644961713Sgirish p_tx_mbox_t *); 67678453a8Sspeer static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t); 6844961713Sgirish 6944961713Sgirish static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t, 7044961713Sgirish p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t); 7144961713Sgirish static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t); 7244961713Sgirish 7344961713Sgirish static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t, 7444961713Sgirish p_nxge_dma_common_t *, p_tx_ring_t, 7544961713Sgirish p_tx_mbox_t *); 7644961713Sgirish static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t, 7744961713Sgirish p_tx_ring_t, p_tx_mbox_t); 7844961713Sgirish 7944961713Sgirish static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t, 8044961713Sgirish p_tx_ring_t, p_tx_mbox_t); 81678453a8Sspeer static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t); 8244961713Sgirish 8344961713Sgirish static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t); 8444961713Sgirish static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t, 8544961713Sgirish p_nxge_ldv_t, tx_cs_t); 8644961713Sgirish static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t); 8744961713Sgirish static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t, 8844961713Sgirish uint16_t, p_tx_ring_t); 8944961713Sgirish 90678453a8Sspeer static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, 91678453a8Sspeer p_tx_ring_t ring_p, uint16_t channel); 92678453a8Sspeer 9344961713Sgirish nxge_status_t 9444961713Sgirish nxge_init_txdma_channels(p_nxge_t nxgep) 9544961713Sgirish { 96e11f0814SMichael Speer 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; 101678453a8Sspeer 102678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels")); 103678453a8Sspeer 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; 120678453a8Sspeer } 121678453a8Sspeer 122678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels")); 123678453a8Sspeer 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 145678453a8Sspeer } 146678453a8Sspeer 147678453a8Sspeer nxge_status_t 148678453a8Sspeer nxge_init_txdma_channel( 149678453a8Sspeer p_nxge_t nxge, 150678453a8Sspeer int channel) 151678453a8Sspeer { 152678453a8Sspeer nxge_status_t status; 15344961713Sgirish 154678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel")); 15544961713Sgirish 156678453a8Sspeer status = nxge_map_txdma(nxge, channel); 15744961713Sgirish 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); 16144961713Sgirish return (status); 16244961713Sgirish } 16344961713Sgirish 164678453a8Sspeer status = nxge_txdma_hw_start(nxge, channel); 16544961713Sgirish if (status != NXGE_OK) { 166678453a8Sspeer (void) nxge_unmap_txdma_channel(nxge, channel); 167678453a8Sspeer (void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel); 16844961713Sgirish return (status); 16944961713Sgirish } 17044961713Sgirish 171678453a8Sspeer if (!nxge->statsp->tdc_ksp[channel]) 172678453a8Sspeer nxge_setup_tdc_kstats(nxge, channel); 17344961713Sgirish 174678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel")); 175678453a8Sspeer 176678453a8Sspeer return (status); 17744961713Sgirish } 17844961713Sgirish 17944961713Sgirish void 18044961713Sgirish nxge_uninit_txdma_channels(p_nxge_t nxgep) 18144961713Sgirish { 182678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 183678453a8Sspeer int tdc; 184678453a8Sspeer 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 } 21144961713Sgirish 212678453a8Sspeer (void) nxge_txdma_stop_channel(nxgep, channel); 213678453a8Sspeer nxge_unmap_txdma_channel(nxgep, channel); 21444961713Sgirish 21544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 21652ccf843Smisaki "<== nxge_uninit_txdma_channel")); 21744961713Sgirish } 21844961713Sgirish 21944961713Sgirish void 22044961713Sgirish nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p, 22144961713Sgirish uint32_t entries, uint32_t size) 22244961713Sgirish { 22344961713Sgirish size_t tsize; 22444961713Sgirish *dest_p = *src_p; 22544961713Sgirish tsize = size * entries; 22644961713Sgirish dest_p->alength = tsize; 22744961713Sgirish dest_p->nblocks = entries; 22844961713Sgirish dest_p->block_size = size; 22944961713Sgirish dest_p->offset += tsize; 23044961713Sgirish 23144961713Sgirish src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize; 23244961713Sgirish src_p->alength -= tsize; 23344961713Sgirish src_p->dma_cookie.dmac_laddress += tsize; 23444961713Sgirish src_p->dma_cookie.dmac_size -= tsize; 23544961713Sgirish } 23644961713Sgirish 237678453a8Sspeer /* 238678453a8Sspeer * nxge_reset_txdma_channel 239678453a8Sspeer * 240678453a8Sspeer * Reset a TDC. 241678453a8Sspeer * 242678453a8Sspeer * Arguments: 243678453a8Sspeer * nxgep 244678453a8Sspeer * channel The channel to reset. 245678453a8Sspeer * reg_data The current TX_CS. 246678453a8Sspeer * 247678453a8Sspeer * Notes: 248678453a8Sspeer * 249678453a8Sspeer * NPI/NXGE function calls: 250678453a8Sspeer * npi_txdma_channel_reset() 251678453a8Sspeer * npi_txdma_channel_control() 252678453a8Sspeer * 253678453a8Sspeer * Registers accessed: 254678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 255678453a8Sspeer * TX_RING_KICK DMC+0x40018 Transmit Ring Kick 256678453a8Sspeer * 257678453a8Sspeer * Context: 258678453a8Sspeer * Any domain 259678453a8Sspeer */ 26044961713Sgirish nxge_status_t 26144961713Sgirish nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data) 26244961713Sgirish { 26344961713Sgirish npi_status_t rs = NPI_SUCCESS; 26444961713Sgirish nxge_status_t status = NXGE_OK; 26544961713Sgirish npi_handle_t handle; 26644961713Sgirish 26744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel")); 26844961713Sgirish 26944961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 27044961713Sgirish if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) { 27144961713Sgirish rs = npi_txdma_channel_reset(handle, channel); 27244961713Sgirish } else { 27344961713Sgirish rs = npi_txdma_channel_control(handle, TXDMA_RESET, 27452ccf843Smisaki channel); 27544961713Sgirish } 27644961713Sgirish 27744961713Sgirish if (rs != NPI_SUCCESS) { 27844961713Sgirish status = NXGE_ERROR | rs; 27944961713Sgirish } 28044961713Sgirish 28144961713Sgirish /* 28244961713Sgirish * Reset the tail (kick) register to 0. 28344961713Sgirish * (Hardware will not reset it. Tx overflow fatal 28444961713Sgirish * error if tail is not set to 0 after reset! 28544961713Sgirish */ 28644961713Sgirish TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0); 28744961713Sgirish 28844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel")); 28944961713Sgirish return (status); 29044961713Sgirish } 29144961713Sgirish 292678453a8Sspeer /* 293678453a8Sspeer * nxge_init_txdma_channel_event_mask 294678453a8Sspeer * 295678453a8Sspeer * Enable interrupts for a set of events. 296678453a8Sspeer * 297678453a8Sspeer * Arguments: 298678453a8Sspeer * nxgep 299678453a8Sspeer * channel The channel to map. 300678453a8Sspeer * mask_p The events to enable. 301678453a8Sspeer * 302678453a8Sspeer * Notes: 303678453a8Sspeer * 304678453a8Sspeer * NPI/NXGE function calls: 305678453a8Sspeer * npi_txdma_event_mask() 306678453a8Sspeer * 307678453a8Sspeer * Registers accessed: 308678453a8Sspeer * TX_ENT_MSK DMC+0x40020 Transmit Event Mask 309678453a8Sspeer * 310678453a8Sspeer * Context: 311678453a8Sspeer * Any domain 312678453a8Sspeer */ 31344961713Sgirish nxge_status_t 31444961713Sgirish nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel, 31544961713Sgirish p_tx_dma_ent_msk_t mask_p) 31644961713Sgirish { 31744961713Sgirish npi_handle_t handle; 31844961713Sgirish npi_status_t rs = NPI_SUCCESS; 31944961713Sgirish nxge_status_t status = NXGE_OK; 32044961713Sgirish 32144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 32252ccf843Smisaki "<== nxge_init_txdma_channel_event_mask")); 32344961713Sgirish 32444961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 32544961713Sgirish rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p); 32644961713Sgirish if (rs != NPI_SUCCESS) { 32744961713Sgirish status = NXGE_ERROR | rs; 32844961713Sgirish } 32944961713Sgirish 33044961713Sgirish return (status); 33144961713Sgirish } 33244961713Sgirish 333678453a8Sspeer /* 334678453a8Sspeer * nxge_init_txdma_channel_cntl_stat 335678453a8Sspeer * 336678453a8Sspeer * Stop a TDC. If at first we don't succeed, inject an error. 337678453a8Sspeer * 338678453a8Sspeer * Arguments: 339678453a8Sspeer * nxgep 340678453a8Sspeer * channel The channel to stop. 341678453a8Sspeer * 342678453a8Sspeer * Notes: 343678453a8Sspeer * 344678453a8Sspeer * NPI/NXGE function calls: 345678453a8Sspeer * npi_txdma_control_status() 346678453a8Sspeer * 347678453a8Sspeer * Registers accessed: 348678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 349678453a8Sspeer * 350678453a8Sspeer * Context: 351678453a8Sspeer * Any domain 352678453a8Sspeer */ 35344961713Sgirish nxge_status_t 35444961713Sgirish nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel, 35544961713Sgirish uint64_t reg_data) 35644961713Sgirish { 35744961713Sgirish npi_handle_t handle; 35844961713Sgirish npi_status_t rs = NPI_SUCCESS; 35944961713Sgirish nxge_status_t status = NXGE_OK; 36044961713Sgirish 36144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 36252ccf843Smisaki "<== nxge_init_txdma_channel_cntl_stat")); 36344961713Sgirish 36444961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 36544961713Sgirish rs = npi_txdma_control_status(handle, OP_SET, channel, 36652ccf843Smisaki (p_tx_cs_t)®_data); 36744961713Sgirish 36844961713Sgirish if (rs != NPI_SUCCESS) { 36944961713Sgirish status = NXGE_ERROR | rs; 37044961713Sgirish } 37144961713Sgirish 37244961713Sgirish return (status); 37344961713Sgirish } 37444961713Sgirish 375678453a8Sspeer /* 376678453a8Sspeer * nxge_enable_txdma_channel 377678453a8Sspeer * 378678453a8Sspeer * Enable a TDC. 379678453a8Sspeer * 380678453a8Sspeer * Arguments: 381678453a8Sspeer * nxgep 382678453a8Sspeer * channel The channel to enable. 383678453a8Sspeer * tx_desc_p channel's transmit descriptor ring. 384678453a8Sspeer * mbox_p channel's mailbox, 385678453a8Sspeer * 386678453a8Sspeer * Notes: 387678453a8Sspeer * 388678453a8Sspeer * NPI/NXGE function calls: 389678453a8Sspeer * npi_txdma_ring_config() 390678453a8Sspeer * npi_txdma_mbox_config() 391678453a8Sspeer * npi_txdma_channel_init_enable() 392678453a8Sspeer * 393678453a8Sspeer * Registers accessed: 394678453a8Sspeer * TX_RNG_CFIG DMC+0x40000 Transmit Ring Configuration 395678453a8Sspeer * TXDMA_MBH DMC+0x40030 TXDMA Mailbox High 396678453a8Sspeer * TXDMA_MBL DMC+0x40038 TXDMA Mailbox Low 397678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 398678453a8Sspeer * 399678453a8Sspeer * Context: 400678453a8Sspeer * Any domain 401678453a8Sspeer */ 40244961713Sgirish nxge_status_t 40344961713Sgirish nxge_enable_txdma_channel(p_nxge_t nxgep, 40444961713Sgirish uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p) 40544961713Sgirish { 40644961713Sgirish npi_handle_t handle; 40744961713Sgirish npi_status_t rs = NPI_SUCCESS; 40844961713Sgirish nxge_status_t status = NXGE_OK; 40944961713Sgirish 41044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel")); 41144961713Sgirish 41244961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 41344961713Sgirish /* 41444961713Sgirish * Use configuration data composed at init time. 41544961713Sgirish * Write to hardware the transmit ring configurations. 41644961713Sgirish */ 41744961713Sgirish rs = npi_txdma_ring_config(handle, OP_SET, channel, 418678453a8Sspeer (uint64_t *)&(tx_desc_p->tx_ring_cfig.value)); 41944961713Sgirish 42044961713Sgirish if (rs != NPI_SUCCESS) { 42144961713Sgirish return (NXGE_ERROR | rs); 42244961713Sgirish } 42344961713Sgirish 424678453a8Sspeer if (isLDOMguest(nxgep)) { 425678453a8Sspeer /* Add interrupt handler for this channel. */ 426678453a8Sspeer if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK) 427678453a8Sspeer return (NXGE_ERROR); 428678453a8Sspeer } 429678453a8Sspeer 43044961713Sgirish /* Write to hardware the mailbox */ 43144961713Sgirish rs = npi_txdma_mbox_config(handle, OP_SET, channel, 43252ccf843Smisaki (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress); 43344961713Sgirish 43444961713Sgirish if (rs != NPI_SUCCESS) { 43544961713Sgirish return (NXGE_ERROR | rs); 43644961713Sgirish } 43744961713Sgirish 43844961713Sgirish /* Start the DMA engine. */ 43944961713Sgirish rs = npi_txdma_channel_init_enable(handle, channel); 44044961713Sgirish 44144961713Sgirish if (rs != NPI_SUCCESS) { 44244961713Sgirish return (NXGE_ERROR | rs); 44344961713Sgirish } 44444961713Sgirish 44544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel")); 44644961713Sgirish 44744961713Sgirish return (status); 44844961713Sgirish } 44944961713Sgirish 45044961713Sgirish void 45144961713Sgirish nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len, 45244961713Sgirish boolean_t l4_cksum, int pkt_len, uint8_t npads, 453b4d05839Sml p_tx_pkt_hdr_all_t pkthdrp, 454b4d05839Sml t_uscalar_t start_offset, 455b4d05839Sml t_uscalar_t stuff_offset) 45644961713Sgirish { 45744961713Sgirish p_tx_pkt_header_t hdrp; 45844961713Sgirish p_mblk_t nmp; 45944961713Sgirish uint64_t tmp; 46044961713Sgirish size_t mblk_len; 46144961713Sgirish size_t iph_len; 46244961713Sgirish size_t hdrs_size; 46344961713Sgirish uint8_t hdrs_buf[sizeof (struct ether_header) + 46452ccf843Smisaki 64 + sizeof (uint32_t)]; 465ae2d3f74Smisaki uint8_t *cursor; 46644961713Sgirish uint8_t *ip_buf; 46744961713Sgirish uint16_t eth_type; 46844961713Sgirish uint8_t ipproto; 46944961713Sgirish boolean_t is_vlan = B_FALSE; 47044961713Sgirish size_t eth_hdr_size; 47144961713Sgirish 47244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp)); 47344961713Sgirish 47444961713Sgirish /* 47544961713Sgirish * Caller should zero out the headers first. 47644961713Sgirish */ 47744961713Sgirish hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr; 47844961713Sgirish 47944961713Sgirish if (fill_len) { 48044961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 48152ccf843Smisaki "==> nxge_fill_tx_hdr: pkt_len %d " 48252ccf843Smisaki "npads %d", pkt_len, npads)); 48344961713Sgirish tmp = (uint64_t)pkt_len; 48444961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT); 48544961713Sgirish goto fill_tx_header_done; 48644961713Sgirish } 48744961713Sgirish 488b4d05839Sml hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT); 48944961713Sgirish 49044961713Sgirish /* 49144961713Sgirish * mp is the original data packet (does not include the 49244961713Sgirish * Neptune transmit header). 49344961713Sgirish */ 49444961713Sgirish nmp = mp; 49544961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: " 49652ccf843Smisaki "mp $%p b_rptr $%p len %d", 49752ccf843Smisaki mp, nmp->b_rptr, MBLKL(nmp))); 498ae2d3f74Smisaki /* copy ether_header from mblk to hdrs_buf */ 499ae2d3f74Smisaki cursor = &hdrs_buf[0]; 500ae2d3f74Smisaki tmp = sizeof (struct ether_vlan_header); 501ae2d3f74Smisaki while ((nmp != NULL) && (tmp > 0)) { 502ae2d3f74Smisaki size_t buflen; 503ae2d3f74Smisaki mblk_len = MBLKL(nmp); 5047c29db66Smisaki buflen = min((size_t)tmp, mblk_len); 505ae2d3f74Smisaki bcopy(nmp->b_rptr, cursor, buflen); 506ae2d3f74Smisaki cursor += buflen; 507ae2d3f74Smisaki tmp -= buflen; 508ae2d3f74Smisaki nmp = nmp->b_cont; 509ae2d3f74Smisaki } 510ae2d3f74Smisaki 511ae2d3f74Smisaki nmp = mp; 512ae2d3f74Smisaki mblk_len = MBLKL(nmp); 51344961713Sgirish ip_buf = NULL; 51444961713Sgirish eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type); 51544961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) " 51652ccf843Smisaki "ether type 0x%x", eth_type, hdrp->value)); 51744961713Sgirish 51844961713Sgirish if (eth_type < ETHERMTU) { 51944961713Sgirish tmp = 1ull; 52044961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT); 52144961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC " 52252ccf843Smisaki "value 0x%llx", hdrp->value)); 52344961713Sgirish if (*(hdrs_buf + sizeof (struct ether_header)) 52452ccf843Smisaki == LLC_SNAP_SAP) { 52544961713Sgirish eth_type = ntohs(*((uint16_t *)(hdrs_buf + 52652ccf843Smisaki sizeof (struct ether_header) + 6))); 52744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 52852ccf843Smisaki "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x", 52952ccf843Smisaki eth_type)); 53044961713Sgirish } else { 53144961713Sgirish goto fill_tx_header_done; 53244961713Sgirish } 53344961713Sgirish } else if (eth_type == VLAN_ETHERTYPE) { 53444961713Sgirish tmp = 1ull; 53544961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT); 53644961713Sgirish 53744961713Sgirish eth_type = ntohs(((struct ether_vlan_header *) 53852ccf843Smisaki hdrs_buf)->ether_type); 53944961713Sgirish is_vlan = B_TRUE; 54044961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN " 54152ccf843Smisaki "value 0x%llx", hdrp->value)); 54244961713Sgirish } 54344961713Sgirish 54444961713Sgirish if (!is_vlan) { 54544961713Sgirish eth_hdr_size = sizeof (struct ether_header); 54644961713Sgirish } else { 54744961713Sgirish eth_hdr_size = sizeof (struct ether_vlan_header); 54844961713Sgirish } 54944961713Sgirish 55044961713Sgirish switch (eth_type) { 55144961713Sgirish case ETHERTYPE_IP: 55244961713Sgirish if (mblk_len > eth_hdr_size + sizeof (uint8_t)) { 55344961713Sgirish ip_buf = nmp->b_rptr + eth_hdr_size; 55444961713Sgirish mblk_len -= eth_hdr_size; 55544961713Sgirish iph_len = ((*ip_buf) & 0x0f); 55644961713Sgirish if (mblk_len > (iph_len + sizeof (uint32_t))) { 55744961713Sgirish ip_buf = nmp->b_rptr; 55844961713Sgirish ip_buf += eth_hdr_size; 55944961713Sgirish } else { 56044961713Sgirish ip_buf = NULL; 56144961713Sgirish } 56244961713Sgirish 56344961713Sgirish } 56444961713Sgirish if (ip_buf == NULL) { 56544961713Sgirish hdrs_size = 0; 56644961713Sgirish ((p_ether_header_t)hdrs_buf)->ether_type = 0; 56744961713Sgirish while ((nmp) && (hdrs_size < 56852ccf843Smisaki sizeof (hdrs_buf))) { 56944961713Sgirish mblk_len = (size_t)nmp->b_wptr - 57052ccf843Smisaki (size_t)nmp->b_rptr; 57144961713Sgirish if (mblk_len >= 57252ccf843Smisaki (sizeof (hdrs_buf) - hdrs_size)) 57344961713Sgirish mblk_len = sizeof (hdrs_buf) - 57452ccf843Smisaki hdrs_size; 57544961713Sgirish bcopy(nmp->b_rptr, 57652ccf843Smisaki &hdrs_buf[hdrs_size], mblk_len); 57744961713Sgirish hdrs_size += mblk_len; 57844961713Sgirish nmp = nmp->b_cont; 57944961713Sgirish } 58044961713Sgirish ip_buf = hdrs_buf; 58144961713Sgirish ip_buf += eth_hdr_size; 58244961713Sgirish iph_len = ((*ip_buf) & 0x0f); 58344961713Sgirish } 58444961713Sgirish 58544961713Sgirish ipproto = ip_buf[9]; 58644961713Sgirish 58744961713Sgirish tmp = (uint64_t)iph_len; 58844961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT); 58944961713Sgirish tmp = (uint64_t)(eth_hdr_size >> 1); 59044961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT); 59144961713Sgirish 59244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 " 59352ccf843Smisaki " iph_len %d l3start %d eth_hdr_size %d proto 0x%x" 59452ccf843Smisaki "tmp 0x%x", 59552ccf843Smisaki iph_len, hdrp->bits.hdw.l3start, eth_hdr_size, 59652ccf843Smisaki ipproto, tmp)); 59744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP " 59852ccf843Smisaki "value 0x%llx", hdrp->value)); 59944961713Sgirish 60044961713Sgirish break; 60144961713Sgirish 60244961713Sgirish case ETHERTYPE_IPV6: 60344961713Sgirish hdrs_size = 0; 60444961713Sgirish ((p_ether_header_t)hdrs_buf)->ether_type = 0; 60544961713Sgirish while ((nmp) && (hdrs_size < 60652ccf843Smisaki sizeof (hdrs_buf))) { 60744961713Sgirish mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr; 60844961713Sgirish if (mblk_len >= 60952ccf843Smisaki (sizeof (hdrs_buf) - hdrs_size)) 61044961713Sgirish mblk_len = sizeof (hdrs_buf) - 61152ccf843Smisaki hdrs_size; 61244961713Sgirish bcopy(nmp->b_rptr, 61352ccf843Smisaki &hdrs_buf[hdrs_size], mblk_len); 61444961713Sgirish hdrs_size += mblk_len; 61544961713Sgirish nmp = nmp->b_cont; 61644961713Sgirish } 61744961713Sgirish ip_buf = hdrs_buf; 61844961713Sgirish ip_buf += eth_hdr_size; 61944961713Sgirish 62044961713Sgirish tmp = 1ull; 62144961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT); 62244961713Sgirish 62344961713Sgirish tmp = (eth_hdr_size >> 1); 62444961713Sgirish hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT); 62544961713Sgirish 62644961713Sgirish /* byte 6 is the next header protocol */ 62744961713Sgirish ipproto = ip_buf[6]; 62844961713Sgirish 62944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 " 63052ccf843Smisaki " iph_len %d l3start %d eth_hdr_size %d proto 0x%x", 63152ccf843Smisaki iph_len, hdrp->bits.hdw.l3start, eth_hdr_size, 63252ccf843Smisaki ipproto)); 63344961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 " 63452ccf843Smisaki "value 0x%llx", hdrp->value)); 63544961713Sgirish 63644961713Sgirish break; 63744961713Sgirish 63844961713Sgirish default: 63944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP")); 64044961713Sgirish goto fill_tx_header_done; 64144961713Sgirish } 64244961713Sgirish 64344961713Sgirish switch (ipproto) { 64444961713Sgirish case IPPROTO_TCP: 64544961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 646b4d05839Sml "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum)); 64744961713Sgirish if (l4_cksum) { 648b4d05839Sml hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP; 649b4d05839Sml hdrp->value |= 650b4d05839Sml (((uint64_t)(start_offset >> 1)) << 651b4d05839Sml TX_PKT_HEADER_L4START_SHIFT); 652b4d05839Sml hdrp->value |= 653b4d05839Sml (((uint64_t)(stuff_offset >> 1)) << 654b4d05839Sml TX_PKT_HEADER_L4STUFF_SHIFT); 655b4d05839Sml 65644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 657b4d05839Sml "==> nxge_tx_pkt_hdr_init: TCP CKSUM " 658b4d05839Sml "value 0x%llx", hdrp->value)); 65944961713Sgirish } 66044961713Sgirish 66144961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP " 662b4d05839Sml "value 0x%llx", hdrp->value)); 66344961713Sgirish break; 66444961713Sgirish 66544961713Sgirish case IPPROTO_UDP: 66644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP")); 66744961713Sgirish if (l4_cksum) { 668b4d05839Sml if (!nxge_cksum_offload) { 669b4d05839Sml uint16_t *up; 670b4d05839Sml uint16_t cksum; 671b4d05839Sml t_uscalar_t stuff_len; 672b4d05839Sml 673b4d05839Sml /* 674b4d05839Sml * The checksum field has the 675b4d05839Sml * partial checksum. 676b4d05839Sml * IP_CSUM() macro calls ip_cksum() which 677b4d05839Sml * can add in the partial checksum. 678b4d05839Sml */ 679b4d05839Sml cksum = IP_CSUM(mp, start_offset, 0); 680b4d05839Sml stuff_len = stuff_offset; 681b4d05839Sml nmp = mp; 682b4d05839Sml mblk_len = MBLKL(nmp); 683b4d05839Sml while ((nmp != NULL) && 684b4d05839Sml (mblk_len < stuff_len)) { 685b4d05839Sml stuff_len -= mblk_len; 686b4d05839Sml nmp = nmp->b_cont; 687b4d05839Sml } 688b4d05839Sml ASSERT(nmp); 689b4d05839Sml up = (uint16_t *)(nmp->b_rptr + stuff_len); 690b4d05839Sml 691b4d05839Sml *up = cksum; 692b4d05839Sml hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP; 693b4d05839Sml NXGE_DEBUG_MSG((NULL, TX_CTL, 694b4d05839Sml "==> nxge_tx_pkt_hdr_init: UDP offset %d " 695b4d05839Sml "use sw cksum " 696b4d05839Sml "write to $%p cksum 0x%x content up 0x%x", 697b4d05839Sml stuff_len, 698b4d05839Sml up, 699b4d05839Sml cksum, 700b4d05839Sml *up)); 701b4d05839Sml } else { 702b4d05839Sml /* Hardware will compute the full checksum */ 703b4d05839Sml hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP; 704b4d05839Sml hdrp->value |= 705b4d05839Sml (((uint64_t)(start_offset >> 1)) << 706b4d05839Sml TX_PKT_HEADER_L4START_SHIFT); 707b4d05839Sml hdrp->value |= 708b4d05839Sml (((uint64_t)(stuff_offset >> 1)) << 709b4d05839Sml TX_PKT_HEADER_L4STUFF_SHIFT); 710b4d05839Sml 711b4d05839Sml NXGE_DEBUG_MSG((NULL, TX_CTL, 712b4d05839Sml "==> nxge_tx_pkt_hdr_init: UDP offset %d " 713b4d05839Sml " use partial checksum " 714b4d05839Sml "cksum 0x%x ", 715b4d05839Sml "value 0x%llx", 716b4d05839Sml stuff_offset, 717b4d05839Sml IP_CSUM(mp, start_offset, 0), 718b4d05839Sml hdrp->value)); 719b4d05839Sml } 72044961713Sgirish } 721b4d05839Sml 72244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 72352ccf843Smisaki "==> nxge_tx_pkt_hdr_init: UDP" 72452ccf843Smisaki "value 0x%llx", hdrp->value)); 72544961713Sgirish break; 72644961713Sgirish 72744961713Sgirish default: 72844961713Sgirish goto fill_tx_header_done; 72944961713Sgirish } 73044961713Sgirish 73144961713Sgirish fill_tx_header_done: 73244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 73352ccf843Smisaki "==> nxge_fill_tx_hdr: pkt_len %d " 73452ccf843Smisaki "npads %d value 0x%llx", pkt_len, npads, hdrp->value)); 73544961713Sgirish 73644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr")); 73744961713Sgirish } 73844961713Sgirish 73944961713Sgirish /*ARGSUSED*/ 74044961713Sgirish p_mblk_t 74144961713Sgirish nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads) 74244961713Sgirish { 74344961713Sgirish p_mblk_t newmp = NULL; 74444961713Sgirish 74544961713Sgirish if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) { 74644961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 74752ccf843Smisaki "<== nxge_tx_pkt_header_reserve: allocb failed")); 74844961713Sgirish return (NULL); 74944961713Sgirish } 75044961713Sgirish 75144961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 75252ccf843Smisaki "==> nxge_tx_pkt_header_reserve: get new mp")); 75344961713Sgirish DB_TYPE(newmp) = M_DATA; 75444961713Sgirish newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp); 75544961713Sgirish linkb(newmp, mp); 75644961713Sgirish newmp->b_rptr -= TX_PKT_HEADER_SIZE; 75744961713Sgirish 75844961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: " 75952ccf843Smisaki "b_rptr $%p b_wptr $%p", 76052ccf843Smisaki newmp->b_rptr, newmp->b_wptr)); 76144961713Sgirish 76244961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 76352ccf843Smisaki "<== nxge_tx_pkt_header_reserve: use new mp")); 76444961713Sgirish 76544961713Sgirish return (newmp); 76644961713Sgirish } 76744961713Sgirish 76844961713Sgirish int 76944961713Sgirish nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p) 77044961713Sgirish { 77144961713Sgirish uint_t nmblks; 77244961713Sgirish ssize_t len; 77344961713Sgirish uint_t pkt_len; 77444961713Sgirish p_mblk_t nmp, bmp, tmp; 77544961713Sgirish uint8_t *b_wptr; 77644961713Sgirish 77744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 77852ccf843Smisaki "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p " 77952ccf843Smisaki "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp))); 78044961713Sgirish 78144961713Sgirish nmp = mp; 78244961713Sgirish bmp = mp; 78344961713Sgirish nmblks = 0; 78444961713Sgirish pkt_len = 0; 78544961713Sgirish *tot_xfer_len_p = 0; 78644961713Sgirish 78744961713Sgirish while (nmp) { 78844961713Sgirish len = MBLKL(nmp); 78944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: " 79052ccf843Smisaki "len %d pkt_len %d nmblks %d tot_xfer_len %d", 79152ccf843Smisaki len, pkt_len, nmblks, 79252ccf843Smisaki *tot_xfer_len_p)); 79344961713Sgirish 79444961713Sgirish if (len <= 0) { 79544961713Sgirish bmp = nmp; 79644961713Sgirish nmp = nmp->b_cont; 79744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 79852ccf843Smisaki "==> nxge_tx_pkt_nmblocks: " 79952ccf843Smisaki "len (0) pkt_len %d nmblks %d", 80052ccf843Smisaki pkt_len, nmblks)); 80144961713Sgirish continue; 80244961713Sgirish } 80344961713Sgirish 80444961713Sgirish *tot_xfer_len_p += len; 80544961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: " 80652ccf843Smisaki "len %d pkt_len %d nmblks %d tot_xfer_len %d", 80752ccf843Smisaki len, pkt_len, nmblks, 80852ccf843Smisaki *tot_xfer_len_p)); 80944961713Sgirish 81044961713Sgirish if (len < nxge_bcopy_thresh) { 81144961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 81252ccf843Smisaki "==> nxge_tx_pkt_nmblocks: " 81352ccf843Smisaki "len %d (< thresh) pkt_len %d nmblks %d", 81452ccf843Smisaki len, pkt_len, nmblks)); 81544961713Sgirish if (pkt_len == 0) 81644961713Sgirish nmblks++; 81744961713Sgirish pkt_len += len; 81844961713Sgirish if (pkt_len >= nxge_bcopy_thresh) { 81944961713Sgirish pkt_len = 0; 82044961713Sgirish len = 0; 82144961713Sgirish nmp = bmp; 82244961713Sgirish } 82344961713Sgirish } else { 82444961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 82552ccf843Smisaki "==> nxge_tx_pkt_nmblocks: " 82652ccf843Smisaki "len %d (> thresh) pkt_len %d nmblks %d", 82752ccf843Smisaki len, pkt_len, nmblks)); 82844961713Sgirish pkt_len = 0; 82944961713Sgirish nmblks++; 83044961713Sgirish /* 83144961713Sgirish * Hardware limits the transfer length to 4K. 83244961713Sgirish * If len is more than 4K, we need to break 83344961713Sgirish * it up to at most 2 more blocks. 83444961713Sgirish */ 83544961713Sgirish if (len > TX_MAX_TRANSFER_LENGTH) { 83644961713Sgirish uint32_t nsegs; 83744961713Sgirish 838678453a8Sspeer nsegs = 1; 83944961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 84052ccf843Smisaki "==> nxge_tx_pkt_nmblocks: " 84152ccf843Smisaki "len %d pkt_len %d nmblks %d nsegs %d", 84252ccf843Smisaki len, pkt_len, nmblks, nsegs)); 84344961713Sgirish if (len % (TX_MAX_TRANSFER_LENGTH * 2)) { 84444961713Sgirish ++nsegs; 84544961713Sgirish } 84644961713Sgirish do { 84744961713Sgirish b_wptr = nmp->b_rptr + 84852ccf843Smisaki TX_MAX_TRANSFER_LENGTH; 84944961713Sgirish nmp->b_wptr = b_wptr; 85044961713Sgirish if ((tmp = dupb(nmp)) == NULL) { 85144961713Sgirish return (0); 85244961713Sgirish } 85344961713Sgirish tmp->b_rptr = b_wptr; 85444961713Sgirish tmp->b_wptr = nmp->b_wptr; 85544961713Sgirish tmp->b_cont = nmp->b_cont; 85644961713Sgirish nmp->b_cont = tmp; 85744961713Sgirish nmblks++; 85844961713Sgirish if (--nsegs) { 85944961713Sgirish nmp = tmp; 86044961713Sgirish } 86144961713Sgirish } while (nsegs); 86244961713Sgirish nmp = tmp; 86344961713Sgirish } 86444961713Sgirish } 86544961713Sgirish 86644961713Sgirish /* 86744961713Sgirish * Hardware limits the transmit gather pointers to 15. 86844961713Sgirish */ 86944961713Sgirish if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) > 87052ccf843Smisaki TX_MAX_GATHER_POINTERS) { 87144961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 87252ccf843Smisaki "==> nxge_tx_pkt_nmblocks: pull msg - " 87352ccf843Smisaki "len %d pkt_len %d nmblks %d", 87452ccf843Smisaki len, pkt_len, nmblks)); 87544961713Sgirish /* Pull all message blocks from b_cont */ 87644961713Sgirish if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) { 87744961713Sgirish return (0); 87844961713Sgirish } 87944961713Sgirish freemsg(nmp->b_cont); 88044961713Sgirish nmp->b_cont = tmp; 88144961713Sgirish pkt_len = 0; 88244961713Sgirish } 88344961713Sgirish bmp = nmp; 88444961713Sgirish nmp = nmp->b_cont; 88544961713Sgirish } 88644961713Sgirish 88744961713Sgirish NXGE_DEBUG_MSG((NULL, TX_CTL, 88852ccf843Smisaki "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p " 88952ccf843Smisaki "nmblks %d len %d tot_xfer_len %d", 89052ccf843Smisaki mp->b_rptr, mp->b_wptr, nmblks, 89152ccf843Smisaki MBLKL(mp), *tot_xfer_len_p)); 89244961713Sgirish 89344961713Sgirish return (nmblks); 89444961713Sgirish } 89544961713Sgirish 89644961713Sgirish boolean_t 89744961713Sgirish nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks) 89844961713Sgirish { 89944961713Sgirish boolean_t status = B_TRUE; 90044961713Sgirish p_nxge_dma_common_t tx_desc_dma_p; 90144961713Sgirish nxge_dma_common_t desc_area; 90244961713Sgirish p_tx_desc_t tx_desc_ring_vp; 90344961713Sgirish p_tx_desc_t tx_desc_p; 90444961713Sgirish p_tx_desc_t tx_desc_pp; 90544961713Sgirish tx_desc_t r_tx_desc; 90644961713Sgirish p_tx_msg_t tx_msg_ring; 90744961713Sgirish p_tx_msg_t tx_msg_p; 90844961713Sgirish npi_handle_t handle; 90944961713Sgirish tx_ring_hdl_t tx_head; 91044961713Sgirish uint32_t pkt_len; 91144961713Sgirish uint_t tx_rd_index; 91244961713Sgirish uint16_t head_index, tail_index; 91344961713Sgirish uint8_t tdc; 91444961713Sgirish boolean_t head_wrap, tail_wrap; 915da14cebeSEric Cheng p_nxge_tx_ring_stats_t tdc_stats; 91644961713Sgirish int rc; 91744961713Sgirish 91844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim")); 91944961713Sgirish 92044961713Sgirish status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) && 92152ccf843Smisaki (nmblks != 0)); 92244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 92352ccf843Smisaki "==> nxge_txdma_reclaim: pending %d reclaim %d nmblks %d", 92452ccf843Smisaki tx_ring_p->descs_pending, nxge_reclaim_pending, 92552ccf843Smisaki nmblks)); 92644961713Sgirish if (!status) { 92744961713Sgirish tx_desc_dma_p = &tx_ring_p->tdc_desc; 92844961713Sgirish desc_area = tx_ring_p->tdc_desc; 92944961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 93044961713Sgirish tx_desc_ring_vp = tx_desc_dma_p->kaddrp; 93144961713Sgirish tx_desc_ring_vp = 93252ccf843Smisaki (p_tx_desc_t)DMA_COMMON_VPTR(desc_area); 93344961713Sgirish tx_rd_index = tx_ring_p->rd_index; 93444961713Sgirish tx_desc_p = &tx_desc_ring_vp[tx_rd_index]; 93544961713Sgirish tx_msg_ring = tx_ring_p->tx_msg_ring; 93644961713Sgirish tx_msg_p = &tx_msg_ring[tx_rd_index]; 93744961713Sgirish tdc = tx_ring_p->tdc; 93844961713Sgirish tdc_stats = tx_ring_p->tdc_stats; 93944961713Sgirish if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) { 94044961713Sgirish tdc_stats->tx_max_pend = tx_ring_p->descs_pending; 94144961713Sgirish } 94244961713Sgirish 94344961713Sgirish tail_index = tx_ring_p->wr_index; 94444961713Sgirish tail_wrap = tx_ring_p->wr_index_wrap; 94544961713Sgirish 94644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 94752ccf843Smisaki "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d " 94852ccf843Smisaki "tail_index %d tail_wrap %d " 94952ccf843Smisaki "tx_desc_p $%p ($%p) ", 95052ccf843Smisaki tdc, tx_rd_index, tail_index, tail_wrap, 95152ccf843Smisaki tx_desc_p, (*(uint64_t *)tx_desc_p))); 95244961713Sgirish /* 95344961713Sgirish * Read the hardware maintained transmit head 95444961713Sgirish * and wrap around bit. 95544961713Sgirish */ 95644961713Sgirish TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value); 95744961713Sgirish head_index = tx_head.bits.ldw.head; 95844961713Sgirish head_wrap = tx_head.bits.ldw.wrap; 95944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 96052ccf843Smisaki "==> nxge_txdma_reclaim: " 96152ccf843Smisaki "tx_rd_index %d tail %d tail_wrap %d " 96252ccf843Smisaki "head %d wrap %d", 96352ccf843Smisaki tx_rd_index, tail_index, tail_wrap, 96452ccf843Smisaki head_index, head_wrap)); 96544961713Sgirish 96644961713Sgirish if (head_index == tail_index) { 96744961713Sgirish if (TXDMA_RING_EMPTY(head_index, head_wrap, 96852ccf843Smisaki tail_index, tail_wrap) && 96952ccf843Smisaki (head_index == tx_rd_index)) { 97044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 97152ccf843Smisaki "==> nxge_txdma_reclaim: EMPTY")); 97244961713Sgirish return (B_TRUE); 97344961713Sgirish } 97444961713Sgirish 97544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 97652ccf843Smisaki "==> nxge_txdma_reclaim: Checking " 97752ccf843Smisaki "if ring full")); 97844961713Sgirish if (TXDMA_RING_FULL(head_index, head_wrap, tail_index, 97952ccf843Smisaki tail_wrap)) { 98044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 98152ccf843Smisaki "==> nxge_txdma_reclaim: full")); 98244961713Sgirish return (B_FALSE); 98344961713Sgirish } 98444961713Sgirish } 98544961713Sgirish 98644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 98752ccf843Smisaki "==> nxge_txdma_reclaim: tx_rd_index and head_index")); 98844961713Sgirish 98944961713Sgirish tx_desc_pp = &r_tx_desc; 99044961713Sgirish while ((tx_rd_index != head_index) && 99152ccf843Smisaki (tx_ring_p->descs_pending != 0)) { 99244961713Sgirish 99344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 99452ccf843Smisaki "==> nxge_txdma_reclaim: Checking if pending")); 99544961713Sgirish 99644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 99752ccf843Smisaki "==> nxge_txdma_reclaim: " 99852ccf843Smisaki "descs_pending %d ", 99952ccf843Smisaki tx_ring_p->descs_pending)); 100044961713Sgirish 100144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 100252ccf843Smisaki "==> nxge_txdma_reclaim: " 100352ccf843Smisaki "(tx_rd_index %d head_index %d " 100452ccf843Smisaki "(tx_desc_p $%p)", 100552ccf843Smisaki tx_rd_index, head_index, 100652ccf843Smisaki tx_desc_p)); 100744961713Sgirish 100844961713Sgirish tx_desc_pp->value = tx_desc_p->value; 100944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 101052ccf843Smisaki "==> nxge_txdma_reclaim: " 101152ccf843Smisaki "(tx_rd_index %d head_index %d " 101252ccf843Smisaki "tx_desc_p $%p (desc value 0x%llx) ", 101352ccf843Smisaki tx_rd_index, head_index, 101452ccf843Smisaki tx_desc_pp, (*(uint64_t *)tx_desc_pp))); 101544961713Sgirish 101644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 101752ccf843Smisaki "==> nxge_txdma_reclaim: dump desc:")); 101844961713Sgirish 101944961713Sgirish pkt_len = tx_desc_pp->bits.hdw.tr_len; 102044961713Sgirish tdc_stats->obytes += pkt_len; 102144961713Sgirish tdc_stats->opackets += tx_desc_pp->bits.hdw.sop; 102244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 102352ccf843Smisaki "==> nxge_txdma_reclaim: pkt_len %d " 102452ccf843Smisaki "tdc channel %d opackets %d", 102552ccf843Smisaki pkt_len, 102652ccf843Smisaki tdc, 102752ccf843Smisaki tdc_stats->opackets)); 102844961713Sgirish 102944961713Sgirish if (tx_msg_p->flags.dma_type == USE_DVMA) { 103044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 103152ccf843Smisaki "tx_desc_p = $%p " 103252ccf843Smisaki "tx_desc_pp = $%p " 103352ccf843Smisaki "index = %d", 103452ccf843Smisaki tx_desc_p, 103552ccf843Smisaki tx_desc_pp, 103652ccf843Smisaki tx_ring_p->rd_index)); 103744961713Sgirish (void) dvma_unload(tx_msg_p->dvma_handle, 103852ccf843Smisaki 0, -1); 103944961713Sgirish tx_msg_p->dvma_handle = NULL; 104044961713Sgirish if (tx_ring_p->dvma_wr_index == 104152ccf843Smisaki tx_ring_p->dvma_wrap_mask) { 104244961713Sgirish tx_ring_p->dvma_wr_index = 0; 104344961713Sgirish } else { 104444961713Sgirish tx_ring_p->dvma_wr_index++; 104544961713Sgirish } 104644961713Sgirish tx_ring_p->dvma_pending--; 104744961713Sgirish } else if (tx_msg_p->flags.dma_type == 104852ccf843Smisaki USE_DMA) { 104944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 105052ccf843Smisaki "==> nxge_txdma_reclaim: " 105152ccf843Smisaki "USE DMA")); 105244961713Sgirish if (rc = ddi_dma_unbind_handle 105352ccf843Smisaki (tx_msg_p->dma_handle)) { 105444961713Sgirish cmn_err(CE_WARN, "!nxge_reclaim: " 105552ccf843Smisaki "ddi_dma_unbind_handle " 105652ccf843Smisaki "failed. status %d", rc); 105744961713Sgirish } 105844961713Sgirish } 105944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 106052ccf843Smisaki "==> nxge_txdma_reclaim: count packets")); 106144961713Sgirish /* 106244961713Sgirish * count a chained packet only once. 106344961713Sgirish */ 106444961713Sgirish if (tx_msg_p->tx_message != NULL) { 1065da14cebeSEric Cheng freemsg(tx_msg_p->tx_message); 1066da14cebeSEric Cheng tx_msg_p->tx_message = NULL; 106744961713Sgirish } 106844961713Sgirish 106944961713Sgirish tx_msg_p->flags.dma_type = USE_NONE; 107044961713Sgirish tx_rd_index = tx_ring_p->rd_index; 107144961713Sgirish tx_rd_index = (tx_rd_index + 1) & 107252ccf843Smisaki tx_ring_p->tx_wrap_mask; 107344961713Sgirish tx_ring_p->rd_index = tx_rd_index; 107444961713Sgirish tx_ring_p->descs_pending--; 107544961713Sgirish tx_desc_p = &tx_desc_ring_vp[tx_rd_index]; 107644961713Sgirish tx_msg_p = &tx_msg_ring[tx_rd_index]; 107744961713Sgirish } 107844961713Sgirish 1079257bdc55SMichael Speer status = (nmblks <= ((int)tx_ring_p->tx_ring_size - 1080257bdc55SMichael Speer (int)tx_ring_p->descs_pending - TX_FULL_MARK)); 108144961713Sgirish if (status) { 1082952a2464SMichael Speer (void) cas32((uint32_t *)&tx_ring_p->queueing, 1, 0); 108344961713Sgirish } 108444961713Sgirish } else { 1085257bdc55SMichael Speer status = (nmblks <= ((int)tx_ring_p->tx_ring_size - 1086257bdc55SMichael Speer (int)tx_ring_p->descs_pending - TX_FULL_MARK)); 108744961713Sgirish } 108844961713Sgirish 108944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 109052ccf843Smisaki "<== nxge_txdma_reclaim status = 0x%08x", status)); 109144961713Sgirish 109244961713Sgirish return (status); 109344961713Sgirish } 109444961713Sgirish 1095678453a8Sspeer /* 1096678453a8Sspeer * nxge_tx_intr 1097678453a8Sspeer * 1098678453a8Sspeer * Process a TDC interrupt 1099678453a8Sspeer * 1100678453a8Sspeer * Arguments: 1101678453a8Sspeer * arg1 A Logical Device state Vector (LSV) data structure. 1102678453a8Sspeer * arg2 nxge_t * 1103678453a8Sspeer * 1104678453a8Sspeer * Notes: 1105678453a8Sspeer * 1106678453a8Sspeer * NPI/NXGE function calls: 1107678453a8Sspeer * npi_txdma_control_status() 1108678453a8Sspeer * npi_intr_ldg_mgmt_set() 1109678453a8Sspeer * 1110678453a8Sspeer * nxge_tx_err_evnts() 1111678453a8Sspeer * nxge_txdma_reclaim() 1112678453a8Sspeer * 1113678453a8Sspeer * Registers accessed: 1114678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1115678453a8Sspeer * PIO_LDSV 1116678453a8Sspeer * 1117678453a8Sspeer * Context: 1118678453a8Sspeer * Any domain 1119678453a8Sspeer */ 112044961713Sgirish uint_t 112144961713Sgirish nxge_tx_intr(void *arg1, void *arg2) 112244961713Sgirish { 112344961713Sgirish p_nxge_ldv_t ldvp = (p_nxge_ldv_t)arg1; 112444961713Sgirish p_nxge_t nxgep = (p_nxge_t)arg2; 112544961713Sgirish p_nxge_ldg_t ldgp; 112644961713Sgirish uint8_t channel; 112744961713Sgirish uint32_t vindex; 112844961713Sgirish npi_handle_t handle; 112944961713Sgirish tx_cs_t cs; 113044961713Sgirish p_tx_ring_t *tx_rings; 113144961713Sgirish p_tx_ring_t tx_ring_p; 113244961713Sgirish npi_status_t rs = NPI_SUCCESS; 113344961713Sgirish uint_t serviced = DDI_INTR_UNCLAIMED; 113444961713Sgirish nxge_status_t status = NXGE_OK; 113544961713Sgirish 113644961713Sgirish if (ldvp == NULL) { 113744961713Sgirish NXGE_DEBUG_MSG((NULL, INT_CTL, 113852ccf843Smisaki "<== nxge_tx_intr: nxgep $%p ldvp $%p", 113952ccf843Smisaki nxgep, ldvp)); 114044961713Sgirish return (DDI_INTR_UNCLAIMED); 114144961713Sgirish } 114244961713Sgirish 114344961713Sgirish if (arg2 == NULL || (void *)ldvp->nxgep != arg2) { 114444961713Sgirish nxgep = ldvp->nxgep; 114544961713Sgirish } 114644961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 114752ccf843Smisaki "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p", 114852ccf843Smisaki nxgep, ldvp)); 114922c0d73aSspeer 115022c0d73aSspeer if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) || 115122c0d73aSspeer (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) { 115222c0d73aSspeer NXGE_DEBUG_MSG((nxgep, INT_CTL, 115322c0d73aSspeer "<== nxge_tx_intr: interface not started or intialized")); 115422c0d73aSspeer return (DDI_INTR_CLAIMED); 115522c0d73aSspeer } 115622c0d73aSspeer 115744961713Sgirish /* 115844961713Sgirish * This interrupt handler is for a specific 115944961713Sgirish * transmit dma channel. 116044961713Sgirish */ 116144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 116244961713Sgirish /* Get the control and status for this channel. */ 116344961713Sgirish channel = ldvp->channel; 116444961713Sgirish ldgp = ldvp->ldgp; 116544961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 116652ccf843Smisaki "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p " 116752ccf843Smisaki "channel %d", 116852ccf843Smisaki nxgep, ldvp, channel)); 116944961713Sgirish 117044961713Sgirish rs = npi_txdma_control_status(handle, OP_GET, channel, &cs); 117144961713Sgirish vindex = ldvp->vdma_index; 117244961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 117352ccf843Smisaki "==> nxge_tx_intr:channel %d ring index %d status 0x%08x", 117452ccf843Smisaki channel, vindex, rs)); 117544961713Sgirish if (!rs && cs.bits.ldw.mk) { 117644961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 117752ccf843Smisaki "==> nxge_tx_intr:channel %d ring index %d " 117852ccf843Smisaki "status 0x%08x (mk bit set)", 117952ccf843Smisaki channel, vindex, rs)); 118044961713Sgirish tx_rings = nxgep->tx_rings->rings; 118144961713Sgirish tx_ring_p = tx_rings[vindex]; 118244961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 118352ccf843Smisaki "==> nxge_tx_intr:channel %d ring index %d " 118452ccf843Smisaki "status 0x%08x (mk bit set, calling reclaim)", 118552ccf843Smisaki channel, vindex, rs)); 118644961713Sgirish 1187da14cebeSEric Cheng nxge_tx_ring_task((void *)tx_ring_p); 118844961713Sgirish } 118944961713Sgirish 119044961713Sgirish /* 119144961713Sgirish * Process other transmit control and status. 119244961713Sgirish * Check the ldv state. 119344961713Sgirish */ 119444961713Sgirish status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs); 119544961713Sgirish /* 119644961713Sgirish * Rearm this logical group if this is a single device 119744961713Sgirish * group. 119844961713Sgirish */ 119944961713Sgirish if (ldgp->nldvs == 1) { 120044961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, 120152ccf843Smisaki "==> nxge_tx_intr: rearm")); 120244961713Sgirish if (status == NXGE_OK) { 1203678453a8Sspeer if (isLDOMguest(nxgep)) { 1204678453a8Sspeer nxge_hio_ldgimgn(nxgep, ldgp); 1205678453a8Sspeer } else { 1206678453a8Sspeer (void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg, 1207678453a8Sspeer B_TRUE, ldgp->ldg_timer); 1208678453a8Sspeer } 120944961713Sgirish } 121044961713Sgirish } 121144961713Sgirish 121244961713Sgirish NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr")); 121344961713Sgirish serviced = DDI_INTR_CLAIMED; 121444961713Sgirish return (serviced); 121544961713Sgirish } 121644961713Sgirish 121744961713Sgirish void 1218678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep) /* Dead */ 121944961713Sgirish { 122044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop")); 122144961713Sgirish 122244961713Sgirish (void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP); 122344961713Sgirish 122444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop")); 122544961713Sgirish } 122644961713Sgirish 122744961713Sgirish void 1228678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */ 122944961713Sgirish { 123044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start")); 123144961713Sgirish 123244961713Sgirish (void) nxge_txdma_stop(nxgep); 123344961713Sgirish 123444961713Sgirish (void) nxge_fixup_txdma_rings(nxgep); 123544961713Sgirish (void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START); 123644961713Sgirish (void) nxge_tx_mac_enable(nxgep); 123744961713Sgirish (void) nxge_txdma_hw_kick(nxgep); 123844961713Sgirish 123944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start")); 124044961713Sgirish } 124144961713Sgirish 1242678453a8Sspeer npi_status_t 1243678453a8Sspeer nxge_txdma_channel_disable( 1244678453a8Sspeer nxge_t *nxge, 1245678453a8Sspeer int channel) 1246678453a8Sspeer { 1247678453a8Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge); 1248678453a8Sspeer npi_status_t rs; 1249678453a8Sspeer tdmc_intr_dbg_t intr_dbg; 1250678453a8Sspeer 1251678453a8Sspeer /* 1252678453a8Sspeer * Stop the dma channel and wait for the stop-done. 1253678453a8Sspeer * If the stop-done bit is not present, then force 1254678453a8Sspeer * an error so TXC will stop. 1255678453a8Sspeer * All channels bound to this port need to be stopped 1256678453a8Sspeer * and reset after injecting an interrupt error. 1257678453a8Sspeer */ 1258678453a8Sspeer rs = npi_txdma_channel_disable(handle, channel); 1259678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 126052ccf843Smisaki "==> nxge_txdma_channel_disable(%d) " 126152ccf843Smisaki "rs 0x%x", channel, rs)); 1262678453a8Sspeer if (rs != NPI_SUCCESS) { 1263678453a8Sspeer /* Inject any error */ 1264678453a8Sspeer intr_dbg.value = 0; 1265678453a8Sspeer intr_dbg.bits.ldw.nack_pref = 1; 1266678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 126752ccf843Smisaki "==> nxge_txdma_hw_mode: " 126852ccf843Smisaki "channel %d (stop failed 0x%x) " 126952ccf843Smisaki "(inject err)", rs, channel)); 1270678453a8Sspeer (void) npi_txdma_inj_int_error_set( 127152ccf843Smisaki handle, channel, &intr_dbg); 1272678453a8Sspeer rs = npi_txdma_channel_disable(handle, channel); 1273678453a8Sspeer NXGE_DEBUG_MSG((nxge, MEM3_CTL, 127452ccf843Smisaki "==> nxge_txdma_hw_mode: " 127552ccf843Smisaki "channel %d (stop again 0x%x) " 127652ccf843Smisaki "(after inject err)", 127752ccf843Smisaki rs, channel)); 1278678453a8Sspeer } 1279678453a8Sspeer 1280678453a8Sspeer return (rs); 1281678453a8Sspeer } 1282678453a8Sspeer 1283678453a8Sspeer /* 1284678453a8Sspeer * nxge_txdma_hw_mode 1285678453a8Sspeer * 1286678453a8Sspeer * Toggle all TDCs on (enable) or off (disable). 1287678453a8Sspeer * 1288678453a8Sspeer * Arguments: 1289678453a8Sspeer * nxgep 1290678453a8Sspeer * enable Enable or disable a TDC. 1291678453a8Sspeer * 1292678453a8Sspeer * Notes: 1293678453a8Sspeer * 1294678453a8Sspeer * NPI/NXGE function calls: 1295678453a8Sspeer * npi_txdma_channel_enable(TX_CS) 1296678453a8Sspeer * npi_txdma_channel_disable(TX_CS) 1297678453a8Sspeer * npi_txdma_inj_int_error_set(TDMC_INTR_DBG) 1298678453a8Sspeer * 1299678453a8Sspeer * Registers accessed: 1300678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1301678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1302678453a8Sspeer * 1303678453a8Sspeer * Context: 1304678453a8Sspeer * Any domain 1305678453a8Sspeer */ 130644961713Sgirish nxge_status_t 130744961713Sgirish nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable) 130844961713Sgirish { 1309678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1310678453a8Sspeer 1311678453a8Sspeer npi_handle_t handle; 1312678453a8Sspeer nxge_status_t status; 1313678453a8Sspeer npi_status_t rs; 1314678453a8Sspeer int tdc; 131544961713Sgirish 131644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 131752ccf843Smisaki "==> nxge_txdma_hw_mode: enable mode %d", enable)); 131844961713Sgirish 131944961713Sgirish if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { 132044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 132152ccf843Smisaki "<== nxge_txdma_mode: not initialized")); 132244961713Sgirish return (NXGE_ERROR); 132344961713Sgirish } 132444961713Sgirish 1325678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 132644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1327678453a8Sspeer "<== nxge_txdma_hw_mode: NULL ring pointer(s)")); 132844961713Sgirish return (NXGE_ERROR); 132944961713Sgirish } 133044961713Sgirish 1331678453a8Sspeer /* Enable or disable all of the TDCs owned by us. */ 133244961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 1333678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1334678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1335678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1336678453a8Sspeer if (ring) { 1337678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1338678453a8Sspeer "==> nxge_txdma_hw_mode: channel %d", tdc)); 1339678453a8Sspeer if (enable) { 1340678453a8Sspeer rs = npi_txdma_channel_enable 1341678453a8Sspeer (handle, tdc); 134244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1343678453a8Sspeer "==> nxge_txdma_hw_mode: " 1344678453a8Sspeer "channel %d (enable) rs 0x%x", 1345678453a8Sspeer tdc, rs)); 1346678453a8Sspeer } else { 1347678453a8Sspeer rs = nxge_txdma_channel_disable 1348678453a8Sspeer (nxgep, tdc); 134944961713Sgirish } 135044961713Sgirish } 135144961713Sgirish } 135244961713Sgirish } 135344961713Sgirish 135444961713Sgirish status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 135544961713Sgirish 135644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 135752ccf843Smisaki "<== nxge_txdma_hw_mode: status 0x%x", status)); 135844961713Sgirish 135944961713Sgirish return (status); 136044961713Sgirish } 136144961713Sgirish 136244961713Sgirish void 136344961713Sgirish nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel) 136444961713Sgirish { 136544961713Sgirish npi_handle_t handle; 136644961713Sgirish 136744961713Sgirish NXGE_DEBUG_MSG((nxgep, DMA_CTL, 136852ccf843Smisaki "==> nxge_txdma_enable_channel: channel %d", channel)); 136944961713Sgirish 137044961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 137144961713Sgirish /* enable the transmit dma channels */ 137244961713Sgirish (void) npi_txdma_channel_enable(handle, channel); 137344961713Sgirish 137444961713Sgirish NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel")); 137544961713Sgirish } 137644961713Sgirish 137744961713Sgirish void 137844961713Sgirish nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel) 137944961713Sgirish { 138044961713Sgirish npi_handle_t handle; 138144961713Sgirish 138244961713Sgirish NXGE_DEBUG_MSG((nxgep, DMA_CTL, 138352ccf843Smisaki "==> nxge_txdma_disable_channel: channel %d", channel)); 138444961713Sgirish 138544961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 138644961713Sgirish /* stop the transmit dma channels */ 138744961713Sgirish (void) npi_txdma_channel_disable(handle, channel); 138844961713Sgirish 138944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel")); 139044961713Sgirish } 139144961713Sgirish 1392678453a8Sspeer /* 1393678453a8Sspeer * nxge_txdma_stop_inj_err 1394678453a8Sspeer * 1395678453a8Sspeer * Stop a TDC. If at first we don't succeed, inject an error. 1396678453a8Sspeer * 1397678453a8Sspeer * Arguments: 1398678453a8Sspeer * nxgep 1399678453a8Sspeer * channel The channel to stop. 1400678453a8Sspeer * 1401678453a8Sspeer * Notes: 1402678453a8Sspeer * 1403678453a8Sspeer * NPI/NXGE function calls: 1404678453a8Sspeer * npi_txdma_channel_disable() 1405678453a8Sspeer * npi_txdma_inj_int_error_set() 1406678453a8Sspeer * #if defined(NXGE_DEBUG) 1407678453a8Sspeer * nxge_txdma_regs_dump_channels(nxgep); 1408678453a8Sspeer * #endif 1409678453a8Sspeer * 1410678453a8Sspeer * Registers accessed: 1411678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1412678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1413678453a8Sspeer * 1414678453a8Sspeer * Context: 1415678453a8Sspeer * Any domain 1416678453a8Sspeer */ 141744961713Sgirish int 141844961713Sgirish nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel) 141944961713Sgirish { 142044961713Sgirish npi_handle_t handle; 142144961713Sgirish tdmc_intr_dbg_t intr_dbg; 142244961713Sgirish int status; 142344961713Sgirish npi_status_t rs = NPI_SUCCESS; 142444961713Sgirish 142544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err")); 142644961713Sgirish /* 142744961713Sgirish * Stop the dma channel waits for the stop done. 142844961713Sgirish * If the stop done bit is not set, then create 142944961713Sgirish * an error. 143044961713Sgirish */ 143144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 143244961713Sgirish rs = npi_txdma_channel_disable(handle, channel); 143344961713Sgirish status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 143444961713Sgirish if (status == NXGE_OK) { 143544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 143652ccf843Smisaki "<== nxge_txdma_stop_inj_err (channel %d): " 143752ccf843Smisaki "stopped OK", channel)); 143844961713Sgirish return (status); 143944961713Sgirish } 144044961713Sgirish 144144961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 144252ccf843Smisaki "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) " 144352ccf843Smisaki "injecting error", channel, rs)); 144444961713Sgirish /* Inject any error */ 144544961713Sgirish intr_dbg.value = 0; 144644961713Sgirish intr_dbg.bits.ldw.nack_pref = 1; 144744961713Sgirish (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg); 144844961713Sgirish 144944961713Sgirish /* Stop done bit will be set as a result of error injection */ 145044961713Sgirish rs = npi_txdma_channel_disable(handle, channel); 145144961713Sgirish status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs); 145244961713Sgirish if (!(rs & NPI_TXDMA_STOP_FAILED)) { 145344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 145452ccf843Smisaki "<== nxge_txdma_stop_inj_err (channel %d): " 145552ccf843Smisaki "stopped OK ", channel)); 145644961713Sgirish return (status); 145744961713Sgirish } 145844961713Sgirish 145944961713Sgirish #if defined(NXGE_DEBUG) 146044961713Sgirish nxge_txdma_regs_dump_channels(nxgep); 146144961713Sgirish #endif 146244961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 146352ccf843Smisaki "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) " 146452ccf843Smisaki " (injected error but still not stopped)", channel, rs)); 146544961713Sgirish 146644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err")); 146744961713Sgirish return (status); 146844961713Sgirish } 146944961713Sgirish 147044961713Sgirish /*ARGSUSED*/ 147144961713Sgirish void 147244961713Sgirish nxge_fixup_txdma_rings(p_nxge_t nxgep) 147344961713Sgirish { 1474678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1475678453a8Sspeer int tdc; 147644961713Sgirish 147744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings")); 147844961713Sgirish 1479678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 1480678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1481678453a8Sspeer "<== nxge_fixup_txdma_rings: NULL ring pointer(s)")); 148244961713Sgirish return; 148344961713Sgirish } 148444961713Sgirish 1485678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1486678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1487678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1488678453a8Sspeer if (ring) { 1489678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1490678453a8Sspeer "==> nxge_fixup_txdma_rings: channel %d", 1491678453a8Sspeer tdc)); 1492678453a8Sspeer nxge_txdma_fixup_channel(nxgep, ring, tdc); 1493678453a8Sspeer } 1494678453a8Sspeer } 149544961713Sgirish } 149644961713Sgirish 149744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings")); 149844961713Sgirish } 149944961713Sgirish 150044961713Sgirish /*ARGSUSED*/ 150144961713Sgirish void 150244961713Sgirish nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel) 150344961713Sgirish { 150444961713Sgirish p_tx_ring_t ring_p; 150544961713Sgirish 150644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel")); 150744961713Sgirish ring_p = nxge_txdma_get_ring(nxgep, channel); 150844961713Sgirish if (ring_p == NULL) { 150944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel")); 151044961713Sgirish return; 151144961713Sgirish } 151244961713Sgirish 151344961713Sgirish if (ring_p->tdc != channel) { 151444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 151552ccf843Smisaki "<== nxge_txdma_fix_channel: channel not matched " 151652ccf843Smisaki "ring tdc %d passed channel", 151752ccf843Smisaki ring_p->tdc, channel)); 151844961713Sgirish return; 151944961713Sgirish } 152044961713Sgirish 152144961713Sgirish nxge_txdma_fixup_channel(nxgep, ring_p, channel); 152244961713Sgirish 152344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel")); 152444961713Sgirish } 152544961713Sgirish 152644961713Sgirish /*ARGSUSED*/ 152744961713Sgirish void 152844961713Sgirish nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel) 152944961713Sgirish { 153044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel")); 153144961713Sgirish 153244961713Sgirish if (ring_p == NULL) { 153344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 153452ccf843Smisaki "<== nxge_txdma_fixup_channel: NULL ring pointer")); 153544961713Sgirish return; 153644961713Sgirish } 153744961713Sgirish 153844961713Sgirish if (ring_p->tdc != channel) { 153944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 154052ccf843Smisaki "<== nxge_txdma_fixup_channel: channel not matched " 154152ccf843Smisaki "ring tdc %d passed channel", 154252ccf843Smisaki ring_p->tdc, channel)); 154344961713Sgirish return; 154444961713Sgirish } 154544961713Sgirish 154644961713Sgirish MUTEX_ENTER(&ring_p->lock); 154744961713Sgirish (void) nxge_txdma_reclaim(nxgep, ring_p, 0); 154844961713Sgirish ring_p->rd_index = 0; 154944961713Sgirish ring_p->wr_index = 0; 155044961713Sgirish ring_p->ring_head.value = 0; 155144961713Sgirish ring_p->ring_kick_tail.value = 0; 155244961713Sgirish ring_p->descs_pending = 0; 155344961713Sgirish MUTEX_EXIT(&ring_p->lock); 155444961713Sgirish 155544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel")); 155644961713Sgirish } 155744961713Sgirish 155844961713Sgirish /*ARGSUSED*/ 155944961713Sgirish void 156044961713Sgirish nxge_txdma_hw_kick(p_nxge_t nxgep) 156144961713Sgirish { 1562678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1563678453a8Sspeer int tdc; 156444961713Sgirish 156544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick")); 156644961713Sgirish 1567678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 156844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1569678453a8Sspeer "<== nxge_txdma_hw_kick: NULL ring pointer(s)")); 157044961713Sgirish return; 157144961713Sgirish } 157244961713Sgirish 1573678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1574678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1575678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1576678453a8Sspeer if (ring) { 1577678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 1578678453a8Sspeer "==> nxge_txdma_hw_kick: channel %d", tdc)); 1579678453a8Sspeer nxge_txdma_hw_kick_channel(nxgep, ring, tdc); 1580678453a8Sspeer } 1581678453a8Sspeer } 158244961713Sgirish } 158344961713Sgirish 158444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick")); 158544961713Sgirish } 158644961713Sgirish 158744961713Sgirish /*ARGSUSED*/ 158844961713Sgirish void 158944961713Sgirish nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel) 159044961713Sgirish { 159144961713Sgirish p_tx_ring_t ring_p; 159244961713Sgirish 159344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel")); 159444961713Sgirish 159544961713Sgirish ring_p = nxge_txdma_get_ring(nxgep, channel); 159644961713Sgirish if (ring_p == NULL) { 159744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 159852ccf843Smisaki " nxge_txdma_kick_channel")); 159944961713Sgirish return; 160044961713Sgirish } 160144961713Sgirish 160244961713Sgirish if (ring_p->tdc != channel) { 160344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 160452ccf843Smisaki "<== nxge_txdma_kick_channel: channel not matched " 160552ccf843Smisaki "ring tdc %d passed channel", 160652ccf843Smisaki ring_p->tdc, channel)); 160744961713Sgirish return; 160844961713Sgirish } 160944961713Sgirish 161044961713Sgirish nxge_txdma_hw_kick_channel(nxgep, ring_p, channel); 161144961713Sgirish 161244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel")); 161344961713Sgirish } 1614a3c5bd6dSspeer 161544961713Sgirish /*ARGSUSED*/ 161644961713Sgirish void 161744961713Sgirish nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel) 161844961713Sgirish { 161944961713Sgirish 162044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel")); 162144961713Sgirish 162244961713Sgirish if (ring_p == NULL) { 162344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 162452ccf843Smisaki "<== nxge_txdma_hw_kick_channel: NULL ring pointer")); 162544961713Sgirish return; 162644961713Sgirish } 162744961713Sgirish 162844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel")); 162944961713Sgirish } 163044961713Sgirish 1631678453a8Sspeer /* 1632678453a8Sspeer * nxge_check_tx_hang 1633678453a8Sspeer * 1634678453a8Sspeer * Check the state of all TDCs belonging to nxgep. 1635678453a8Sspeer * 1636678453a8Sspeer * Arguments: 1637678453a8Sspeer * nxgep 1638678453a8Sspeer * 1639678453a8Sspeer * Notes: 1640678453a8Sspeer * Called by nxge_hw.c:nxge_check_hw_state(). 1641678453a8Sspeer * 1642678453a8Sspeer * NPI/NXGE function calls: 1643678453a8Sspeer * 1644678453a8Sspeer * Registers accessed: 1645678453a8Sspeer * 1646678453a8Sspeer * Context: 1647678453a8Sspeer * Any domain 1648678453a8Sspeer */ 164944961713Sgirish /*ARGSUSED*/ 165044961713Sgirish void 165144961713Sgirish nxge_check_tx_hang(p_nxge_t nxgep) 165244961713Sgirish { 165344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang")); 165444961713Sgirish 165522c0d73aSspeer if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) || 165622c0d73aSspeer (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) { 165722c0d73aSspeer goto nxge_check_tx_hang_exit; 165822c0d73aSspeer } 165922c0d73aSspeer 166044961713Sgirish /* 166144961713Sgirish * Needs inputs from hardware for regs: 166244961713Sgirish * head index had not moved since last timeout. 166344961713Sgirish * packets not transmitted or stuffed registers. 166444961713Sgirish */ 166544961713Sgirish if (nxge_txdma_hung(nxgep)) { 166644961713Sgirish nxge_fixup_hung_txdma_rings(nxgep); 166744961713Sgirish } 166822c0d73aSspeer 166922c0d73aSspeer nxge_check_tx_hang_exit: 167044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang")); 167144961713Sgirish } 167244961713Sgirish 1673678453a8Sspeer /* 1674678453a8Sspeer * nxge_txdma_hung 1675678453a8Sspeer * 1676678453a8Sspeer * Reset a TDC. 1677678453a8Sspeer * 1678678453a8Sspeer * Arguments: 1679678453a8Sspeer * nxgep 1680678453a8Sspeer * channel The channel to reset. 1681678453a8Sspeer * reg_data The current TX_CS. 1682678453a8Sspeer * 1683678453a8Sspeer * Notes: 1684678453a8Sspeer * Called by nxge_check_tx_hang() 1685678453a8Sspeer * 1686678453a8Sspeer * NPI/NXGE function calls: 1687678453a8Sspeer * nxge_txdma_channel_hung() 1688678453a8Sspeer * 1689678453a8Sspeer * Registers accessed: 1690678453a8Sspeer * 1691678453a8Sspeer * Context: 1692678453a8Sspeer * Any domain 1693678453a8Sspeer */ 169444961713Sgirish int 169544961713Sgirish nxge_txdma_hung(p_nxge_t nxgep) 169644961713Sgirish { 1697330cd344SMichael Speer nxge_grp_set_t *set = &nxgep->tx_set; 1698330cd344SMichael Speer int tdc; 1699330cd344SMichael Speer boolean_t shared; 170044961713Sgirish 170144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung")); 170244961713Sgirish 1703678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 170444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1705678453a8Sspeer "<== nxge_txdma_hung: NULL ring pointer(s)")); 170644961713Sgirish return (B_FALSE); 170744961713Sgirish } 170844961713Sgirish 1709678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1710330cd344SMichael Speer /* 1711330cd344SMichael Speer * Grab the shared state of the TDC. 1712330cd344SMichael Speer */ 1713330cd344SMichael Speer if (isLDOMservice(nxgep)) { 1714330cd344SMichael Speer nxge_hio_data_t *nhd = 1715330cd344SMichael Speer (nxge_hio_data_t *)nxgep->nxge_hw_p->hio; 1716330cd344SMichael Speer 1717330cd344SMichael Speer MUTEX_ENTER(&nhd->lock); 1718330cd344SMichael Speer shared = nxgep->tdc_is_shared[tdc]; 1719330cd344SMichael Speer MUTEX_EXIT(&nhd->lock); 1720330cd344SMichael Speer } else { 1721330cd344SMichael Speer shared = B_FALSE; 1722330cd344SMichael Speer } 1723330cd344SMichael Speer 1724330cd344SMichael Speer /* 1725330cd344SMichael Speer * Now, process continue to process. 1726330cd344SMichael Speer */ 1727330cd344SMichael Speer if (((1 << tdc) & set->owned.map) && !shared) { 1728678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1729678453a8Sspeer if (ring) { 1730678453a8Sspeer if (nxge_txdma_channel_hung(nxgep, ring, tdc)) { 1731678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1732678453a8Sspeer "==> nxge_txdma_hung: TDC %d hung", 1733678453a8Sspeer tdc)); 1734678453a8Sspeer return (B_TRUE); 1735678453a8Sspeer } 1736678453a8Sspeer } 173744961713Sgirish } 173844961713Sgirish } 173944961713Sgirish 174044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung")); 174144961713Sgirish 174244961713Sgirish return (B_FALSE); 174344961713Sgirish } 174444961713Sgirish 1745678453a8Sspeer /* 1746678453a8Sspeer * nxge_txdma_channel_hung 1747678453a8Sspeer * 1748678453a8Sspeer * Reset a TDC. 1749678453a8Sspeer * 1750678453a8Sspeer * Arguments: 1751678453a8Sspeer * nxgep 1752678453a8Sspeer * ring <channel>'s ring. 1753678453a8Sspeer * channel The channel to reset. 1754678453a8Sspeer * 1755678453a8Sspeer * Notes: 1756678453a8Sspeer * Called by nxge_txdma.c:nxge_txdma_hung() 1757678453a8Sspeer * 1758678453a8Sspeer * NPI/NXGE function calls: 1759678453a8Sspeer * npi_txdma_ring_head_get() 1760678453a8Sspeer * 1761678453a8Sspeer * Registers accessed: 1762678453a8Sspeer * TX_RING_HDL DMC+0x40010 Transmit Ring Head Low 1763678453a8Sspeer * 1764678453a8Sspeer * Context: 1765678453a8Sspeer * Any domain 1766678453a8Sspeer */ 176744961713Sgirish int 176844961713Sgirish nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel) 176944961713Sgirish { 177044961713Sgirish uint16_t head_index, tail_index; 177144961713Sgirish boolean_t head_wrap, tail_wrap; 177244961713Sgirish npi_handle_t handle; 177344961713Sgirish tx_ring_hdl_t tx_head; 177444961713Sgirish uint_t tx_rd_index; 177544961713Sgirish 177644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung")); 177744961713Sgirish 177844961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 177944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 178052ccf843Smisaki "==> nxge_txdma_channel_hung: channel %d", channel)); 178144961713Sgirish MUTEX_ENTER(&tx_ring_p->lock); 178244961713Sgirish (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 178344961713Sgirish 178444961713Sgirish tail_index = tx_ring_p->wr_index; 178544961713Sgirish tail_wrap = tx_ring_p->wr_index_wrap; 178644961713Sgirish tx_rd_index = tx_ring_p->rd_index; 178744961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 178844961713Sgirish 178944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 179052ccf843Smisaki "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d " 179152ccf843Smisaki "tail_index %d tail_wrap %d ", 179252ccf843Smisaki channel, tx_rd_index, tail_index, tail_wrap)); 179344961713Sgirish /* 179444961713Sgirish * Read the hardware maintained transmit head 179544961713Sgirish * and wrap around bit. 179644961713Sgirish */ 179744961713Sgirish (void) npi_txdma_ring_head_get(handle, channel, &tx_head); 179844961713Sgirish head_index = tx_head.bits.ldw.head; 179944961713Sgirish head_wrap = tx_head.bits.ldw.wrap; 180044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 180152ccf843Smisaki "==> nxge_txdma_channel_hung: " 180252ccf843Smisaki "tx_rd_index %d tail %d tail_wrap %d " 180352ccf843Smisaki "head %d wrap %d", 180452ccf843Smisaki tx_rd_index, tail_index, tail_wrap, 180552ccf843Smisaki head_index, head_wrap)); 180644961713Sgirish 180744961713Sgirish if (TXDMA_RING_EMPTY(head_index, head_wrap, 180852ccf843Smisaki tail_index, tail_wrap) && 180952ccf843Smisaki (head_index == tx_rd_index)) { 181044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 181152ccf843Smisaki "==> nxge_txdma_channel_hung: EMPTY")); 181244961713Sgirish return (B_FALSE); 181344961713Sgirish } 181444961713Sgirish 181544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 181652ccf843Smisaki "==> nxge_txdma_channel_hung: Checking if ring full")); 181744961713Sgirish if (TXDMA_RING_FULL(head_index, head_wrap, tail_index, 181852ccf843Smisaki tail_wrap)) { 181944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 182052ccf843Smisaki "==> nxge_txdma_channel_hung: full")); 182144961713Sgirish return (B_TRUE); 182244961713Sgirish } 182344961713Sgirish 182444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung")); 182544961713Sgirish 182644961713Sgirish return (B_FALSE); 182744961713Sgirish } 182844961713Sgirish 1829678453a8Sspeer /* 1830678453a8Sspeer * nxge_fixup_hung_txdma_rings 1831678453a8Sspeer * 1832678453a8Sspeer * Disable a TDC. 1833678453a8Sspeer * 1834678453a8Sspeer * Arguments: 1835678453a8Sspeer * nxgep 1836678453a8Sspeer * channel The channel to reset. 1837678453a8Sspeer * reg_data The current TX_CS. 1838678453a8Sspeer * 1839678453a8Sspeer * Notes: 1840678453a8Sspeer * Called by nxge_check_tx_hang() 1841678453a8Sspeer * 1842678453a8Sspeer * NPI/NXGE function calls: 1843678453a8Sspeer * npi_txdma_ring_head_get() 1844678453a8Sspeer * 1845678453a8Sspeer * Registers accessed: 1846678453a8Sspeer * TX_RING_HDL DMC+0x40010 Transmit Ring Head Low 1847678453a8Sspeer * 1848678453a8Sspeer * Context: 1849678453a8Sspeer * Any domain 1850678453a8Sspeer */ 185144961713Sgirish /*ARGSUSED*/ 185244961713Sgirish void 185344961713Sgirish nxge_fixup_hung_txdma_rings(p_nxge_t nxgep) 185444961713Sgirish { 1855678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 1856678453a8Sspeer int tdc; 185744961713Sgirish 185844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings")); 185944961713Sgirish 1860678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 186144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 1862678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 186344961713Sgirish return; 186444961713Sgirish } 186544961713Sgirish 1866678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 1867678453a8Sspeer if ((1 << tdc) & set->owned.map) { 1868678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 1869678453a8Sspeer if (ring) { 1870678453a8Sspeer nxge_txdma_fixup_hung_channel(nxgep, ring, tdc); 1871678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 1872678453a8Sspeer "==> nxge_fixup_hung_txdma_rings: TDC %d", 1873678453a8Sspeer tdc)); 1874678453a8Sspeer } 1875678453a8Sspeer } 187644961713Sgirish } 187744961713Sgirish 187844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings")); 187944961713Sgirish } 188044961713Sgirish 1881678453a8Sspeer /* 1882678453a8Sspeer * nxge_txdma_fixup_hung_channel 1883678453a8Sspeer * 1884678453a8Sspeer * 'Fix' a hung TDC. 1885678453a8Sspeer * 1886678453a8Sspeer * Arguments: 1887678453a8Sspeer * nxgep 1888678453a8Sspeer * channel The channel to fix. 1889678453a8Sspeer * 1890678453a8Sspeer * Notes: 1891678453a8Sspeer * Called by nxge_fixup_hung_txdma_rings() 1892678453a8Sspeer * 1893678453a8Sspeer * 1. Reclaim the TDC. 1894678453a8Sspeer * 2. Disable the TDC. 1895678453a8Sspeer * 1896678453a8Sspeer * NPI/NXGE function calls: 1897678453a8Sspeer * nxge_txdma_reclaim() 1898678453a8Sspeer * npi_txdma_channel_disable(TX_CS) 1899678453a8Sspeer * npi_txdma_inj_int_error_set(TDMC_INTR_DBG) 1900678453a8Sspeer * 1901678453a8Sspeer * Registers accessed: 1902678453a8Sspeer * TX_CS DMC+0x40028 Transmit Control And Status 1903678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 1904678453a8Sspeer * 1905678453a8Sspeer * Context: 1906678453a8Sspeer * Any domain 1907678453a8Sspeer */ 190844961713Sgirish /*ARGSUSED*/ 190944961713Sgirish void 191044961713Sgirish nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel) 191144961713Sgirish { 191244961713Sgirish p_tx_ring_t ring_p; 191344961713Sgirish 191444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel")); 191544961713Sgirish ring_p = nxge_txdma_get_ring(nxgep, channel); 191644961713Sgirish if (ring_p == NULL) { 191744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 191852ccf843Smisaki "<== nxge_txdma_fix_hung_channel")); 191944961713Sgirish return; 192044961713Sgirish } 192144961713Sgirish 192244961713Sgirish if (ring_p->tdc != channel) { 192344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 192452ccf843Smisaki "<== nxge_txdma_fix_hung_channel: channel not matched " 192552ccf843Smisaki "ring tdc %d passed channel", 192652ccf843Smisaki ring_p->tdc, channel)); 192744961713Sgirish return; 192844961713Sgirish } 192944961713Sgirish 193044961713Sgirish nxge_txdma_fixup_channel(nxgep, ring_p, channel); 193144961713Sgirish 193244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel")); 193344961713Sgirish } 193444961713Sgirish 193544961713Sgirish /*ARGSUSED*/ 193644961713Sgirish void 193744961713Sgirish nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, 193844961713Sgirish uint16_t channel) 193944961713Sgirish { 194044961713Sgirish npi_handle_t handle; 194144961713Sgirish tdmc_intr_dbg_t intr_dbg; 194244961713Sgirish int status = NXGE_OK; 194344961713Sgirish 194444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel")); 194544961713Sgirish 194644961713Sgirish if (ring_p == NULL) { 194744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 194852ccf843Smisaki "<== nxge_txdma_fixup_channel: NULL ring pointer")); 194944961713Sgirish return; 195044961713Sgirish } 195144961713Sgirish 195244961713Sgirish if (ring_p->tdc != channel) { 195344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 195452ccf843Smisaki "<== nxge_txdma_fixup_hung_channel: channel " 195552ccf843Smisaki "not matched " 195652ccf843Smisaki "ring tdc %d passed channel", 195752ccf843Smisaki ring_p->tdc, channel)); 195844961713Sgirish return; 195944961713Sgirish } 196044961713Sgirish 196144961713Sgirish /* Reclaim descriptors */ 196244961713Sgirish MUTEX_ENTER(&ring_p->lock); 196344961713Sgirish (void) nxge_txdma_reclaim(nxgep, ring_p, 0); 196444961713Sgirish MUTEX_EXIT(&ring_p->lock); 196544961713Sgirish 196644961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 196744961713Sgirish /* 196844961713Sgirish * Stop the dma channel waits for the stop done. 196944961713Sgirish * If the stop done bit is not set, then force 197044961713Sgirish * an error. 197144961713Sgirish */ 197244961713Sgirish status = npi_txdma_channel_disable(handle, channel); 197344961713Sgirish if (!(status & NPI_TXDMA_STOP_FAILED)) { 197444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 197552ccf843Smisaki "<== nxge_txdma_fixup_hung_channel: stopped OK " 197652ccf843Smisaki "ring tdc %d passed channel %d", 197752ccf843Smisaki ring_p->tdc, channel)); 197844961713Sgirish return; 197944961713Sgirish } 198044961713Sgirish 198144961713Sgirish /* Inject any error */ 198244961713Sgirish intr_dbg.value = 0; 198344961713Sgirish intr_dbg.bits.ldw.nack_pref = 1; 198444961713Sgirish (void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg); 198544961713Sgirish 198644961713Sgirish /* Stop done bit will be set as a result of error injection */ 198744961713Sgirish status = npi_txdma_channel_disable(handle, channel); 198844961713Sgirish if (!(status & NPI_TXDMA_STOP_FAILED)) { 198944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 199052ccf843Smisaki "<== nxge_txdma_fixup_hung_channel: stopped again" 199152ccf843Smisaki "ring tdc %d passed channel", 199252ccf843Smisaki ring_p->tdc, channel)); 199344961713Sgirish return; 199444961713Sgirish } 199544961713Sgirish 199644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 199752ccf843Smisaki "<== nxge_txdma_fixup_hung_channel: stop done still not set!! " 199852ccf843Smisaki "ring tdc %d passed channel", 199952ccf843Smisaki ring_p->tdc, channel)); 200044961713Sgirish 200144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel")); 200244961713Sgirish } 200344961713Sgirish 200444961713Sgirish /*ARGSUSED*/ 200544961713Sgirish void 200644961713Sgirish nxge_reclaim_rings(p_nxge_t nxgep) 200744961713Sgirish { 2008678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 2009678453a8Sspeer int tdc; 201044961713Sgirish 2011678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings")); 201244961713Sgirish 2013678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 201444961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 2015678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 201644961713Sgirish return; 201744961713Sgirish } 201844961713Sgirish 2019678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 2020678453a8Sspeer if ((1 << tdc) & set->owned.map) { 2021678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 2022678453a8Sspeer if (ring) { 2023678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2024678453a8Sspeer "==> nxge_reclaim_rings: TDC %d", tdc)); 2025678453a8Sspeer MUTEX_ENTER(&ring->lock); 2026da14cebeSEric Cheng (void) nxge_txdma_reclaim(nxgep, ring, 0); 2027678453a8Sspeer MUTEX_EXIT(&ring->lock); 2028678453a8Sspeer } 2029678453a8Sspeer } 203044961713Sgirish } 203144961713Sgirish 203244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings")); 203344961713Sgirish } 203444961713Sgirish 203544961713Sgirish void 203644961713Sgirish nxge_txdma_regs_dump_channels(p_nxge_t nxgep) 203744961713Sgirish { 2038678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 2039678453a8Sspeer npi_handle_t handle; 2040678453a8Sspeer int tdc; 204144961713Sgirish 2042678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels")); 204344961713Sgirish 204444961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 204544961713Sgirish 2046678453a8Sspeer if (!isLDOMguest(nxgep)) { 2047678453a8Sspeer (void) npi_txdma_dump_fzc_regs(handle); 204844961713Sgirish 2049678453a8Sspeer /* Dump TXC registers. */ 2050678453a8Sspeer (void) npi_txc_dump_fzc_regs(handle); 2051678453a8Sspeer (void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num); 205244961713Sgirish } 205344961713Sgirish 2054678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 205544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 2056678453a8Sspeer "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)")); 205744961713Sgirish return; 205844961713Sgirish } 205944961713Sgirish 2060678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 2061678453a8Sspeer if ((1 << tdc) & set->owned.map) { 2062678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 2063678453a8Sspeer if (ring) { 2064678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2065678453a8Sspeer "==> nxge_txdma_regs_dump_channels: " 2066678453a8Sspeer "TDC %d", tdc)); 2067678453a8Sspeer (void) npi_txdma_dump_tdc_regs(handle, tdc); 2068678453a8Sspeer 2069678453a8Sspeer /* Dump TXC registers, if able to. */ 2070678453a8Sspeer if (!isLDOMguest(nxgep)) { 2071678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2072678453a8Sspeer "==> nxge_txdma_regs_dump_channels:" 2073678453a8Sspeer " FZC TDC %d", tdc)); 2074678453a8Sspeer (void) npi_txc_dump_tdc_fzc_regs 2075678453a8Sspeer (handle, tdc); 2076678453a8Sspeer } 2077678453a8Sspeer nxge_txdma_regs_dump(nxgep, tdc); 2078678453a8Sspeer } 2079678453a8Sspeer } 208044961713Sgirish } 208144961713Sgirish 208244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump")); 208344961713Sgirish } 208444961713Sgirish 208544961713Sgirish void 208644961713Sgirish nxge_txdma_regs_dump(p_nxge_t nxgep, int channel) 208744961713Sgirish { 208844961713Sgirish npi_handle_t handle; 208944961713Sgirish tx_ring_hdl_t hdl; 209044961713Sgirish tx_ring_kick_t kick; 209144961713Sgirish tx_cs_t cs; 209244961713Sgirish txc_control_t control; 209344961713Sgirish uint32_t bitmap = 0; 209444961713Sgirish uint32_t burst = 0; 209544961713Sgirish uint32_t bytes = 0; 209644961713Sgirish dma_log_page_t cfg; 209744961713Sgirish 209844961713Sgirish printf("\n\tfunc # %d tdc %d ", 209952ccf843Smisaki nxgep->function_num, channel); 210044961713Sgirish cfg.page_num = 0; 210144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 210244961713Sgirish (void) npi_txdma_log_page_get(handle, channel, &cfg); 210344961713Sgirish printf("\n\tlog page func %d valid page 0 %d", 210452ccf843Smisaki cfg.func_num, cfg.valid); 210544961713Sgirish cfg.page_num = 1; 210644961713Sgirish (void) npi_txdma_log_page_get(handle, channel, &cfg); 210744961713Sgirish printf("\n\tlog page func %d valid page 1 %d", 210852ccf843Smisaki cfg.func_num, cfg.valid); 210944961713Sgirish 211044961713Sgirish (void) npi_txdma_ring_head_get(handle, channel, &hdl); 211144961713Sgirish (void) npi_txdma_desc_kick_reg_get(handle, channel, &kick); 211244961713Sgirish printf("\n\thead value is 0x%0llx", 211352ccf843Smisaki (long long)hdl.value); 211444961713Sgirish printf("\n\thead index %d", hdl.bits.ldw.head); 211544961713Sgirish printf("\n\tkick value is 0x%0llx", 211652ccf843Smisaki (long long)kick.value); 211744961713Sgirish printf("\n\ttail index %d\n", kick.bits.ldw.tail); 211844961713Sgirish 211944961713Sgirish (void) npi_txdma_control_status(handle, OP_GET, channel, &cs); 212044961713Sgirish printf("\n\tControl statue is 0x%0llx", (long long)cs.value); 212144961713Sgirish printf("\n\tControl status RST state %d", cs.bits.ldw.rst); 212244961713Sgirish 212344961713Sgirish (void) npi_txc_control(handle, OP_GET, &control); 212444961713Sgirish (void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap); 212544961713Sgirish (void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst); 212644961713Sgirish (void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes); 212744961713Sgirish 212844961713Sgirish printf("\n\tTXC port control 0x%0llx", 212952ccf843Smisaki (long long)control.value); 213044961713Sgirish printf("\n\tTXC port bitmap 0x%x", bitmap); 213144961713Sgirish printf("\n\tTXC max burst %d", burst); 213244961713Sgirish printf("\n\tTXC bytes xmt %d\n", bytes); 213344961713Sgirish 213444961713Sgirish { 213544961713Sgirish ipp_status_t status; 213644961713Sgirish 213744961713Sgirish (void) npi_ipp_get_status(handle, nxgep->function_num, &status); 2138adfcba55Sjoycey #if defined(__i386) 2139adfcba55Sjoycey printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value); 2140adfcba55Sjoycey #else 214144961713Sgirish printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value); 2142adfcba55Sjoycey #endif 214344961713Sgirish } 214444961713Sgirish } 214544961713Sgirish 214644961713Sgirish /* 2147678453a8Sspeer * nxge_tdc_hvio_setup 2148678453a8Sspeer * 2149678453a8Sspeer * I'm not exactly sure what this code does. 2150678453a8Sspeer * 2151678453a8Sspeer * Arguments: 2152678453a8Sspeer * nxgep 2153678453a8Sspeer * channel The channel to map. 2154678453a8Sspeer * 2155678453a8Sspeer * Notes: 2156678453a8Sspeer * 2157678453a8Sspeer * NPI/NXGE function calls: 2158678453a8Sspeer * na 2159678453a8Sspeer * 2160678453a8Sspeer * Context: 2161678453a8Sspeer * Service domain? 216244961713Sgirish */ 2163678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND) 2164678453a8Sspeer static void 2165678453a8Sspeer nxge_tdc_hvio_setup( 2166678453a8Sspeer nxge_t *nxgep, int channel) 216744961713Sgirish { 2168678453a8Sspeer nxge_dma_common_t *data; 2169678453a8Sspeer nxge_dma_common_t *control; 2170678453a8Sspeer tx_ring_t *ring; 2171678453a8Sspeer 2172678453a8Sspeer ring = nxgep->tx_rings->rings[channel]; 2173678453a8Sspeer data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel]; 2174678453a8Sspeer 2175678453a8Sspeer ring->hv_set = B_FALSE; 2176678453a8Sspeer 2177678453a8Sspeer ring->hv_tx_buf_base_ioaddr_pp = 2178678453a8Sspeer (uint64_t)data->orig_ioaddr_pp; 2179678453a8Sspeer ring->hv_tx_buf_ioaddr_size = 2180678453a8Sspeer (uint64_t)data->orig_alength; 2181678453a8Sspeer 2182678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: " 218352ccf843Smisaki "hv data buf base io $%p size 0x%llx (%d) buf base io $%p " 218452ccf843Smisaki "orig vatopa base io $%p orig_len 0x%llx (%d)", 218552ccf843Smisaki ring->hv_tx_buf_base_ioaddr_pp, 218652ccf843Smisaki ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size, 218752ccf843Smisaki data->ioaddr_pp, data->orig_vatopa, 218852ccf843Smisaki data->orig_alength, data->orig_alength)); 2189678453a8Sspeer 2190678453a8Sspeer control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel]; 2191678453a8Sspeer 2192678453a8Sspeer ring->hv_tx_cntl_base_ioaddr_pp = 2193678453a8Sspeer (uint64_t)control->orig_ioaddr_pp; 2194678453a8Sspeer ring->hv_tx_cntl_ioaddr_size = 2195678453a8Sspeer (uint64_t)control->orig_alength; 2196678453a8Sspeer 2197678453a8Sspeer NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: " 219852ccf843Smisaki "hv cntl base io $%p orig ioaddr_pp ($%p) " 219952ccf843Smisaki "orig vatopa ($%p) size 0x%llx (%d 0x%x)", 220052ccf843Smisaki ring->hv_tx_cntl_base_ioaddr_pp, 220152ccf843Smisaki control->orig_ioaddr_pp, control->orig_vatopa, 220252ccf843Smisaki ring->hv_tx_cntl_ioaddr_size, 220352ccf843Smisaki control->orig_alength, control->orig_alength)); 2204678453a8Sspeer } 220544961713Sgirish #endif 220644961713Sgirish 2207678453a8Sspeer static nxge_status_t 2208678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel) 2209678453a8Sspeer { 2210678453a8Sspeer nxge_dma_common_t **pData; 2211678453a8Sspeer nxge_dma_common_t **pControl; 2212678453a8Sspeer tx_ring_t **pRing, *ring; 2213678453a8Sspeer tx_mbox_t **mailbox; 2214678453a8Sspeer uint32_t num_chunks; 2215678453a8Sspeer 2216678453a8Sspeer nxge_status_t status = NXGE_OK; 221744961713Sgirish 2218678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma")); 221944961713Sgirish 2220678453a8Sspeer if (!nxgep->tx_cntl_pool_p->buf_allocated) { 2221678453a8Sspeer if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) { 2222678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 2223678453a8Sspeer "<== nxge_map_txdma: buf not allocated")); 2224678453a8Sspeer return (NXGE_ERROR); 2225678453a8Sspeer } 222644961713Sgirish } 222744961713Sgirish 2228678453a8Sspeer if (nxge_alloc_txb(nxgep, channel) != NXGE_OK) 222944961713Sgirish return (NXGE_ERROR); 223044961713Sgirish 2231678453a8Sspeer num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel]; 2232678453a8Sspeer pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel]; 2233678453a8Sspeer pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel]; 2234678453a8Sspeer pRing = &nxgep->tx_rings->rings[channel]; 2235678453a8Sspeer mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 223644961713Sgirish 2237678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: " 223852ccf843Smisaki "tx_rings $%p tx_desc_rings $%p", 223952ccf843Smisaki nxgep->tx_rings, nxgep->tx_rings->rings)); 224044961713Sgirish 224144961713Sgirish /* 2242678453a8Sspeer * Map descriptors from the buffer pools for <channel>. 224344961713Sgirish */ 224444961713Sgirish 2245678453a8Sspeer /* 2246678453a8Sspeer * Set up and prepare buffer blocks, descriptors 2247678453a8Sspeer * and mailbox. 2248678453a8Sspeer */ 2249678453a8Sspeer status = nxge_map_txdma_channel(nxgep, channel, 2250678453a8Sspeer pData, pRing, num_chunks, pControl, mailbox); 2251678453a8Sspeer if (status != NXGE_OK) { 2252678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 225352ccf843Smisaki "==> nxge_map_txdma(%d): nxge_map_txdma_channel() " 225452ccf843Smisaki "returned 0x%x", 225552ccf843Smisaki nxgep, channel, status)); 2256678453a8Sspeer return (status); 225744961713Sgirish } 225844961713Sgirish 2259678453a8Sspeer ring = *pRing; 226044961713Sgirish 2261678453a8Sspeer ring->index = (uint16_t)channel; 2262678453a8Sspeer ring->tdc_stats = &nxgep->statsp->tdc_stats[channel]; 226344961713Sgirish 2264678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND) 2265678453a8Sspeer if (isLDOMguest(nxgep)) { 2266678453a8Sspeer (void) nxge_tdc_lp_conf(nxgep, channel); 2267678453a8Sspeer } else { 2268678453a8Sspeer nxge_tdc_hvio_setup(nxgep, channel); 226944961713Sgirish } 2270678453a8Sspeer #endif 227144961713Sgirish 2272678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: " 2273678453a8Sspeer "(status 0x%x channel %d)", status, channel)); 227444961713Sgirish 2275678453a8Sspeer return (status); 227644961713Sgirish } 227744961713Sgirish 227844961713Sgirish static nxge_status_t 227944961713Sgirish nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel, 228044961713Sgirish p_nxge_dma_common_t *dma_buf_p, 228144961713Sgirish p_tx_ring_t *tx_desc_p, 228244961713Sgirish uint32_t num_chunks, 228344961713Sgirish p_nxge_dma_common_t *dma_cntl_p, 228444961713Sgirish p_tx_mbox_t *tx_mbox_p) 228544961713Sgirish { 228644961713Sgirish int status = NXGE_OK; 228744961713Sgirish 228844961713Sgirish /* 228944961713Sgirish * Set up and prepare buffer blocks, descriptors 229044961713Sgirish * and mailbox. 229144961713Sgirish */ 2292678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 229352ccf843Smisaki "==> nxge_map_txdma_channel (channel %d)", channel)); 229444961713Sgirish /* 229544961713Sgirish * Transmit buffer blocks 229644961713Sgirish */ 229744961713Sgirish status = nxge_map_txdma_channel_buf_ring(nxgep, channel, 229852ccf843Smisaki dma_buf_p, tx_desc_p, num_chunks); 229944961713Sgirish if (status != NXGE_OK) { 230044961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 230152ccf843Smisaki "==> nxge_map_txdma_channel (channel %d): " 230252ccf843Smisaki "map buffer failed 0x%x", channel, status)); 230344961713Sgirish goto nxge_map_txdma_channel_exit; 230444961713Sgirish } 230544961713Sgirish 230644961713Sgirish /* 230744961713Sgirish * Transmit block ring, and mailbox. 230844961713Sgirish */ 230944961713Sgirish nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p, 231052ccf843Smisaki tx_mbox_p); 231144961713Sgirish 231244961713Sgirish goto nxge_map_txdma_channel_exit; 231344961713Sgirish 231444961713Sgirish nxge_map_txdma_channel_fail1: 2315678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 231652ccf843Smisaki "==> nxge_map_txdma_channel: unmap buf" 231752ccf843Smisaki "(status 0x%x channel %d)", 231852ccf843Smisaki status, channel)); 231944961713Sgirish nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p); 232044961713Sgirish 232144961713Sgirish nxge_map_txdma_channel_exit: 2322678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, 232352ccf843Smisaki "<== nxge_map_txdma_channel: " 232452ccf843Smisaki "(status 0x%x channel %d)", 232552ccf843Smisaki status, channel)); 232644961713Sgirish 232744961713Sgirish return (status); 232844961713Sgirish } 232944961713Sgirish 233044961713Sgirish /*ARGSUSED*/ 233144961713Sgirish static void 2332678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel) 233344961713Sgirish { 2334678453a8Sspeer tx_ring_t *ring; 2335678453a8Sspeer tx_mbox_t *mailbox; 2336678453a8Sspeer 233744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 233852ccf843Smisaki "==> nxge_unmap_txdma_channel (channel %d)", channel)); 233944961713Sgirish /* 234044961713Sgirish * unmap tx block ring, and mailbox. 234144961713Sgirish */ 2342678453a8Sspeer ring = nxgep->tx_rings->rings[channel]; 2343678453a8Sspeer mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 2344678453a8Sspeer 2345678453a8Sspeer (void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox); 234644961713Sgirish 234744961713Sgirish /* unmap buffer blocks */ 2348678453a8Sspeer (void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring); 2349678453a8Sspeer 2350678453a8Sspeer nxge_free_txb(nxgep, channel); 235144961713Sgirish 2352*48056c53SMichael Speer /* 2353*48056c53SMichael Speer * Cleanup the reference to the ring now that it does not exist. 2354*48056c53SMichael Speer */ 2355*48056c53SMichael Speer nxgep->tx_rings->rings[channel] = NULL; 2356*48056c53SMichael Speer 235744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel")); 235844961713Sgirish } 235944961713Sgirish 2360678453a8Sspeer /* 2361678453a8Sspeer * nxge_map_txdma_channel_cfg_ring 2362678453a8Sspeer * 2363678453a8Sspeer * Map a TDC into our kernel space. 2364678453a8Sspeer * This function allocates all of the per-channel data structures. 2365678453a8Sspeer * 2366678453a8Sspeer * Arguments: 2367678453a8Sspeer * nxgep 2368678453a8Sspeer * dma_channel The channel to map. 2369678453a8Sspeer * dma_cntl_p 2370678453a8Sspeer * tx_ring_p dma_channel's transmit ring 2371678453a8Sspeer * tx_mbox_p dma_channel's mailbox 2372678453a8Sspeer * 2373678453a8Sspeer * Notes: 2374678453a8Sspeer * 2375678453a8Sspeer * NPI/NXGE function calls: 2376678453a8Sspeer * nxge_setup_dma_common() 2377678453a8Sspeer * 2378678453a8Sspeer * Registers accessed: 2379678453a8Sspeer * none. 2380678453a8Sspeer * 2381678453a8Sspeer * Context: 2382678453a8Sspeer * Any domain 2383678453a8Sspeer */ 238444961713Sgirish /*ARGSUSED*/ 238544961713Sgirish static void 238644961713Sgirish nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel, 238744961713Sgirish p_nxge_dma_common_t *dma_cntl_p, 238844961713Sgirish p_tx_ring_t tx_ring_p, 238944961713Sgirish p_tx_mbox_t *tx_mbox_p) 239044961713Sgirish { 239144961713Sgirish p_tx_mbox_t mboxp; 239244961713Sgirish p_nxge_dma_common_t cntl_dmap; 239344961713Sgirish p_nxge_dma_common_t dmap; 239444961713Sgirish p_tx_rng_cfig_t tx_ring_cfig_p; 239544961713Sgirish p_tx_ring_kick_t tx_ring_kick_p; 239644961713Sgirish p_tx_cs_t tx_cs_p; 239744961713Sgirish p_tx_dma_ent_msk_t tx_evmask_p; 239844961713Sgirish p_txdma_mbh_t mboxh_p; 239944961713Sgirish p_txdma_mbl_t mboxl_p; 240044961713Sgirish uint64_t tx_desc_len; 240144961713Sgirish 240244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 240352ccf843Smisaki "==> nxge_map_txdma_channel_cfg_ring")); 240444961713Sgirish 240544961713Sgirish cntl_dmap = *dma_cntl_p; 240644961713Sgirish 240744961713Sgirish dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc; 240844961713Sgirish nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size, 240952ccf843Smisaki sizeof (tx_desc_t)); 241044961713Sgirish /* 241144961713Sgirish * Zero out transmit ring descriptors. 241244961713Sgirish */ 241344961713Sgirish bzero((caddr_t)dmap->kaddrp, dmap->alength); 241444961713Sgirish tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig); 241544961713Sgirish tx_ring_kick_p = &(tx_ring_p->tx_ring_kick); 241644961713Sgirish tx_cs_p = &(tx_ring_p->tx_cs); 241744961713Sgirish tx_evmask_p = &(tx_ring_p->tx_evmask); 241844961713Sgirish tx_ring_cfig_p->value = 0; 241944961713Sgirish tx_ring_kick_p->value = 0; 242044961713Sgirish tx_cs_p->value = 0; 242144961713Sgirish tx_evmask_p->value = 0; 242244961713Sgirish 242344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 242452ccf843Smisaki "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p", 242552ccf843Smisaki dma_channel, 242652ccf843Smisaki dmap->dma_cookie.dmac_laddress)); 242744961713Sgirish 242844961713Sgirish tx_ring_cfig_p->value = 0; 242944961713Sgirish tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3); 243044961713Sgirish tx_ring_cfig_p->value = 243152ccf843Smisaki (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) | 243252ccf843Smisaki (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT); 243344961713Sgirish 243444961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 243552ccf843Smisaki "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx", 243652ccf843Smisaki dma_channel, 243752ccf843Smisaki tx_ring_cfig_p->value)); 243844961713Sgirish 243944961713Sgirish tx_cs_p->bits.ldw.rst = 1; 244044961713Sgirish 244144961713Sgirish /* Map in mailbox */ 244244961713Sgirish mboxp = (p_tx_mbox_t) 244352ccf843Smisaki KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP); 244444961713Sgirish dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox; 244544961713Sgirish nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t)); 244644961713Sgirish mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh; 244744961713Sgirish mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl; 244844961713Sgirish mboxh_p->value = mboxl_p->value = 0; 244944961713Sgirish 245044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 245152ccf843Smisaki "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx", 245252ccf843Smisaki dmap->dma_cookie.dmac_laddress)); 245344961713Sgirish 245444961713Sgirish mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >> 245552ccf843Smisaki TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK); 245644961713Sgirish 245744961713Sgirish mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress & 245852ccf843Smisaki TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT); 245944961713Sgirish 246044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 246152ccf843Smisaki "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx", 246252ccf843Smisaki dmap->dma_cookie.dmac_laddress)); 246344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 246452ccf843Smisaki "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p " 246552ccf843Smisaki "mbox $%p", 246652ccf843Smisaki mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr)); 246744961713Sgirish tx_ring_p->page_valid.value = 0; 246844961713Sgirish tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0; 246944961713Sgirish tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0; 247044961713Sgirish tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0; 247144961713Sgirish tx_ring_p->page_hdl.value = 0; 247244961713Sgirish 247344961713Sgirish tx_ring_p->page_valid.bits.ldw.page0 = 1; 247444961713Sgirish tx_ring_p->page_valid.bits.ldw.page1 = 1; 247544961713Sgirish 247644961713Sgirish tx_ring_p->max_burst.value = 0; 247744961713Sgirish tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT; 247844961713Sgirish 247944961713Sgirish *tx_mbox_p = mboxp; 248044961713Sgirish 248144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 248252ccf843Smisaki "<== nxge_map_txdma_channel_cfg_ring")); 248344961713Sgirish } 248444961713Sgirish 248544961713Sgirish /*ARGSUSED*/ 248644961713Sgirish static void 248744961713Sgirish nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep, 248844961713Sgirish p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p) 248944961713Sgirish { 249044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 249152ccf843Smisaki "==> nxge_unmap_txdma_channel_cfg_ring: channel %d", 249252ccf843Smisaki tx_ring_p->tdc)); 249344961713Sgirish 249444961713Sgirish KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t)); 249544961713Sgirish 249644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 249752ccf843Smisaki "<== nxge_unmap_txdma_channel_cfg_ring")); 249844961713Sgirish } 249944961713Sgirish 2500678453a8Sspeer /* 2501678453a8Sspeer * nxge_map_txdma_channel_buf_ring 2502678453a8Sspeer * 2503678453a8Sspeer * 2504678453a8Sspeer * Arguments: 2505678453a8Sspeer * nxgep 2506678453a8Sspeer * channel The channel to map. 2507678453a8Sspeer * dma_buf_p 2508678453a8Sspeer * tx_desc_p channel's descriptor ring 2509678453a8Sspeer * num_chunks 2510678453a8Sspeer * 2511678453a8Sspeer * Notes: 2512678453a8Sspeer * 2513678453a8Sspeer * NPI/NXGE function calls: 2514678453a8Sspeer * nxge_setup_dma_common() 2515678453a8Sspeer * 2516678453a8Sspeer * Registers accessed: 2517678453a8Sspeer * none. 2518678453a8Sspeer * 2519678453a8Sspeer * Context: 2520678453a8Sspeer * Any domain 2521678453a8Sspeer */ 252244961713Sgirish static nxge_status_t 252344961713Sgirish nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel, 252444961713Sgirish p_nxge_dma_common_t *dma_buf_p, 252544961713Sgirish p_tx_ring_t *tx_desc_p, uint32_t num_chunks) 252644961713Sgirish { 252744961713Sgirish p_nxge_dma_common_t dma_bufp, tmp_bufp; 252844961713Sgirish p_nxge_dma_common_t dmap; 252944961713Sgirish nxge_os_dma_handle_t tx_buf_dma_handle; 253044961713Sgirish p_tx_ring_t tx_ring_p; 253144961713Sgirish p_tx_msg_t tx_msg_ring; 253244961713Sgirish nxge_status_t status = NXGE_OK; 253344961713Sgirish int ddi_status = DDI_SUCCESS; 253444961713Sgirish int i, j, index; 253544961713Sgirish uint32_t size, bsize; 253644961713Sgirish uint32_t nblocks, nmsgs; 2537da14cebeSEric Cheng char qname[TASKQ_NAMELEN]; 253844961713Sgirish 253944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 254052ccf843Smisaki "==> nxge_map_txdma_channel_buf_ring")); 254144961713Sgirish 254244961713Sgirish dma_bufp = tmp_bufp = *dma_buf_p; 254344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 254444961713Sgirish " nxge_map_txdma_channel_buf_ring: channel %d to map %d " 254544961713Sgirish "chunks bufp $%p", 254652ccf843Smisaki channel, num_chunks, dma_bufp)); 254744961713Sgirish 254844961713Sgirish nmsgs = 0; 254944961713Sgirish for (i = 0; i < num_chunks; i++, tmp_bufp++) { 255044961713Sgirish nmsgs += tmp_bufp->nblocks; 255144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 255252ccf843Smisaki "==> nxge_map_txdma_channel_buf_ring: channel %d " 255352ccf843Smisaki "bufp $%p nblocks %d nmsgs %d", 255452ccf843Smisaki channel, tmp_bufp, tmp_bufp->nblocks, nmsgs)); 255544961713Sgirish } 255644961713Sgirish if (!nmsgs) { 255744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 255852ccf843Smisaki "<== nxge_map_txdma_channel_buf_ring: channel %d " 255952ccf843Smisaki "no msg blocks", 256052ccf843Smisaki channel)); 256144961713Sgirish status = NXGE_ERROR; 256244961713Sgirish goto nxge_map_txdma_channel_buf_ring_exit; 256344961713Sgirish } 256444961713Sgirish 256544961713Sgirish tx_ring_p = (p_tx_ring_t) 256652ccf843Smisaki KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP); 256744961713Sgirish MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER, 256852ccf843Smisaki (void *)nxgep->interrupt_cookie); 25691f8914d5Sml 257022c0d73aSspeer (void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE); 25716895688eSspeer tx_ring_p->tx_ring_busy = B_FALSE; 25721f8914d5Sml tx_ring_p->nxgep = nxgep; 2573da14cebeSEric Cheng tx_ring_p->tx_ring_handle = (mac_ring_handle_t)NULL; 2574da14cebeSEric Cheng (void) snprintf(qname, TASKQ_NAMELEN, "tx_%d_%d", 2575da14cebeSEric Cheng nxgep->instance, channel); 2576da14cebeSEric Cheng tx_ring_p->taskq = ddi_taskq_create(nxgep->dip, qname, 1, 2577da14cebeSEric Cheng TASKQ_DEFAULTPRI, 0); 2578da14cebeSEric Cheng if (tx_ring_p->taskq == NULL) { 2579da14cebeSEric Cheng goto nxge_map_txdma_channel_buf_ring_fail1; 2580da14cebeSEric Cheng } 2581da14cebeSEric Cheng 258244961713Sgirish /* 258344961713Sgirish * Allocate transmit message rings and handles for packets 258444961713Sgirish * not to be copied to premapped buffers. 258544961713Sgirish */ 258644961713Sgirish size = nmsgs * sizeof (tx_msg_t); 258744961713Sgirish tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP); 258844961713Sgirish for (i = 0; i < nmsgs; i++) { 258944961713Sgirish ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr, 259052ccf843Smisaki DDI_DMA_DONTWAIT, 0, 259152ccf843Smisaki &tx_msg_ring[i].dma_handle); 259244961713Sgirish if (ddi_status != DDI_SUCCESS) { 259344961713Sgirish status |= NXGE_DDI_FAILED; 259444961713Sgirish break; 259544961713Sgirish } 259644961713Sgirish } 259744961713Sgirish if (i < nmsgs) { 259856d930aeSspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 259956d930aeSspeer "Allocate handles failed.")); 260044961713Sgirish goto nxge_map_txdma_channel_buf_ring_fail1; 260144961713Sgirish } 260244961713Sgirish 260344961713Sgirish tx_ring_p->tdc = channel; 260444961713Sgirish tx_ring_p->tx_msg_ring = tx_msg_ring; 260544961713Sgirish tx_ring_p->tx_ring_size = nmsgs; 260644961713Sgirish tx_ring_p->num_chunks = num_chunks; 260744961713Sgirish if (!nxge_tx_intr_thres) { 260844961713Sgirish nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4; 260944961713Sgirish } 261044961713Sgirish tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1; 261144961713Sgirish tx_ring_p->rd_index = 0; 261244961713Sgirish tx_ring_p->wr_index = 0; 261344961713Sgirish tx_ring_p->ring_head.value = 0; 261444961713Sgirish tx_ring_p->ring_kick_tail.value = 0; 261544961713Sgirish tx_ring_p->descs_pending = 0; 261644961713Sgirish 261744961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 261852ccf843Smisaki "==> nxge_map_txdma_channel_buf_ring: channel %d " 261952ccf843Smisaki "actual tx desc max %d nmsgs %d " 262052ccf843Smisaki "(config nxge_tx_ring_size %d)", 262152ccf843Smisaki channel, tx_ring_p->tx_ring_size, nmsgs, 262252ccf843Smisaki nxge_tx_ring_size)); 262344961713Sgirish 262444961713Sgirish /* 262544961713Sgirish * Map in buffers from the buffer pool. 262644961713Sgirish */ 262744961713Sgirish index = 0; 262844961713Sgirish bsize = dma_bufp->block_size; 262944961713Sgirish 263044961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: " 263152ccf843Smisaki "dma_bufp $%p tx_rng_p $%p " 263252ccf843Smisaki "tx_msg_rng_p $%p bsize %d", 263352ccf843Smisaki dma_bufp, tx_ring_p, tx_msg_ring, bsize)); 263444961713Sgirish 263544961713Sgirish tx_buf_dma_handle = dma_bufp->dma_handle; 263644961713Sgirish for (i = 0; i < num_chunks; i++, dma_bufp++) { 263744961713Sgirish bsize = dma_bufp->block_size; 263844961713Sgirish nblocks = dma_bufp->nblocks; 263944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 264052ccf843Smisaki "==> nxge_map_txdma_channel_buf_ring: dma chunk %d " 264152ccf843Smisaki "size %d dma_bufp $%p", 264252ccf843Smisaki i, sizeof (nxge_dma_common_t), dma_bufp)); 264344961713Sgirish 264444961713Sgirish for (j = 0; j < nblocks; j++) { 264544961713Sgirish tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle; 264644961713Sgirish dmap = &tx_msg_ring[index++].buf_dma; 264744961713Sgirish #ifdef TX_MEM_DEBUG 264844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 264952ccf843Smisaki "==> nxge_map_txdma_channel_buf_ring: j %d" 265052ccf843Smisaki "dmap $%p", i, dmap)); 265144961713Sgirish #endif 265244961713Sgirish nxge_setup_dma_common(dmap, dma_bufp, 1, 265352ccf843Smisaki bsize); 265444961713Sgirish } 265544961713Sgirish } 265644961713Sgirish 265744961713Sgirish if (i < num_chunks) { 265856d930aeSspeer status = NXGE_ERROR; 265944961713Sgirish goto nxge_map_txdma_channel_buf_ring_fail1; 266044961713Sgirish } 266144961713Sgirish 266244961713Sgirish *tx_desc_p = tx_ring_p; 266344961713Sgirish 266444961713Sgirish goto nxge_map_txdma_channel_buf_ring_exit; 266544961713Sgirish 266644961713Sgirish nxge_map_txdma_channel_buf_ring_fail1: 2667da14cebeSEric Cheng if (tx_ring_p->taskq) { 2668da14cebeSEric Cheng ddi_taskq_destroy(tx_ring_p->taskq); 2669da14cebeSEric Cheng tx_ring_p->taskq = NULL; 26701f8914d5Sml } 26711f8914d5Sml 267244961713Sgirish index--; 267344961713Sgirish for (; index >= 0; index--) { 267456d930aeSspeer if (tx_msg_ring[index].dma_handle != NULL) { 267556d930aeSspeer ddi_dma_free_handle(&tx_msg_ring[index].dma_handle); 267644961713Sgirish } 267744961713Sgirish } 267844961713Sgirish MUTEX_DESTROY(&tx_ring_p->lock); 267956d930aeSspeer KMEM_FREE(tx_msg_ring, size); 268044961713Sgirish KMEM_FREE(tx_ring_p, sizeof (tx_ring_t)); 268144961713Sgirish 268256d930aeSspeer status = NXGE_ERROR; 268356d930aeSspeer 268444961713Sgirish nxge_map_txdma_channel_buf_ring_exit: 268544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 268652ccf843Smisaki "<== nxge_map_txdma_channel_buf_ring status 0x%x", status)); 268744961713Sgirish 268844961713Sgirish return (status); 268944961713Sgirish } 269044961713Sgirish 269144961713Sgirish /*ARGSUSED*/ 269244961713Sgirish static void 269344961713Sgirish nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p) 269444961713Sgirish { 269544961713Sgirish p_tx_msg_t tx_msg_ring; 269644961713Sgirish p_tx_msg_t tx_msg_p; 269744961713Sgirish int i; 269844961713Sgirish 269944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 270052ccf843Smisaki "==> nxge_unmap_txdma_channel_buf_ring")); 270144961713Sgirish if (tx_ring_p == NULL) { 270244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 270352ccf843Smisaki "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp")); 270444961713Sgirish return; 270544961713Sgirish } 270644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 270752ccf843Smisaki "==> nxge_unmap_txdma_channel_buf_ring: channel %d", 270852ccf843Smisaki tx_ring_p->tdc)); 270944961713Sgirish 271044961713Sgirish tx_msg_ring = tx_ring_p->tx_msg_ring; 2711678453a8Sspeer 2712678453a8Sspeer /* 2713678453a8Sspeer * Since the serialization thread, timer thread and 2714678453a8Sspeer * interrupt thread can all call the transmit reclaim, 2715678453a8Sspeer * the unmapping function needs to acquire the lock 2716678453a8Sspeer * to free those buffers which were transmitted 2717678453a8Sspeer * by the hardware already. 2718678453a8Sspeer */ 2719678453a8Sspeer MUTEX_ENTER(&tx_ring_p->lock); 2720678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 2721678453a8Sspeer "==> nxge_unmap_txdma_channel_buf_ring (reclaim): " 2722678453a8Sspeer "channel %d", 2723678453a8Sspeer tx_ring_p->tdc)); 2724678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 2725678453a8Sspeer 272644961713Sgirish for (i = 0; i < tx_ring_p->tx_ring_size; i++) { 272744961713Sgirish tx_msg_p = &tx_msg_ring[i]; 272844961713Sgirish if (tx_msg_p->tx_message != NULL) { 272944961713Sgirish freemsg(tx_msg_p->tx_message); 273044961713Sgirish tx_msg_p->tx_message = NULL; 273144961713Sgirish } 273244961713Sgirish } 273344961713Sgirish 273444961713Sgirish for (i = 0; i < tx_ring_p->tx_ring_size; i++) { 273544961713Sgirish if (tx_msg_ring[i].dma_handle != NULL) { 273644961713Sgirish ddi_dma_free_handle(&tx_msg_ring[i].dma_handle); 273744961713Sgirish } 2738678453a8Sspeer tx_msg_ring[i].dma_handle = NULL; 273944961713Sgirish } 274044961713Sgirish 2741678453a8Sspeer MUTEX_EXIT(&tx_ring_p->lock); 2742678453a8Sspeer 2743da14cebeSEric Cheng if (tx_ring_p->taskq) { 2744da14cebeSEric Cheng ddi_taskq_destroy(tx_ring_p->taskq); 2745da14cebeSEric Cheng tx_ring_p->taskq = NULL; 27461f8914d5Sml } 27471f8914d5Sml 274844961713Sgirish MUTEX_DESTROY(&tx_ring_p->lock); 274944961713Sgirish KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size); 275044961713Sgirish KMEM_FREE(tx_ring_p, sizeof (tx_ring_t)); 275144961713Sgirish 275244961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 275352ccf843Smisaki "<== nxge_unmap_txdma_channel_buf_ring")); 275444961713Sgirish } 275544961713Sgirish 275644961713Sgirish static nxge_status_t 2757678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel) 275844961713Sgirish { 275944961713Sgirish p_tx_rings_t tx_rings; 276044961713Sgirish p_tx_ring_t *tx_desc_rings; 276144961713Sgirish p_tx_mbox_areas_t tx_mbox_areas_p; 276244961713Sgirish p_tx_mbox_t *tx_mbox_p; 276344961713Sgirish nxge_status_t status = NXGE_OK; 276444961713Sgirish 276544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start")); 276644961713Sgirish 276744961713Sgirish tx_rings = nxgep->tx_rings; 276844961713Sgirish if (tx_rings == NULL) { 276944961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 277052ccf843Smisaki "<== nxge_txdma_hw_start: NULL ring pointer")); 277144961713Sgirish return (NXGE_ERROR); 277244961713Sgirish } 277344961713Sgirish tx_desc_rings = tx_rings->rings; 277444961713Sgirish if (tx_desc_rings == NULL) { 277544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 277652ccf843Smisaki "<== nxge_txdma_hw_start: NULL ring pointers")); 277744961713Sgirish return (NXGE_ERROR); 277844961713Sgirish } 277944961713Sgirish 2780678453a8Sspeer NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 2781678453a8Sspeer "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings)); 278244961713Sgirish 278344961713Sgirish tx_mbox_areas_p = nxgep->tx_mbox_areas_p; 278444961713Sgirish tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p; 278544961713Sgirish 2786678453a8Sspeer status = nxge_txdma_start_channel(nxgep, channel, 2787678453a8Sspeer (p_tx_ring_t)tx_desc_rings[channel], 2788678453a8Sspeer (p_tx_mbox_t)tx_mbox_p[channel]); 2789678453a8Sspeer if (status != NXGE_OK) { 2790678453a8Sspeer goto nxge_txdma_hw_start_fail1; 279144961713Sgirish } 279244961713Sgirish 279344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 279452ccf843Smisaki "tx_rings $%p rings $%p", 279552ccf843Smisaki nxgep->tx_rings, nxgep->tx_rings->rings)); 279644961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: " 279752ccf843Smisaki "tx_rings $%p tx_desc_rings $%p", 279852ccf843Smisaki nxgep->tx_rings, tx_desc_rings)); 279944961713Sgirish 280044961713Sgirish goto nxge_txdma_hw_start_exit; 280144961713Sgirish 280244961713Sgirish nxge_txdma_hw_start_fail1: 280344961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 280452ccf843Smisaki "==> nxge_txdma_hw_start: disable " 280552ccf843Smisaki "(status 0x%x channel %d)", status, channel)); 280644961713Sgirish 280744961713Sgirish nxge_txdma_hw_start_exit: 280844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 280952ccf843Smisaki "==> nxge_txdma_hw_start: (status 0x%x)", status)); 281044961713Sgirish 281144961713Sgirish return (status); 281244961713Sgirish } 281344961713Sgirish 2814678453a8Sspeer /* 2815678453a8Sspeer * nxge_txdma_start_channel 2816678453a8Sspeer * 2817678453a8Sspeer * Start a TDC. 2818678453a8Sspeer * 2819678453a8Sspeer * Arguments: 2820678453a8Sspeer * nxgep 2821678453a8Sspeer * channel The channel to start. 2822678453a8Sspeer * tx_ring_p channel's transmit descriptor ring. 2823678453a8Sspeer * tx_mbox_p channel' smailbox. 2824678453a8Sspeer * 2825678453a8Sspeer * Notes: 2826678453a8Sspeer * 2827678453a8Sspeer * NPI/NXGE function calls: 2828678453a8Sspeer * nxge_reset_txdma_channel() 2829678453a8Sspeer * nxge_init_txdma_channel_event_mask() 2830678453a8Sspeer * nxge_enable_txdma_channel() 2831678453a8Sspeer * 2832678453a8Sspeer * Registers accessed: 2833678453a8Sspeer * none directly (see functions above). 2834678453a8Sspeer * 2835678453a8Sspeer * Context: 2836678453a8Sspeer * Any domain 2837678453a8Sspeer */ 283844961713Sgirish static nxge_status_t 283944961713Sgirish nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel, 284044961713Sgirish p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p) 284144961713Sgirish 284244961713Sgirish { 284344961713Sgirish nxge_status_t status = NXGE_OK; 284444961713Sgirish 284544961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 284644961713Sgirish "==> nxge_txdma_start_channel (channel %d)", channel)); 284744961713Sgirish /* 284844961713Sgirish * TXDMA/TXC must be in stopped state. 284944961713Sgirish */ 285044961713Sgirish (void) nxge_txdma_stop_inj_err(nxgep, channel); 285144961713Sgirish 285244961713Sgirish /* 285344961713Sgirish * Reset TXDMA channel 285444961713Sgirish */ 285544961713Sgirish tx_ring_p->tx_cs.value = 0; 285644961713Sgirish tx_ring_p->tx_cs.bits.ldw.rst = 1; 285744961713Sgirish status = nxge_reset_txdma_channel(nxgep, channel, 285844961713Sgirish tx_ring_p->tx_cs.value); 285944961713Sgirish if (status != NXGE_OK) { 286044961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 286144961713Sgirish "==> nxge_txdma_start_channel (channel %d)" 286244961713Sgirish " reset channel failed 0x%x", channel, status)); 286344961713Sgirish goto nxge_txdma_start_channel_exit; 286444961713Sgirish } 286544961713Sgirish 286644961713Sgirish /* 286744961713Sgirish * Initialize the TXDMA channel specific FZC control 286844961713Sgirish * configurations. These FZC registers are pertaining 286944961713Sgirish * to each TX channel (i.e. logical pages). 287044961713Sgirish */ 2871678453a8Sspeer if (!isLDOMguest(nxgep)) { 2872678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, channel, 2873678453a8Sspeer tx_ring_p, tx_mbox_p); 2874678453a8Sspeer if (status != NXGE_OK) { 2875678453a8Sspeer goto nxge_txdma_start_channel_exit; 2876678453a8Sspeer } 287744961713Sgirish } 287844961713Sgirish 287944961713Sgirish /* 288044961713Sgirish * Initialize the event masks. 288144961713Sgirish */ 288244961713Sgirish tx_ring_p->tx_evmask.value = 0; 288344961713Sgirish status = nxge_init_txdma_channel_event_mask(nxgep, 2884678453a8Sspeer channel, &tx_ring_p->tx_evmask); 288544961713Sgirish if (status != NXGE_OK) { 288644961713Sgirish goto nxge_txdma_start_channel_exit; 288744961713Sgirish } 288844961713Sgirish 288944961713Sgirish /* 289044961713Sgirish * Load TXDMA descriptors, buffers, mailbox, 289144961713Sgirish * initialise the DMA channels and 289244961713Sgirish * enable each DMA channel. 289344961713Sgirish */ 289444961713Sgirish status = nxge_enable_txdma_channel(nxgep, channel, 289544961713Sgirish tx_ring_p, tx_mbox_p); 289644961713Sgirish if (status != NXGE_OK) { 289744961713Sgirish goto nxge_txdma_start_channel_exit; 289844961713Sgirish } 289944961713Sgirish 290044961713Sgirish nxge_txdma_start_channel_exit: 290144961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel")); 290244961713Sgirish 290344961713Sgirish return (status); 290444961713Sgirish } 290544961713Sgirish 2906678453a8Sspeer /* 2907678453a8Sspeer * nxge_txdma_stop_channel 2908678453a8Sspeer * 2909678453a8Sspeer * Stop a TDC. 2910678453a8Sspeer * 2911678453a8Sspeer * Arguments: 2912678453a8Sspeer * nxgep 2913678453a8Sspeer * channel The channel to stop. 2914678453a8Sspeer * tx_ring_p channel's transmit descriptor ring. 2915678453a8Sspeer * tx_mbox_p channel' smailbox. 2916678453a8Sspeer * 2917678453a8Sspeer * Notes: 2918678453a8Sspeer * 2919678453a8Sspeer * NPI/NXGE function calls: 2920678453a8Sspeer * nxge_txdma_stop_inj_err() 2921678453a8Sspeer * nxge_reset_txdma_channel() 2922678453a8Sspeer * nxge_init_txdma_channel_event_mask() 2923678453a8Sspeer * nxge_init_txdma_channel_cntl_stat() 2924678453a8Sspeer * nxge_disable_txdma_channel() 2925678453a8Sspeer * 2926678453a8Sspeer * Registers accessed: 2927678453a8Sspeer * none directly (see functions above). 2928678453a8Sspeer * 2929678453a8Sspeer * Context: 2930678453a8Sspeer * Any domain 2931678453a8Sspeer */ 293244961713Sgirish /*ARGSUSED*/ 293344961713Sgirish static nxge_status_t 2934678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel) 293544961713Sgirish { 2936678453a8Sspeer p_tx_ring_t tx_ring_p; 2937678453a8Sspeer int status = NXGE_OK; 293844961713Sgirish 293944961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 294052ccf843Smisaki "==> nxge_txdma_stop_channel: channel %d", channel)); 294144961713Sgirish 294244961713Sgirish /* 294344961713Sgirish * Stop (disable) TXDMA and TXC (if stop bit is set 294444961713Sgirish * and STOP_N_GO bit not set, the TXDMA reset state will 294544961713Sgirish * not be set if reset TXDMA. 294644961713Sgirish */ 294744961713Sgirish (void) nxge_txdma_stop_inj_err(nxgep, channel); 294844961713Sgirish 2949678453a8Sspeer tx_ring_p = nxgep->tx_rings->rings[channel]; 2950678453a8Sspeer 295144961713Sgirish /* 295244961713Sgirish * Reset TXDMA channel 295344961713Sgirish */ 295444961713Sgirish tx_ring_p->tx_cs.value = 0; 295544961713Sgirish tx_ring_p->tx_cs.bits.ldw.rst = 1; 295644961713Sgirish status = nxge_reset_txdma_channel(nxgep, channel, 295752ccf843Smisaki tx_ring_p->tx_cs.value); 295844961713Sgirish if (status != NXGE_OK) { 295944961713Sgirish goto nxge_txdma_stop_channel_exit; 296044961713Sgirish } 296144961713Sgirish 296244961713Sgirish #ifdef HARDWARE_REQUIRED 296344961713Sgirish /* Set up the interrupt event masks. */ 296444961713Sgirish tx_ring_p->tx_evmask.value = 0; 296544961713Sgirish status = nxge_init_txdma_channel_event_mask(nxgep, 296652ccf843Smisaki channel, &tx_ring_p->tx_evmask); 296744961713Sgirish if (status != NXGE_OK) { 296844961713Sgirish goto nxge_txdma_stop_channel_exit; 296944961713Sgirish } 297044961713Sgirish 297144961713Sgirish /* Initialize the DMA control and status register */ 297244961713Sgirish tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL; 297344961713Sgirish status = nxge_init_txdma_channel_cntl_stat(nxgep, channel, 297452ccf843Smisaki tx_ring_p->tx_cs.value); 297544961713Sgirish if (status != NXGE_OK) { 297644961713Sgirish goto nxge_txdma_stop_channel_exit; 297744961713Sgirish } 297844961713Sgirish 2979678453a8Sspeer tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel]; 2980678453a8Sspeer 298144961713Sgirish /* Disable channel */ 298244961713Sgirish status = nxge_disable_txdma_channel(nxgep, channel, 2983678453a8Sspeer tx_ring_p, tx_mbox_p); 298444961713Sgirish if (status != NXGE_OK) { 298544961713Sgirish goto nxge_txdma_start_channel_exit; 298644961713Sgirish } 298744961713Sgirish 298844961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, 298952ccf843Smisaki "==> nxge_txdma_stop_channel: event done")); 299044961713Sgirish 299144961713Sgirish #endif 299244961713Sgirish 299344961713Sgirish nxge_txdma_stop_channel_exit: 299444961713Sgirish NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel")); 299544961713Sgirish return (status); 299644961713Sgirish } 299744961713Sgirish 2998678453a8Sspeer /* 2999678453a8Sspeer * nxge_txdma_get_ring 3000678453a8Sspeer * 3001678453a8Sspeer * Get the ring for a TDC. 3002678453a8Sspeer * 3003678453a8Sspeer * Arguments: 3004678453a8Sspeer * nxgep 3005678453a8Sspeer * channel 3006678453a8Sspeer * 3007678453a8Sspeer * Notes: 3008678453a8Sspeer * 3009678453a8Sspeer * NPI/NXGE function calls: 3010678453a8Sspeer * 3011678453a8Sspeer * Registers accessed: 3012678453a8Sspeer * 3013678453a8Sspeer * Context: 3014678453a8Sspeer * Any domain 3015678453a8Sspeer */ 301644961713Sgirish static p_tx_ring_t 301744961713Sgirish nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel) 301844961713Sgirish { 3019678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3020678453a8Sspeer int tdc; 302144961713Sgirish 302244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring")); 302344961713Sgirish 3024678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 302544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 3026678453a8Sspeer "<== nxge_txdma_get_ring: NULL ring pointer(s)")); 3027678453a8Sspeer goto return_null; 3028678453a8Sspeer } 3029678453a8Sspeer 3030678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3031678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3032678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3033678453a8Sspeer if (ring) { 3034678453a8Sspeer if (channel == ring->tdc) { 3035678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3036678453a8Sspeer "<== nxge_txdma_get_ring: " 3037678453a8Sspeer "tdc %d ring $%p", tdc, ring)); 3038678453a8Sspeer return (ring); 3039678453a8Sspeer } 3040678453a8Sspeer } 304144961713Sgirish } 304244961713Sgirish } 304344961713Sgirish 3044678453a8Sspeer return_null: 3045678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: " 304652ccf843Smisaki "ring not found")); 3047678453a8Sspeer 304844961713Sgirish return (NULL); 304944961713Sgirish } 305044961713Sgirish 3051678453a8Sspeer /* 3052678453a8Sspeer * nxge_txdma_get_mbox 3053678453a8Sspeer * 3054678453a8Sspeer * Get the mailbox for a TDC. 3055678453a8Sspeer * 3056678453a8Sspeer * Arguments: 3057678453a8Sspeer * nxgep 3058678453a8Sspeer * channel 3059678453a8Sspeer * 3060678453a8Sspeer * Notes: 3061678453a8Sspeer * 3062678453a8Sspeer * NPI/NXGE function calls: 3063678453a8Sspeer * 3064678453a8Sspeer * Registers accessed: 3065678453a8Sspeer * 3066678453a8Sspeer * Context: 3067678453a8Sspeer * Any domain 3068678453a8Sspeer */ 306944961713Sgirish static p_tx_mbox_t 307044961713Sgirish nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel) 307144961713Sgirish { 3072678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3073678453a8Sspeer int tdc; 307444961713Sgirish 307544961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox")); 307644961713Sgirish 3077678453a8Sspeer if (nxgep->tx_mbox_areas_p == 0 || 3078678453a8Sspeer nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) { 3079678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3080678453a8Sspeer "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)")); 3081678453a8Sspeer goto return_null; 308244961713Sgirish } 308344961713Sgirish 3084678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 3085678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3086678453a8Sspeer "<== nxge_txdma_get_mbox: NULL ring pointer(s)")); 3087678453a8Sspeer goto return_null; 3088678453a8Sspeer } 3089678453a8Sspeer 3090678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3091678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3092678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3093678453a8Sspeer if (ring) { 3094678453a8Sspeer if (channel == ring->tdc) { 3095678453a8Sspeer tx_mbox_t *mailbox = nxgep-> 3096678453a8Sspeer tx_mbox_areas_p-> 3097678453a8Sspeer txmbox_areas_p[tdc]; 3098678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3099678453a8Sspeer "<== nxge_txdma_get_mbox: tdc %d " 3100678453a8Sspeer "ring $%p", tdc, mailbox)); 3101678453a8Sspeer return (mailbox); 3102678453a8Sspeer } 3103678453a8Sspeer } 310444961713Sgirish } 310544961713Sgirish } 310644961713Sgirish 3107678453a8Sspeer return_null: 3108678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: " 310952ccf843Smisaki "mailbox not found")); 3110678453a8Sspeer 311144961713Sgirish return (NULL); 311244961713Sgirish } 311344961713Sgirish 3114678453a8Sspeer /* 3115678453a8Sspeer * nxge_tx_err_evnts 3116678453a8Sspeer * 3117678453a8Sspeer * Recover a TDC. 3118678453a8Sspeer * 3119678453a8Sspeer * Arguments: 3120678453a8Sspeer * nxgep 3121678453a8Sspeer * index The index to the TDC ring. 3122678453a8Sspeer * ldvp Used to get the channel number ONLY. 3123678453a8Sspeer * cs A copy of the bits from TX_CS. 3124678453a8Sspeer * 3125678453a8Sspeer * Notes: 3126678453a8Sspeer * Calling tree: 3127678453a8Sspeer * nxge_tx_intr() 3128678453a8Sspeer * 3129678453a8Sspeer * NPI/NXGE function calls: 3130678453a8Sspeer * npi_txdma_ring_error_get() 3131678453a8Sspeer * npi_txdma_inj_par_error_get() 3132678453a8Sspeer * nxge_txdma_fatal_err_recover() 3133678453a8Sspeer * 3134678453a8Sspeer * Registers accessed: 3135678453a8Sspeer * TX_RNG_ERR_LOGH DMC+0x40048 Transmit Ring Error Log High 3136678453a8Sspeer * TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low 3137678453a8Sspeer * TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error 3138678453a8Sspeer * 3139678453a8Sspeer * Context: 3140678453a8Sspeer * Any domain XXX Remove code which accesses TDMC_INJ_PAR_ERR. 3141678453a8Sspeer */ 314244961713Sgirish /*ARGSUSED*/ 314344961713Sgirish static nxge_status_t 314444961713Sgirish nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs) 314544961713Sgirish { 314644961713Sgirish npi_handle_t handle; 314744961713Sgirish npi_status_t rs; 314844961713Sgirish uint8_t channel; 314944961713Sgirish p_tx_ring_t *tx_rings; 315044961713Sgirish p_tx_ring_t tx_ring_p; 315144961713Sgirish p_nxge_tx_ring_stats_t tdc_stats; 315244961713Sgirish boolean_t txchan_fatal = B_FALSE; 315344961713Sgirish nxge_status_t status = NXGE_OK; 315444961713Sgirish tdmc_inj_par_err_t par_err; 315544961713Sgirish uint32_t value; 315644961713Sgirish 3157678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts")); 315844961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 315944961713Sgirish channel = ldvp->channel; 316044961713Sgirish 316144961713Sgirish tx_rings = nxgep->tx_rings->rings; 316244961713Sgirish tx_ring_p = tx_rings[index]; 316344961713Sgirish tdc_stats = tx_ring_p->tdc_stats; 316444961713Sgirish if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) || 316552ccf843Smisaki (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) || 316652ccf843Smisaki (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) { 316744961713Sgirish if ((rs = npi_txdma_ring_error_get(handle, channel, 316852ccf843Smisaki &tdc_stats->errlog)) != NPI_SUCCESS) 316944961713Sgirish return (NXGE_ERROR | rs); 317044961713Sgirish } 317144961713Sgirish 317244961713Sgirish if (cs.bits.ldw.mbox_err) { 317344961713Sgirish tdc_stats->mbox_err++; 317444961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 317552ccf843Smisaki NXGE_FM_EREPORT_TDMC_MBOX_ERR); 317644961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 317752ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 317852ccf843Smisaki "fatal error: mailbox", channel)); 317944961713Sgirish txchan_fatal = B_TRUE; 318044961713Sgirish } 318144961713Sgirish if (cs.bits.ldw.pkt_size_err) { 318244961713Sgirish tdc_stats->pkt_size_err++; 318344961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 318452ccf843Smisaki NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR); 318544961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 318652ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 318752ccf843Smisaki "fatal error: pkt_size_err", channel)); 318844961713Sgirish txchan_fatal = B_TRUE; 318944961713Sgirish } 319044961713Sgirish if (cs.bits.ldw.tx_ring_oflow) { 319144961713Sgirish tdc_stats->tx_ring_oflow++; 319244961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 319352ccf843Smisaki NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW); 319444961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 319552ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 319652ccf843Smisaki "fatal error: tx_ring_oflow", channel)); 319744961713Sgirish txchan_fatal = B_TRUE; 319844961713Sgirish } 319944961713Sgirish if (cs.bits.ldw.pref_buf_par_err) { 320044961713Sgirish tdc_stats->pre_buf_par_err++; 320144961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 320252ccf843Smisaki NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR); 320344961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 320452ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 320552ccf843Smisaki "fatal error: pre_buf_par_err", channel)); 320644961713Sgirish /* Clear error injection source for parity error */ 320744961713Sgirish (void) npi_txdma_inj_par_error_get(handle, &value); 320844961713Sgirish par_err.value = value; 320944961713Sgirish par_err.bits.ldw.inject_parity_error &= ~(1 << channel); 321044961713Sgirish (void) npi_txdma_inj_par_error_set(handle, par_err.value); 321144961713Sgirish txchan_fatal = B_TRUE; 321244961713Sgirish } 321344961713Sgirish if (cs.bits.ldw.nack_pref) { 321444961713Sgirish tdc_stats->nack_pref++; 321544961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 321652ccf843Smisaki NXGE_FM_EREPORT_TDMC_NACK_PREF); 321744961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 321852ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 321952ccf843Smisaki "fatal error: nack_pref", channel)); 322044961713Sgirish txchan_fatal = B_TRUE; 322144961713Sgirish } 322244961713Sgirish if (cs.bits.ldw.nack_pkt_rd) { 322344961713Sgirish tdc_stats->nack_pkt_rd++; 322444961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 322552ccf843Smisaki NXGE_FM_EREPORT_TDMC_NACK_PKT_RD); 322644961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 322752ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 322852ccf843Smisaki "fatal error: nack_pkt_rd", channel)); 322944961713Sgirish txchan_fatal = B_TRUE; 323044961713Sgirish } 323144961713Sgirish if (cs.bits.ldw.conf_part_err) { 323244961713Sgirish tdc_stats->conf_part_err++; 323344961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 323452ccf843Smisaki NXGE_FM_EREPORT_TDMC_CONF_PART_ERR); 323544961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 323652ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 323752ccf843Smisaki "fatal error: config_partition_err", channel)); 323844961713Sgirish txchan_fatal = B_TRUE; 323944961713Sgirish } 324044961713Sgirish if (cs.bits.ldw.pkt_prt_err) { 324144961713Sgirish tdc_stats->pkt_part_err++; 324244961713Sgirish NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel, 324352ccf843Smisaki NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR); 324444961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 324552ccf843Smisaki "==> nxge_tx_err_evnts(channel %d): " 324652ccf843Smisaki "fatal error: pkt_prt_err", channel)); 324744961713Sgirish txchan_fatal = B_TRUE; 324844961713Sgirish } 324944961713Sgirish 325044961713Sgirish /* Clear error injection source in case this is an injected error */ 325144961713Sgirish TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0); 325244961713Sgirish 325344961713Sgirish if (txchan_fatal) { 325444961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 325552ccf843Smisaki " nxge_tx_err_evnts: " 325652ccf843Smisaki " fatal error on channel %d cs 0x%llx\n", 325752ccf843Smisaki channel, cs.value)); 325844961713Sgirish status = nxge_txdma_fatal_err_recover(nxgep, channel, 325952ccf843Smisaki tx_ring_p); 326044961713Sgirish if (status == NXGE_OK) { 326144961713Sgirish FM_SERVICE_RESTORED(nxgep); 326244961713Sgirish } 326344961713Sgirish } 326444961713Sgirish 3265678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts")); 326644961713Sgirish 326744961713Sgirish return (status); 326844961713Sgirish } 326944961713Sgirish 327044961713Sgirish static nxge_status_t 3271678453a8Sspeer nxge_txdma_fatal_err_recover( 3272678453a8Sspeer p_nxge_t nxgep, 3273678453a8Sspeer uint16_t channel, 3274678453a8Sspeer p_tx_ring_t tx_ring_p) 327544961713Sgirish { 327644961713Sgirish npi_handle_t handle; 327744961713Sgirish npi_status_t rs = NPI_SUCCESS; 327844961713Sgirish p_tx_mbox_t tx_mbox_p; 327944961713Sgirish nxge_status_t status = NXGE_OK; 328044961713Sgirish 328144961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover")); 328244961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 328352ccf843Smisaki "Recovering from TxDMAChannel#%d error...", channel)); 328444961713Sgirish 328544961713Sgirish /* 328644961713Sgirish * Stop the dma channel waits for the stop done. 328744961713Sgirish * If the stop done bit is not set, then create 328844961713Sgirish * an error. 328944961713Sgirish */ 329044961713Sgirish 329144961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 329244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop...")); 329344961713Sgirish MUTEX_ENTER(&tx_ring_p->lock); 329444961713Sgirish rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel); 329544961713Sgirish if (rs != NPI_SUCCESS) { 329644961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 329752ccf843Smisaki "==> nxge_txdma_fatal_err_recover (channel %d): " 329852ccf843Smisaki "stop failed ", channel)); 329944961713Sgirish goto fail; 330044961713Sgirish } 330144961713Sgirish 330244961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim...")); 330344961713Sgirish (void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0); 330444961713Sgirish 330544961713Sgirish /* 330644961713Sgirish * Reset TXDMA channel 330744961713Sgirish */ 330844961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset...")); 330944961713Sgirish if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) != 331052ccf843Smisaki NPI_SUCCESS) { 331144961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 331252ccf843Smisaki "==> nxge_txdma_fatal_err_recover (channel %d)" 331352ccf843Smisaki " reset channel failed 0x%x", channel, rs)); 331444961713Sgirish goto fail; 331544961713Sgirish } 331644961713Sgirish 331744961713Sgirish /* 331844961713Sgirish * Reset the tail (kick) register to 0. 331944961713Sgirish * (Hardware will not reset it. Tx overflow fatal 332044961713Sgirish * error if tail is not set to 0 after reset! 332144961713Sgirish */ 332244961713Sgirish TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0); 332344961713Sgirish 332444961713Sgirish /* Restart TXDMA channel */ 332544961713Sgirish 3326678453a8Sspeer if (!isLDOMguest(nxgep)) { 3327678453a8Sspeer tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel); 332844961713Sgirish 3329678453a8Sspeer // XXX This is a problem in HIO! 3330678453a8Sspeer /* 3331678453a8Sspeer * Initialize the TXDMA channel specific FZC control 3332678453a8Sspeer * configurations. These FZC registers are pertaining 3333678453a8Sspeer * to each TX channel (i.e. logical pages). 3334678453a8Sspeer */ 3335678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart...")); 3336678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, channel, 3337678453a8Sspeer tx_ring_p, tx_mbox_p); 3338678453a8Sspeer if (status != NXGE_OK) 3339678453a8Sspeer goto fail; 3340678453a8Sspeer } 334144961713Sgirish 334244961713Sgirish /* 334344961713Sgirish * Initialize the event masks. 334444961713Sgirish */ 334544961713Sgirish tx_ring_p->tx_evmask.value = 0; 334644961713Sgirish status = nxge_init_txdma_channel_event_mask(nxgep, channel, 334752ccf843Smisaki &tx_ring_p->tx_evmask); 334844961713Sgirish if (status != NXGE_OK) 334944961713Sgirish goto fail; 335044961713Sgirish 335144961713Sgirish tx_ring_p->wr_index_wrap = B_FALSE; 335244961713Sgirish tx_ring_p->wr_index = 0; 335344961713Sgirish tx_ring_p->rd_index = 0; 335444961713Sgirish 335544961713Sgirish /* 335644961713Sgirish * Load TXDMA descriptors, buffers, mailbox, 335744961713Sgirish * initialise the DMA channels and 335844961713Sgirish * enable each DMA channel. 335944961713Sgirish */ 336044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable...")); 336144961713Sgirish status = nxge_enable_txdma_channel(nxgep, channel, 336252ccf843Smisaki tx_ring_p, tx_mbox_p); 336344961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 336444961713Sgirish if (status != NXGE_OK) 336544961713Sgirish goto fail; 336644961713Sgirish 336744961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 336852ccf843Smisaki "Recovery Successful, TxDMAChannel#%d Restored", 336952ccf843Smisaki channel)); 337044961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover")); 337144961713Sgirish 337244961713Sgirish return (NXGE_OK); 337344961713Sgirish 337444961713Sgirish fail: 337544961713Sgirish MUTEX_EXIT(&tx_ring_p->lock); 33762d99c5d4SMichael Speer 337744961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, 337852ccf843Smisaki "nxge_txdma_fatal_err_recover (channel %d): " 337952ccf843Smisaki "failed to recover this txdma channel", channel)); 338044961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed")); 338144961713Sgirish 338244961713Sgirish return (status); 338344961713Sgirish } 338444961713Sgirish 3385678453a8Sspeer /* 3386678453a8Sspeer * nxge_tx_port_fatal_err_recover 3387678453a8Sspeer * 3388678453a8Sspeer * Attempt to recover from a fatal port error. 3389678453a8Sspeer * 3390678453a8Sspeer * Arguments: 3391678453a8Sspeer * nxgep 3392678453a8Sspeer * 3393678453a8Sspeer * Notes: 3394678453a8Sspeer * How would a guest do this? 3395678453a8Sspeer * 3396678453a8Sspeer * NPI/NXGE function calls: 3397678453a8Sspeer * 3398678453a8Sspeer * Registers accessed: 3399678453a8Sspeer * 3400678453a8Sspeer * Context: 3401678453a8Sspeer * Service domain 3402678453a8Sspeer */ 340344961713Sgirish nxge_status_t 340444961713Sgirish nxge_tx_port_fatal_err_recover(p_nxge_t nxgep) 340544961713Sgirish { 3406678453a8Sspeer nxge_grp_set_t *set = &nxgep->tx_set; 3407678453a8Sspeer nxge_channel_t tdc; 3408678453a8Sspeer 3409678453a8Sspeer tx_ring_t *ring; 3410678453a8Sspeer tx_mbox_t *mailbox; 3411678453a8Sspeer 341244961713Sgirish npi_handle_t handle; 3413678453a8Sspeer nxge_status_t status; 3414678453a8Sspeer npi_status_t rs; 341544961713Sgirish 341644961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover")); 341744961713Sgirish NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3418678453a8Sspeer "Recovering from TxPort error...")); 341944961713Sgirish 3420678453a8Sspeer if (isLDOMguest(nxgep)) { 3421678453a8Sspeer return (NXGE_OK); 342244961713Sgirish } 342344961713Sgirish 3424678453a8Sspeer if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) { 3425678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3426678453a8Sspeer "<== nxge_tx_port_fatal_err_recover: not initialized")); 3427678453a8Sspeer return (NXGE_ERROR); 342844961713Sgirish } 342944961713Sgirish 3430678453a8Sspeer if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) { 3431678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, 3432678453a8Sspeer "<== nxge_tx_port_fatal_err_recover: " 3433678453a8Sspeer "NULL ring pointer(s)")); 3434678453a8Sspeer return (NXGE_ERROR); 3435678453a8Sspeer } 343644961713Sgirish 3437678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3438678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3439678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3440678453a8Sspeer if (ring) 3441678453a8Sspeer MUTEX_ENTER(&ring->lock); 344244961713Sgirish } 344344961713Sgirish } 344444961713Sgirish 3445678453a8Sspeer handle = NXGE_DEV_NPI_HANDLE(nxgep); 3446678453a8Sspeer 344744961713Sgirish /* 3448678453a8Sspeer * Stop all the TDCs owned by us. 3449678453a8Sspeer * (The shared TDCs will have been stopped by their owners.) 345044961713Sgirish */ 3451678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3452678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3453678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3454678453a8Sspeer if (ring) { 3455678453a8Sspeer rs = npi_txdma_channel_control 3456678453a8Sspeer (handle, TXDMA_STOP, tdc); 3457678453a8Sspeer if (rs != NPI_SUCCESS) { 3458678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3459678453a8Sspeer "nxge_tx_port_fatal_err_recover " 3460678453a8Sspeer "(channel %d): stop failed ", tdc)); 3461678453a8Sspeer goto fail; 3462678453a8Sspeer } 3463678453a8Sspeer } 346444961713Sgirish } 3465678453a8Sspeer } 346644961713Sgirish 3467678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs...")); 346844961713Sgirish 3469678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3470678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3471678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 34722d99c5d4SMichael Speer if (ring) { 3473678453a8Sspeer (void) nxge_txdma_reclaim(nxgep, ring, 0); 34742d99c5d4SMichael Speer } 3475678453a8Sspeer } 347644961713Sgirish } 347744961713Sgirish 347844961713Sgirish /* 3479678453a8Sspeer * Reset all the TDCs. 348044961713Sgirish */ 3481678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting 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]; 3486678453a8Sspeer if (ring) { 3487678453a8Sspeer if ((rs = npi_txdma_channel_control 348852ccf843Smisaki (handle, TXDMA_RESET, tdc)) 3489678453a8Sspeer != NPI_SUCCESS) { 3490678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 3491678453a8Sspeer "nxge_tx_port_fatal_err_recover " 3492678453a8Sspeer "(channel %d) reset channel " 3493678453a8Sspeer "failed 0x%x", tdc, rs)); 3494678453a8Sspeer goto fail; 3495678453a8Sspeer } 3496678453a8Sspeer } 3497678453a8Sspeer /* 3498678453a8Sspeer * Reset the tail (kick) register to 0. 3499678453a8Sspeer * (Hardware will not reset it. Tx overflow fatal 3500678453a8Sspeer * error if tail is not set to 0 after reset! 3501678453a8Sspeer */ 3502678453a8Sspeer TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0); 350344961713Sgirish } 3504678453a8Sspeer } 350544961713Sgirish 3506678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs...")); 3507678453a8Sspeer 3508678453a8Sspeer /* Restart all the TDCs */ 3509678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3510678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3511678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3512678453a8Sspeer if (ring) { 3513678453a8Sspeer mailbox = nxge_txdma_get_mbox(nxgep, tdc); 3514678453a8Sspeer status = nxge_init_fzc_txdma_channel(nxgep, tdc, 3515678453a8Sspeer ring, mailbox); 3516678453a8Sspeer ring->tx_evmask.value = 0; 3517678453a8Sspeer /* 3518678453a8Sspeer * Initialize the event masks. 3519678453a8Sspeer */ 3520678453a8Sspeer status = nxge_init_txdma_channel_event_mask 3521678453a8Sspeer (nxgep, tdc, &ring->tx_evmask); 3522678453a8Sspeer 3523678453a8Sspeer ring->wr_index_wrap = B_FALSE; 3524678453a8Sspeer ring->wr_index = 0; 3525678453a8Sspeer ring->rd_index = 0; 3526678453a8Sspeer 3527678453a8Sspeer if (status != NXGE_OK) 3528678453a8Sspeer goto fail; 3529678453a8Sspeer if (status != NXGE_OK) 3530678453a8Sspeer goto fail; 3531678453a8Sspeer } 3532678453a8Sspeer } 353344961713Sgirish } 353444961713Sgirish 3535678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs...")); 353644961713Sgirish 3537678453a8Sspeer /* Re-enable all the TDCs */ 3538678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3539678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3540678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3541678453a8Sspeer if (ring) { 3542678453a8Sspeer mailbox = nxge_txdma_get_mbox(nxgep, tdc); 3543678453a8Sspeer status = nxge_enable_txdma_channel(nxgep, tdc, 3544678453a8Sspeer ring, mailbox); 3545678453a8Sspeer if (status != NXGE_OK) 3546678453a8Sspeer goto fail; 3547678453a8Sspeer } 354844961713Sgirish } 354944961713Sgirish } 355044961713Sgirish 3551678453a8Sspeer /* 3552678453a8Sspeer * Unlock all the TDCs. 3553678453a8Sspeer */ 3554678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3555678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3556678453a8Sspeer tx_ring_t *ring = nxgep->tx_rings->rings[tdc]; 3557678453a8Sspeer if (ring) 3558678453a8Sspeer MUTEX_EXIT(&ring->lock); 355944961713Sgirish } 356044961713Sgirish } 356144961713Sgirish 3562678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded")); 356344961713Sgirish NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover")); 356444961713Sgirish 356544961713Sgirish return (NXGE_OK); 356644961713Sgirish 356744961713Sgirish fail: 3568678453a8Sspeer for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) { 3569678453a8Sspeer if ((1 << tdc) & set->owned.map) { 3570678453a8Sspeer ring = nxgep->tx_rings->rings[tdc]; 3571678453a8Sspeer if (ring) 3572678453a8Sspeer MUTEX_EXIT(&ring->lock); 357344961713Sgirish } 357444961713Sgirish } 357544961713Sgirish 3576678453a8Sspeer NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed")); 3577678453a8Sspeer NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover")); 357844961713Sgirish 357944961713Sgirish return (status); 358044961713Sgirish } 358144961713Sgirish 3582678453a8Sspeer /* 3583678453a8Sspeer * nxge_txdma_inject_err 3584678453a8Sspeer * 3585678453a8Sspeer * Inject an error into a TDC. 3586678453a8Sspeer * 3587678453a8Sspeer * Arguments: 3588678453a8Sspeer * nxgep 3589678453a8Sspeer * err_id The error to inject. 3590678453a8Sspeer * chan The channel to inject into. 3591678453a8Sspeer * 3592678453a8Sspeer * Notes: 3593678453a8Sspeer * This is called from nxge_main.c:nxge_err_inject() 3594678453a8Sspeer * Has this ioctl ever been used? 3595678453a8Sspeer * 3596678453a8Sspeer * NPI/NXGE function calls: 3597678453a8Sspeer * npi_txdma_inj_par_error_get() 3598678453a8Sspeer * npi_txdma_inj_par_error_set() 3599678453a8Sspeer * 3600678453a8Sspeer * Registers accessed: 3601678453a8Sspeer * TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error 3602678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 3603678453a8Sspeer * TDMC_INTR_DBG DMC + 0x40060 Transmit DMA Interrupt Debug 3604678453a8Sspeer * 3605678453a8Sspeer * Context: 3606678453a8Sspeer * Service domain 3607678453a8Sspeer */ 360844961713Sgirish void 360944961713Sgirish nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan) 361044961713Sgirish { 361144961713Sgirish tdmc_intr_dbg_t tdi; 361244961713Sgirish tdmc_inj_par_err_t par_err; 361344961713Sgirish uint32_t value; 361444961713Sgirish npi_handle_t handle; 361544961713Sgirish 361644961713Sgirish switch (err_id) { 361744961713Sgirish 361844961713Sgirish case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR: 361944961713Sgirish handle = NXGE_DEV_NPI_HANDLE(nxgep); 362044961713Sgirish /* Clear error injection source for parity error */ 362144961713Sgirish (void) npi_txdma_inj_par_error_get(handle, &value); 362244961713Sgirish par_err.value = value; 362344961713Sgirish par_err.bits.ldw.inject_parity_error &= ~(1 << chan); 362444961713Sgirish (void) npi_txdma_inj_par_error_set(handle, par_err.value); 362544961713Sgirish 362644961713Sgirish par_err.bits.ldw.inject_parity_error = (1 << chan); 362744961713Sgirish (void) npi_txdma_inj_par_error_get(handle, &value); 362844961713Sgirish par_err.value = value; 362944961713Sgirish par_err.bits.ldw.inject_parity_error |= (1 << chan); 363044961713Sgirish cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n", 363152ccf843Smisaki (unsigned long long)par_err.value); 363244961713Sgirish (void) npi_txdma_inj_par_error_set(handle, par_err.value); 363344961713Sgirish break; 363444961713Sgirish 363544961713Sgirish case NXGE_FM_EREPORT_TDMC_MBOX_ERR: 363644961713Sgirish case NXGE_FM_EREPORT_TDMC_NACK_PREF: 363744961713Sgirish case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD: 363844961713Sgirish case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR: 363944961713Sgirish case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW: 364044961713Sgirish case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR: 364144961713Sgirish case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR: 364244961713Sgirish TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG, 364352ccf843Smisaki chan, &tdi.value); 364444961713Sgirish if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR) 364544961713Sgirish tdi.bits.ldw.pref_buf_par_err = 1; 364644961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR) 364744961713Sgirish tdi.bits.ldw.mbox_err = 1; 364844961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF) 364944961713Sgirish tdi.bits.ldw.nack_pref = 1; 365044961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD) 365144961713Sgirish tdi.bits.ldw.nack_pkt_rd = 1; 365244961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR) 365344961713Sgirish tdi.bits.ldw.pkt_size_err = 1; 365444961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW) 365544961713Sgirish tdi.bits.ldw.tx_ring_oflow = 1; 365644961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR) 365744961713Sgirish tdi.bits.ldw.conf_part_err = 1; 365844961713Sgirish else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR) 365944961713Sgirish tdi.bits.ldw.pkt_part_err = 1; 3660adfcba55Sjoycey #if defined(__i386) 3661adfcba55Sjoycey cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n", 366252ccf843Smisaki tdi.value); 3663adfcba55Sjoycey #else 366444961713Sgirish cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n", 366552ccf843Smisaki tdi.value); 3666adfcba55Sjoycey #endif 366744961713Sgirish TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, 366852ccf843Smisaki chan, tdi.value); 366944961713Sgirish 367044961713Sgirish break; 367144961713Sgirish } 367244961713Sgirish } 3673