From d2295042b783c2b17d93cd5ab786bbfd4f2f5c90 Mon Sep 17 00:00:00 2001 From: Fernando Guzman Lugo Date: Mon, 29 Nov 2010 20:24:11 +0000 Subject: [PATCH 01/11] OMAP: mailbox: change full flag per mailbox queue instead of global The variable rq_full flag is a global variable, so if there are multiple mailbox users there will be conflicts. Now there is a full flag per mailbox queue. Reported-by: Ohad Ben-Cohen Signed-off-by: Fernando Guzman Lugo Signed-off-by: Hari Kanigeri Acked-by: Hiroshi Doyu --- arch/arm/plat-omap/include/plat/mailbox.h | 1 + arch/arm/plat-omap/mailbox.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h index 997656552109..13f2ef3ea0ff 100644 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ b/arch/arm/plat-omap/include/plat/mailbox.h @@ -48,6 +48,7 @@ struct omap_mbox_queue { struct tasklet_struct tasklet; int (*callback)(void *); struct omap_mbox *mbox; + bool full; }; struct omap_mbox { diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index d2fafb892f7f..48e161c642a5 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -33,7 +33,6 @@ static struct workqueue_struct *mboxd; static struct omap_mbox **mboxes; -static bool rq_full; static int mbox_configured; static DEFINE_MUTEX(mbox_configured_lock); @@ -148,6 +147,12 @@ static void mbox_rx_work(struct work_struct *work) if (mq->callback) mq->callback((void *)msg); + spin_lock_irq(&mq->lock); + if (mq->full) { + mq->full = false; + omap_mbox_enable_irq(mq->mbox, IRQ_RX); + } + spin_unlock_irq(&mq->lock); } } @@ -170,7 +175,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) while (!mbox_fifo_empty(mbox)) { if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { omap_mbox_disable_irq(mbox, IRQ_RX); - rq_full = true; + mq->full = true; goto nomem; } From ab66ac3007cb3e59fe80dfcf36aff243d3008cb9 Mon Sep 17 00:00:00 2001 From: "Kanigeri, Hari" Date: Mon, 29 Nov 2010 20:24:12 +0000 Subject: [PATCH 02/11] OMAP: mailbox: fix checkpatch warnings Fix the following checkpatch warnings observed in mailbox module. WARNING: please, no space for starting a line, excluding comments + fail_alloc_rxq:$ WARNING: please, no space for starting a line, excluding comments + fail_alloc_txq:$ WARNING: please, no space for starting a line, excluding comments + fail_request_irq:$ WARNING: line over 80 characters + mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t)); Signed-off-by: Hari Kanigeri Acked-by: Hiroshi Doyu --- arch/arm/plat-omap/mailbox.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 48e161c642a5..d9aa87c0a921 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -281,11 +281,11 @@ static int omap_mbox_startup(struct omap_mbox *mbox) return 0; - fail_alloc_rxq: +fail_alloc_rxq: mbox_queue_free(mbox->txq); - fail_alloc_txq: +fail_alloc_txq: free_irq(mbox->irq, mbox); - fail_request_irq: +fail_request_irq: if (mbox->ops->shutdown) mbox->ops->shutdown(mbox); @@ -396,7 +396,8 @@ static int __init omap_mbox_init(void) /* kfifo size sanity check: alignment and minimal size */ mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); - mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t)); + mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, + sizeof(mbox_msg_t)); return 0; } From a42743c26a53a2a5f2b2018a9659ab3fb604d5bc Mon Sep 17 00:00:00 2001 From: "Kanigeri, Hari" Date: Mon, 29 Nov 2010 20:24:13 +0000 Subject: [PATCH 03/11] OMAP: mailbox: send message in process context Schedule the Tasklet to send only when mailbox fifo is full and there are pending messages in kfifo, else send the message directly in the Process context. This would avoid needless scheduling of Tasklet for every message transfer Signed-off-by: Hari Kanigeri Acked-by: Hiroshi Doyu --- arch/arm/plat-omap/mailbox.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index d9aa87c0a921..cc58b44325f2 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -92,20 +92,25 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) struct omap_mbox_queue *mq = mbox->txq; int ret = 0, len; - spin_lock(&mq->lock); + spin_lock_bh(&mq->lock); if (kfifo_avail(&mq->fifo) < sizeof(msg)) { ret = -ENOMEM; goto out; } + if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { + mbox_fifo_write(mbox, msg); + goto out; + } + len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); WARN_ON(len != sizeof(msg)); tasklet_schedule(&mbox->txq->tasklet); out: - spin_unlock(&mq->lock); + spin_unlock_bh(&mq->lock); return ret; } EXPORT_SYMBOL(omap_mbox_msg_send); From 582563074a691eb45cb22d2eca70eed8f2091c5f Mon Sep 17 00:00:00 2001 From: "Kanigeri, Hari" Date: Mon, 29 Nov 2010 20:24:14 +0000 Subject: [PATCH 04/11] OMAP: mailbox: add notification support for multiple readers In the current mailbox driver, the mailbox internal pointer for callback can be directly manipulated by the Users, so a second User can easily corrupt the first user's callback pointer. The initial effort to correct this issue can be referred here: https://patchwork.kernel.org/patch/107520/ Along with fixing the above stated issue, this patch adds the flexibility option to register notifications from multiple readers to the events received on a mailbox instance. The discussion regarding this can be referred here. http://www.mail-archive.com/linux-omap@vger.kernel.org/msg30671.html Signed-off-by: Hari Kanigeri Signed-off-by: Fernando Guzman Lugo Acked-by: Hiroshi Doyu --- arch/arm/plat-omap/include/plat/mailbox.h | 7 +- arch/arm/plat-omap/mailbox.c | 105 ++++++++++++---------- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h index 13f2ef3ea0ff..cc3921e9059c 100644 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ b/arch/arm/plat-omap/include/plat/mailbox.h @@ -46,7 +46,6 @@ struct omap_mbox_queue { struct kfifo fifo; struct work_struct work; struct tasklet_struct tasklet; - int (*callback)(void *); struct omap_mbox *mbox; bool full; }; @@ -58,13 +57,15 @@ struct omap_mbox { struct omap_mbox_ops *ops; struct device *dev; void *priv; + int use_count; + struct blocking_notifier_head notifier; }; int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); void omap_mbox_init_seq(struct omap_mbox *); -struct omap_mbox *omap_mbox_get(const char *); -void omap_mbox_put(struct omap_mbox *); +struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); +void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); int omap_mbox_register(struct device *parent, struct omap_mbox **); int omap_mbox_unregister(void); diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index cc58b44325f2..459b319a9fad 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -150,8 +151,8 @@ static void mbox_rx_work(struct work_struct *work) len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); WARN_ON(len != sizeof(msg)); - if (mq->callback) - mq->callback((void *)msg); + blocking_notifier_call_chain(&mq->mbox->notifier, len, + (void *)msg); spin_lock_irq(&mq->lock); if (mq->full) { mq->full = false; @@ -249,41 +250,40 @@ static int omap_mbox_startup(struct omap_mbox *mbox) int ret = 0; struct omap_mbox_queue *mq; - if (mbox->ops->startup) { - mutex_lock(&mbox_configured_lock); - if (!mbox_configured) + mutex_lock(&mbox_configured_lock); + if (!mbox_configured++) { + if (likely(mbox->ops->startup)) { ret = mbox->ops->startup(mbox); + if (unlikely(ret)) + goto fail_startup; + } else + goto fail_startup; + } - if (ret) { - mutex_unlock(&mbox_configured_lock); - return ret; + if (!mbox->use_count++) { + ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, + mbox->name, mbox); + if (unlikely(ret)) { + pr_err("failed to register mailbox interrupt:%d\n", + ret); + goto fail_request_irq; } - mbox_configured++; - mutex_unlock(&mbox_configured_lock); - } + mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_txq; + } + mbox->txq = mq; - ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, - mbox->name, mbox); - if (ret) { - printk(KERN_ERR - "failed to register mailbox interrupt:%d\n", ret); - goto fail_request_irq; + mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_rxq; + } + mbox->rxq = mq; + mq->mbox = mbox; } - - mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_txq; - } - mbox->txq = mq; - - mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); - if (!mq) { - ret = -ENOMEM; - goto fail_alloc_rxq; - } - mbox->rxq = mq; - + mutex_unlock(&mbox_configured_lock); return 0; fail_alloc_rxq: @@ -293,29 +293,34 @@ static int omap_mbox_startup(struct omap_mbox *mbox) fail_request_irq: if (mbox->ops->shutdown) mbox->ops->shutdown(mbox); - + mbox->use_count--; +fail_startup: + mbox_configured--; + mutex_unlock(&mbox_configured_lock); return ret; } static void omap_mbox_fini(struct omap_mbox *mbox) { - free_irq(mbox->irq, mbox); - tasklet_kill(&mbox->txq->tasklet); - flush_work(&mbox->rxq->work); - mbox_queue_free(mbox->txq); - mbox_queue_free(mbox->rxq); + mutex_lock(&mbox_configured_lock); - if (mbox->ops->shutdown) { - mutex_lock(&mbox_configured_lock); - if (mbox_configured > 0) - mbox_configured--; - if (!mbox_configured) - mbox->ops->shutdown(mbox); - mutex_unlock(&mbox_configured_lock); + if (!--mbox->use_count) { + free_irq(mbox->irq, mbox); + tasklet_kill(&mbox->txq->tasklet); + flush_work(&mbox->rxq->work); + mbox_queue_free(mbox->txq); + mbox_queue_free(mbox->rxq); } + + if (likely(mbox->ops->shutdown)) { + if (!--mbox_configured) + mbox->ops->shutdown(mbox); + } + + mutex_unlock(&mbox_configured_lock); } -struct omap_mbox *omap_mbox_get(const char *name) +struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) { struct omap_mbox *mbox; int ret; @@ -334,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name) if (ret) return ERR_PTR(-ENODEV); + if (nb) + blocking_notifier_chain_register(&mbox->notifier, nb); + return mbox; } EXPORT_SYMBOL(omap_mbox_get); -void omap_mbox_put(struct omap_mbox *mbox) +void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) { + blocking_notifier_chain_unregister(&mbox->notifier, nb); omap_mbox_fini(mbox); } EXPORT_SYMBOL(omap_mbox_put); @@ -363,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list) ret = PTR_ERR(mbox->dev); goto err_out; } + + BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); } return 0; From 5d783731c683161d5d921c2ed03a43d6d31cf418 Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Wed, 1 Dec 2010 14:15:08 -0600 Subject: [PATCH 05/11] OMAP: mailbox: remove unreachable return Remove unreachable return statement. Signed-off-by: Omar Ramirez Luna Acked-by: Benoit Cousson Acked-by: Hiroshi Doyu --- arch/arm/mach-omap2/mailbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 40ddecab93a9..02ab0cb43459 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -432,9 +432,8 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) iounmap(mbox_base); return ret; } - return 0; - return ret; + return 0; } static int __devexit omap2_mbox_remove(struct platform_device *pdev) From ff0fba0bca4182e022c0a2ac0f3e63508e86e9f1 Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Fri, 22 Oct 2010 20:10:58 -0500 Subject: [PATCH 06/11] OMAP: mailbox: fix detection for previously supported chips Fix the mailbox detection for OMAP3630 and 2430, also minor cleanup on conditional ifdef's that could affect it. Given that 2430 has an iva too, include it, as the same steps for omap3 apply. Signed-off-by: Omar Ramirez Luna Acked-by: Hiroshi Doyu --- arch/arm/mach-omap2/mailbox.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 02ab0cb43459..394413dc7deb 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -281,7 +281,7 @@ static struct omap_mbox_ops omap2_mbox_ops = { /* FIXME: the following structs should be filled automatically by the user id */ -#if defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_ARCH_OMAP2420) +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2) /* DSP */ static struct omap_mbox2_priv omap2_mbox_dsp_priv = { .tx_fifo = { @@ -306,7 +306,7 @@ struct omap_mbox mbox_dsp_info = { }; #endif -#if defined(CONFIG_ARCH_OMAP3430) +#if defined(CONFIG_ARCH_OMAP3) struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; #endif @@ -394,15 +394,19 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) if (false) ; -#if defined(CONFIG_ARCH_OMAP3430) - else if (cpu_is_omap3430()) { +#if defined(CONFIG_ARCH_OMAP3) + else if (cpu_is_omap34xx()) { list = omap3_mboxes; list[0]->irq = platform_get_irq_byname(pdev, "dsp"); } #endif -#if defined(CONFIG_ARCH_OMAP2420) - else if (cpu_is_omap2420()) { +#if defined(CONFIG_ARCH_OMAP2) + else if (cpu_is_omap2430()) { + list = omap2_mboxes; + + list[0]->irq = platform_get_irq_byname(pdev, "dsp"); + } else if (cpu_is_omap2420()) { list = omap2_mboxes; list[0]->irq = platform_get_irq_byname(pdev, "dsp"); From ba6e1f4ff41314906d81e6d96e646cdeafe42827 Mon Sep 17 00:00:00 2001 From: "Guzman Lugo, Fernando" Date: Wed, 15 Dec 2010 00:54:00 +0000 Subject: [PATCH 07/11] OMAP: iovmm: no gap checking for fixed address If some fixed da address is wanted to be mapped and the page is freed but it is used as gap, the mapping will fail. This patch is fixing that and olny keeps the gap for not fixed address. Signed-off-by: Fernando Guzman Lugo Acked-by: Hiroshi DOYU --- arch/arm/plat-omap/iovmm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index 8ce0de247c71..34f0012b5676 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -289,10 +289,10 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, prev_end = 0; list_for_each_entry(tmp, &obj->mmap, list) { - if (prev_end >= start) + if (prev_end > start) break; - if (start + bytes < tmp->da_start) + if (start + bytes <= tmp->da_start) goto found; if (flags & IOVMF_DA_ANON) @@ -301,7 +301,7 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, prev_end = tmp->da_end; } - if ((start > prev_end) && (ULONG_MAX - start >= bytes)) + if ((start >= prev_end) && (ULONG_MAX - start + 1 >= bytes)) goto found; dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n", From ad1081210f3c91874f9fe9b48c3934c7db9714b7 Mon Sep 17 00:00:00 2001 From: "Guzman Lugo, Fernando" Date: Wed, 15 Dec 2010 00:54:01 +0000 Subject: [PATCH 08/11] OMAP: iovmm: add superpages support to fixed da address This patch adds superpages support to fixed ad address inside iommu_kmap function. Signed-off-by: Fernando Guzman Lugo Acked-by: Hiroshi DOYU --- arch/arm/plat-omap/iovmm.c | 62 ++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index 34f0012b5676..93a34d92b3a2 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -87,35 +87,43 @@ static size_t sgtable_len(const struct sg_table *sgt) } #define sgtable_ok(x) (!!sgtable_len(x)) +static unsigned max_alignment(u32 addr) +{ + int i; + unsigned pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, }; + for (i = 0; i < ARRAY_SIZE(pagesize) && addr & (pagesize[i] - 1); i++) + ; + return (i < ARRAY_SIZE(pagesize)) ? pagesize[i] : 0; +} + /* * calculate the optimal number sg elements from total bytes based on * iommu superpages */ -static unsigned int sgtable_nents(size_t bytes) +static unsigned sgtable_nents(size_t bytes, u32 da, u32 pa) { - int i; - unsigned int nr_entries; - const unsigned long pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, }; + unsigned nr_entries = 0, ent_sz; if (!IS_ALIGNED(bytes, PAGE_SIZE)) { pr_err("%s: wrong size %08x\n", __func__, bytes); return 0; } - nr_entries = 0; - for (i = 0; i < ARRAY_SIZE(pagesize); i++) { - if (bytes >= pagesize[i]) { - nr_entries += (bytes / pagesize[i]); - bytes %= pagesize[i]; - } + while (bytes) { + ent_sz = max_alignment(da | pa); + ent_sz = min_t(unsigned, ent_sz, iopgsz_max(bytes)); + nr_entries++; + da += ent_sz; + pa += ent_sz; + bytes -= ent_sz; } - BUG_ON(bytes); return nr_entries; } /* allocate and initialize sg_table header(a kind of 'superblock') */ -static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags) +static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags, + u32 da, u32 pa) { unsigned int nr_entries; int err; @@ -127,9 +135,8 @@ static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags) if (!IS_ALIGNED(bytes, PAGE_SIZE)) return ERR_PTR(-EINVAL); - /* FIXME: IOVMF_DA_FIXED should support 'superpages' */ - if ((flags & IOVMF_LINEAR) && (flags & IOVMF_DA_ANON)) { - nr_entries = sgtable_nents(bytes); + if (flags & IOVMF_LINEAR) { + nr_entries = sgtable_nents(bytes, da, pa); if (!nr_entries) return ERR_PTR(-EINVAL); } else @@ -409,7 +416,8 @@ static inline void sgtable_drain_vmalloc(struct sg_table *sgt) BUG_ON(!sgt); } -static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) +static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, u32 da, + size_t len) { unsigned int i; struct scatterlist *sg; @@ -418,9 +426,10 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) va = phys_to_virt(pa); for_each_sg(sgt->sgl, sg, sgt->nents, i) { - size_t bytes; + unsigned bytes; - bytes = iopgsz_max(len); + bytes = max_alignment(da | pa); + bytes = min_t(unsigned, bytes, iopgsz_max(len)); BUG_ON(!iopgsz_ok(bytes)); @@ -429,6 +438,7 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) * 'pa' is cotinuous(linear). */ pa += bytes; + da += bytes; len -= bytes; } BUG_ON(len); @@ -695,18 +705,18 @@ u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags) if (!va) return -ENOMEM; - sgt = sgtable_alloc(bytes, flags); + flags &= IOVMF_HW_MASK; + flags |= IOVMF_DISCONT; + flags |= IOVMF_ALLOC; + flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON); + + sgt = sgtable_alloc(bytes, flags, da, 0); if (IS_ERR(sgt)) { da = PTR_ERR(sgt); goto err_sgt_alloc; } sgtable_fill_vmalloc(sgt, va); - flags &= IOVMF_HW_MASK; - flags |= IOVMF_DISCONT; - flags |= IOVMF_ALLOC; - flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON); - da = __iommu_vmap(obj, da, sgt, va, bytes, flags); if (IS_ERR_VALUE(da)) goto err_iommu_vmap; @@ -746,11 +756,11 @@ static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va, { struct sg_table *sgt; - sgt = sgtable_alloc(bytes, flags); + sgt = sgtable_alloc(bytes, flags, da, pa); if (IS_ERR(sgt)) return PTR_ERR(sgt); - sgtable_fill_kmalloc(sgt, pa, bytes); + sgtable_fill_kmalloc(sgt, pa, da, bytes); da = map_iommu_region(obj, da, sgt, va, bytes, flags); if (IS_ERR_VALUE(da)) { From 9205a109fbeee180254bb5a4020eb71d50735944 Mon Sep 17 00:00:00 2001 From: "Guzman Lugo, Fernando" Date: Wed, 15 Dec 2010 00:54:02 +0000 Subject: [PATCH 09/11] OMAP: iovmm: replace __iounmap with iounmap __iounmap function is wrong for OMAP architecture, instead use iounmap which will call to the correct function. Signed-off-by: Fernando Guzman Lugo Acked-by: Hiroshi DOYU --- arch/arm/plat-omap/iovmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index 93a34d92b3a2..fa6e64332a9e 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -821,7 +821,7 @@ void iommu_kunmap(struct iommu *obj, u32 da) struct sg_table *sgt; typedef void (*func_t)(const void *); - sgt = unmap_vm_area(obj, da, (func_t)__iounmap, + sgt = unmap_vm_area(obj, da, (func_t)iounmap, IOVMF_LINEAR | IOVMF_MMIO); if (!sgt) dev_dbg(obj->dev, "%s: No sgt\n", __func__); From c7f4ab26e3bcdaeb3e19ec658e3ad9092f1a6ceb Mon Sep 17 00:00:00 2001 From: "Guzman Lugo, Fernando" Date: Wed, 15 Dec 2010 00:54:03 +0000 Subject: [PATCH 10/11] OMAP: iommu: create new api to set valid da range Some IOMMUs cannot use the whole 0x0 - 0xFFFFFFFF range. With this new API the valid range can be set. Signed-off-by: Fernando Guzman Lugo Acked-by: Hiroshi DOYU --- arch/arm/mach-omap2/omap-iommu.c | 8 ++++++++ arch/arm/plat-omap/include/plat/iommu.h | 5 +++++ arch/arm/plat-omap/iommu.c | 24 ++++++++++++++++++++++++ arch/arm/plat-omap/iovmm.c | 15 ++++++++------- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index f5a1aad1a5c0..6be548cdd800 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -33,6 +33,8 @@ static struct iommu_device omap3_devices[] = { .name = "isp", .nr_tlb_entries = 8, .clk_name = "cam_ick", + .da_start = 0x0, + .da_end = 0xFFFFF000, }, }, #if defined(CONFIG_MPU_BRIDGE_IOMMU) @@ -43,6 +45,8 @@ static struct iommu_device omap3_devices[] = { .name = "iva2", .nr_tlb_entries = 32, .clk_name = "iva2_ck", + .da_start = 0x11000000, + .da_end = 0xFFFFF000, }, }, #endif @@ -64,6 +68,8 @@ static struct iommu_device omap4_devices[] = { .name = "ducati", .nr_tlb_entries = 32, .clk_name = "ducati_ick", + .da_start = 0x0, + .da_end = 0xFFFFF000, }, }, #if defined(CONFIG_MPU_TESLA_IOMMU) @@ -74,6 +80,8 @@ static struct iommu_device omap4_devices[] = { .name = "tesla", .nr_tlb_entries = 32, .clk_name = "tesla_ick", + .da_start = 0x0, + .da_end = 0xFFFFF000, }, }, #endif diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h index 33c7d41cb6a5..69230d685538 100644 --- a/arch/arm/plat-omap/include/plat/iommu.h +++ b/arch/arm/plat-omap/include/plat/iommu.h @@ -50,6 +50,8 @@ struct iommu { int (*isr)(struct iommu *obj); void *ctx; /* iommu context: registres saved area */ + u32 da_start; + u32 da_end; }; struct cr_regs { @@ -103,6 +105,8 @@ struct iommu_platform_data { const char *name; const char *clk_name; const int nr_tlb_entries; + u32 da_start; + u32 da_end; }; #if defined(CONFIG_ARCH_OMAP1) @@ -152,6 +156,7 @@ extern void flush_iotlb_all(struct iommu *obj); extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e); extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova); +extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end); extern struct iommu *iommu_get(const char *name); extern void iommu_put(struct iommu *obj); diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 6cd151b31bc5..b1107c08da56 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -829,6 +829,28 @@ static int device_match_by_alias(struct device *dev, void *data) return strcmp(obj->name, name) == 0; } +/** + * iommu_set_da_range - Set a valid device address range + * @obj: target iommu + * @start Start of valid range + * @end End of valid range + **/ +int iommu_set_da_range(struct iommu *obj, u32 start, u32 end) +{ + + if (!obj) + return -EFAULT; + + if (end < start || !PAGE_ALIGN(start | end)) + return -EINVAL; + + obj->da_start = start; + obj->da_end = end; + + return 0; +} +EXPORT_SYMBOL_GPL(iommu_set_da_range); + /** * iommu_get - Get iommu handler * @name: target iommu name @@ -922,6 +944,8 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) obj->name = pdata->name; obj->dev = &pdev->dev; obj->ctx = (void *)obj + sizeof(*obj); + obj->da_start = pdata->da_start; + obj->da_end = pdata->da_end; mutex_init(&obj->iommu_lock); mutex_init(&obj->mmap_lock); diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index fa6e64332a9e..6dc1296c8c77 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -280,13 +280,14 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, alignement = PAGE_SIZE; if (flags & IOVMF_DA_ANON) { - /* - * Reserve the first page for NULL - */ - start = PAGE_SIZE; + start = obj->da_start; + if (flags & IOVMF_LINEAR) alignement = iopgsz_max(bytes); start = roundup(start, alignement); + } else if (start < obj->da_start || start > obj->da_end || + obj->da_end - start < bytes) { + return ERR_PTR(-EINVAL); } tmp = NULL; @@ -299,16 +300,16 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, if (prev_end > start) break; - if (start + bytes <= tmp->da_start) + if (tmp->da_start > start && (tmp->da_start - start) >= bytes) goto found; - if (flags & IOVMF_DA_ANON) + if (tmp->da_end >= start && flags & IOVMF_DA_ANON) start = roundup(tmp->da_end + 1, alignement); prev_end = tmp->da_end; } - if ((start >= prev_end) && (ULONG_MAX - start + 1 >= bytes)) + if ((start >= prev_end) && (obj->da_end - start >= bytes)) goto found; dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n", From 1cd25df4e53b9507f7abbb8aff8ce2ba644a1468 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Mon, 11 Oct 2010 09:53:49 +0000 Subject: [PATCH 11/11] OMAP: iommu: make iva2 iommu selectable It seems dsp-link will do this, and tidspbridge too at some point, but right now it's not possible to select CONFIG_MPU_BRIDGE_IOMMU. Cc: Fernando Guzman Lugo Cc: Yogesh Marathe Signed-off-by: Felipe Contreras --- arch/arm/mach-omap2/omap-iommu.c | 2 +- arch/arm/plat-omap/Kconfig | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index 6be548cdd800..3fc5dc7233da 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -37,7 +37,7 @@ static struct iommu_device omap3_devices[] = { .da_end = 0xFFFFF000, }, }, -#if defined(CONFIG_MPU_BRIDGE_IOMMU) +#if defined(CONFIG_OMAP_IOMMU_IVA2) { .base = 0x5d000000, .irq = 28, diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 92c5bb7909f5..5e63e5069e0d 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -109,6 +109,9 @@ config OMAP_IOMMU_DEBUG Say N unless you know you need this. +config OMAP_IOMMU_IVA2 + bool + choice prompt "System timer" default OMAP_32K_TIMER if !ARCH_OMAP15XX