in bcm-flexrm-mailbox.c [1084:1160]
static int flexrm_process_completions(struct flexrm_ring *ring)
{
u64 desc;
int err, count = 0;
unsigned long flags;
struct brcm_message *msg = NULL;
u32 reqid, cmpl_read_offset, cmpl_write_offset;
struct mbox_chan *chan = &ring->mbox->controller.chans[ring->num];
spin_lock_irqsave(&ring->lock, flags);
/*
* Get current completion read and write offset
*
* Note: We should read completion write pointer at least once
* after we get a MSI interrupt because HW maintains internal
* MSI status which will allow next MSI interrupt only after
* completion write pointer is read.
*/
cmpl_write_offset = readl_relaxed(ring->regs + RING_CMPL_WRITE_PTR);
cmpl_write_offset *= RING_DESC_SIZE;
cmpl_read_offset = ring->cmpl_read_offset;
ring->cmpl_read_offset = cmpl_write_offset;
spin_unlock_irqrestore(&ring->lock, flags);
/* For each completed request notify mailbox clients */
reqid = 0;
while (cmpl_read_offset != cmpl_write_offset) {
/* Dequeue next completion descriptor */
desc = *((u64 *)(ring->cmpl_base + cmpl_read_offset));
/* Next read offset */
cmpl_read_offset += RING_DESC_SIZE;
if (cmpl_read_offset == RING_CMPL_SIZE)
cmpl_read_offset = 0;
/* Decode error from completion descriptor */
err = flexrm_cmpl_desc_to_error(desc);
if (err < 0) {
dev_warn(ring->mbox->dev,
"ring%d got completion desc=0x%lx with error %d\n",
ring->num, (unsigned long)desc, err);
}
/* Determine request id from completion descriptor */
reqid = flexrm_cmpl_desc_to_reqid(desc);
/* Determine message pointer based on reqid */
msg = ring->requests[reqid];
if (!msg) {
dev_warn(ring->mbox->dev,
"ring%d null msg pointer for completion desc=0x%lx\n",
ring->num, (unsigned long)desc);
continue;
}
/* Release reqid for recycling */
ring->requests[reqid] = NULL;
spin_lock_irqsave(&ring->lock, flags);
bitmap_release_region(ring->requests_bmap, reqid, 0);
spin_unlock_irqrestore(&ring->lock, flags);
/* Unmap DMA mappings */
flexrm_dma_unmap(ring->mbox->dev, msg);
/* Give-back message to mailbox client */
msg->error = err;
mbox_chan_received_data(chan, msg);
/* Increment number of completions processed */
atomic_inc_return(&ring->msg_cmpl_count);
count++;
}
return count;
}