Fix deadlock in VNIC when using single CPU only

Number of free Tx descriptors does not need to be locked since
it can be modified atomically between SND and CQ tasks.
It will also block Tx routine from sending packets while CQ will not
be able to free descriptors.

Obtained from:	Semihalf
Sponsored by:	Cavium
Differential Revision: https://reviews.freebsd.org/D6266
This commit is contained in:
Zbigniew Bodek 2016-05-11 13:38:29 +00:00
parent 46542fb652
commit f6cdb4ceb3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=299446

View File

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/sockio.h>
#include <sys/socket.h>
#include <sys/stdatomic.h>
#include <sys/cpuset.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@ -691,7 +692,7 @@ nicvf_rcv_pkt_handler(struct nicvf *nic, struct cmp_queue *cq,
return (0);
}
static int
static void
nicvf_snd_pkt_handler(struct nicvf *nic, struct cmp_queue *cq,
struct cqe_send_t *cqe_tx, int cqe_type)
{
@ -702,15 +703,10 @@ nicvf_snd_pkt_handler(struct nicvf *nic, struct cmp_queue *cq,
mbuf = NULL;
sq = &nic->qs->sq[cqe_tx->sq_idx];
/* Avoid blocking here since we hold a non-sleepable NICVF_CMP_LOCK */
if (NICVF_TX_TRYLOCK(sq) == 0)
return (EAGAIN);
hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr);
if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) {
NICVF_TX_UNLOCK(sq);
return (0);
}
if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER)
return;
dprintf(nic->dev,
"%s Qset #%d SQ #%d SQ ptr #%d subdesc count %d\n",
@ -728,9 +724,6 @@ nicvf_snd_pkt_handler(struct nicvf *nic, struct cmp_queue *cq,
}
nicvf_check_cqe_tx_errs(nic, cq, cqe_tx);
NICVF_TX_UNLOCK(sq);
return (0);
}
static int
@ -788,16 +781,8 @@ nicvf_cq_intr_handler(struct nicvf *nic, uint8_t cq_idx)
work_done++;
break;
case CQE_TYPE_SEND:
cmp_err = nicvf_snd_pkt_handler(nic, cq,
(void *)cq_desc, CQE_TYPE_SEND);
if (__predict_false(cmp_err != 0)) {
/*
* Ups. Cannot finish now.
* Let's try again later.
*/
goto done;
}
nicvf_snd_pkt_handler(nic, cq, (void *)cq_desc,
CQE_TYPE_SEND);
tx_done++;
break;
case CQE_TYPE_INVALID:
@ -1085,7 +1070,7 @@ nicvf_init_snd_queue(struct nicvf *nic, struct snd_queue *sq, int q_len,
sq->desc = sq->dmem.base;
sq->head = sq->tail = 0;
sq->free_cnt = q_len - 1;
atomic_store_rel_int(&sq->free_cnt, q_len - 1);
sq->thresh = SND_QUEUE_THRESH;
sq->idx = qidx;
sq->nic = nic;
@ -1676,7 +1661,7 @@ nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt)
int qentry;
qentry = sq->tail;
sq->free_cnt -= desc_cnt;
atomic_subtract_int(&sq->free_cnt, desc_cnt);
sq->tail += desc_cnt;
sq->tail &= (sq->dmem.q_len - 1);
@ -1688,7 +1673,7 @@ static void
nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt)
{
sq->free_cnt += desc_cnt;
atomic_add_int(&sq->free_cnt, desc_cnt);
sq->head += desc_cnt;
sq->head &= (sq->dmem.q_len - 1);
}