Merge branches 'devel-iommu-mailbox' and 'devel-l2x0' into omap-for-linus
This commit is contained in:
commit
4584acc3ee
21 changed files with 239 additions and 138 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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__);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue