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_MASK (0xf << 6)
#define L2X0_CACHE_ID_PART_L210 (1 << 6) #define L2X0_CACHE_ID_PART_L210 (1 << 6)
#define L2X0_CACHE_ID_PART_L310 (3 << 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__ #ifndef __ASSEMBLY__
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); 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 #ifndef __arch_ioremap
#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE) #define __arch_ioremap __arm_ioremap
#define ioremap_nocache(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE) #define __arch_iounmap __iounmap
#define ioremap_cached(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_CACHED) #endif
#define ioremap_wc(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_WC)
#define iounmap(cookie) __iounmap(cookie)
#else
#define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE) #define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(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_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC) #define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap(cookie) __arch_iounmap(cookie) #define iounmap __arch_iounmap
#endif
/* /*
* io{read,write}{8,16,32} macros * io{read,write}{8,16,32} macros

View file

@ -22,8 +22,8 @@
#define __mem_isa(a) (a) #define __mem_isa(a) (a)
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
#define __arch_ioremap(p, s, t) davinci_ioremap(p, s, t) #define __arch_ioremap davinci_ioremap
#define __arch_iounmap(v) davinci_iounmap(v) #define __arch_iounmap davinci_iounmap
void __iomem *davinci_ioremap(unsigned long phys, size_t size, void __iomem *davinci_ioremap(unsigned long phys, size_t size,
unsigned int type); 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_atue_mem_size;
extern size_t iop13xx_atux_mem_size; extern size_t iop13xx_atux_mem_size;
#define __arch_ioremap(a, s, f) __iop13xx_ioremap(a, s, f) #define __arch_ioremap __iop13xx_ioremap
#define __arch_iounmap(a) __iop13xx_iounmap(a) #define __arch_iounmap __iop13xx_iounmap
#endif #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 __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
#define __mem_pci(a) (a) #define __mem_pci(a) (a)
#define __arch_ioremap(a, s, f) __iop3xx_ioremap(a, s, f) #define __arch_ioremap __iop3xx_ioremap
#define __arch_iounmap(a) __iop3xx_iounmap(a) #define __arch_iounmap __iop3xx_iounmap
#endif #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 __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
#define __mem_pci(a) (a) #define __mem_pci(a) (a)
#define __arch_ioremap(a, s, f) __iop3xx_ioremap(a, s, f) #define __arch_ioremap __iop3xx_ioremap
#define __arch_iounmap(a) __iop3xx_iounmap(a) #define __arch_iounmap __iop3xx_iounmap
#endif #endif

View file

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

View file

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

View file

@ -42,8 +42,8 @@ __arch_iounmap(void __iomem *addr)
__iounmap(addr); __iounmap(addr);
} }
#define __arch_ioremap(p, s, m) __arch_ioremap(p, s, m) #define __arch_ioremap __arch_ioremap
#define __arch_iounmap(a) __arch_iounmap(a) #define __arch_iounmap __arch_iounmap
#define __io(a) __io(a) #define __io(a) __io(a)
#define __mem_pci(a) (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 */ /* 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 = {
}; };
#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)
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)
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)

View file

@ -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[] = {
.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[] = {
.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[] = {
.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

View file

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

View file

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

View file

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

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, extern void omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0,
struct omap_sdrc_params *sdrc_cs1); struct omap_sdrc_params *sdrc_cs1);
#define __arch_ioremap(p,s,t) omap_ioremap(p,s,t) #define __arch_ioremap omap_ioremap
#define __arch_iounmap(v) omap_iounmap(v) #define __arch_iounmap omap_iounmap
void __iomem *omap_ioremap(unsigned long phys, size_t size, unsigned int type); void __iomem *omap_ioremap(unsigned long phys, size_t size, unsigned int type);
void omap_iounmap(volatile void __iomem *addr); void omap_iounmap(volatile void __iomem *addr);

View file

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

View file

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

View file

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

View file

@ -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)
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,
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,
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)
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)
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)
* '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)
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,
{ {
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)
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__);

View file

@ -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)
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)
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)
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)
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))
goto fail_startup;
} else
goto fail_startup;
}
if (ret) { if (!mbox->use_count++) {
mutex_unlock(&mbox_configured_lock); ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
return ret; mbox->name, mbox);
if (unlikely(ret)) {
pr_err("failed to register mailbox interrupt:%d\n",
ret);
goto fail_request_irq;
} }
mbox_configured++; mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
mutex_unlock(&mbox_configured_lock); if (!mq) {
} ret = -ENOMEM;
goto fail_alloc_txq;
}
mbox->txq = mq;
ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
mbox->name, mbox); if (!mq) {
if (ret) { ret = -ENOMEM;
printk(KERN_ERR goto fail_alloc_rxq;
"failed to register mailbox interrupt:%d\n", ret); }
goto fail_request_irq; mbox->rxq = mq;
mq->mbox = mbox;
} }
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;
mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
if (!mq) {
ret = -ENOMEM;
goto fail_alloc_rxq;
}
mbox->rxq = mq;
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);
mbox_queue_free(mbox->txq);
mbox_queue_free(mbox->rxq);
if (mbox->ops->shutdown) { if (!--mbox->use_count) {
mutex_lock(&mbox_configured_lock); free_irq(mbox->irq, mbox);
if (mbox_configured > 0) tasklet_kill(&mbox->txq->tasklet);
mbox_configured--; flush_work(&mbox->rxq->work);
if (!mbox_configured) mbox_queue_free(mbox->txq);
mbox->ops->shutdown(mbox); mbox_queue_free(mbox->rxq);
mutex_unlock(&mbox_configured_lock);
} }
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; struct omap_mbox *mbox;
int ret; int ret;
@ -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)
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)
/* 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;
} }