From f42cce3c2409960adebe8e970574b23cbbf34e7d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 20 Oct 2016 00:34:04 -0300 Subject: mailbox: mailbox-test: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mailbox/mailbox-test.ko | grep alias $ After this patch: $ modinfo drivers/mailbox/mailbox-test.ko | grep alias alias: of:N*T*Cmailbox-testC* alias: of:N*T*Cmailbox-test Signed-off-by: Javier Martinez Canillas Acked-by: Lee Jones Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 9ca96e9db6bf..deb9c61aebb4 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -357,6 +357,7 @@ static const struct of_device_id mbox_test_match[] = { { .compatible = "mailbox-test" }, {}, }; +MODULE_DEVICE_TABLE(of, mbox_test_match); static struct platform_driver mbox_test_driver = { .driver = { -- cgit v1.2.3 From 2f50497d71e2982584d1a11d636d43eea0f992e6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 20 Oct 2016 00:34:05 -0300 Subject: mailbox: sti: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mailbox/mailbox-sti.ko | grep alias alias: platform:mailbox-sti After this patch: $ modinfo drivers/mailbox/mailbox-sti.ko | grep alias alias: platform:mailbox-sti alias: of:N*T*Cst,stih407-mailboxC* alias: of:N*T*Cst,stih407-mailbox Signed-off-by: Javier Martinez Canillas Acked-by: Lee Jones Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-sti.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c index a334db5c9f1c..41bcd339b68a 100644 --- a/drivers/mailbox/mailbox-sti.c +++ b/drivers/mailbox/mailbox-sti.c @@ -403,6 +403,7 @@ static const struct of_device_id sti_mailbox_match[] = { }, { } }; +MODULE_DEVICE_TABLE(of, sti_mailbox_match); static int sti_mbox_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 9b1b2b3adb310560a31ea248fa0defc8f09129ff Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:25:55 -0500 Subject: mailbox: bcm-pdc: Use octal permissions rather than symbolic When creating the debugfs files for the PDC driver, use octal file permissions rather than symbolic file permissions. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index c19dd820ea9b..a9c804fa3fbe 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -480,7 +480,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs) if (!debugfs_dir) debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, S_IRUSR, + /* S_IRUSR == 0400 */ + pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs, &pdc_debugfs_stats); } -- cgit v1.2.3 From 9fb0f9ac54b393ddfe49be7da7751f02bb133db6 Mon Sep 17 00:00:00 2001 From: Steve Lin Date: Mon, 14 Nov 2016 13:25:56 -0500 Subject: mailbox: bcm-pdc: Changes so mbox client can be removed / re-inserted Ensure that DMA is disabled, and pointers reset, when changing DMA base addresses in pdc_ring_init(). This allows a mailbox client to be re-inserted after being removed. Otherwise, the DMA doesn't restart so the client hangs while being reinserted. Signed-off-by: Steve Lin Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 54 +++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index a9c804fa3fbe..3b4ebbe81964 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -117,15 +117,16 @@ /* * Sets the following bits for write to transmit control reg: - * 0 - XmtEn - enable activity on the tx channel * 11 - PtyChkDisable - parity check is disabled * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory */ -#define PDC_TX_CTL 0x000C0801 +#define PDC_TX_CTL 0x000C0800 + +/* Bit in tx control reg to enable tx channel */ +#define PDC_TX_ENABLE 0x1 /* * Sets the following bits for write to receive control reg: - * 0 - RcvEn - enable activity on the rx channel * 7:1 - RcvOffset - size in bytes of status region at start of rx frame buf * 9 - SepRxHdrDescEn - place start of new frames only in descriptors * that have StartOfFrame set @@ -135,7 +136,10 @@ * 11 - PtyChkDisable - parity check is disabled * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory */ -#define PDC_RX_CTL 0x000C0E01 +#define PDC_RX_CTL 0x000C0E00 + +/* Bit in rx control reg to enable rx channel */ +#define PDC_RX_ENABLE 0x1 #define CRYPTO_D64_RS0_CD_MASK ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1) @@ -1054,6 +1058,15 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) /* Tell device the base DMA address of each ring */ dma_reg = &pdcs->regs->dmaregs[ringset]; + + /* But first disable DMA and set curptr to 0 for both TX & RX */ + iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); + iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)), + (void *)&dma_reg->dmarcv.control); + iowrite32(0, (void *)&dma_reg->dmaxmt.ptr); + iowrite32(0, (void *)&dma_reg->dmarcv.ptr); + + /* Set base DMA addresses */ iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase), (void *)&dma_reg->dmaxmt.addrlow); iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase), @@ -1064,6 +1077,11 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase), (void *)&dma_reg->dmarcv.addrhigh); + /* Re-enable DMA */ + iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control); + iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)), + (void *)&dma_reg->dmarcv.control); + /* Initialize descriptors */ for (i = 0; i < PDC_RING_ENTRIES; i++) { /* Every tx descriptor can be used for start of frame. */ @@ -1235,22 +1253,40 @@ void pdc_hw_init(struct pdc_state *pdcs) pdcs->nrxd = PDC_RING_ENTRIES; pdcs->ntxpost = PDC_RING_ENTRIES - 1; pdcs->nrxpost = PDC_RING_ENTRIES - 1; - pdcs->regs->intmask = 0; + iowrite32(0, &pdcs->regs->intmask); dma_reg = &pdcs->regs->dmaregs[ringset]; - iowrite32(0, (void *)&dma_reg->dmaxmt.ptr); - iowrite32(0, (void *)&dma_reg->dmarcv.ptr); - iowrite32(PDC_TX_CTL, (void *)&dma_reg->dmaxmt.control); + /* Configure DMA but will enable later in pdc_ring_init() */ + iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1), (void *)&dma_reg->dmarcv.control); + /* Reset current index pointers after making sure DMA is disabled */ + iowrite32(0, &dma_reg->dmaxmt.ptr); + iowrite32(0, &dma_reg->dmarcv.ptr); + if (pdcs->pdc_resp_hdr_len == PDC_SPU2_RESP_HDR_LEN) iowrite32(PDC_CKSUM_CTRL, pdcs->pdc_reg_vbase + PDC_CKSUM_CTRL_OFFSET); } +/** + * pdc_hw_disable() - Disable the tx and rx control in the hw. + * @pdcs: PDC state structure + * + */ +static void pdc_hw_disable(struct pdc_state *pdcs) +{ + struct dma64 *dma_reg; + + dma_reg = &pdcs->regs->dmaregs[PDC_RINGSET]; + iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); + iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1), + &dma_reg->dmarcv.control); +} + /** * pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata * header returned with each response message. @@ -1505,6 +1541,8 @@ static int pdc_remove(struct platform_device *pdev) pdc_free_debugfs(); + pdc_hw_disable(pdcs); + mbox_controller_unregister(&pdcs->mbc); dma_pool_destroy(pdcs->rx_buf_pool); -- cgit v1.2.3 From 9310f1ded44067b2da61fa0471ca5b7768dd28ae Mon Sep 17 00:00:00 2001 From: Steve Lin Date: Mon, 14 Nov 2016 13:25:57 -0500 Subject: mailbox: bcm-pdc: PDC driver leaves debugfs files after removal Minor fix to ensure that debugfs stats pseudo-files are removed when driver module is unloaded. Previously, the call to debugfs_remove_recursive() was never being called since the directory was not empty, and a seg fault would occur if another process tried to access these leftover files. Signed-off-by: Steve Lin Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 3b4ebbe81964..c9434a756bf3 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -492,10 +492,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs) static void pdc_free_debugfs(void) { - if (debugfs_dir && simple_empty(debugfs_dir)) { - debugfs_remove_recursive(debugfs_dir); - debugfs_dir = NULL; - } + debugfs_remove_recursive(debugfs_dir); + debugfs_dir = NULL; } /** -- cgit v1.2.3 From ab8d1b2d564f6649547b97e65806556c42f93a26 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:25:58 -0500 Subject: mailbox: bcm-pdc: Convert from interrupts to poll for tx done The PDC driver is a mailbox controller. A mailbox controller can report that a mailbox message has been "transmitted" either when a tx interrupt fires or by having the mailbox framework poll. This commit converts the PDC driver to the poll method. We found that the tx interrupt happens when the descriptors are read by the SPU hw. Thus, the interrupt method does not allow more than one tx message in the PDC tx DMA ring at a time. To keep the SPU hw busy, we would like to keep the tx ring full under heavy load. With the poll method, the PDC driver responds that the previous message has been transmitted if the tx ring has space for another message. SPU request messages take a variable number of descriptors. If 15 descriptors are available, there is a good chance another message will fit. Also increased the ring size from 128 to 512 descriptors. With this change, I found the PDC driver hangs on its spinlock under heavy load. The PDC spinlock is not required; so I removed it. Calls to pdc_send_data() are already synchronized because of the channel spinlock in the mailbox framework. Other references to ring indexes should not require locking because they only written on either the tx or rx side. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 207 ++++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 62 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index c9434a756bf3..fa3f484d3771 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -60,7 +60,13 @@ #define RING_ENTRY_SIZE sizeof(struct dma64dd) /* # entries in PDC dma ring */ -#define PDC_RING_ENTRIES 128 +#define PDC_RING_ENTRIES 512 +/* + * Minimum number of ring descriptor entries that must be free to tell mailbox + * framework that it can submit another request + */ +#define PDC_RING_SPACE_MIN 15 + #define PDC_RING_SIZE (PDC_RING_ENTRIES * RING_ENTRY_SIZE) /* Rings are 8k aligned */ #define RING_ALIGN_ORDER 13 @@ -93,11 +99,9 @@ * Interrupt mask and status definitions. Enable interrupts for tx and rx on * ring 0 */ -#define PDC_XMTINT_0 (24 + PDC_RINGSET) #define PDC_RCVINT_0 (16 + PDC_RINGSET) -#define PDC_XMTINTEN_0 BIT(PDC_XMTINT_0) #define PDC_RCVINTEN_0 BIT(PDC_RCVINT_0) -#define PDC_INTMASK (PDC_XMTINTEN_0 | PDC_RCVINTEN_0) +#define PDC_INTMASK (PDC_RCVINTEN_0) #define PDC_LAZY_FRAMECOUNT 1 #define PDC_LAZY_TIMEOUT 10000 #define PDC_LAZY_INT (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24)) @@ -258,9 +262,6 @@ struct pdc_ring_alloc { /* PDC state structure */ struct pdc_state { - /* synchronize access to this PDC state structure */ - spinlock_t pdc_lock; - /* Index of the PDC whose state is in this structure instance */ u8 pdc_idx; @@ -401,11 +402,14 @@ struct pdc_state { struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ /* counters */ - u32 pdc_requests; /* number of request messages submitted */ - u32 pdc_replies; /* number of reply messages received */ - u32 txnobuf; /* count of tx ring full */ - u32 rxnobuf; /* count of rx ring full */ - u32 rx_oflow; /* count of rx overflows */ + u32 pdc_requests; /* number of request messages submitted */ + u32 pdc_replies; /* number of reply messages received */ + u32 last_tx_not_done; /* too few tx descriptors to indicate done */ + u32 tx_ring_full; /* unable to accept msg because tx ring full */ + u32 rx_ring_full; /* unable to accept msg because rx ring full */ + u32 txnobuf; /* unable to create tx descriptor */ + u32 rxnobuf; /* unable to create rx descriptor */ + u32 rx_oflow; /* count of rx overflows */ }; /* Global variables */ @@ -438,20 +442,33 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf, out_offset += snprintf(buf + out_offset, out_count - out_offset, "SPU %u stats:\n", pdcs->pdc_idx); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "PDC requests............%u\n", + "PDC requests....................%u\n", pdcs->pdc_requests); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "PDC responses...........%u\n", + "PDC responses...................%u\n", pdcs->pdc_replies); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Tx err ring full........%u\n", + "Tx not done.....................%u\n", + pdcs->last_tx_not_done); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Tx ring full....................%u\n", + pdcs->tx_ring_full); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Rx ring full....................%u\n", + pdcs->rx_ring_full); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Tx desc write fail. Ring full...%u\n", pdcs->txnobuf); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Rx err ring full........%u\n", + "Rx desc write fail. Ring full...%u\n", pdcs->rxnobuf); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Receive overflow........%u\n", + "Receive overflow................%u\n", pdcs->rx_oflow); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Num frags in rx ring............%u\n", + NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, + pdcs->nrxpost)); if (out_offset > out_count) out_offset = out_count; @@ -582,8 +599,6 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) u32 rx_idx; /* ring index of start of receive frame */ dma_addr_t resp_hdr_daddr; - spin_lock(&pdcs->pdc_lock); - /* * return if a complete response message is not yet ready. * rxin_numd[rxin] is the number of fragments in the next msg @@ -600,7 +615,6 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) { /* No response ready */ - spin_unlock(&pdcs->pdc_lock); return -EAGAIN; } /* can't read descriptors/data until write index is read */ @@ -630,8 +644,6 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) for (i = 0; i < num_frags; i++) pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost); - spin_unlock(&pdcs->pdc_lock); - dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", pdcs->pdc_idx, num_frags); @@ -920,8 +932,6 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) struct pdc_state *pdcs = cookie; u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); - if (intstatus & PDC_XMTINTEN_0) - set_bit(PDC_XMTINT_0, &pdcs->intstatus); if (intstatus & PDC_RCVINTEN_0) set_bit(PDC_RCVINT_0, &pdcs->intstatus); @@ -953,45 +963,35 @@ static irqreturn_t pdc_irq_thread(int irq, void *cookie) struct pdc_state *pdcs = cookie; struct mbox_controller *mbc; struct mbox_chan *chan; - bool tx_int; bool rx_int; int rx_status; struct brcm_message mssg; - tx_int = test_and_clear_bit(PDC_XMTINT_0, &pdcs->intstatus); rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (pdcs && (tx_int || rx_int)) { + if (pdcs && rx_int) { dev_dbg(&pdcs->pdev->dev, - "%s() got irq %d with tx_int %s, rx_int %s", - __func__, irq, - tx_int ? "set" : "clear", rx_int ? "set" : "clear"); + "%s() got irq %d with rx_int %s", + __func__, irq, rx_int ? "set" : "clear"); mbc = &pdcs->mbc; chan = &mbc->chans[0]; - if (tx_int) { - dev_dbg(&pdcs->pdev->dev, "%s(): tx done", __func__); - /* only one frame in flight at a time */ - mbox_chan_txdone(chan, PDC_SUCCESS); - } - if (rx_int) { - while (1) { - /* Could be many frames ready */ - memset(&mssg, 0, sizeof(mssg)); - mssg.type = BRCM_MESSAGE_SPU; - rx_status = pdc_receive(pdcs, &mssg); - if (rx_status >= 0) { - dev_dbg(&pdcs->pdev->dev, - "%s(): invoking client rx cb", - __func__); - mbox_chan_received_data(chan, &mssg); - } else { - dev_dbg(&pdcs->pdev->dev, - "%s(): no SPU response available", - __func__); - break; - } + while (1) { + /* Could be many frames ready */ + memset(&mssg, 0, sizeof(mssg)); + mssg.type = BRCM_MESSAGE_SPU; + rx_status = pdc_receive(pdcs, &mssg); + if (rx_status >= 0) { + dev_dbg(&pdcs->pdev->dev, + "%s(): invoking client rx cb", + __func__); + mbox_chan_received_data(chan, &mssg); + } else { + dev_dbg(&pdcs->pdev->dev, + "%s(): no SPU response available", + __func__); + break; } } return IRQ_HANDLED; @@ -1036,9 +1036,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) dev_dbg(dev, " - base DMA addr of rx ring %pad", &rx.dmabase); dev_dbg(dev, " - base virtual addr of rx ring %p", rx.vbase); - /* lock after ring allocation to avoid scheduling while atomic */ - spin_lock(&pdcs->pdc_lock); - memcpy(&pdcs->tx_ring_alloc, &tx, sizeof(tx)); memcpy(&pdcs->rx_ring_alloc, &rx, sizeof(rx)); @@ -1103,7 +1100,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) (void *)&pdcs->rxd_64[i].ctrl1); } } - spin_unlock(&pdcs->pdc_lock); return PDC_SUCCESS; fail_dealloc: @@ -1127,6 +1123,80 @@ static void pdc_ring_free(struct pdc_state *pdcs) } } +/** + * pdc_desc_count() - Count the number of DMA descriptors that will be required + * for a given scatterlist. Account for the max length of a DMA buffer. + * @sg: Scatterlist to be DMA'd + * Return: Number of descriptors required + */ +static u32 pdc_desc_count(struct scatterlist *sg) +{ + u32 cnt = 0; + + while (sg) { + cnt += ((sg->length / PDC_DMA_BUF_MAX) + 1); + sg = sg_next(sg); + } + return cnt; +} + +/** + * pdc_rings_full() - Check whether the tx ring has room for tx_cnt descriptors + * and the rx ring has room for rx_cnt descriptors. + * @pdcs: PDC state + * @tx_cnt: The number of descriptors required in the tx ring + * @rx_cnt: The number of descriptors required i the rx ring + * + * Return: true if one of the rings does not have enough space + * false if sufficient space is available in both rings + */ +static bool pdc_rings_full(struct pdc_state *pdcs, int tx_cnt, int rx_cnt) +{ + u32 rx_avail; + u32 tx_avail; + bool full = false; + + /* Check if the tx and rx rings are likely to have enough space */ + rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, + pdcs->nrxpost); + if (unlikely(rx_cnt > rx_avail)) { + pdcs->rx_ring_full++; + full = true; + } + + if (likely(!full)) { + tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout, + pdcs->ntxpost); + if (unlikely(tx_cnt > tx_avail)) { + pdcs->tx_ring_full++; + full = true; + } + } + return full; +} + +/** + * pdc_last_tx_done() - If both the tx and rx rings have at least + * PDC_RING_SPACE_MIN descriptors available, then indicate that the mailbox + * framework can submit another message. + * @chan: mailbox channel to check + * Return: true if PDC can accept another message on this channel + */ +static bool pdc_last_tx_done(struct mbox_chan *chan) +{ + struct pdc_state *pdcs = chan->con_priv; + bool ret; + + if (unlikely(pdc_rings_full(pdcs, PDC_RING_SPACE_MIN, + PDC_RING_SPACE_MIN))) { + pdcs->last_tx_not_done++; + ret = false; + } else { + ret = true; + } + return ret; +} + /** * pdc_send_data() - mailbox send_data function * @chan: The mailbox channel on which the data is sent. The channel @@ -1158,6 +1228,8 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) int src_nent; int dst_nent; int nent; + u32 tx_desc_req; + u32 rx_desc_req; if (mssg->type != BRCM_MESSAGE_SPU) return -ENOTSUPP; @@ -1180,7 +1252,19 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) } } - spin_lock(&pdcs->pdc_lock); + /* + * Check if the tx and rx rings have enough space. Do this prior to + * writing any tx or rx descriptors. Need to ensure that we do not write + * a partial set of descriptors, or write just rx descriptors but + * corresponding tx descriptors don't fit. Note that we want this check + * and the entire sequence of descriptor to happen without another + * thread getting in. The channel spin lock in the mailbox framework + * ensures this. + */ + tx_desc_req = pdc_desc_count(mssg->spu.src); + rx_desc_req = pdc_desc_count(mssg->spu.dst); + if (pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)) + return -ENOSPC; /* Create rx descriptors to SPU catch response */ err = pdc_rx_list_init(pdcs, mssg->spu.dst, mssg->ctx); @@ -1190,8 +1274,6 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src); err |= pdc_tx_list_final(pdcs); /* initiate transfer */ - spin_unlock(&pdcs->pdc_lock); - if (err) dev_err(&pdcs->pdev->dev, "%s failed with error %d", __func__, err); @@ -1359,6 +1441,7 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) static const struct mbox_chan_ops pdc_mbox_chan_ops = { .send_data = pdc_send_data, + .last_tx_done = pdc_last_tx_done, .startup = pdc_startup, .shutdown = pdc_shutdown }; @@ -1391,8 +1474,9 @@ static int pdc_mb_init(struct pdc_state *pdcs) if (!mbc->chans) return -ENOMEM; - mbc->txdone_irq = true; - mbc->txdone_poll = false; + mbc->txdone_irq = false; + mbc->txdone_poll = true; + mbc->txpoll_period = 1; for (chan_index = 0; chan_index < mbc->num_chans; chan_index++) mbc->chans[chan_index].con_priv = pdcs; @@ -1462,7 +1546,6 @@ static int pdc_probe(struct platform_device *pdev) goto cleanup; } - spin_lock_init(&pdcs->pdc_lock); pdcs->pdev = pdev; platform_set_drvdata(pdev, pdcs); pdcs->pdc_idx = pdcg.num_spu; -- cgit v1.2.3 From e004c7e7d3b873a671fecf04f197982806e380eb Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:25:59 -0500 Subject: mailbox: bcm-pdc: streamline rx code Remove the unnecessary rmb() from the receive path. If the rx ring has multiple messages ready, avoid reading last_rx_curr multiple times from the register. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 108 +++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 60 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index fa3f484d3771..21957609ea91 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -570,27 +570,23 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len, } /** - * pdc_receive() - Receive a response message from a given SPU. + * pdc_receive_one() - Receive a response message from a given SPU. * @pdcs: PDC state for the SPU to receive from - * @mssg: mailbox message to be returned to client * * When the return code indicates success, the response message is available in * the receive buffers provided prior to submission of the request. * - * Input: - * pdcs - PDC state structure for the SPU to be polled - * mssg - mailbox message to be returned to client. This function sets the - * context pointer on the message to help the client associate the - * response with a request. - * * Return: PDC_SUCCESS if one or more receive descriptors was processed * -EAGAIN indicates that no response message is available * -EIO an error occurred */ static int -pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) +pdc_receive_one(struct pdc_state *pdcs) { struct device *dev = &pdcs->pdev->dev; + struct mbox_controller *mbc; + struct mbox_chan *chan; + struct brcm_message mssg; u32 len, rx_status; u32 num_frags; int i; @@ -599,29 +595,23 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) u32 rx_idx; /* ring index of start of receive frame */ dma_addr_t resp_hdr_daddr; + mbc = &pdcs->mbc; + chan = &mbc->chans[0]; + mssg.type = BRCM_MESSAGE_SPU; + /* * return if a complete response message is not yet ready. * rxin_numd[rxin] is the number of fragments in the next msg * to read. */ frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost); - if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) { - /* See if the hw has written more fragments than we know */ - pdcs->last_rx_curr = - (ioread32((void *)&pdcs->rxregs_64->status0) & - CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE; - frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, - pdcs->nrxpost); - if ((frags_rdy == 0) || - (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) { - /* No response ready */ - return -EAGAIN; - } - /* can't read descriptors/data until write index is read */ - rmb(); - } + if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) + /* No response ready */ + return -EAGAIN; num_frags = pdcs->txin_numd[pdcs->txin]; + WARN_ON(num_frags == 0); + dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); @@ -634,7 +624,7 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) rx_idx = pdcs->rxin; num_frags = pdcs->rxin_numd[rx_idx]; /* Return opaque context with result */ - mssg->ctx = pdcs->rxp_ctx[rx_idx]; + mssg.ctx = pdcs->rxp_ctx[rx_idx]; pdcs->rxp_ctx[rx_idx] = NULL; resp_hdr = pdcs->resp_hdr[rx_idx]; resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx]; @@ -674,12 +664,35 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) dma_pool_free(pdcs->rx_buf_pool, resp_hdr, resp_hdr_daddr); + mbox_chan_received_data(chan, &mssg); + pdcs->pdc_replies++; - /* if we read one or more rx descriptors, claim success */ - if (num_frags > 0) - return PDC_SUCCESS; - else - return -EIO; + return PDC_SUCCESS; +} + +/** + * pdc_receive() - Process as many responses as are available in the rx ring. + * @pdcs: PDC state + * + * Called within the hard IRQ. + * Return: + */ +static int +pdc_receive(struct pdc_state *pdcs) +{ + int rx_status; + + /* read last_rx_curr from register once */ + pdcs->last_rx_curr = + (ioread32((void *)&pdcs->rxregs_64->status0) & + CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE; + + do { + /* Could be many frames ready */ + rx_status = pdc_receive_one(pdcs); + } while (rx_status == PDC_SUCCESS); + + return 0; } /** @@ -946,14 +959,13 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) } /** - * pdc_irq_thread() - Function invoked on deferred thread when a DMA tx has - * completed or data is available to receive. + * pdc_irq_thread() - Function invoked on deferred thread when data is available + * to receive. * @irq: Interrupt number * @cookie: PDC state for PDC that generated the interrupt * - * On DMA tx complete, notify the mailbox client. On DMA rx complete, process - * as many SPU response messages as are available and send each to the mailbox - * client. + * On DMA rx complete, process as many SPU response messages as are available + * and send each to the mailbox client. * * Return: IRQ_HANDLED if we recognized and handled the interrupt * IRQ_NONE otherwise @@ -961,39 +973,15 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) static irqreturn_t pdc_irq_thread(int irq, void *cookie) { struct pdc_state *pdcs = cookie; - struct mbox_controller *mbc; - struct mbox_chan *chan; bool rx_int; - int rx_status; - struct brcm_message mssg; rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (pdcs && rx_int) { dev_dbg(&pdcs->pdev->dev, "%s() got irq %d with rx_int %s", __func__, irq, rx_int ? "set" : "clear"); - mbc = &pdcs->mbc; - chan = &mbc->chans[0]; - - while (1) { - /* Could be many frames ready */ - memset(&mssg, 0, sizeof(mssg)); - mssg.type = BRCM_MESSAGE_SPU; - rx_status = pdc_receive(pdcs, &mssg); - if (rx_status >= 0) { - dev_dbg(&pdcs->pdev->dev, - "%s(): invoking client rx cb", - __func__); - mbox_chan_received_data(chan, &mssg); - } else { - dev_dbg(&pdcs->pdev->dev, - "%s(): no SPU response available", - __func__); - break; - } - } + pdc_receive(pdcs); return IRQ_HANDLED; } return IRQ_NONE; -- cgit v1.2.3 From 7493cde34efc28641c295ee0d52ab9d790853c62 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:00 -0500 Subject: mailbox: bcm-pdc: Try to improve branch prediction Use likely/unlikely directives to improve branch prediction. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 21957609ea91..7ed3f0247cb8 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -834,7 +834,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, /* allocate a buffer for the dma rx status */ vaddr = dma_pool_zalloc(pdcs->rx_buf_pool, GFP_ATOMIC, &daddr); - if (!vaddr) + if (unlikely(!vaddr)) return -ENOMEM; /* @@ -945,14 +945,14 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) struct pdc_state *pdcs = cookie; u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); - if (intstatus & PDC_RCVINTEN_0) + if (likely(intstatus & PDC_RCVINTEN_0)) set_bit(PDC_RCVINT_0, &pdcs->intstatus); /* Clear interrupt flags in device */ iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); /* Wakeup IRQ thread */ - if (pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK)) + if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) return IRQ_WAKE_THREAD; return IRQ_NONE; @@ -976,7 +976,7 @@ static irqreturn_t pdc_irq_thread(int irq, void *cookie) bool rx_int; rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (pdcs && rx_int) { + if (likely(pdcs && rx_int)) { dev_dbg(&pdcs->pdev->dev, "%s() got irq %d with rx_int %s", __func__, irq, rx_int ? "set" : "clear"); @@ -1007,14 +1007,14 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) /* Allocate tx ring */ tx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &tx.dmabase); - if (!tx.vbase) { + if (unlikely(!tx.vbase)) { err = -ENOMEM; goto done; } /* Allocate rx ring */ rx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &rx.dmabase); - if (!rx.vbase) { + if (unlikely(!rx.vbase)) { err = -ENOMEM; goto fail_dealloc; } @@ -1219,21 +1219,21 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) u32 tx_desc_req; u32 rx_desc_req; - if (mssg->type != BRCM_MESSAGE_SPU) + if (unlikely(mssg->type != BRCM_MESSAGE_SPU)) return -ENOTSUPP; src_nent = sg_nents(mssg->spu.src); - if (src_nent) { + if (likely(src_nent)) { nent = dma_map_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE); - if (nent == 0) + if (unlikely(nent == 0)) return -EIO; } dst_nent = sg_nents(mssg->spu.dst); - if (dst_nent) { + if (likely(dst_nent)) { nent = dma_map_sg(dev, mssg->spu.dst, dst_nent, DMA_FROM_DEVICE); - if (nent == 0) { + if (unlikely(nent == 0)) { dma_unmap_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE); return -EIO; @@ -1251,7 +1251,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) */ tx_desc_req = pdc_desc_count(mssg->spu.src); rx_desc_req = pdc_desc_count(mssg->spu.dst); - if (pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)) + if (unlikely(pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1))) return -ENOSPC; /* Create rx descriptors to SPU catch response */ @@ -1262,7 +1262,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src); err |= pdc_tx_list_final(pdcs); /* initiate transfer */ - if (err) + if (unlikely(err)) dev_err(&pdcs->pdev->dev, "%s failed with error %d", __func__, err); -- cgit v1.2.3 From 8aef00f090bcbe5237c5a6628e7c000890267efe Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:01 -0500 Subject: mailbox: bcm-pdc: Convert from threaded IRQ to tasklet Previously used threaded IRQs in the PDC driver to defer processing the rx DMA ring after getting an rx done interrupt. Instead, use a tasklet at normal priority for deferred processing. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 57 +++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 32 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 7ed3f0247cb8..16e544018a68 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -285,6 +285,9 @@ struct pdc_state { */ unsigned long intstatus; + /* tasklet for deferred processing after DMA rx interrupt */ + struct tasklet_struct rx_tasklet; + /* Number of bytes of receive status prior to each rx frame */ u32 rx_status_len; /* Whether a BCM header is prepended to each frame */ @@ -931,7 +934,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) /** * pdc_irq_handler() - Interrupt handler called in interrupt context. * @irq: Interrupt number that has fired - * @cookie: PDC state for DMA engine that generated the interrupt + * @data: device struct for DMA engine that generated the interrupt * * We have to clear the device interrupt status flags here. So cache the * status for later use in the thread function. Other than that, just return @@ -940,9 +943,10 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) * Return: IRQ_WAKE_THREAD if interrupt is ours * IRQ_NONE otherwise */ -static irqreturn_t pdc_irq_handler(int irq, void *cookie) +static irqreturn_t pdc_irq_handler(int irq, void *data) { - struct pdc_state *pdcs = cookie; + struct device *dev = (struct device *)data; + struct pdc_state *pdcs = dev_get_drvdata(dev); u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); if (likely(intstatus & PDC_RCVINTEN_0)) @@ -952,39 +956,22 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); /* Wakeup IRQ thread */ - if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) - return IRQ_WAKE_THREAD; - + if (likely(pdcs && (irq == pdcs->pdc_irq) && + (intstatus & PDC_INTMASK))) { + tasklet_schedule(&pdcs->rx_tasklet); + return IRQ_HANDLED; + } return IRQ_NONE; } -/** - * pdc_irq_thread() - Function invoked on deferred thread when data is available - * to receive. - * @irq: Interrupt number - * @cookie: PDC state for PDC that generated the interrupt - * - * On DMA rx complete, process as many SPU response messages as are available - * and send each to the mailbox client. - * - * Return: IRQ_HANDLED if we recognized and handled the interrupt - * IRQ_NONE otherwise - */ -static irqreturn_t pdc_irq_thread(int irq, void *cookie) +static void pdc_tasklet_cb(unsigned long data) { - struct pdc_state *pdcs = cookie; + struct pdc_state *pdcs = (struct pdc_state *)data; bool rx_int; rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (likely(pdcs && rx_int)) { - dev_dbg(&pdcs->pdev->dev, - "%s() got irq %d with rx_int %s", - __func__, irq, rx_int ? "set" : "clear"); - + if (likely(pdcs && rx_int)) pdc_receive(pdcs); - return IRQ_HANDLED; - } - return IRQ_NONE; } /** @@ -1416,11 +1403,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) pdcs->pdc_irq = irq_of_parse_and_map(dn, 0); dev_dbg(dev, "pdc device %s irq %u for pdcs %p", dev_name(dev), pdcs->pdc_irq, pdcs); - err = devm_request_threaded_irq(dev, pdcs->pdc_irq, - pdc_irq_handler, - pdc_irq_thread, 0, dev_name(dev), pdcs); + + err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0, + dev_name(dev), dev); if (err) { - dev_err(dev, "threaded tx IRQ %u request failed with err %d\n", + dev_err(dev, "IRQ %u request failed with err %d\n", pdcs->pdc_irq, err); return err; } @@ -1579,6 +1566,9 @@ static int pdc_probe(struct platform_device *pdev) pdc_hw_init(pdcs); + /* Init tasklet for deferred DMA rx processing */ + tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long) pdcs); + err = pdc_interrupts_init(pdcs); if (err) goto cleanup_buf_pool; @@ -1595,6 +1585,7 @@ static int pdc_probe(struct platform_device *pdev) return PDC_SUCCESS; cleanup_buf_pool: + tasklet_kill(&pdcs->rx_tasklet); dma_pool_destroy(pdcs->rx_buf_pool); cleanup_ring_pool: @@ -1610,6 +1601,8 @@ static int pdc_remove(struct platform_device *pdev) pdc_free_debugfs(); + tasklet_kill(&pdcs->rx_tasklet); + pdc_hw_disable(pdcs); mbox_controller_unregister(&pdcs->mbc); -- cgit v1.2.3 From 38ed49ed4a99942f1a340f4a82a5a8b492e3463b Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:02 -0500 Subject: mailbox: bcm-pdc: Don't use iowrite32 to write DMA descriptors In PDC driver, it is not necessary to use iowrite32() when writing DMA descriptors to the transmit and receive rings. The ring memory is in host memory. So convert to normal assignment statements. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 16e544018a68..e7dc1a227713 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -528,17 +528,17 @@ pdc_build_rxd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len, u32 flags) { struct device *dev = &pdcs->pdev->dev; + struct dma64dd *rxd = &pdcs->rxd_64[pdcs->rxout]; dev_dbg(dev, "Writing rx descriptor for PDC %u at index %u with length %u. flags %#x\n", pdcs->pdc_idx, pdcs->rxout, buf_len, flags); - iowrite32(lower_32_bits(dma_addr), - (void *)&pdcs->rxd_64[pdcs->rxout].addrlow); - iowrite32(upper_32_bits(dma_addr), - (void *)&pdcs->rxd_64[pdcs->rxout].addrhigh); - iowrite32(flags, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl1); - iowrite32(buf_len, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl2); + rxd->addrlow = cpu_to_le32(lower_32_bits(dma_addr)); + rxd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr)); + rxd->ctrl1 = cpu_to_le32(flags); + rxd->ctrl2 = cpu_to_le32(buf_len); + /* bump ring index and return */ pdcs->rxout = NEXTRXD(pdcs->rxout, pdcs->nrxpost); } @@ -556,17 +556,16 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len, u32 flags) { struct device *dev = &pdcs->pdev->dev; + struct dma64dd *txd = &pdcs->txd_64[pdcs->txout]; dev_dbg(dev, "Writing tx descriptor for PDC %u at index %u with length %u, flags %#x\n", pdcs->pdc_idx, pdcs->txout, buf_len, flags); - iowrite32(lower_32_bits(dma_addr), - (void *)&pdcs->txd_64[pdcs->txout].addrlow); - iowrite32(upper_32_bits(dma_addr), - (void *)&pdcs->txd_64[pdcs->txout].addrhigh); - iowrite32(flags, (void *)&pdcs->txd_64[pdcs->txout].ctrl1); - iowrite32(buf_len, (void *)&pdcs->txd_64[pdcs->txout].ctrl2); + txd->addrlow = cpu_to_le32(lower_32_bits(dma_addr)); + txd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr)); + txd->ctrl1 = cpu_to_le32(flags); + txd->ctrl2 = cpu_to_le32(buf_len); /* bump ring index and return */ pdcs->txout = NEXTTXD(pdcs->txout, pdcs->ntxpost); -- cgit v1.2.3 From 63bb50bdb997f4bede1b5f2d56645f393f7f39fb Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:03 -0500 Subject: 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 Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 85 ++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 36 deletions(-) (limited to 'drivers/mailbox') 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 { 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 */ struct pdc_state { /* Index of the PDC whose state is in this structure instance */ @@ -377,11 +398,7 @@ struct pdc_state { /* Index of next rx descriptor to post. */ u32 rxout; - /* - * opaque context associated with frame that starts at each - * rx ring index. - */ - void *rxp_ctx[PDC_RING_ENTRIES]; + struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES]; /* * Scatterlists used to form request and reply frames beginning at a @@ -389,18 +406,6 @@ struct pdc_state { * is processed */ 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 */ @@ -591,11 +596,11 @@ pdc_receive_one(struct pdc_state *pdcs) struct brcm_message mssg; u32 len, rx_status; u32 num_frags; - int i; u8 *resp_hdr; /* virtual addr of start of resp message DMA header */ u32 frags_rdy; /* number of fragments ready to read */ u32 rx_idx; /* ring index of start of receive frame */ dma_addr_t resp_hdr_daddr; + struct pdc_rx_ctx *rx_ctx; mbc = &pdcs->mbc; chan = &mbc->chans[0]; @@ -607,7 +612,8 @@ pdc_receive_one(struct pdc_state *pdcs) * to read. */ 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 */ return -EAGAIN; @@ -617,24 +623,23 @@ pdc_receive_one(struct pdc_state *pdcs) dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); - for (i = 0; i < num_frags; i++) - pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost); + pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost; dev_dbg(dev, "PDC %u reclaimed %d tx descriptors", pdcs->pdc_idx, num_frags); 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 */ - mssg.ctx = pdcs->rxp_ctx[rx_idx]; - pdcs->rxp_ctx[rx_idx] = NULL; - resp_hdr = pdcs->resp_hdr[rx_idx]; - resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx]; - dma_unmap_sg(dev, pdcs->dst_sg[rx_idx], - sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE); + mssg.ctx = rx_ctx->rxp_ctx; + rx_ctx->rxp_ctx = NULL; + resp_hdr = rx_ctx->resp_hdr; + resp_hdr_daddr = rx_ctx->resp_hdr_daddr; + dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg), + DMA_FROM_DEVICE); - for (i = 0; i < num_frags; i++) - pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost); + pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost; dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", pdcs->pdc_idx, num_frags); @@ -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 */ dma_addr_t daddr; void *vaddr; + struct pdc_rx_ctx *rx_ctx; rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, pdcs->nrxpost); @@ -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 */ 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))) flags |= D64_CTRL1_EOT; - pdcs->rxp_ctx[pdcs->rxout] = ctx; - pdcs->dst_sg[pdcs->rxout] = dst_sg; - pdcs->resp_hdr[pdcs->rxout] = vaddr; - pdcs->resp_hdr_daddr[pdcs->rxout] = daddr; + rx_ctx = &pdcs->rx_ctx[pdcs->rxout]; + rx_ctx->rxp_ctx = ctx; + rx_ctx->dst_sg = dst_sg; + rx_ctx->resp_hdr = vaddr; + rx_ctx->resp_hdr_daddr = daddr; pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags); return PDC_SUCCESS; } @@ -925,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) desc_w++; 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; } @@ -954,6 +961,9 @@ static irqreturn_t pdc_irq_handler(int irq, void *data) /* Clear interrupt flags in device */ 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 */ if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) { @@ -971,6 +981,9 @@ static void pdc_tasklet_cb(unsigned long data) rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); if (likely(pdcs && rx_int)) pdc_receive(pdcs); + + /* reenable interrupts */ + iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); } /** -- cgit v1.2.3 From 30d1ef623fd1e99bc1bab5211ba1da0d97d40e64 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:04 -0500 Subject: mailbox: bcm-pdc: Simplify interrupt handler logic Earlier versions of the PDC driver registered for both transmit and receive interrupts. The hard IRQ handler had to communicate to the soft handler which interrupt(s) had occurred. The PDC driver no longer registers for tx interrupts. So there is no reason to save the intstatus. So remove the intstatus member of the PDC state. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 8c2aa7c9c27f..c1ec17cfa03a 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -298,14 +298,6 @@ struct pdc_state { unsigned int pdc_irq; - /* - * Last interrupt status read from PDC device. Saved in interrupt - * handler so the handler can clear the interrupt in the device, - * and the interrupt thread called later can know which interrupt - * bits are active. - */ - unsigned long intstatus; - /* tasklet for deferred processing after DMA rx interrupt */ struct tasklet_struct rx_tasklet; @@ -955,32 +947,30 @@ static irqreturn_t pdc_irq_handler(int irq, void *data) struct pdc_state *pdcs = dev_get_drvdata(dev); u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); - if (likely(intstatus & PDC_RCVINTEN_0)) - set_bit(PDC_RCVINT_0, &pdcs->intstatus); - - /* Clear interrupt flags in device */ - iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); + if (unlikely(intstatus == 0)) + return IRQ_NONE; /* Disable interrupts until soft handler runs */ iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); + /* Clear interrupt flags in device */ + iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); + /* Wakeup IRQ thread */ - if (likely(pdcs && (irq == pdcs->pdc_irq) && - (intstatus & PDC_INTMASK))) { - tasklet_schedule(&pdcs->rx_tasklet); - return IRQ_HANDLED; - } - return IRQ_NONE; + tasklet_schedule(&pdcs->rx_tasklet); + return IRQ_HANDLED; } +/** + * pdc_tasklet_cb() - Tasklet callback that runs the deferred processing after + * a DMA receive interrupt. Reenables the receive interrupt. + * @data: PDC state structure + */ static void pdc_tasklet_cb(unsigned long data) { struct pdc_state *pdcs = (struct pdc_state *)data; - bool rx_int; - rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (likely(pdcs && rx_int)) - pdc_receive(pdcs); + pdc_receive(pdcs); /* reenable interrupts */ iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); @@ -1405,8 +1395,6 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) struct device_node *dn = pdev->dev.of_node; int err; - pdcs->intstatus = 0; - /* interrupt configuration */ iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase + PDC_RCVLAZY0_OFFSET); -- cgit v1.2.3 From cf17581340d730175f1f3f4ce6e90ae434154e37 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:05 -0500 Subject: mailbox: bcm-pdc: Remove unnecessary void* casts Remove unnecessary void* casts in register writes. Fix two other minor formatting issues. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Reviewed-by: Jon Mason Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index c1ec17cfa03a..2aeb034d5fb9 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -468,7 +468,7 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf, out_offset += snprintf(buf + out_offset, out_count - out_offset, "Num frags in rx ring............%u\n", NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, - pdcs->nrxpost)); + pdcs->nrxpost)); if (out_offset > out_count) out_offset = out_count; @@ -683,7 +683,7 @@ pdc_receive(struct pdc_state *pdcs) /* read last_rx_curr from register once */ pdcs->last_rx_curr = - (ioread32((void *)&pdcs->rxregs_64->status0) & + (ioread32(&pdcs->rxregs_64->status0) & CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE; do { @@ -793,8 +793,8 @@ static int pdc_tx_list_final(struct pdc_state *pdcs) * before chip starts to process new request */ wmb(); - iowrite32(pdcs->rxout << 4, (void *)&pdcs->rxregs_64->ptr); - iowrite32(pdcs->txout << 4, (void *)&pdcs->txregs_64->ptr); + iowrite32(pdcs->rxout << 4, &pdcs->rxregs_64->ptr); + iowrite32(pdcs->txout << 4, &pdcs->txregs_64->ptr); pdcs->pdc_requests++; return PDC_SUCCESS; @@ -1034,47 +1034,46 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) /* But first disable DMA and set curptr to 0 for both TX & RX */ iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)), - (void *)&dma_reg->dmarcv.control); - iowrite32(0, (void *)&dma_reg->dmaxmt.ptr); - iowrite32(0, (void *)&dma_reg->dmarcv.ptr); + &dma_reg->dmarcv.control); + iowrite32(0, &dma_reg->dmaxmt.ptr); + iowrite32(0, &dma_reg->dmarcv.ptr); /* Set base DMA addresses */ iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase), - (void *)&dma_reg->dmaxmt.addrlow); + &dma_reg->dmaxmt.addrlow); iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase), - (void *)&dma_reg->dmaxmt.addrhigh); + &dma_reg->dmaxmt.addrhigh); iowrite32(lower_32_bits(pdcs->rx_ring_alloc.dmabase), - (void *)&dma_reg->dmarcv.addrlow); + &dma_reg->dmarcv.addrlow); iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase), - (void *)&dma_reg->dmarcv.addrhigh); + &dma_reg->dmarcv.addrhigh); /* Re-enable DMA */ iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control); iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)), - (void *)&dma_reg->dmarcv.control); + &dma_reg->dmarcv.control); /* Initialize descriptors */ for (i = 0; i < PDC_RING_ENTRIES; i++) { /* Every tx descriptor can be used for start of frame. */ if (i != pdcs->ntxpost) { iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF, - (void *)&pdcs->txd_64[i].ctrl1); + &pdcs->txd_64[i].ctrl1); } else { /* Last descriptor in ringset. Set End of Table. */ iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF | - D64_CTRL1_EOT, - (void *)&pdcs->txd_64[i].ctrl1); + D64_CTRL1_EOT, &pdcs->txd_64[i].ctrl1); } /* Every rx descriptor can be used for start of frame */ if (i != pdcs->nrxpost) { iowrite32(D64_CTRL1_SOF, - (void *)&pdcs->rxd_64[i].ctrl1); + &pdcs->rxd_64[i].ctrl1); } else { /* Last descriptor in ringset. Set End of Table. */ iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOT, - (void *)&pdcs->rxd_64[i].ctrl1); + &pdcs->rxd_64[i].ctrl1); } } return PDC_SUCCESS; @@ -1300,10 +1299,10 @@ void pdc_hw_init(struct pdc_state *pdcs) /* initialize data structures */ pdcs->regs = (struct pdc_regs *)pdcs->pdc_reg_vbase; pdcs->txregs_64 = (struct dma64_regs *) - (void *)(((u8 *)pdcs->pdc_reg_vbase) + + (((u8 *)pdcs->pdc_reg_vbase) + PDC_TXREGS_OFFSET + (sizeof(struct dma64) * ringset)); pdcs->rxregs_64 = (struct dma64_regs *) - (void *)(((u8 *)pdcs->pdc_reg_vbase) + + (((u8 *)pdcs->pdc_reg_vbase) + PDC_RXREGS_OFFSET + (sizeof(struct dma64) * ringset)); pdcs->ntxd = PDC_RING_ENTRIES; @@ -1318,7 +1317,7 @@ void pdc_hw_init(struct pdc_state *pdcs) iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1), - (void *)&dma_reg->dmarcv.control); + &dma_reg->dmarcv.control); /* Reset current index pointers after making sure DMA is disabled */ iowrite32(0, &dma_reg->dmaxmt.ptr); @@ -1567,7 +1566,7 @@ static int pdc_probe(struct platform_device *pdev) pdc_hw_init(pdcs); /* Init tasklet for deferred DMA rx processing */ - tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long) pdcs); + tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long)pdcs); err = pdc_interrupts_init(pdcs); if (err) -- cgit v1.2.3 From baef9a35d24626ebdc5a9074455e63eea6c7f6af Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 29 Nov 2016 14:37:04 +0000 Subject: mailbox: mailbox-test: add support for fasync/poll Currently the read operation on the message debug file returns error if there's no data ready to be read. It expects the userspace to retry if it fails. Since the mailbox response could be asynchronous, it would be good to add support to block the read until the data is available. We can also implement poll file operations so that the userspace can wait to become ready to perform any I/O. This patch implements the poll and fasync file operation callback for the test mailbox device. Cc: Lee Jones Signed-off-by: Sudeep Holla Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 79 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 8 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index deb9c61aebb4..383a8b7600ac 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -11,12 +11,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -39,6 +41,8 @@ struct mbox_test_device { char *signal; char *message; spinlock_t lock; + wait_queue_head_t waitq; + struct fasync_struct *async_queue; }; static ssize_t mbox_test_signal_write(struct file *filp, @@ -81,6 +85,13 @@ static const struct file_operations mbox_test_signal_ops = { .llseek = generic_file_llseek, }; +static int mbox_test_message_fasync(int fd, struct file *filp, int on) +{ + struct mbox_test_device *tdev = filp->private_data; + + return fasync_helper(fd, filp, on, &tdev->async_queue); +} + static ssize_t mbox_test_message_write(struct file *filp, const char __user *userbuf, size_t count, loff_t *ppos) @@ -138,6 +149,20 @@ out: return ret < 0 ? ret : count; } +static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) +{ + unsigned char data; + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); + data = tdev->rx_buffer[0]; + spin_unlock_irqrestore(&tdev->lock, flags); + + if (data != '\0') + return true; + return false; +} + static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, size_t count, loff_t *ppos) { @@ -147,6 +172,8 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, int l = 0; int ret; + DECLARE_WAITQUEUE(wait, current); + touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL); if (!touser) return -ENOMEM; @@ -155,15 +182,29 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, ret = snprintf(touser, 20, "\n"); ret = simple_read_from_buffer(userbuf, count, ppos, touser, ret); - goto out; + goto kfree_err; } - if (tdev->rx_buffer[0] == '\0') { - ret = snprintf(touser, 9, "\n"); - ret = simple_read_from_buffer(userbuf, count, ppos, - touser, ret); - goto out; - } + add_wait_queue(&tdev->waitq, &wait); + + do { + __set_current_state(TASK_INTERRUPTIBLE); + + if (mbox_test_message_data_ready(tdev)) + break; + + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto waitq_err; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto waitq_err; + } + schedule(); + + } while (1); spin_lock_irqsave(&tdev->lock, flags); @@ -185,14 +226,31 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, spin_unlock_irqrestore(&tdev->lock, flags); ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN); -out: +waitq_err: + __set_current_state(TASK_RUNNING); + remove_wait_queue(&tdev->waitq, &wait); +kfree_err: kfree(touser); return ret; } +static unsigned int +mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct mbox_test_device *tdev = filp->private_data; + + poll_wait(filp, &tdev->waitq, wait); + + if (mbox_test_message_data_ready(tdev)) + return POLLIN | POLLRDNORM; + return 0; +} + static const struct file_operations mbox_test_message_ops = { .write = mbox_test_message_write, .read = mbox_test_message_read, + .fasync = mbox_test_message_fasync, + .poll = mbox_test_message_poll, .open = simple_open, .llseek = generic_file_llseek, }; @@ -234,6 +292,10 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); } spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); + + kill_fasync(&tdev->async_queue, SIGIO, POLL_IN); } static void mbox_test_prepare_message(struct mbox_client *client, void *message) @@ -334,6 +396,7 @@ static int mbox_test_probe(struct platform_device *pdev) if (ret) return ret; + init_waitqueue_head(&tdev->waitq); dev_info(&pdev->dev, "Successfully registered\n"); return 0; -- cgit v1.2.3 From db4d22c07e3e652eeec82abcc1399e6305edd838 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 29 Nov 2016 14:37:05 +0000 Subject: mailbox: mailbox-test: allow reserved areas in SRAM When CONFIG_SRAM is enable and the SRAM region is found, the entire SRAM region resource is requested and marked as occupied by SRAM driver even if certain parts of regions is marked reserved. It's quite possible that a small region of the SRAM is reserved for all the mailbox communication and hence it may fail to request the region as it's already marked busy region. This patch tries to just do a ioremap of this mailbox memory region if it finds it busy. Cc: Lee Jones Signed-off-by: Sudeep Holla Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/mailbox') diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 383a8b7600ac..9c79f8019d2a 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -352,6 +352,7 @@ static int mbox_test_probe(struct platform_device *pdev) { struct mbox_test_device *tdev; struct resource *res; + resource_size_t size; int ret; tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); @@ -360,14 +361,21 @@ static int mbox_test_probe(struct platform_device *pdev) /* It's okay for MMIO to be NULL */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + size = resource_size(res); tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(tdev->tx_mmio)) + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) + /* if reserved area in SRAM, try just ioremap */ + tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); + else if (IS_ERR(tdev->tx_mmio)) tdev->tx_mmio = NULL; /* If specified, second reg entry is Rx MMIO */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + size = resource_size(res); tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(tdev->rx_mmio)) + if (PTR_ERR(tdev->rx_mmio) == -EBUSY) + tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); + else if (IS_ERR(tdev->rx_mmio)) tdev->rx_mmio = tdev->tx_mmio; tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); -- cgit v1.2.3