62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * Copyright (C) 2007 VMware, Inc. All rights reserved.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * The contents of this file are subject to the terms of the Common
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * Development and Distribution License (the "License") version 1.0
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * and no later version. You may not use this file except in
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * compliance with the License.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * You can obtain a copy of the License at
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * See the License for the specific language governing permissions
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * and limitations under the License.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roystatic void vmxnet3_put_rxbuf(vmxnet3_rxbuf_t *);
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Allocate a new rxBuf from memory. All its fields are set except
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * for its associated mblk which has to be allocated later.
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * A new rxBuf or NULL.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_alloc_rxbuf(vmxnet3_softc_t *dp, boolean_t canSleep)
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov rxBuf = kmem_zalloc(sizeof (vmxnet3_rxbuf_t), flag);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov if ((err = vmxnet3_alloc_dma_mem_1(dp, &rxBuf->dma, (dp->cur_mtu + 18),
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov VMXNET3_DEBUG(dp, 0, "Failed to allocate %d bytes for rx buf, "
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_free_rxbuf(vmxnet3_softc_t *dp, vmxnet3_rxbuf_t *rxBuf)
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy uint32_t nv = atomic_dec_32_nv(&dp->rx_num_bufs);
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * Return a rxBuf to the pool. The init argument, when B_TRUE, indicates
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * that we're being called for the purpose of pool initialization, and
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * therefore, we should place the buffer in the pool even if the device
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * isn't enabled.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * B_TRUE if the buffer was returned to the pool, or B_FALSE if it
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * wasn't (e.g. if the device is stopped).
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Royvmxnet3_put_rxpool_buf(vmxnet3_softc_t *dp, vmxnet3_rxbuf_t *rxBuf,
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if ((dp->devEnabled || init) && rxPool->nBufs < rxPool->nBufsLimit) {
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov ASSERT((rxPool->listHead == NULL && rxPool->nBufs == 0) ||
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov (rxPool->listHead != NULL && rxPool->nBufs != 0));
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Return a rxBuf to the pool or free it.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if (!vmxnet3_put_rxpool_buf(dp, rxBuf, B_FALSE))
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Get an unused rxBuf from the pool.
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * A rxBuf or NULL if there are no buffers in the pool.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov ASSERT((rxPool->listHead == NULL && rxPool->nBufs == 0) ||
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov (rxPool->listHead != NULL && rxPool->nBufs != 0));
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * Fill a rxPool by allocating the maximum number of buffers.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * 0 on success, non-zero on failure.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy while (dp->rxPool.nBufs < dp->rxPool.nBufsLimit) {
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if ((rxBuf = vmxnet3_alloc_rxbuf(dp, B_FALSE)) == NULL) {
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy VERIFY(vmxnet3_put_rxpool_buf(dp, rxBuf, B_TRUE));
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy while ((rxBuf = vmxnet3_get_rxpool_buf(dp)) != NULL) {
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * Populate a Rx descriptor with a new rxBuf. If the pool argument is B_TRUE,
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * then try to take a buffer from rxPool. If the pool is empty and the
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * dp->alloc_ok is true, then fall back to dynamic allocation. If pool is
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * B_FALSE, then always allocate a new buffer (this is only used when
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * populating the initial set of buffers in the receive queue during start).
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * 0 on success, non-zero on failure.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_rx_populate(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq, uint16_t idx,
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if (pool && (rxBuf = vmxnet3_get_rxpool_buf(dp)) == NULL) {
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy /* The maximum number of pool buffers have been allocated. */
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if (rxBuf == NULL && (!pool || dp->alloc_ok)) {
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy rxBuf->mblk = desballoc((uchar_t *)rxBuf->dma.buf,
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov Vmxnet3_GenericDesc *rxDesc = VMXNET3_GET_DESC(cmdRing, idx);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov /* rxDesc->rxd.btype = 0; */
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Initialize a RxQueue by populating the whole Rx ring with rxBufs.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * 0 on success, non-zero on failure.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_rxqueue_init(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq)
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy dp->rxPool.nBufsLimit = vmxnet3_getprop(dp, "RxBufPoolLimit", 0,
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if ((err = vmxnet3_rx_populate(dp, rxq, cmdRing->next2fill,
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov VMXNET3_INC_RING_IDX(cmdRing, cmdRing->next2fill);
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * Pre-allocate rxPool buffers so that we never have to allocate
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * new buffers from interrupt context when we need to replace a buffer
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy * in the rxqueue.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov VMXNET3_DEC_RING_IDX(cmdRing, cmdRing->next2fill);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov vmxnet3_free_rxbuf(dp, rxq->bufRing[cmdRing->next2fill].rxBuf);
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Finish a RxQueue by freeing all the related rxBufs.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_rxqueue_fini(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq)
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov unsigned int i;
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov /* First the rxPool */
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov /* Then the ring */
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * Here, freemsg() will trigger a call to vmxnet3_put_rxbuf()
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * which will then call vmxnet3_free_rxbuf() because the
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * underlying device is disabled.
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Determine if a received packet was checksummed by the Vmxnet3
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * device and tag the mp appropriately.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_rx_hwcksum(vmxnet3_softc_t *dp, mblk_t *mp,
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov VMXNET3_DEBUG(dp, 3, "rx cksum flags = 0x%x\n", flags);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov (void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0, 0, flags, 0);
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * Interrupt handler for Rx. Look if there are any pending Rx and
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * put them in mplist.
ca5345b6a28e9e9bfd0c135121d62c6b35a5390dSebastien Roy * A list of messages to pass to the MAC subystem.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankovvmxnet3_rx_intr(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq)
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov vmxnet3_rxbuf_t *rxBuf = rxq->bufRing[rxdIdx].rxBuf;
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * H/W may be still be in the middle of
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * generating this entry, so hold on until
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * the gen bit is flipped.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov /* Some Rx descriptors may have been skipped */
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * Now we have a piece of the packet in the rxdIdx
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * descriptor. Grab it only if we achieve to replace
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * it with a fresh buffer.
6849994e8263545ed3c0f6f5676e47b38e14f63eSebastien Roy if (vmxnet3_rx_populate(dp, rxq, rxdIdx, B_FALSE,
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov /* Success, we can chain the mblk with the mp */
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov mblk->b_wptr = mblk->b_rptr + compDesc->rcd.len;
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * Tag the mp if it was
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * checksummed by the H/W
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * Keep the same buffer, we still need
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * to flip the gen bit
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov VMXNET3_INC_RING_IDX(compRing, compRing->next2comp);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov VMXNET3_INC_RING_IDX(cmdRing, cmdRing->next2fill);
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov /* This message got holes, drop it */
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * All buffers are actually available, but we can't tell that to
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * the device because it may interpret that as an empty ring.
62dadd654b88164ac263978699c78aa01647a39bYuri Pankov * So skip one buffer.