QTAILQ_FOREACH_SAFE(req, &cq->req_list, entry, next)
{
+ if (ufs_mcq_cq_full(u, cq->cqid)) {
+ break;
+ }
+
ufs_dma_write_rsp_upiu(req);
/* UTRD/CQE are LE; round-trip through host to keep BE correct. */
tail = (tail + sizeof(req->cqe)) % (cq->size * sizeof(req->cqe));
ufs_mcq_update_cq_tail(u, cq->cqid, tail);
+ if (QTAILQ_EMPTY(&req->sq->req_list) &&
+ !ufs_mcq_sq_empty(u, req->sq->sqid)) {
+ /* Dequeueing from SQ was blocked due to lack of free requests */
+ qemu_bh_schedule(req->sq->bh);
+ }
+
ufs_clear_req(req);
QTAILQ_INSERT_TAIL(&req->sq->req_list, req, entry);
}
}
opr->sq.tp = data;
break;
- case offsetof(UfsMcqOpReg, cq.hp):
+ case offsetof(UfsMcqOpReg, cq.hp): {
+ UfsCq *cq = u->cq[qid];
+
+ if (ufs_mcq_cq_full(u, qid) && !QTAILQ_EMPTY(&cq->req_list)) {
+ /* Enqueueing to CQ was blocked because it was full */
+ qemu_bh_schedule(cq->bh);
+ }
+
opr->cq.hp = data;
ufs_mcq_update_cq_head(u, qid, data);
break;
+ }
case offsetof(UfsMcqOpReg, cq_int.is):
opr->cq_int.is &= ~data;
break;
return ufs_mcq_cq_tail(u, qid) == ufs_mcq_cq_head(u, qid);
}
+static inline bool ufs_mcq_cq_full(UfsHc *u, uint32_t qid)
+{
+ uint32_t tail = ufs_mcq_cq_tail(u, qid);
+ uint16_t cq_size = u->cq[qid]->size;
+
+ tail = (tail + sizeof(UfsCqEntry)) % (sizeof(UfsCqEntry) * cq_size);
+ return tail == ufs_mcq_cq_head(u, qid);
+}
+
#define TYPE_UFS "ufs"
#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)