1*62dadd65SYuri Pankov /* 2*62dadd65SYuri Pankov * Copyright (C) 2007 VMware, Inc. All rights reserved. 3*62dadd65SYuri Pankov * 4*62dadd65SYuri Pankov * The contents of this file are subject to the terms of the Common 5*62dadd65SYuri Pankov * Development and Distribution License (the "License") version 1.0 6*62dadd65SYuri Pankov * and no later version. You may not use this file except in 7*62dadd65SYuri Pankov * compliance with the License. 8*62dadd65SYuri Pankov * 9*62dadd65SYuri Pankov * You can obtain a copy of the License at 10*62dadd65SYuri Pankov * http://www.opensource.org/licenses/cddl1.php 11*62dadd65SYuri Pankov * 12*62dadd65SYuri Pankov * See the License for the specific language governing permissions 13*62dadd65SYuri Pankov * and limitations under the License. 14*62dadd65SYuri Pankov */ 15*62dadd65SYuri Pankov 16*62dadd65SYuri Pankov /* 17*62dadd65SYuri Pankov * Copyright (c) 2012 by Delphix. All rights reserved. 18*62dadd65SYuri Pankov */ 19*62dadd65SYuri Pankov 20*62dadd65SYuri Pankov #include <vmxnet3.h> 21*62dadd65SYuri Pankov 22*62dadd65SYuri Pankov typedef enum vmxnet3_txstatus { 23*62dadd65SYuri Pankov VMXNET3_TX_OK, 24*62dadd65SYuri Pankov VMXNET3_TX_FAILURE, 25*62dadd65SYuri Pankov VMXNET3_TX_PULLUP, 26*62dadd65SYuri Pankov VMXNET3_TX_RINGFULL 27*62dadd65SYuri Pankov } vmxnet3_txstatus; 28*62dadd65SYuri Pankov 29*62dadd65SYuri Pankov typedef struct vmxnet3_offload_t { 30*62dadd65SYuri Pankov uint16_t om; 31*62dadd65SYuri Pankov uint16_t hlen; 32*62dadd65SYuri Pankov uint16_t msscof; 33*62dadd65SYuri Pankov } vmxnet3_offload_t; 34*62dadd65SYuri Pankov 35*62dadd65SYuri Pankov /* 36*62dadd65SYuri Pankov * vmxnet3_txqueue_init -- 37*62dadd65SYuri Pankov * 38*62dadd65SYuri Pankov * Initialize a TxQueue. Currently nothing needs to be done. 39*62dadd65SYuri Pankov * 40*62dadd65SYuri Pankov * Results: 41*62dadd65SYuri Pankov * DDI_SUCCESS. 42*62dadd65SYuri Pankov * 43*62dadd65SYuri Pankov * Side effects: 44*62dadd65SYuri Pankov * None. 45*62dadd65SYuri Pankov */ 46*62dadd65SYuri Pankov /* ARGSUSED */ 47*62dadd65SYuri Pankov int 48*62dadd65SYuri Pankov vmxnet3_txqueue_init(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq) 49*62dadd65SYuri Pankov { 50*62dadd65SYuri Pankov return (DDI_SUCCESS); 51*62dadd65SYuri Pankov } 52*62dadd65SYuri Pankov 53*62dadd65SYuri Pankov /* 54*62dadd65SYuri Pankov * vmxnet3_txqueue_fini -- 55*62dadd65SYuri Pankov * 56*62dadd65SYuri Pankov * Finish a TxQueue by freeing all pending Tx. 57*62dadd65SYuri Pankov * 58*62dadd65SYuri Pankov * Results: 59*62dadd65SYuri Pankov * DDI_SUCCESS. 60*62dadd65SYuri Pankov * 61*62dadd65SYuri Pankov * Side effects: 62*62dadd65SYuri Pankov * None. 63*62dadd65SYuri Pankov */ 64*62dadd65SYuri Pankov void 65*62dadd65SYuri Pankov vmxnet3_txqueue_fini(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq) 66*62dadd65SYuri Pankov { 67*62dadd65SYuri Pankov unsigned int i; 68*62dadd65SYuri Pankov 69*62dadd65SYuri Pankov ASSERT(!dp->devEnabled); 70*62dadd65SYuri Pankov 71*62dadd65SYuri Pankov for (i = 0; i < txq->cmdRing.size; i++) { 72*62dadd65SYuri Pankov mblk_t *mp = txq->metaRing[i].mp; 73*62dadd65SYuri Pankov if (mp) { 74*62dadd65SYuri Pankov freemsg(mp); 75*62dadd65SYuri Pankov } 76*62dadd65SYuri Pankov } 77*62dadd65SYuri Pankov } 78*62dadd65SYuri Pankov 79*62dadd65SYuri Pankov /* 80*62dadd65SYuri Pankov * vmxnet3_tx_prepare_offload -- 81*62dadd65SYuri Pankov * 82*62dadd65SYuri Pankov * Build the offload context of a msg. 83*62dadd65SYuri Pankov * 84*62dadd65SYuri Pankov * Results: 85*62dadd65SYuri Pankov * 0 if everything went well. 86*62dadd65SYuri Pankov * +n if n bytes need to be pulled up. 87*62dadd65SYuri Pankov * -1 in case of error (not used). 88*62dadd65SYuri Pankov * 89*62dadd65SYuri Pankov * Side effects: 90*62dadd65SYuri Pankov * None. 91*62dadd65SYuri Pankov */ 92*62dadd65SYuri Pankov static int 93*62dadd65SYuri Pankov vmxnet3_tx_prepare_offload(vmxnet3_softc_t *dp, vmxnet3_offload_t *ol, 94*62dadd65SYuri Pankov mblk_t *mp) 95*62dadd65SYuri Pankov { 96*62dadd65SYuri Pankov int ret = 0; 97*62dadd65SYuri Pankov uint32_t start, stuff, value, flags, lsoflags, mss; 98*62dadd65SYuri Pankov 99*62dadd65SYuri Pankov ol->om = VMXNET3_OM_NONE; 100*62dadd65SYuri Pankov ol->hlen = 0; 101*62dadd65SYuri Pankov ol->msscof = 0; 102*62dadd65SYuri Pankov 103*62dadd65SYuri Pankov hcksum_retrieve(mp, NULL, NULL, &start, &stuff, NULL, &value, &flags); 104*62dadd65SYuri Pankov 105*62dadd65SYuri Pankov mac_lso_get(mp, &mss, &lsoflags); 106*62dadd65SYuri Pankov if (lsoflags & HW_LSO) { 107*62dadd65SYuri Pankov flags |= HW_LSO; 108*62dadd65SYuri Pankov } 109*62dadd65SYuri Pankov 110*62dadd65SYuri Pankov if (flags) { 111*62dadd65SYuri Pankov struct ether_vlan_header *eth = (void *) mp->b_rptr; 112*62dadd65SYuri Pankov uint8_t ethLen; 113*62dadd65SYuri Pankov 114*62dadd65SYuri Pankov if (eth->ether_tpid == htons(ETHERTYPE_VLAN)) { 115*62dadd65SYuri Pankov ethLen = sizeof (struct ether_vlan_header); 116*62dadd65SYuri Pankov } else { 117*62dadd65SYuri Pankov ethLen = sizeof (struct ether_header); 118*62dadd65SYuri Pankov } 119*62dadd65SYuri Pankov 120*62dadd65SYuri Pankov VMXNET3_DEBUG(dp, 4, "flags=0x%x, ethLen=%u, start=%u, " 121*62dadd65SYuri Pankov "stuff=%u, value=%u\n", flags, ethLen, start, stuff, value); 122*62dadd65SYuri Pankov 123*62dadd65SYuri Pankov if (flags & HCK_PARTIALCKSUM) { 124*62dadd65SYuri Pankov ol->om = VMXNET3_OM_CSUM; 125*62dadd65SYuri Pankov ol->hlen = start + ethLen; 126*62dadd65SYuri Pankov ol->msscof = stuff + ethLen; 127*62dadd65SYuri Pankov } 128*62dadd65SYuri Pankov if (flags & HW_LSO) { 129*62dadd65SYuri Pankov mblk_t *mblk = mp; 130*62dadd65SYuri Pankov uint8_t *ip, *tcp; 131*62dadd65SYuri Pankov uint8_t ipLen, tcpLen; 132*62dadd65SYuri Pankov 133*62dadd65SYuri Pankov /* 134*62dadd65SYuri Pankov * Copy e1000g's behavior: 135*62dadd65SYuri Pankov * - Do not assume all the headers are in the same mblk. 136*62dadd65SYuri Pankov * - Assume each header is always within one mblk. 137*62dadd65SYuri Pankov * - Assume the ethernet header is in the first mblk. 138*62dadd65SYuri Pankov */ 139*62dadd65SYuri Pankov ip = mblk->b_rptr + ethLen; 140*62dadd65SYuri Pankov if (ip >= mblk->b_wptr) { 141*62dadd65SYuri Pankov mblk = mblk->b_cont; 142*62dadd65SYuri Pankov ip = mblk->b_rptr; 143*62dadd65SYuri Pankov } 144*62dadd65SYuri Pankov ipLen = IPH_HDR_LENGTH((ipha_t *)ip); 145*62dadd65SYuri Pankov tcp = ip + ipLen; 146*62dadd65SYuri Pankov if (tcp >= mblk->b_wptr) { 147*62dadd65SYuri Pankov mblk = mblk->b_cont; 148*62dadd65SYuri Pankov tcp = mblk->b_rptr; 149*62dadd65SYuri Pankov } 150*62dadd65SYuri Pankov tcpLen = TCP_HDR_LENGTH((tcph_t *)tcp); 151*62dadd65SYuri Pankov /* Careful, '>' instead of '>=' here */ 152*62dadd65SYuri Pankov if (tcp + tcpLen > mblk->b_wptr) { 153*62dadd65SYuri Pankov mblk = mblk->b_cont; 154*62dadd65SYuri Pankov } 155*62dadd65SYuri Pankov 156*62dadd65SYuri Pankov ol->om = VMXNET3_OM_TSO; 157*62dadd65SYuri Pankov ol->hlen = ethLen + ipLen + tcpLen; 158*62dadd65SYuri Pankov ol->msscof = DB_LSOMSS(mp); 159*62dadd65SYuri Pankov 160*62dadd65SYuri Pankov if (mblk != mp) { 161*62dadd65SYuri Pankov ret = ol->hlen; 162*62dadd65SYuri Pankov } 163*62dadd65SYuri Pankov } 164*62dadd65SYuri Pankov } 165*62dadd65SYuri Pankov 166*62dadd65SYuri Pankov return (ret); 167*62dadd65SYuri Pankov } 168*62dadd65SYuri Pankov 169*62dadd65SYuri Pankov /* 170*62dadd65SYuri Pankov * vmxnet3_tx_one -- 171*62dadd65SYuri Pankov * 172*62dadd65SYuri Pankov * Map a msg into the Tx command ring of a vmxnet3 device. 173*62dadd65SYuri Pankov * 174*62dadd65SYuri Pankov * Results: 175*62dadd65SYuri Pankov * VMXNET3_TX_OK if everything went well. 176*62dadd65SYuri Pankov * VMXNET3_TX_RINGFULL if the ring is nearly full. 177*62dadd65SYuri Pankov * VMXNET3_TX_PULLUP if the msg is overfragmented. 178*62dadd65SYuri Pankov * VMXNET3_TX_FAILURE if there was a DMA or offload error. 179*62dadd65SYuri Pankov * 180*62dadd65SYuri Pankov * Side effects: 181*62dadd65SYuri Pankov * The ring is filled if VMXNET3_TX_OK is returned. 182*62dadd65SYuri Pankov */ 183*62dadd65SYuri Pankov static vmxnet3_txstatus 184*62dadd65SYuri Pankov vmxnet3_tx_one(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq, 185*62dadd65SYuri Pankov vmxnet3_offload_t *ol, mblk_t *mp) 186*62dadd65SYuri Pankov { 187*62dadd65SYuri Pankov int ret = VMXNET3_TX_OK; 188*62dadd65SYuri Pankov unsigned int frags = 0, totLen = 0; 189*62dadd65SYuri Pankov vmxnet3_cmdring_t *cmdRing = &txq->cmdRing; 190*62dadd65SYuri Pankov Vmxnet3_TxQueueCtrl *txqCtrl = txq->sharedCtrl; 191*62dadd65SYuri Pankov Vmxnet3_GenericDesc *txDesc; 192*62dadd65SYuri Pankov uint16_t sopIdx, eopIdx; 193*62dadd65SYuri Pankov uint8_t sopGen, curGen; 194*62dadd65SYuri Pankov mblk_t *mblk; 195*62dadd65SYuri Pankov 196*62dadd65SYuri Pankov mutex_enter(&dp->txLock); 197*62dadd65SYuri Pankov 198*62dadd65SYuri Pankov sopIdx = eopIdx = cmdRing->next2fill; 199*62dadd65SYuri Pankov sopGen = cmdRing->gen; 200*62dadd65SYuri Pankov curGen = !cmdRing->gen; 201*62dadd65SYuri Pankov 202*62dadd65SYuri Pankov for (mblk = mp; mblk != NULL; mblk = mblk->b_cont) { 203*62dadd65SYuri Pankov unsigned int len = MBLKL(mblk); 204*62dadd65SYuri Pankov ddi_dma_cookie_t cookie; 205*62dadd65SYuri Pankov uint_t cookieCount; 206*62dadd65SYuri Pankov 207*62dadd65SYuri Pankov if (len) { 208*62dadd65SYuri Pankov totLen += len; 209*62dadd65SYuri Pankov } else { 210*62dadd65SYuri Pankov continue; 211*62dadd65SYuri Pankov } 212*62dadd65SYuri Pankov 213*62dadd65SYuri Pankov if (ddi_dma_addr_bind_handle(dp->txDmaHandle, NULL, 214*62dadd65SYuri Pankov (caddr_t)mblk->b_rptr, len, 215*62dadd65SYuri Pankov DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 216*62dadd65SYuri Pankov &cookie, &cookieCount) != DDI_DMA_MAPPED) { 217*62dadd65SYuri Pankov VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed\n"); 218*62dadd65SYuri Pankov ret = VMXNET3_TX_FAILURE; 219*62dadd65SYuri Pankov goto error; 220*62dadd65SYuri Pankov } 221*62dadd65SYuri Pankov 222*62dadd65SYuri Pankov ASSERT(cookieCount); 223*62dadd65SYuri Pankov 224*62dadd65SYuri Pankov do { 225*62dadd65SYuri Pankov uint64_t addr = cookie.dmac_laddress; 226*62dadd65SYuri Pankov size_t len = cookie.dmac_size; 227*62dadd65SYuri Pankov 228*62dadd65SYuri Pankov do { 229*62dadd65SYuri Pankov uint32_t dw2, dw3; 230*62dadd65SYuri Pankov size_t chunkLen; 231*62dadd65SYuri Pankov 232*62dadd65SYuri Pankov ASSERT(!txq->metaRing[eopIdx].mp); 233*62dadd65SYuri Pankov ASSERT(cmdRing->avail - frags); 234*62dadd65SYuri Pankov 235*62dadd65SYuri Pankov if (frags >= cmdRing->size - 1 || 236*62dadd65SYuri Pankov (ol->om != VMXNET3_OM_TSO && 237*62dadd65SYuri Pankov frags >= VMXNET3_MAX_TXD_PER_PKT)) { 238*62dadd65SYuri Pankov VMXNET3_DEBUG(dp, 2, 239*62dadd65SYuri Pankov "overfragmented mp (%u)\n", frags); 240*62dadd65SYuri Pankov (void) ddi_dma_unbind_handle( 241*62dadd65SYuri Pankov dp->txDmaHandle); 242*62dadd65SYuri Pankov ret = VMXNET3_TX_PULLUP; 243*62dadd65SYuri Pankov goto error; 244*62dadd65SYuri Pankov } 245*62dadd65SYuri Pankov if (cmdRing->avail - frags <= 1) { 246*62dadd65SYuri Pankov dp->txMustResched = B_TRUE; 247*62dadd65SYuri Pankov (void) ddi_dma_unbind_handle( 248*62dadd65SYuri Pankov dp->txDmaHandle); 249*62dadd65SYuri Pankov ret = VMXNET3_TX_RINGFULL; 250*62dadd65SYuri Pankov goto error; 251*62dadd65SYuri Pankov } 252*62dadd65SYuri Pankov 253*62dadd65SYuri Pankov if (len > VMXNET3_MAX_TX_BUF_SIZE) { 254*62dadd65SYuri Pankov chunkLen = VMXNET3_MAX_TX_BUF_SIZE; 255*62dadd65SYuri Pankov } else { 256*62dadd65SYuri Pankov chunkLen = len; 257*62dadd65SYuri Pankov } 258*62dadd65SYuri Pankov 259*62dadd65SYuri Pankov frags++; 260*62dadd65SYuri Pankov eopIdx = cmdRing->next2fill; 261*62dadd65SYuri Pankov 262*62dadd65SYuri Pankov txDesc = VMXNET3_GET_DESC(cmdRing, eopIdx); 263*62dadd65SYuri Pankov ASSERT(txDesc->txd.gen != cmdRing->gen); 264*62dadd65SYuri Pankov 265*62dadd65SYuri Pankov /* txd.addr */ 266*62dadd65SYuri Pankov txDesc->txd.addr = addr; 267*62dadd65SYuri Pankov /* txd.dw2 */ 268*62dadd65SYuri Pankov dw2 = chunkLen == VMXNET3_MAX_TX_BUF_SIZE ? 269*62dadd65SYuri Pankov 0 : chunkLen; 270*62dadd65SYuri Pankov dw2 |= curGen << VMXNET3_TXD_GEN_SHIFT; 271*62dadd65SYuri Pankov txDesc->dword[2] = dw2; 272*62dadd65SYuri Pankov ASSERT(txDesc->txd.len == len || 273*62dadd65SYuri Pankov txDesc->txd.len == 0); 274*62dadd65SYuri Pankov /* txd.dw3 */ 275*62dadd65SYuri Pankov dw3 = 0; 276*62dadd65SYuri Pankov txDesc->dword[3] = dw3; 277*62dadd65SYuri Pankov 278*62dadd65SYuri Pankov VMXNET3_INC_RING_IDX(cmdRing, 279*62dadd65SYuri Pankov cmdRing->next2fill); 280*62dadd65SYuri Pankov curGen = cmdRing->gen; 281*62dadd65SYuri Pankov 282*62dadd65SYuri Pankov addr += chunkLen; 283*62dadd65SYuri Pankov len -= chunkLen; 284*62dadd65SYuri Pankov } while (len); 285*62dadd65SYuri Pankov 286*62dadd65SYuri Pankov if (--cookieCount) { 287*62dadd65SYuri Pankov ddi_dma_nextcookie(dp->txDmaHandle, &cookie); 288*62dadd65SYuri Pankov } 289*62dadd65SYuri Pankov } while (cookieCount); 290*62dadd65SYuri Pankov 291*62dadd65SYuri Pankov (void) ddi_dma_unbind_handle(dp->txDmaHandle); 292*62dadd65SYuri Pankov } 293*62dadd65SYuri Pankov 294*62dadd65SYuri Pankov /* Update the EOP descriptor */ 295*62dadd65SYuri Pankov txDesc = VMXNET3_GET_DESC(cmdRing, eopIdx); 296*62dadd65SYuri Pankov txDesc->dword[3] |= VMXNET3_TXD_CQ | VMXNET3_TXD_EOP; 297*62dadd65SYuri Pankov 298*62dadd65SYuri Pankov /* Update the SOP descriptor. Must be done last */ 299*62dadd65SYuri Pankov txDesc = VMXNET3_GET_DESC(cmdRing, sopIdx); 300*62dadd65SYuri Pankov if (ol->om == VMXNET3_OM_TSO && txDesc->txd.len != 0 && 301*62dadd65SYuri Pankov txDesc->txd.len < ol->hlen) { 302*62dadd65SYuri Pankov ret = VMXNET3_TX_FAILURE; 303*62dadd65SYuri Pankov goto error; 304*62dadd65SYuri Pankov } 305*62dadd65SYuri Pankov txDesc->txd.om = ol->om; 306*62dadd65SYuri Pankov txDesc->txd.hlen = ol->hlen; 307*62dadd65SYuri Pankov txDesc->txd.msscof = ol->msscof; 308*62dadd65SYuri Pankov membar_producer(); 309*62dadd65SYuri Pankov txDesc->txd.gen = sopGen; 310*62dadd65SYuri Pankov 311*62dadd65SYuri Pankov /* Update the meta ring & metadata */ 312*62dadd65SYuri Pankov txq->metaRing[sopIdx].mp = mp; 313*62dadd65SYuri Pankov txq->metaRing[eopIdx].sopIdx = sopIdx; 314*62dadd65SYuri Pankov txq->metaRing[eopIdx].frags = frags; 315*62dadd65SYuri Pankov cmdRing->avail -= frags; 316*62dadd65SYuri Pankov if (ol->om == VMXNET3_OM_TSO) { 317*62dadd65SYuri Pankov txqCtrl->txNumDeferred += 318*62dadd65SYuri Pankov (totLen - ol->hlen + ol->msscof - 1) / ol->msscof; 319*62dadd65SYuri Pankov } else { 320*62dadd65SYuri Pankov txqCtrl->txNumDeferred++; 321*62dadd65SYuri Pankov } 322*62dadd65SYuri Pankov 323*62dadd65SYuri Pankov VMXNET3_DEBUG(dp, 3, "tx 0x%p on [%u;%u]\n", mp, sopIdx, eopIdx); 324*62dadd65SYuri Pankov 325*62dadd65SYuri Pankov goto done; 326*62dadd65SYuri Pankov 327*62dadd65SYuri Pankov error: 328*62dadd65SYuri Pankov /* Reverse the generation bits */ 329*62dadd65SYuri Pankov while (sopIdx != cmdRing->next2fill) { 330*62dadd65SYuri Pankov VMXNET3_DEC_RING_IDX(cmdRing, cmdRing->next2fill); 331*62dadd65SYuri Pankov txDesc = VMXNET3_GET_DESC(cmdRing, cmdRing->next2fill); 332*62dadd65SYuri Pankov txDesc->txd.gen = !cmdRing->gen; 333*62dadd65SYuri Pankov } 334*62dadd65SYuri Pankov 335*62dadd65SYuri Pankov done: 336*62dadd65SYuri Pankov mutex_exit(&dp->txLock); 337*62dadd65SYuri Pankov 338*62dadd65SYuri Pankov return (ret); 339*62dadd65SYuri Pankov } 340*62dadd65SYuri Pankov 341*62dadd65SYuri Pankov /* 342*62dadd65SYuri Pankov * vmxnet3_tx -- 343*62dadd65SYuri Pankov * 344*62dadd65SYuri Pankov * Send packets on a vmxnet3 device. 345*62dadd65SYuri Pankov * 346*62dadd65SYuri Pankov * Results: 347*62dadd65SYuri Pankov * NULL in case of success or failure. 348*62dadd65SYuri Pankov * The mps to be retransmitted later if the ring is full. 349*62dadd65SYuri Pankov * 350*62dadd65SYuri Pankov * Side effects: 351*62dadd65SYuri Pankov * None. 352*62dadd65SYuri Pankov */ 353*62dadd65SYuri Pankov mblk_t * 354*62dadd65SYuri Pankov vmxnet3_tx(void *data, mblk_t *mps) 355*62dadd65SYuri Pankov { 356*62dadd65SYuri Pankov vmxnet3_softc_t *dp = data; 357*62dadd65SYuri Pankov vmxnet3_txqueue_t *txq = &dp->txQueue; 358*62dadd65SYuri Pankov vmxnet3_cmdring_t *cmdRing = &txq->cmdRing; 359*62dadd65SYuri Pankov Vmxnet3_TxQueueCtrl *txqCtrl = txq->sharedCtrl; 360*62dadd65SYuri Pankov vmxnet3_txstatus status = VMXNET3_TX_OK; 361*62dadd65SYuri Pankov mblk_t *mp; 362*62dadd65SYuri Pankov 363*62dadd65SYuri Pankov ASSERT(mps != NULL); 364*62dadd65SYuri Pankov 365*62dadd65SYuri Pankov do { 366*62dadd65SYuri Pankov vmxnet3_offload_t ol; 367*62dadd65SYuri Pankov int pullup; 368*62dadd65SYuri Pankov 369*62dadd65SYuri Pankov mp = mps; 370*62dadd65SYuri Pankov mps = mp->b_next; 371*62dadd65SYuri Pankov mp->b_next = NULL; 372*62dadd65SYuri Pankov 373*62dadd65SYuri Pankov if (DB_TYPE(mp) != M_DATA) { 374*62dadd65SYuri Pankov /* 375*62dadd65SYuri Pankov * PR #315560: M_PROTO mblks could be passed for 376*62dadd65SYuri Pankov * some reason. Drop them because we don't understand 377*62dadd65SYuri Pankov * them and because their contents are not Ethernet 378*62dadd65SYuri Pankov * frames anyway. 379*62dadd65SYuri Pankov */ 380*62dadd65SYuri Pankov ASSERT(B_FALSE); 381*62dadd65SYuri Pankov freemsg(mp); 382*62dadd65SYuri Pankov continue; 383*62dadd65SYuri Pankov } 384*62dadd65SYuri Pankov 385*62dadd65SYuri Pankov /* 386*62dadd65SYuri Pankov * Prepare the offload while we're still handling the original 387*62dadd65SYuri Pankov * message -- msgpullup() discards the metadata afterwards. 388*62dadd65SYuri Pankov */ 389*62dadd65SYuri Pankov pullup = vmxnet3_tx_prepare_offload(dp, &ol, mp); 390*62dadd65SYuri Pankov if (pullup) { 391*62dadd65SYuri Pankov mblk_t *new_mp = msgpullup(mp, pullup); 392*62dadd65SYuri Pankov atomic_inc_32(&dp->tx_pullup_needed); 393*62dadd65SYuri Pankov freemsg(mp); 394*62dadd65SYuri Pankov if (new_mp) { 395*62dadd65SYuri Pankov mp = new_mp; 396*62dadd65SYuri Pankov } else { 397*62dadd65SYuri Pankov atomic_inc_32(&dp->tx_pullup_failed); 398*62dadd65SYuri Pankov continue; 399*62dadd65SYuri Pankov } 400*62dadd65SYuri Pankov } 401*62dadd65SYuri Pankov 402*62dadd65SYuri Pankov /* 403*62dadd65SYuri Pankov * Try to map the message in the Tx ring. 404*62dadd65SYuri Pankov * This call might fail for non-fatal reasons. 405*62dadd65SYuri Pankov */ 406*62dadd65SYuri Pankov status = vmxnet3_tx_one(dp, txq, &ol, mp); 407*62dadd65SYuri Pankov if (status == VMXNET3_TX_PULLUP) { 408*62dadd65SYuri Pankov /* 409*62dadd65SYuri Pankov * Try one more time after flattening 410*62dadd65SYuri Pankov * the message with msgpullup(). 411*62dadd65SYuri Pankov */ 412*62dadd65SYuri Pankov if (mp->b_cont != NULL) { 413*62dadd65SYuri Pankov mblk_t *new_mp = msgpullup(mp, -1); 414*62dadd65SYuri Pankov atomic_inc_32(&dp->tx_pullup_needed); 415*62dadd65SYuri Pankov freemsg(mp); 416*62dadd65SYuri Pankov if (new_mp) { 417*62dadd65SYuri Pankov mp = new_mp; 418*62dadd65SYuri Pankov status = vmxnet3_tx_one(dp, txq, &ol, 419*62dadd65SYuri Pankov mp); 420*62dadd65SYuri Pankov } else { 421*62dadd65SYuri Pankov atomic_inc_32(&dp->tx_pullup_failed); 422*62dadd65SYuri Pankov continue; 423*62dadd65SYuri Pankov } 424*62dadd65SYuri Pankov } 425*62dadd65SYuri Pankov } 426*62dadd65SYuri Pankov if (status != VMXNET3_TX_OK && status != VMXNET3_TX_RINGFULL) { 427*62dadd65SYuri Pankov /* Fatal failure, drop it */ 428*62dadd65SYuri Pankov atomic_inc_32(&dp->tx_error); 429*62dadd65SYuri Pankov freemsg(mp); 430*62dadd65SYuri Pankov } 431*62dadd65SYuri Pankov } while (mps && status != VMXNET3_TX_RINGFULL); 432*62dadd65SYuri Pankov 433*62dadd65SYuri Pankov if (status == VMXNET3_TX_RINGFULL) { 434*62dadd65SYuri Pankov atomic_inc_32(&dp->tx_ring_full); 435*62dadd65SYuri Pankov mp->b_next = mps; 436*62dadd65SYuri Pankov mps = mp; 437*62dadd65SYuri Pankov } else { 438*62dadd65SYuri Pankov ASSERT(!mps); 439*62dadd65SYuri Pankov } 440*62dadd65SYuri Pankov 441*62dadd65SYuri Pankov /* Notify the device */ 442*62dadd65SYuri Pankov mutex_enter(&dp->txLock); 443*62dadd65SYuri Pankov if (txqCtrl->txNumDeferred >= txqCtrl->txThreshold) { 444*62dadd65SYuri Pankov txqCtrl->txNumDeferred = 0; 445*62dadd65SYuri Pankov VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_TXPROD, cmdRing->next2fill); 446*62dadd65SYuri Pankov } 447*62dadd65SYuri Pankov mutex_exit(&dp->txLock); 448*62dadd65SYuri Pankov 449*62dadd65SYuri Pankov return (mps); 450*62dadd65SYuri Pankov } 451*62dadd65SYuri Pankov 452*62dadd65SYuri Pankov /* 453*62dadd65SYuri Pankov * vmxnet3_tx_complete -- 454*62dadd65SYuri Pankov * 455*62dadd65SYuri Pankov * Parse a transmit queue and complete packets. 456*62dadd65SYuri Pankov * 457*62dadd65SYuri Pankov * Results: 458*62dadd65SYuri Pankov * B_TRUE if Tx must be updated or B_FALSE if no action is required. 459*62dadd65SYuri Pankov * 460*62dadd65SYuri Pankov * Side effects: 461*62dadd65SYuri Pankov * None. 462*62dadd65SYuri Pankov */ 463*62dadd65SYuri Pankov boolean_t 464*62dadd65SYuri Pankov vmxnet3_tx_complete(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq) 465*62dadd65SYuri Pankov { 466*62dadd65SYuri Pankov vmxnet3_cmdring_t *cmdRing = &txq->cmdRing; 467*62dadd65SYuri Pankov vmxnet3_compring_t *compRing = &txq->compRing; 468*62dadd65SYuri Pankov Vmxnet3_GenericDesc *compDesc; 469*62dadd65SYuri Pankov boolean_t completedTx = B_FALSE; 470*62dadd65SYuri Pankov boolean_t ret = B_FALSE; 471*62dadd65SYuri Pankov 472*62dadd65SYuri Pankov mutex_enter(&dp->txLock); 473*62dadd65SYuri Pankov 474*62dadd65SYuri Pankov compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp); 475*62dadd65SYuri Pankov while (compDesc->tcd.gen == compRing->gen) { 476*62dadd65SYuri Pankov vmxnet3_metatx_t *sopMetaDesc, *eopMetaDesc; 477*62dadd65SYuri Pankov uint16_t sopIdx, eopIdx; 478*62dadd65SYuri Pankov mblk_t *mp; 479*62dadd65SYuri Pankov 480*62dadd65SYuri Pankov eopIdx = compDesc->tcd.txdIdx; 481*62dadd65SYuri Pankov eopMetaDesc = &txq->metaRing[eopIdx]; 482*62dadd65SYuri Pankov sopIdx = eopMetaDesc->sopIdx; 483*62dadd65SYuri Pankov sopMetaDesc = &txq->metaRing[sopIdx]; 484*62dadd65SYuri Pankov 485*62dadd65SYuri Pankov ASSERT(eopMetaDesc->frags); 486*62dadd65SYuri Pankov cmdRing->avail += eopMetaDesc->frags; 487*62dadd65SYuri Pankov 488*62dadd65SYuri Pankov ASSERT(sopMetaDesc->mp); 489*62dadd65SYuri Pankov mp = sopMetaDesc->mp; 490*62dadd65SYuri Pankov freemsg(mp); 491*62dadd65SYuri Pankov 492*62dadd65SYuri Pankov eopMetaDesc->sopIdx = 0; 493*62dadd65SYuri Pankov eopMetaDesc->frags = 0; 494*62dadd65SYuri Pankov sopMetaDesc->mp = NULL; 495*62dadd65SYuri Pankov 496*62dadd65SYuri Pankov completedTx = B_TRUE; 497*62dadd65SYuri Pankov 498*62dadd65SYuri Pankov VMXNET3_DEBUG(dp, 3, "cp 0x%p on [%u;%u]\n", mp, sopIdx, 499*62dadd65SYuri Pankov eopIdx); 500*62dadd65SYuri Pankov 501*62dadd65SYuri Pankov VMXNET3_INC_RING_IDX(compRing, compRing->next2comp); 502*62dadd65SYuri Pankov compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp); 503*62dadd65SYuri Pankov } 504*62dadd65SYuri Pankov 505*62dadd65SYuri Pankov if (dp->txMustResched && completedTx) { 506*62dadd65SYuri Pankov dp->txMustResched = B_FALSE; 507*62dadd65SYuri Pankov ret = B_TRUE; 508*62dadd65SYuri Pankov } 509*62dadd65SYuri Pankov 510*62dadd65SYuri Pankov mutex_exit(&dp->txLock); 511*62dadd65SYuri Pankov 512*62dadd65SYuri Pankov return (ret); 513*62dadd65SYuri Pankov } 514