Commit 63bb50bd authored by Rob Rice's avatar Rob Rice Committed by Jassi Brar

mailbox: bcm-pdc: Performance improvements

Three changes to improve performance in the PDC driver:
- disable and reenable interrupts while the interrupt handler is
running
- update rxin and txin descriptor indexes more efficiently
- group receive descriptor context into a structure and keep
context in a single array rather than five to improve locality
of reference
Signed-off-by: default avatarRob Rice <rob.rice@broadcom.com>
Reviewed-by: default avatarAndy Gospodarek <gospo@broadcom.com>
Signed-off-by: default avatarJassi Brar <jaswinder.singh@linaro.org>
parent 38ed49ed
...@@ -260,6 +260,27 @@ struct pdc_ring_alloc { ...@@ -260,6 +260,27 @@ struct pdc_ring_alloc {
u32 size; /* ring allocation size in bytes */ u32 size; /* ring allocation size in bytes */
}; };
/*
* context associated with a receive descriptor.
* @rxp_ctx: opaque context associated with frame that starts at each
* rx ring index.
* @dst_sg: Scatterlist used to form reply frames beginning at a given ring
* index. Retained in order to unmap each sg after reply is processed.
* @rxin_numd: Number of rx descriptors associated with the message that starts
* at a descriptor index. Not set for every index. For example,
* if descriptor index i points to a scatterlist with 4 entries,
* then the next three descriptor indexes don't have a value set.
* @resp_hdr: Virtual address of buffer used to catch DMA rx status
* @resp_hdr_daddr: physical address of DMA rx status buffer
*/
struct pdc_rx_ctx {
void *rxp_ctx;
struct scatterlist *dst_sg;
u32 rxin_numd;
void *resp_hdr;
dma_addr_t resp_hdr_daddr;
};
/* PDC state structure */ /* PDC state structure */
struct pdc_state { struct pdc_state {
/* Index of the PDC whose state is in this structure instance */ /* Index of the PDC whose state is in this structure instance */
...@@ -377,11 +398,7 @@ struct pdc_state { ...@@ -377,11 +398,7 @@ struct pdc_state {
/* Index of next rx descriptor to post. */ /* Index of next rx descriptor to post. */
u32 rxout; u32 rxout;
/* struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES];
* opaque context associated with frame that starts at each
* rx ring index.
*/
void *rxp_ctx[PDC_RING_ENTRIES];
/* /*
* Scatterlists used to form request and reply frames beginning at a * Scatterlists used to form request and reply frames beginning at a
...@@ -389,18 +406,6 @@ struct pdc_state { ...@@ -389,18 +406,6 @@ struct pdc_state {
* is processed * is processed
*/ */
struct scatterlist *src_sg[PDC_RING_ENTRIES]; struct scatterlist *src_sg[PDC_RING_ENTRIES];
struct scatterlist *dst_sg[PDC_RING_ENTRIES];
/*
* Number of rx descriptors associated with the message that starts
* at this descriptor index. Not set for every index. For example,
* if descriptor index i points to a scatterlist with 4 entries, then
* the next three descriptor indexes don't have a value set.
*/
u32 rxin_numd[PDC_RING_ENTRIES];
void *resp_hdr[PDC_RING_ENTRIES];
dma_addr_t resp_hdr_daddr[PDC_RING_ENTRIES];
struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ struct dentry *debugfs_stats; /* debug FS stats file for this PDC */
...@@ -591,11 +596,11 @@ pdc_receive_one(struct pdc_state *pdcs) ...@@ -591,11 +596,11 @@ pdc_receive_one(struct pdc_state *pdcs)
struct brcm_message mssg; struct brcm_message mssg;
u32 len, rx_status; u32 len, rx_status;
u32 num_frags; u32 num_frags;
int i;
u8 *resp_hdr; /* virtual addr of start of resp message DMA header */ u8 *resp_hdr; /* virtual addr of start of resp message DMA header */
u32 frags_rdy; /* number of fragments ready to read */ u32 frags_rdy; /* number of fragments ready to read */
u32 rx_idx; /* ring index of start of receive frame */ u32 rx_idx; /* ring index of start of receive frame */
dma_addr_t resp_hdr_daddr; dma_addr_t resp_hdr_daddr;
struct pdc_rx_ctx *rx_ctx;
mbc = &pdcs->mbc; mbc = &pdcs->mbc;
chan = &mbc->chans[0]; chan = &mbc->chans[0];
...@@ -607,7 +612,8 @@ pdc_receive_one(struct pdc_state *pdcs) ...@@ -607,7 +612,8 @@ pdc_receive_one(struct pdc_state *pdcs)
* to read. * to read.
*/ */
frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost); frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost);
if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) if ((frags_rdy == 0) ||
(frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd))
/* No response ready */ /* No response ready */
return -EAGAIN; return -EAGAIN;
...@@ -617,24 +623,23 @@ pdc_receive_one(struct pdc_state *pdcs) ...@@ -617,24 +623,23 @@ pdc_receive_one(struct pdc_state *pdcs)
dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin],
sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE);
for (i = 0; i < num_frags; i++) pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost;
pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost);
dev_dbg(dev, "PDC %u reclaimed %d tx descriptors", dev_dbg(dev, "PDC %u reclaimed %d tx descriptors",
pdcs->pdc_idx, num_frags); pdcs->pdc_idx, num_frags);
rx_idx = pdcs->rxin; rx_idx = pdcs->rxin;
num_frags = pdcs->rxin_numd[rx_idx]; rx_ctx = &pdcs->rx_ctx[rx_idx];
num_frags = rx_ctx->rxin_numd;
/* Return opaque context with result */ /* Return opaque context with result */
mssg.ctx = pdcs->rxp_ctx[rx_idx]; mssg.ctx = rx_ctx->rxp_ctx;
pdcs->rxp_ctx[rx_idx] = NULL; rx_ctx->rxp_ctx = NULL;
resp_hdr = pdcs->resp_hdr[rx_idx]; resp_hdr = rx_ctx->resp_hdr;
resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx]; resp_hdr_daddr = rx_ctx->resp_hdr_daddr;
dma_unmap_sg(dev, pdcs->dst_sg[rx_idx], dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg),
sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE); DMA_FROM_DEVICE);
for (i = 0; i < num_frags; i++) pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost;
pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost);
dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", dev_dbg(dev, "PDC %u reclaimed %d rx descriptors",
pdcs->pdc_idx, num_frags); pdcs->pdc_idx, num_frags);
...@@ -826,6 +831,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, ...@@ -826,6 +831,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
u32 rx_pkt_cnt = 1; /* Adding a single rx buffer */ u32 rx_pkt_cnt = 1; /* Adding a single rx buffer */
dma_addr_t daddr; dma_addr_t daddr;
void *vaddr; void *vaddr;
struct pdc_rx_ctx *rx_ctx;
rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
pdcs->nrxpost); pdcs->nrxpost);
...@@ -849,15 +855,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, ...@@ -849,15 +855,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
/* This is always the first descriptor in the receive sequence */ /* This is always the first descriptor in the receive sequence */
flags = D64_CTRL1_SOF; flags = D64_CTRL1_SOF;
pdcs->rxin_numd[pdcs->rx_msg_start] = 1; pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1;
if (unlikely(pdcs->rxout == (pdcs->nrxd - 1))) if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
flags |= D64_CTRL1_EOT; flags |= D64_CTRL1_EOT;
pdcs->rxp_ctx[pdcs->rxout] = ctx; rx_ctx = &pdcs->rx_ctx[pdcs->rxout];
pdcs->dst_sg[pdcs->rxout] = dst_sg; rx_ctx->rxp_ctx = ctx;
pdcs->resp_hdr[pdcs->rxout] = vaddr; rx_ctx->dst_sg = dst_sg;
pdcs->resp_hdr_daddr[pdcs->rxout] = daddr; rx_ctx->resp_hdr = vaddr;
rx_ctx->resp_hdr_daddr = daddr;
pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags); pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags);
return PDC_SUCCESS; return PDC_SUCCESS;
} }
...@@ -925,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) ...@@ -925,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
desc_w++; desc_w++;
sg = sg_next(sg); sg = sg_next(sg);
} }
pdcs->rxin_numd[pdcs->rx_msg_start] += desc_w; pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w;
return PDC_SUCCESS; return PDC_SUCCESS;
} }
...@@ -954,6 +961,9 @@ static irqreturn_t pdc_irq_handler(int irq, void *data) ...@@ -954,6 +961,9 @@ static irqreturn_t pdc_irq_handler(int irq, void *data)
/* Clear interrupt flags in device */ /* Clear interrupt flags in device */
iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
/* Disable interrupts until soft handler runs */
iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
/* Wakeup IRQ thread */ /* Wakeup IRQ thread */
if (likely(pdcs && (irq == pdcs->pdc_irq) && if (likely(pdcs && (irq == pdcs->pdc_irq) &&
(intstatus & PDC_INTMASK))) { (intstatus & PDC_INTMASK))) {
...@@ -971,6 +981,9 @@ static void pdc_tasklet_cb(unsigned long data) ...@@ -971,6 +981,9 @@ static void pdc_tasklet_cb(unsigned long data)
rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus);
if (likely(pdcs && rx_int)) if (likely(pdcs && rx_int))
pdc_receive(pdcs); pdc_receive(pdcs);
/* reenable interrupts */
iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment