diff options
author | Rob Rice <rob.rice@broadcom.com> | 2016-11-14 13:26:03 -0500 |
---|---|---|
committer | Jassi Brar <jaswinder.singh@linaro.org> | 2016-12-19 09:40:22 -0500 |
commit | 63bb50bdb997f4bede1b5f2d56645f393f7f39fb (patch) | |
tree | a9dc04c94d42199070b742e050db30d624c8e170 | |
parent | 38ed49ed4a99942f1a340f4a82a5a8b492e3463b (diff) |
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: Rob Rice <rob.rice@broadcom.com>
Reviewed-by: Andy Gospodarek <gospo@broadcom.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r-- | drivers/mailbox/bcm-pdc-mailbox.c | 85 |
1 files changed, 49 insertions, 36 deletions
diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index e7dc1a227713..8c2aa7c9c27f 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c | |||
@@ -260,6 +260,27 @@ struct pdc_ring_alloc { | |||
260 | u32 size; /* ring allocation size in bytes */ | 260 | u32 size; /* ring allocation size in bytes */ |
261 | }; | 261 | }; |
262 | 262 | ||
263 | /* | ||
264 | * context associated with a receive descriptor. | ||
265 | * @rxp_ctx: opaque context associated with frame that starts at each | ||
266 | * rx ring index. | ||
267 | * @dst_sg: Scatterlist used to form reply frames beginning at a given ring | ||
268 | * index. Retained in order to unmap each sg after reply is processed. | ||
269 | * @rxin_numd: Number of rx descriptors associated with the message that starts | ||
270 | * at a descriptor index. Not set for every index. For example, | ||
271 | * if descriptor index i points to a scatterlist with 4 entries, | ||
272 | * then the next three descriptor indexes don't have a value set. | ||
273 | * @resp_hdr: Virtual address of buffer used to catch DMA rx status | ||
274 | * @resp_hdr_daddr: physical address of DMA rx status buffer | ||
275 | */ | ||
276 | struct pdc_rx_ctx { | ||
277 | void *rxp_ctx; | ||
278 | struct scatterlist *dst_sg; | ||
279 | u32 rxin_numd; | ||
280 | void *resp_hdr; | ||
281 | dma_addr_t resp_hdr_daddr; | ||
282 | }; | ||
283 | |||
263 | /* PDC state structure */ | 284 | /* PDC state structure */ |
264 | struct pdc_state { | 285 | struct pdc_state { |
265 | /* Index of the PDC whose state is in this structure instance */ | 286 | /* Index of the PDC whose state is in this structure instance */ |
@@ -377,11 +398,7 @@ struct pdc_state { | |||
377 | /* Index of next rx descriptor to post. */ | 398 | /* Index of next rx descriptor to post. */ |
378 | u32 rxout; | 399 | u32 rxout; |
379 | 400 | ||
380 | /* | 401 | struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES]; |
381 | * opaque context associated with frame that starts at each | ||
382 | * rx ring index. | ||
383 | */ | ||
384 | void *rxp_ctx[PDC_RING_ENTRIES]; | ||
385 | 402 | ||
386 | /* | 403 | /* |
387 | * Scatterlists used to form request and reply frames beginning at a | 404 | * Scatterlists used to form request and reply frames beginning at a |
@@ -389,18 +406,6 @@ struct pdc_state { | |||
389 | * is processed | 406 | * is processed |
390 | */ | 407 | */ |
391 | struct scatterlist *src_sg[PDC_RING_ENTRIES]; | 408 | struct scatterlist *src_sg[PDC_RING_ENTRIES]; |
392 | struct scatterlist *dst_sg[PDC_RING_ENTRIES]; | ||
393 | |||
394 | /* | ||
395 | * Number of rx descriptors associated with the message that starts | ||
396 | * at this descriptor index. Not set for every index. For example, | ||
397 | * if descriptor index i points to a scatterlist with 4 entries, then | ||
398 | * the next three descriptor indexes don't have a value set. | ||
399 | */ | ||
400 | u32 rxin_numd[PDC_RING_ENTRIES]; | ||
401 | |||
402 | void *resp_hdr[PDC_RING_ENTRIES]; | ||
403 | dma_addr_t resp_hdr_daddr[PDC_RING_ENTRIES]; | ||
404 | 409 | ||
405 | struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ | 410 | struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ |
406 | 411 | ||
@@ -591,11 +596,11 @@ pdc_receive_one(struct pdc_state *pdcs) | |||
591 | struct brcm_message mssg; | 596 | struct brcm_message mssg; |
592 | u32 len, rx_status; | 597 | u32 len, rx_status; |
593 | u32 num_frags; | 598 | u32 num_frags; |
594 | int i; | ||
595 | u8 *resp_hdr; /* virtual addr of start of resp message DMA header */ | 599 | u8 *resp_hdr; /* virtual addr of start of resp message DMA header */ |
596 | u32 frags_rdy; /* number of fragments ready to read */ | 600 | u32 frags_rdy; /* number of fragments ready to read */ |
597 | u32 rx_idx; /* ring index of start of receive frame */ | 601 | u32 rx_idx; /* ring index of start of receive frame */ |
598 | dma_addr_t resp_hdr_daddr; | 602 | dma_addr_t resp_hdr_daddr; |
603 | struct pdc_rx_ctx *rx_ctx; | ||
599 | 604 | ||
600 | mbc = &pdcs->mbc; | 605 | mbc = &pdcs->mbc; |
601 | chan = &mbc->chans[0]; | 606 | chan = &mbc->chans[0]; |
@@ -607,7 +612,8 @@ pdc_receive_one(struct pdc_state *pdcs) | |||
607 | * to read. | 612 | * to read. |
608 | */ | 613 | */ |
609 | frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost); | 614 | frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost); |
610 | if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) | 615 | if ((frags_rdy == 0) || |
616 | (frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd)) | ||
611 | /* No response ready */ | 617 | /* No response ready */ |
612 | return -EAGAIN; | 618 | return -EAGAIN; |
613 | 619 | ||
@@ -617,24 +623,23 @@ pdc_receive_one(struct pdc_state *pdcs) | |||
617 | dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], | 623 | dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], |
618 | sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); | 624 | sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); |
619 | 625 | ||
620 | for (i = 0; i < num_frags; i++) | 626 | pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost; |
621 | pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost); | ||
622 | 627 | ||
623 | dev_dbg(dev, "PDC %u reclaimed %d tx descriptors", | 628 | dev_dbg(dev, "PDC %u reclaimed %d tx descriptors", |
624 | pdcs->pdc_idx, num_frags); | 629 | pdcs->pdc_idx, num_frags); |
625 | 630 | ||
626 | rx_idx = pdcs->rxin; | 631 | rx_idx = pdcs->rxin; |
627 | num_frags = pdcs->rxin_numd[rx_idx]; | 632 | rx_ctx = &pdcs->rx_ctx[rx_idx]; |
633 | num_frags = rx_ctx->rxin_numd; | ||
628 | /* Return opaque context with result */ | 634 | /* Return opaque context with result */ |
629 | mssg.ctx = pdcs->rxp_ctx[rx_idx]; | 635 | mssg.ctx = rx_ctx->rxp_ctx; |
630 | pdcs->rxp_ctx[rx_idx] = NULL; | 636 | rx_ctx->rxp_ctx = NULL; |
631 | resp_hdr = pdcs->resp_hdr[rx_idx]; | 637 | resp_hdr = rx_ctx->resp_hdr; |
632 | resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx]; | 638 | resp_hdr_daddr = rx_ctx->resp_hdr_daddr; |
633 | dma_unmap_sg(dev, pdcs->dst_sg[rx_idx], | 639 | dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg), |
634 | sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE); | 640 | DMA_FROM_DEVICE); |
635 | 641 | ||
636 | for (i = 0; i < num_frags; i++) | 642 | pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost; |
637 | pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost); | ||
638 | 643 | ||
639 | dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", | 644 | dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", |
640 | pdcs->pdc_idx, num_frags); | 645 | pdcs->pdc_idx, num_frags); |
@@ -826,6 +831,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, | |||
826 | u32 rx_pkt_cnt = 1; /* Adding a single rx buffer */ | 831 | u32 rx_pkt_cnt = 1; /* Adding a single rx buffer */ |
827 | dma_addr_t daddr; | 832 | dma_addr_t daddr; |
828 | void *vaddr; | 833 | void *vaddr; |
834 | struct pdc_rx_ctx *rx_ctx; | ||
829 | 835 | ||
830 | rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, | 836 | rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, |
831 | pdcs->nrxpost); | 837 | pdcs->nrxpost); |
@@ -849,15 +855,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, | |||
849 | 855 | ||
850 | /* This is always the first descriptor in the receive sequence */ | 856 | /* This is always the first descriptor in the receive sequence */ |
851 | flags = D64_CTRL1_SOF; | 857 | flags = D64_CTRL1_SOF; |
852 | pdcs->rxin_numd[pdcs->rx_msg_start] = 1; | 858 | pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1; |
853 | 859 | ||
854 | if (unlikely(pdcs->rxout == (pdcs->nrxd - 1))) | 860 | if (unlikely(pdcs->rxout == (pdcs->nrxd - 1))) |
855 | flags |= D64_CTRL1_EOT; | 861 | flags |= D64_CTRL1_EOT; |
856 | 862 | ||
857 | pdcs->rxp_ctx[pdcs->rxout] = ctx; | 863 | rx_ctx = &pdcs->rx_ctx[pdcs->rxout]; |
858 | pdcs->dst_sg[pdcs->rxout] = dst_sg; | 864 | rx_ctx->rxp_ctx = ctx; |
859 | pdcs->resp_hdr[pdcs->rxout] = vaddr; | 865 | rx_ctx->dst_sg = dst_sg; |
860 | pdcs->resp_hdr_daddr[pdcs->rxout] = daddr; | 866 | rx_ctx->resp_hdr = vaddr; |
867 | rx_ctx->resp_hdr_daddr = daddr; | ||
861 | pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags); | 868 | pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags); |
862 | return PDC_SUCCESS; | 869 | return PDC_SUCCESS; |
863 | } | 870 | } |
@@ -925,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) | |||
925 | desc_w++; | 932 | desc_w++; |
926 | sg = sg_next(sg); | 933 | sg = sg_next(sg); |
927 | } | 934 | } |
928 | pdcs->rxin_numd[pdcs->rx_msg_start] += desc_w; | 935 | pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w; |
929 | 936 | ||
930 | return PDC_SUCCESS; | 937 | return PDC_SUCCESS; |
931 | } | 938 | } |
@@ -954,6 +961,9 @@ static irqreturn_t pdc_irq_handler(int irq, void *data) | |||
954 | /* Clear interrupt flags in device */ | 961 | /* Clear interrupt flags in device */ |
955 | iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); | 962 | iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); |
956 | 963 | ||
964 | /* Disable interrupts until soft handler runs */ | ||
965 | iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); | ||
966 | |||
957 | /* Wakeup IRQ thread */ | 967 | /* Wakeup IRQ thread */ |
958 | if (likely(pdcs && (irq == pdcs->pdc_irq) && | 968 | if (likely(pdcs && (irq == pdcs->pdc_irq) && |
959 | (intstatus & PDC_INTMASK))) { | 969 | (intstatus & PDC_INTMASK))) { |
@@ -971,6 +981,9 @@ static void pdc_tasklet_cb(unsigned long data) | |||
971 | rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); | 981 | rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); |
972 | if (likely(pdcs && rx_int)) | 982 | if (likely(pdcs && rx_int)) |
973 | pdc_receive(pdcs); | 983 | pdc_receive(pdcs); |
984 | |||
985 | /* reenable interrupts */ | ||
986 | iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); | ||
974 | } | 987 | } |
975 | 988 | ||
976 | /** | 989 | /** |