Merge branches 'devel-iommu-mailbox' and 'devel-l2x0' into omap-for-linus

This commit is contained in:
Tony Lindgren 2010-12-20 19:13:40 -08:00
commit 4584acc3ee
21 changed files with 239 additions and 138 deletions

View file

@ -59,7 +59,17 @@
#define L2X0_CACHE_ID_PART_MASK (0xf << 6)
#define L2X0_CACHE_ID_PART_L210 (1 << 6)
#define L2X0_CACHE_ID_PART_L310 (3 << 6)
#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17)
#define L2X0_AUX_CTRL_MASK 0xc0000fff
#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17)
#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22
#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26
#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27
#define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT 28
#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29
#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
#ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);

View file

@ -241,18 +241,15 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
*
*/
#ifndef __arch_ioremap
#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
#define ioremap_nocache(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
#define ioremap_cached(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_WC)
#define iounmap(cookie) __iounmap(cookie)
#else
#define __arch_ioremap __arm_ioremap
#define __arch_iounmap __iounmap
#endif
#define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap(cookie) __arch_iounmap(cookie)
#endif
#define iounmap __arch_iounmap
/*
* io{read,write}{8,16,32} macros

View file

@ -22,8 +22,8 @@
#define __mem_isa(a) (a)
#ifndef __ASSEMBLER__
#define __arch_ioremap(p, s, t) davinci_ioremap(p, s, t)
#define __arch_iounmap(v) davinci_iounmap(v)
#define __arch_ioremap davinci_ioremap
#define __arch_iounmap davinci_iounmap
void __iomem *davinci_ioremap(unsigned long phys, size_t size,
unsigned int type);

View file

@ -35,7 +35,7 @@ extern u32 iop13xx_atux_mem_base;
extern size_t iop13xx_atue_mem_size;
extern size_t iop13xx_atux_mem_size;
#define __arch_ioremap(a, s, f) __iop13xx_ioremap(a, s, f)
#define __arch_iounmap(a) __iop13xx_iounmap(a)
#define __arch_ioremap __iop13xx_ioremap
#define __arch_iounmap __iop13xx_iounmap
#endif

View file

@ -21,7 +21,7 @@ extern void __iop3xx_iounmap(void __iomem *addr);
#define __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
#define __mem_pci(a) (a)
#define __arch_ioremap(a, s, f) __iop3xx_ioremap(a, s, f)
#define __arch_iounmap(a) __iop3xx_iounmap(a)
#define __arch_ioremap __iop3xx_ioremap
#define __arch_iounmap __iop3xx_iounmap
#endif

View file

@ -21,7 +21,7 @@ extern void __iop3xx_iounmap(void __iomem *addr);
#define __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
#define __mem_pci(a) (a)
#define __arch_ioremap(a, s, f) __iop3xx_ioremap(a, s, f)
#define __arch_iounmap(a) __iop3xx_iounmap(a)
#define __arch_ioremap __iop3xx_ioremap
#define __arch_iounmap __iop3xx_iounmap
#endif

View file

@ -45,8 +45,8 @@ ixp23xx_iounmap(void __iomem *addr)
__iounmap(addr);
}
#define __arch_ioremap(a,s,f) ixp23xx_ioremap(a,s,f)
#define __arch_iounmap(a) ixp23xx_iounmap(a)
#define __arch_ioremap ixp23xx_ioremap
#define __arch_iounmap ixp23xx_iounmap
#endif

View file

@ -74,8 +74,8 @@ static inline void __indirect_iounmap(void __iomem *addr)
__iounmap(addr);
}
#define __arch_ioremap(a, s, f) __indirect_ioremap(a, s, f)
#define __arch_iounmap(a) __indirect_iounmap(a)
#define __arch_ioremap __indirect_ioremap
#define __arch_iounmap __indirect_iounmap
#define writeb(v, p) __indirect_writeb(v, p)
#define writew(v, p) __indirect_writew(v, p)

View file

@ -42,8 +42,8 @@ __arch_iounmap(void __iomem *addr)
__iounmap(addr);
}
#define __arch_ioremap(p, s, m) __arch_ioremap(p, s, m)
#define __arch_iounmap(a) __arch_iounmap(a)
#define __arch_ioremap __arch_ioremap
#define __arch_iounmap __arch_iounmap
#define __io(a) __io(a)
#define __mem_pci(a) (a)

View file

@ -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");
@ -432,9 +436,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)

View file

@ -33,9 +33,11 @@ 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)
#if defined(CONFIG_OMAP_IOMMU_IVA2)
{
.base = 0x5d000000,
.irq = 28,
@ -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

View file

@ -53,6 +53,8 @@ static void omap4_l2x0_disable(void)
static int __init omap_l2_cache_init(void)
{
u32 aux_ctrl = 0;
/*
* To avoid code running on other OMAPs in
* multi-omap builds
@ -64,18 +66,32 @@ static int __init omap_l2_cache_init(void)
l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K);
BUG_ON(!l2cache_base);
/* Enable PL310 L2 Cache controller */
omap_smc1(0x102, 0x1);
/*
* 16-way associativity, parity disabled
* Way size - 32KB (es1.0)
* Way size - 64KB (es2.0 +)
*/
if (omap_rev() == OMAP4430_REV_ES1_0)
l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
else
l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff);
aux_ctrl = ((1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) |
(0x1 << 25) |
(0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) |
(0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT));
if (omap_rev() == OMAP4430_REV_ES1_0) {
aux_ctrl |= 0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT;
} else {
aux_ctrl |= ((0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) |
(1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) |
(1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) |
(1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) |
(1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT));
}
if (omap_rev() != OMAP4430_REV_ES1_0)
omap_smc1(0x109, aux_ctrl);
/* Enable PL310 L2 Cache controller */
omap_smc1(0x102, 0x1);
l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK);
/*
* Override default outer_cache.disable with a OMAP4

View file

@ -38,8 +38,8 @@ __arch_iounmap(void __iomem *addr)
__iounmap(addr);
}
#define __arch_ioremap(p, s, m) __arch_ioremap(p, s, m)
#define __arch_iounmap(a) __arch_iounmap(a)
#define __arch_ioremap __arch_ioremap
#define __arch_iounmap __arch_iounmap
#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)

View file

@ -65,8 +65,8 @@
#ifndef __ASSEMBLER__
#define __arch_ioremap(p, s, t) tegra_ioremap(p, s, t)
#define __arch_iounmap(v) tegra_iounmap(v)
#define __arch_ioremap tegra_ioremap
#define __arch_iounmap tegra_iounmap
void __iomem *tegra_ioremap(unsigned long phys, size_t size, unsigned int type);
void tegra_iounmap(volatile void __iomem *addr);

View file

@ -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

View file

@ -294,8 +294,8 @@ static inline void omap44xx_map_common_io(void)
extern void omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
struct omap_sdrc_params *sdrc_cs1);
#define __arch_ioremap(p,s,t) omap_ioremap(p,s,t)
#define __arch_iounmap(v) omap_iounmap(v)
#define __arch_ioremap omap_ioremap
#define __arch_iounmap omap_iounmap
void __iomem *omap_ioremap(unsigned long phys, size_t size, unsigned int type);
void omap_iounmap(volatile void __iomem *addr);

View file

@ -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);

View file

@ -46,8 +46,8 @@ struct omap_mbox_queue {
struct kfifo fifo;
struct work_struct work;
struct tasklet_struct tasklet;
int (*callback)(void *);
struct omap_mbox *mbox;
bool full;
};
struct omap_mbox {
@ -57,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);

View file

@ -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);

View file

@ -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
@ -273,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;
@ -289,19 +297,19 @@ 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 (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 >= 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",
@ -409,7 +417,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 +427,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 +439,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 +706,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 +757,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)) {
@ -811,7 +822,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__);

View file

@ -28,12 +28,12 @@
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <linux/err.h>
#include <linux/notifier.h>
#include <plat/mailbox.h>
static struct workqueue_struct *mboxd;
static struct omap_mbox **mboxes;
static bool rq_full;
static int mbox_configured;
static DEFINE_MUTEX(mbox_configured_lock);
@ -93,20 +93,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);
@ -146,8 +151,14 @@ 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;
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)
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;
}
@ -239,73 +250,77 @@ 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:
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);
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;
@ -324,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);
@ -353,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;
@ -391,7 +412,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;
}