Commit c7d3e9e8 authored by Tony Lindgren's avatar Tony Lindgren

Merge branch 'for_2.6.38' of git://gitorious.org/iommu_mailbox/iommu_mailbox...

Merge branch 'for_2.6.38' of git://gitorious.org/iommu_mailbox/iommu_mailbox into devel-iommu-mailbox
parents 28257f7f 1cd25df4
...@@ -281,7 +281,7 @@ static struct omap_mbox_ops omap2_mbox_ops = { ...@@ -281,7 +281,7 @@ static struct omap_mbox_ops omap2_mbox_ops = {
/* FIXME: the following structs should be filled automatically by the user id */ /* 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 */ /* DSP */
static struct omap_mbox2_priv omap2_mbox_dsp_priv = { static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
.tx_fifo = { .tx_fifo = {
...@@ -306,7 +306,7 @@ struct omap_mbox mbox_dsp_info = { ...@@ -306,7 +306,7 @@ struct omap_mbox mbox_dsp_info = {
}; };
#endif #endif
#if defined(CONFIG_ARCH_OMAP3430) #if defined(CONFIG_ARCH_OMAP3)
struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL };
#endif #endif
...@@ -394,15 +394,19 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) ...@@ -394,15 +394,19 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
if (false) if (false)
; ;
#if defined(CONFIG_ARCH_OMAP3430) #if defined(CONFIG_ARCH_OMAP3)
else if (cpu_is_omap3430()) { else if (cpu_is_omap34xx()) {
list = omap3_mboxes; list = omap3_mboxes;
list[0]->irq = platform_get_irq_byname(pdev, "dsp"); list[0]->irq = platform_get_irq_byname(pdev, "dsp");
} }
#endif #endif
#if defined(CONFIG_ARCH_OMAP2420) #if defined(CONFIG_ARCH_OMAP2)
else if (cpu_is_omap2420()) { 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 = omap2_mboxes;
list[0]->irq = platform_get_irq_byname(pdev, "dsp"); list[0]->irq = platform_get_irq_byname(pdev, "dsp");
...@@ -432,9 +436,8 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) ...@@ -432,9 +436,8 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
iounmap(mbox_base); iounmap(mbox_base);
return ret; return ret;
} }
return 0;
return ret; return 0;
} }
static int __devexit omap2_mbox_remove(struct platform_device *pdev) static int __devexit omap2_mbox_remove(struct platform_device *pdev)
......
...@@ -33,9 +33,11 @@ static struct iommu_device omap3_devices[] = { ...@@ -33,9 +33,11 @@ static struct iommu_device omap3_devices[] = {
.name = "isp", .name = "isp",
.nr_tlb_entries = 8, .nr_tlb_entries = 8,
.clk_name = "cam_ick", .clk_name = "cam_ick",
.da_start = 0x0,
.da_end = 0xFFFFF000,
}, },
}, },
#if defined(CONFIG_MPU_BRIDGE_IOMMU) #if defined(CONFIG_OMAP_IOMMU_IVA2)
{ {
.base = 0x5d000000, .base = 0x5d000000,
.irq = 28, .irq = 28,
...@@ -43,6 +45,8 @@ static struct iommu_device omap3_devices[] = { ...@@ -43,6 +45,8 @@ static struct iommu_device omap3_devices[] = {
.name = "iva2", .name = "iva2",
.nr_tlb_entries = 32, .nr_tlb_entries = 32,
.clk_name = "iva2_ck", .clk_name = "iva2_ck",
.da_start = 0x11000000,
.da_end = 0xFFFFF000,
}, },
}, },
#endif #endif
...@@ -64,6 +68,8 @@ static struct iommu_device omap4_devices[] = { ...@@ -64,6 +68,8 @@ static struct iommu_device omap4_devices[] = {
.name = "ducati", .name = "ducati",
.nr_tlb_entries = 32, .nr_tlb_entries = 32,
.clk_name = "ducati_ick", .clk_name = "ducati_ick",
.da_start = 0x0,
.da_end = 0xFFFFF000,
}, },
}, },
#if defined(CONFIG_MPU_TESLA_IOMMU) #if defined(CONFIG_MPU_TESLA_IOMMU)
...@@ -74,6 +80,8 @@ static struct iommu_device omap4_devices[] = { ...@@ -74,6 +80,8 @@ static struct iommu_device omap4_devices[] = {
.name = "tesla", .name = "tesla",
.nr_tlb_entries = 32, .nr_tlb_entries = 32,
.clk_name = "tesla_ick", .clk_name = "tesla_ick",
.da_start = 0x0,
.da_end = 0xFFFFF000,
}, },
}, },
#endif #endif
......
...@@ -109,6 +109,9 @@ config OMAP_IOMMU_DEBUG ...@@ -109,6 +109,9 @@ config OMAP_IOMMU_DEBUG
Say N unless you know you need this. Say N unless you know you need this.
config OMAP_IOMMU_IVA2
bool
choice choice
prompt "System timer" prompt "System timer"
default OMAP_32K_TIMER if !ARCH_OMAP15XX default OMAP_32K_TIMER if !ARCH_OMAP15XX
......
...@@ -50,6 +50,8 @@ struct iommu { ...@@ -50,6 +50,8 @@ struct iommu {
int (*isr)(struct iommu *obj); int (*isr)(struct iommu *obj);
void *ctx; /* iommu context: registres saved area */ void *ctx; /* iommu context: registres saved area */
u32 da_start;
u32 da_end;
}; };
struct cr_regs { struct cr_regs {
...@@ -103,6 +105,8 @@ struct iommu_platform_data { ...@@ -103,6 +105,8 @@ struct iommu_platform_data {
const char *name; const char *name;
const char *clk_name; const char *clk_name;
const int nr_tlb_entries; const int nr_tlb_entries;
u32 da_start;
u32 da_end;
}; };
#if defined(CONFIG_ARCH_OMAP1) #if defined(CONFIG_ARCH_OMAP1)
...@@ -152,6 +156,7 @@ extern void flush_iotlb_all(struct iommu *obj); ...@@ -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 int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova); 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 struct iommu *iommu_get(const char *name);
extern void iommu_put(struct iommu *obj); extern void iommu_put(struct iommu *obj);
......
...@@ -46,8 +46,8 @@ struct omap_mbox_queue { ...@@ -46,8 +46,8 @@ struct omap_mbox_queue {
struct kfifo fifo; struct kfifo fifo;
struct work_struct work; struct work_struct work;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
int (*callback)(void *);
struct omap_mbox *mbox; struct omap_mbox *mbox;
bool full;
}; };
struct omap_mbox { struct omap_mbox {
...@@ -57,13 +57,15 @@ struct omap_mbox { ...@@ -57,13 +57,15 @@ struct omap_mbox {
struct omap_mbox_ops *ops; struct omap_mbox_ops *ops;
struct device *dev; struct device *dev;
void *priv; void *priv;
int use_count;
struct blocking_notifier_head notifier;
}; };
int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
void omap_mbox_init_seq(struct omap_mbox *); void omap_mbox_init_seq(struct omap_mbox *);
struct omap_mbox *omap_mbox_get(const char *); struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb);
void omap_mbox_put(struct omap_mbox *); 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_register(struct device *parent, struct omap_mbox **);
int omap_mbox_unregister(void); int omap_mbox_unregister(void);
......
...@@ -829,6 +829,28 @@ static int device_match_by_alias(struct device *dev, void *data) ...@@ -829,6 +829,28 @@ static int device_match_by_alias(struct device *dev, void *data)
return strcmp(obj->name, name) == 0; 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 * iommu_get - Get iommu handler
* @name: target iommu name * @name: target iommu name
...@@ -922,6 +944,8 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) ...@@ -922,6 +944,8 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
obj->name = pdata->name; obj->name = pdata->name;
obj->dev = &pdev->dev; obj->dev = &pdev->dev;
obj->ctx = (void *)obj + sizeof(*obj); 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->iommu_lock);
mutex_init(&obj->mmap_lock); mutex_init(&obj->mmap_lock);
......
...@@ -87,35 +87,43 @@ static size_t sgtable_len(const struct sg_table *sgt) ...@@ -87,35 +87,43 @@ static size_t sgtable_len(const struct sg_table *sgt)
} }
#define sgtable_ok(x) (!!sgtable_len(x)) #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 * calculate the optimal number sg elements from total bytes based on
* iommu superpages * iommu superpages
*/ */
static unsigned int sgtable_nents(size_t bytes) static unsigned sgtable_nents(size_t bytes, u32 da, u32 pa)
{ {
int i; unsigned nr_entries = 0, ent_sz;
unsigned int nr_entries;
const unsigned long pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, };
if (!IS_ALIGNED(bytes, PAGE_SIZE)) { if (!IS_ALIGNED(bytes, PAGE_SIZE)) {
pr_err("%s: wrong size %08x\n", __func__, bytes); pr_err("%s: wrong size %08x\n", __func__, bytes);
return 0; return 0;
} }
nr_entries = 0; while (bytes) {
for (i = 0; i < ARRAY_SIZE(pagesize); i++) { ent_sz = max_alignment(da | pa);
if (bytes >= pagesize[i]) { ent_sz = min_t(unsigned, ent_sz, iopgsz_max(bytes));
nr_entries += (bytes / pagesize[i]); nr_entries++;
bytes %= pagesize[i]; da += ent_sz;
} pa += ent_sz;
bytes -= ent_sz;
} }
BUG_ON(bytes);
return nr_entries; return nr_entries;
} }
/* allocate and initialize sg_table header(a kind of 'superblock') */ /* 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; unsigned int nr_entries;
int err; int err;
...@@ -127,9 +135,8 @@ static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags) ...@@ -127,9 +135,8 @@ static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags)
if (!IS_ALIGNED(bytes, PAGE_SIZE)) if (!IS_ALIGNED(bytes, PAGE_SIZE))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
/* FIXME: IOVMF_DA_FIXED should support 'superpages' */ if (flags & IOVMF_LINEAR) {
if ((flags & IOVMF_LINEAR) && (flags & IOVMF_DA_ANON)) { nr_entries = sgtable_nents(bytes, da, pa);
nr_entries = sgtable_nents(bytes);
if (!nr_entries) if (!nr_entries)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} else } else
...@@ -273,13 +280,14 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, ...@@ -273,13 +280,14 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
alignement = PAGE_SIZE; alignement = PAGE_SIZE;
if (flags & IOVMF_DA_ANON) { if (flags & IOVMF_DA_ANON) {
/* start = obj->da_start;
* Reserve the first page for NULL
*/
start = PAGE_SIZE;
if (flags & IOVMF_LINEAR) if (flags & IOVMF_LINEAR)
alignement = iopgsz_max(bytes); alignement = iopgsz_max(bytes);
start = roundup(start, alignement); 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; tmp = NULL;
...@@ -289,19 +297,19 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, ...@@ -289,19 +297,19 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
prev_end = 0; prev_end = 0;
list_for_each_entry(tmp, &obj->mmap, list) { list_for_each_entry(tmp, &obj->mmap, list) {
if (prev_end >= start) if (prev_end > start)
break; break;
if (start + bytes < tmp->da_start) if (tmp->da_start > start && (tmp->da_start - start) >= bytes)
goto found; goto found;
if (flags & IOVMF_DA_ANON) if (tmp->da_end >= start && flags & IOVMF_DA_ANON)
start = roundup(tmp->da_end + 1, alignement); start = roundup(tmp->da_end + 1, alignement);
prev_end = tmp->da_end; prev_end = tmp->da_end;
} }
if ((start > prev_end) && (ULONG_MAX - start >= bytes)) if ((start >= prev_end) && (obj->da_end - start >= bytes))
goto found; goto found;
dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n", dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
...@@ -409,7 +417,8 @@ static inline void sgtable_drain_vmalloc(struct sg_table *sgt) ...@@ -409,7 +417,8 @@ static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
BUG_ON(!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; unsigned int i;
struct scatterlist *sg; struct scatterlist *sg;
...@@ -418,9 +427,10 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) ...@@ -418,9 +427,10 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
va = phys_to_virt(pa); va = phys_to_virt(pa);
for_each_sg(sgt->sgl, sg, sgt->nents, i) { 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)); BUG_ON(!iopgsz_ok(bytes));
...@@ -429,6 +439,7 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) ...@@ -429,6 +439,7 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
* 'pa' is cotinuous(linear). * 'pa' is cotinuous(linear).
*/ */
pa += bytes; pa += bytes;
da += bytes;
len -= bytes; len -= bytes;
} }
BUG_ON(len); BUG_ON(len);
...@@ -695,18 +706,18 @@ u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags) ...@@ -695,18 +706,18 @@ u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
if (!va) if (!va)
return -ENOMEM; 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)) { if (IS_ERR(sgt)) {
da = PTR_ERR(sgt); da = PTR_ERR(sgt);
goto err_sgt_alloc; goto err_sgt_alloc;
} }
sgtable_fill_vmalloc(sgt, va); 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); da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
if (IS_ERR_VALUE(da)) if (IS_ERR_VALUE(da))
goto err_iommu_vmap; goto err_iommu_vmap;
...@@ -746,11 +757,11 @@ static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va, ...@@ -746,11 +757,11 @@ static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va,
{ {
struct sg_table *sgt; struct sg_table *sgt;
sgt = sgtable_alloc(bytes, flags); sgt = sgtable_alloc(bytes, flags, da, pa);
if (IS_ERR(sgt)) if (IS_ERR(sgt))
return PTR_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); da = map_iommu_region(obj, da, sgt, va, bytes, flags);
if (IS_ERR_VALUE(da)) { if (IS_ERR_VALUE(da)) {
...@@ -811,7 +822,7 @@ void iommu_kunmap(struct iommu *obj, u32 da) ...@@ -811,7 +822,7 @@ void iommu_kunmap(struct iommu *obj, u32 da)
struct sg_table *sgt; struct sg_table *sgt;
typedef void (*func_t)(const void *); 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); IOVMF_LINEAR | IOVMF_MMIO);
if (!sgt) if (!sgt)
dev_dbg(obj->dev, "%s: No sgt\n", __func__); dev_dbg(obj->dev, "%s: No sgt\n", __func__);
......
...@@ -28,12 +28,12 @@ ...@@ -28,12 +28,12 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/notifier.h>
#include <plat/mailbox.h> #include <plat/mailbox.h>
static struct workqueue_struct *mboxd; static struct workqueue_struct *mboxd;
static struct omap_mbox **mboxes; static struct omap_mbox **mboxes;
static bool rq_full;
static int mbox_configured; static int mbox_configured;
static DEFINE_MUTEX(mbox_configured_lock); static DEFINE_MUTEX(mbox_configured_lock);
...@@ -93,20 +93,25 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) ...@@ -93,20 +93,25 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
struct omap_mbox_queue *mq = mbox->txq; struct omap_mbox_queue *mq = mbox->txq;
int ret = 0, len; int ret = 0, len;
spin_lock(&mq->lock); spin_lock_bh(&mq->lock);
if (kfifo_avail(&mq->fifo) < sizeof(msg)) { if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; 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)); len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
WARN_ON(len != sizeof(msg)); WARN_ON(len != sizeof(msg));
tasklet_schedule(&mbox->txq->tasklet); tasklet_schedule(&mbox->txq->tasklet);
out: out:
spin_unlock(&mq->lock); spin_unlock_bh(&mq->lock);
return ret; return ret;
} }
EXPORT_SYMBOL(omap_mbox_msg_send); EXPORT_SYMBOL(omap_mbox_msg_send);
...@@ -146,8 +151,14 @@ static void mbox_rx_work(struct work_struct *work) ...@@ -146,8 +151,14 @@ static void mbox_rx_work(struct work_struct *work)
len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
WARN_ON(len != sizeof(msg)); WARN_ON(len != sizeof(msg));
if (mq->callback) blocking_notifier_call_chain(&mq->mbox->notifier, len,
mq->callback((void *)msg); (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 +181,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) ...@@ -170,7 +181,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
while (!mbox_fifo_empty(mbox)) { while (!mbox_fifo_empty(mbox)) {
if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
omap_mbox_disable_irq(mbox, IRQ_RX); omap_mbox_disable_irq(mbox, IRQ_RX);
rq_full = true; mq->full = true;
goto nomem; goto nomem;
} }
...@@ -239,73 +250,77 @@ static int omap_mbox_startup(struct omap_mbox *mbox) ...@@ -239,73 +250,77 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
int ret = 0; int ret = 0;
struct omap_mbox_queue *mq; struct omap_mbox_queue *mq;
if (mbox->ops->startup) { mutex_lock(&mbox_configured_lock);
mutex_lock(&mbox_configured_lock); if (!mbox_configured++) {
if (!mbox_configured) if (likely(mbox->ops->startup)) {
ret = mbox->ops->startup(mbox); ret = mbox->ops->startup(mbox);
if (unlikely(ret))
if (ret) { goto fail_startup;
mutex_unlock(&mbox_configured_lock); } else
return ret; goto fail_startup;
}
mbox_configured++;
mutex_unlock(&mbox_configured_lock);
}
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, NULL, mbox_tx_tasklet); if (!mbox->use_count++) {
if (!mq) { ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
ret = -ENOMEM; mbox->name, mbox);
goto fail_alloc_txq; if (unlikely(ret)) {
} pr_err("failed to register mailbox interrupt:%d\n",
mbox->txq = mq; ret);
goto fail_request_irq;
}
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); mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
if (!mq) { if (!mq) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail_alloc_rxq; goto fail_alloc_rxq;
}
mbox->rxq = mq;
mq->mbox = mbox;
} }
mbox->rxq = mq; mutex_unlock(&mbox_configured_lock);
return 0; return 0;
fail_alloc_rxq: fail_alloc_rxq:
mbox_queue_free(mbox->txq); mbox_queue_free(mbox->txq);
fail_alloc_txq: fail_alloc_txq:
free_irq(mbox->irq, mbox); free_irq(mbox->irq, mbox);
fail_request_irq: fail_request_irq:
if (mbox->ops->shutdown) if (mbox->ops->shutdown)
mbox->ops->shutdown(mbox); mbox->ops->shutdown(mbox);
mbox->use_count--;
fail_startup:
mbox_configured--;
mutex_unlock(&mbox_configured_lock);
return ret; return ret;
} }
static void omap_mbox_fini(struct omap_mbox *mbox) static void omap_mbox_fini(struct omap_mbox *mbox)
{ {
free_irq(mbox->irq, mbox); mutex_lock(&mbox_configured_lock);
tasklet_kill(&mbox->txq->tasklet);
flush_work(&mbox->rxq->work); if (!--mbox->use_count) {
mbox_queue_free(mbox->txq); free_irq(mbox->irq, mbox);
mbox_queue_free(mbox->rxq); tasklet_kill(&mbox->txq->tasklet);
flush_work(&mbox->rxq->work);
mbox_queue_free(mbox->txq);
mbox_queue_free(mbox->rxq);
}
if (mbox->ops->shutdown) { if (likely(mbox->ops->shutdown)) {
mutex_lock(&mbox_configured_lock); if (!--mbox_configured)
if (mbox_configured > 0)
mbox_configured--;
if (!mbox_configured)
mbox->ops->shutdown(mbox); mbox->ops->shutdown(mbox);
mutex_unlock(&mbox_configured_lock);
} }
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; struct omap_mbox *mbox;
int ret; int ret;
...@@ -324,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name) ...@@ -324,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name)
if (ret) if (ret)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
if (nb)
blocking_notifier_chain_register(&mbox->notifier, nb);
return mbox; return mbox;
} }
EXPORT_SYMBOL(omap_mbox_get); 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); omap_mbox_fini(mbox);
} }
EXPORT_SYMBOL(omap_mbox_put); EXPORT_SYMBOL(omap_mbox_put);
...@@ -353,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list) ...@@ -353,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list)
ret = PTR_ERR(mbox->dev); ret = PTR_ERR(mbox->dev);
goto err_out; goto err_out;
} }
BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
} }
return 0; return 0;
...@@ -391,7 +412,8 @@ static int __init omap_mbox_init(void) ...@@ -391,7 +412,8 @@ static int __init omap_mbox_init(void)
/* kfifo size sanity check: alignment and minimal size */ /* kfifo size sanity check: alignment and minimal size */
mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); 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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment