2 * Copyright (C) 2007 VMware, Inc. All rights reserved.
4 * The contents of this file are subject to the terms of the Common
5 * Development and Distribution License (the "License") version 1.0
6 * and no later version. You may not use this file except in
7 * compliance with the License.
9 * You can obtain a copy of the License at
10 * http://www.opensource.org/licenses/cddl1.php
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
16 * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
21 static void vmxnet3_put_rxbuf(vmxnet3_rxbuf_t
*);
24 * Allocate a new rxBuf from memory. All its fields are set except
25 * for its associated mblk which has to be allocated later.
28 * A new rxBuf or NULL.
30 static vmxnet3_rxbuf_t
*
31 vmxnet3_alloc_rxbuf(vmxnet3_softc_t
*dp
, boolean_t canSleep
)
33 vmxnet3_rxbuf_t
*rxBuf
;
34 int flag
= canSleep
? KM_SLEEP
: KM_NOSLEEP
;
37 rxBuf
= kmem_zalloc(sizeof (vmxnet3_rxbuf_t
), flag
);
39 atomic_inc_32(&dp
->rx_alloc_failed
);
43 if ((err
= vmxnet3_alloc_dma_mem_1(dp
, &rxBuf
->dma
, (dp
->cur_mtu
+ 18),
45 VMXNET3_DEBUG(dp
, 0, "Failed to allocate %d bytes for rx buf, "
46 "err:%d\n", (dp
->cur_mtu
+ 18), err
);
47 kmem_free(rxBuf
, sizeof (vmxnet3_rxbuf_t
));
48 atomic_inc_32(&dp
->rx_alloc_failed
);
52 rxBuf
->freeCB
.free_func
= vmxnet3_put_rxbuf
;
53 rxBuf
->freeCB
.free_arg
= (caddr_t
)rxBuf
;
56 atomic_inc_32(&dp
->rx_num_bufs
);
57 atomic_inc_32(&dp
->rx_alloc_buf
);
62 vmxnet3_free_rxbuf(vmxnet3_softc_t
*dp
, vmxnet3_rxbuf_t
*rxBuf
)
64 vmxnet3_free_dma_mem(&rxBuf
->dma
);
65 kmem_free(rxBuf
, sizeof (vmxnet3_rxbuf_t
));
68 atomic_dec_32(&dp
->rx_num_bufs
);
71 uint32_t nv
= atomic_dec_32_nv(&dp
->rx_num_bufs
);
72 ASSERT(nv
!= (uint32_t)-1);
78 * Return a rxBuf to the pool. The init argument, when B_TRUE, indicates
79 * that we're being called for the purpose of pool initialization, and
80 * therefore, we should place the buffer in the pool even if the device
84 * B_TRUE if the buffer was returned to the pool, or B_FALSE if it
85 * wasn't (e.g. if the device is stopped).
88 vmxnet3_put_rxpool_buf(vmxnet3_softc_t
*dp
, vmxnet3_rxbuf_t
*rxBuf
,
91 vmxnet3_rxpool_t
*rxPool
= &dp
->rxPool
;
92 boolean_t returned
= B_FALSE
;
94 mutex_enter(&dp
->rxPoolLock
);
95 ASSERT(rxPool
->nBufs
<= rxPool
->nBufsLimit
);
96 if ((dp
->devEnabled
|| init
) && rxPool
->nBufs
< rxPool
->nBufsLimit
) {
97 ASSERT((rxPool
->listHead
== NULL
&& rxPool
->nBufs
== 0) ||
98 (rxPool
->listHead
!= NULL
&& rxPool
->nBufs
!= 0));
99 rxBuf
->next
= rxPool
->listHead
;
100 rxPool
->listHead
= rxBuf
;
104 mutex_exit(&dp
->rxPoolLock
);
109 * Return a rxBuf to the pool or free it.
112 vmxnet3_put_rxbuf(vmxnet3_rxbuf_t
*rxBuf
)
114 vmxnet3_softc_t
*dp
= rxBuf
->dp
;
116 if (!vmxnet3_put_rxpool_buf(dp
, rxBuf
, B_FALSE
))
117 vmxnet3_free_rxbuf(dp
, rxBuf
);
121 * Get an unused rxBuf from the pool.
124 * A rxBuf or NULL if there are no buffers in the pool.
126 static vmxnet3_rxbuf_t
*
127 vmxnet3_get_rxpool_buf(vmxnet3_softc_t
*dp
)
129 vmxnet3_rxpool_t
*rxPool
= &dp
->rxPool
;
130 vmxnet3_rxbuf_t
*rxBuf
= NULL
;
132 mutex_enter(&dp
->rxPoolLock
);
133 if (rxPool
->listHead
!= NULL
) {
134 rxBuf
= rxPool
->listHead
;
135 rxPool
->listHead
= rxBuf
->next
;
137 ASSERT((rxPool
->listHead
== NULL
&& rxPool
->nBufs
== 0) ||
138 (rxPool
->listHead
!= NULL
&& rxPool
->nBufs
!= 0));
140 mutex_exit(&dp
->rxPoolLock
);
145 * Fill a rxPool by allocating the maximum number of buffers.
148 * 0 on success, non-zero on failure.
151 vmxnet3_rxpool_init(vmxnet3_softc_t
*dp
)
154 vmxnet3_rxbuf_t
*rxBuf
;
156 ASSERT(dp
->rxPool
.nBufsLimit
> 0);
157 while (dp
->rxPool
.nBufs
< dp
->rxPool
.nBufsLimit
) {
158 if ((rxBuf
= vmxnet3_alloc_rxbuf(dp
, B_FALSE
)) == NULL
) {
162 VERIFY(vmxnet3_put_rxpool_buf(dp
, rxBuf
, B_TRUE
));
166 while ((rxBuf
= vmxnet3_get_rxpool_buf(dp
)) != NULL
) {
167 vmxnet3_free_rxbuf(dp
, rxBuf
);
175 * Populate a Rx descriptor with a new rxBuf. If the pool argument is B_TRUE,
176 * then try to take a buffer from rxPool. If the pool is empty and the
177 * dp->alloc_ok is true, then fall back to dynamic allocation. If pool is
178 * B_FALSE, then always allocate a new buffer (this is only used when
179 * populating the initial set of buffers in the receive queue during start).
182 * 0 on success, non-zero on failure.
185 vmxnet3_rx_populate(vmxnet3_softc_t
*dp
, vmxnet3_rxqueue_t
*rxq
, uint16_t idx
,
186 boolean_t canSleep
, boolean_t pool
)
188 vmxnet3_rxbuf_t
*rxBuf
= NULL
;
190 if (pool
&& (rxBuf
= vmxnet3_get_rxpool_buf(dp
)) == NULL
) {
191 /* The maximum number of pool buffers have been allocated. */
192 atomic_inc_32(&dp
->rx_pool_empty
);
194 atomic_inc_32(&dp
->rx_alloc_failed
);
198 if (rxBuf
== NULL
&& (!pool
|| dp
->alloc_ok
)) {
199 rxBuf
= vmxnet3_alloc_rxbuf(dp
, canSleep
);
203 rxBuf
->mblk
= desballoc((uchar_t
*)rxBuf
->dma
.buf
,
204 rxBuf
->dma
.bufLen
, BPRI_MED
, &rxBuf
->freeCB
);
205 if (rxBuf
->mblk
== NULL
) {
207 VERIFY(vmxnet3_put_rxpool_buf(dp
, rxBuf
,
210 vmxnet3_free_rxbuf(dp
, rxBuf
);
212 atomic_inc_32(&dp
->rx_alloc_failed
);
216 vmxnet3_cmdring_t
*cmdRing
= &rxq
->cmdRing
;
217 Vmxnet3_GenericDesc
*rxDesc
= VMXNET3_GET_DESC(cmdRing
, idx
);
219 rxq
->bufRing
[idx
].rxBuf
= rxBuf
;
220 rxDesc
->rxd
.addr
= rxBuf
->dma
.bufPA
;
221 rxDesc
->rxd
.len
= rxBuf
->dma
.bufLen
;
222 /* rxDesc->rxd.btype = 0; */
224 rxDesc
->rxd
.gen
= cmdRing
->gen
;
233 * Initialize a RxQueue by populating the whole Rx ring with rxBufs.
236 * 0 on success, non-zero on failure.
239 vmxnet3_rxqueue_init(vmxnet3_softc_t
*dp
, vmxnet3_rxqueue_t
*rxq
)
241 vmxnet3_cmdring_t
*cmdRing
= &rxq
->cmdRing
;
244 dp
->rxPool
.nBufsLimit
= vmxnet3_getprop(dp
, "RxBufPoolLimit", 0,
245 cmdRing
->size
* 10, cmdRing
->size
* 2);
248 if ((err
= vmxnet3_rx_populate(dp
, rxq
, cmdRing
->next2fill
,
249 B_TRUE
, B_FALSE
)) != 0) {
252 VMXNET3_INC_RING_IDX(cmdRing
, cmdRing
->next2fill
);
253 } while (cmdRing
->next2fill
);
256 * Pre-allocate rxPool buffers so that we never have to allocate
257 * new buffers from interrupt context when we need to replace a buffer
260 if ((err
= vmxnet3_rxpool_init(dp
)) != 0) {
267 while (cmdRing
->next2fill
) {
268 VMXNET3_DEC_RING_IDX(cmdRing
, cmdRing
->next2fill
);
269 vmxnet3_free_rxbuf(dp
, rxq
->bufRing
[cmdRing
->next2fill
].rxBuf
);
276 * Finish a RxQueue by freeing all the related rxBufs.
279 vmxnet3_rxqueue_fini(vmxnet3_softc_t
*dp
, vmxnet3_rxqueue_t
*rxq
)
281 vmxnet3_rxbuf_t
*rxBuf
;
284 ASSERT(!dp
->devEnabled
);
286 /* First the rxPool */
287 while ((rxBuf
= vmxnet3_get_rxpool_buf(dp
)))
288 vmxnet3_free_rxbuf(dp
, rxBuf
);
291 for (i
= 0; i
< rxq
->cmdRing
.size
; i
++) {
292 rxBuf
= rxq
->bufRing
[i
].rxBuf
;
296 * Here, freemsg() will trigger a call to vmxnet3_put_rxbuf()
297 * which will then call vmxnet3_free_rxbuf() because the
298 * underlying device is disabled.
300 freemsg(rxBuf
->mblk
);
305 * Determine if a received packet was checksummed by the Vmxnet3
306 * device and tag the mp appropriately.
309 vmxnet3_rx_hwcksum(vmxnet3_softc_t
*dp
, mblk_t
*mp
,
310 Vmxnet3_GenericDesc
*compDesc
)
314 if (!compDesc
->rcd
.cnc
) {
315 if (compDesc
->rcd
.v4
&& compDesc
->rcd
.ipc
) {
316 flags
|= HCK_IPV4_HDRCKSUM
;
317 if ((compDesc
->rcd
.tcp
|| compDesc
->rcd
.udp
) &&
319 flags
|= HCK_FULLCKSUM
| HCK_FULLCKSUM_OK
;
323 VMXNET3_DEBUG(dp
, 3, "rx cksum flags = 0x%x\n", flags
);
325 (void) hcksum_assoc(mp
, NULL
, NULL
, 0, 0, 0, 0, flags
, 0);
330 * Interrupt handler for Rx. Look if there are any pending Rx and
331 * put them in mplist.
334 * A list of messages to pass to the MAC subystem.
337 vmxnet3_rx_intr(vmxnet3_softc_t
*dp
, vmxnet3_rxqueue_t
*rxq
)
339 vmxnet3_compring_t
*compRing
= &rxq
->compRing
;
340 vmxnet3_cmdring_t
*cmdRing
= &rxq
->cmdRing
;
341 Vmxnet3_RxQueueCtrl
*rxqCtrl
= rxq
->sharedCtrl
;
342 Vmxnet3_GenericDesc
*compDesc
;
343 mblk_t
*mplist
= NULL
, **mplistTail
= &mplist
;
345 ASSERT(mutex_owned(&dp
->intrLock
));
347 compDesc
= VMXNET3_GET_DESC(compRing
, compRing
->next2comp
);
348 while (compDesc
->rcd
.gen
== compRing
->gen
) {
349 mblk_t
*mp
= NULL
, **mpTail
= &mp
;
350 boolean_t mpValid
= B_TRUE
;
353 ASSERT(compDesc
->rcd
.sop
);
356 uint16_t rxdIdx
= compDesc
->rcd
.rxdIdx
;
357 vmxnet3_rxbuf_t
*rxBuf
= rxq
->bufRing
[rxdIdx
].rxBuf
;
358 mblk_t
*mblk
= rxBuf
->mblk
;
359 Vmxnet3_GenericDesc
*rxDesc
;
361 while (compDesc
->rcd
.gen
!= compRing
->gen
) {
363 * H/W may be still be in the middle of
364 * generating this entry, so hold on until
365 * the gen bit is flipped.
369 ASSERT(compDesc
->rcd
.gen
== compRing
->gen
);
373 /* Some Rx descriptors may have been skipped */
374 while (cmdRing
->next2fill
!= rxdIdx
) {
375 rxDesc
= VMXNET3_GET_DESC(cmdRing
,
377 rxDesc
->rxd
.gen
= cmdRing
->gen
;
378 VMXNET3_INC_RING_IDX(cmdRing
,
382 eop
= compDesc
->rcd
.eop
;
385 * Now we have a piece of the packet in the rxdIdx
386 * descriptor. Grab it only if we achieve to replace
387 * it with a fresh buffer.
389 if (vmxnet3_rx_populate(dp
, rxq
, rxdIdx
, B_FALSE
,
391 /* Success, we can chain the mblk with the mp */
392 mblk
->b_wptr
= mblk
->b_rptr
+ compDesc
->rcd
.len
;
394 mpTail
= &mblk
->b_cont
;
395 ASSERT(*mpTail
== NULL
);
397 VMXNET3_DEBUG(dp
, 3, "rx 0x%p on [%u]\n", mblk
,
401 if (!compDesc
->rcd
.err
) {
403 * Tag the mp if it was
404 * checksummed by the H/W
406 vmxnet3_rx_hwcksum(dp
, mp
,
414 * Keep the same buffer, we still need
415 * to flip the gen bit
417 rxDesc
= VMXNET3_GET_DESC(cmdRing
, rxdIdx
);
418 rxDesc
->rxd
.gen
= cmdRing
->gen
;
422 VMXNET3_INC_RING_IDX(compRing
, compRing
->next2comp
);
423 VMXNET3_INC_RING_IDX(cmdRing
, cmdRing
->next2fill
);
424 compDesc
= VMXNET3_GET_DESC(compRing
,
425 compRing
->next2comp
);
431 mplistTail
= &mp
->b_next
;
432 ASSERT(*mplistTail
== NULL
);
434 /* This message got holes, drop it */
440 if (rxqCtrl
->updateRxProd
) {
444 * All buffers are actually available, but we can't tell that to
445 * the device because it may interpret that as an empty ring.
446 * So skip one buffer.
448 if (cmdRing
->next2fill
) {
449 rxprod
= cmdRing
->next2fill
- 1;
451 rxprod
= cmdRing
->size
- 1;
453 VMXNET3_BAR0_PUT32(dp
, VMXNET3_REG_RXPROD
, rxprod
);