Index: sys/dev/vnic/nicvf_queues.c =================================================================== --- sys/dev/vnic/nicvf_queues.c +++ sys/dev/vnic/nicvf_queues.c @@ -301,8 +301,26 @@ /* Now retrieve mbuf to give to stack */ mbuf = rinfo->mbuf; if (__predict_false(mbuf == NULL)) { - panic("%s: Received packet fragment with NULL mbuf", - device_get_nameunit(nic->dev)); + /* + * XXX: Workaround for the rare condition when the descriptor + * (for the secondary fragment) obtained from HW points + * to an empty slot. + * Normally the Rx Completion Queue descriptor (CQE_RX_S) + * encodes the number of Receive Buffers (RB) that was + * used to receive the packet. Pointers to those + * bufferds should be placed in memory after the CQE_RX_S. + * Part of the received buffer is used by the system to + * provide buffer information such as DMA map, mbuf + * pointer, etc. When the mbuf pointer is empty it is + * assumed that the buffer comes from the used pool and + * needs to be refilled. Hardware should not fetch those + * buffers as the HEAD pointer for the RBDR pool should + * always point to the valid (free) buffer with the + * underlying mbuf. Otherwise we just drop the packet + * instead of calling panic(). + */ + if (rinfo->dmat != NULL && rinfo->dmap != NULL) + bus_dmamap_unload(rinfo->dmat, rinfo->dmap); } /* * Clear the mbuf in the descriptor to indicate @@ -1789,12 +1807,23 @@ /* First fragment */ mbuf = nicvf_rb_ptr_to_mbuf(nic, (*rb_ptrs - cqe_rx->align_pad)); + if (mbuf == NULL) + break; mbuf->m_len = payload_len; mbuf->m_data += cqe_rx->align_pad; if_setrcvif(mbuf, nic->ifp); } else { /* Add fragments */ mbuf_frag = nicvf_rb_ptr_to_mbuf(nic, *rb_ptrs); + /* + * XXX: If the packet fragment is broken just drop + * it here. + */ + if (mbuf_frag == NULL) { + m_freem(mbuf); + mbuf = NULL; + break; + } m_append(mbuf, payload_len, mbuf_frag->m_data); m_freem(mbuf_frag); }