diff options
-rw-r--r-- | arch/arm/mach-omap2/mailbox.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-iommu.c | 10 | ||||
-rw-r--r-- | arch/arm/plat-omap/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu.h | 5 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/mailbox.h | 8 | ||||
-rw-r--r-- | arch/arm/plat-omap/iommu.c | 24 | ||||
-rw-r--r-- | arch/arm/plat-omap/iovmm.c | 81 | ||||
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 130 |
8 files changed, 179 insertions, 101 deletions
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index 40ddecab93a9..394413dc7deb 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c | |||
@@ -281,7 +281,7 @@ static struct omap_mbox_ops omap2_mbox_ops = { | |||
281 | 281 | ||
282 | /* FIXME: the following structs should be filled automatically by the user id */ | 282 | /* FIXME: the following structs should be filled automatically by the user id */ |
283 | 283 | ||
284 | #if defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_ARCH_OMAP2420) | 284 | #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP2) |
285 | /* DSP */ | 285 | /* DSP */ |
286 | static struct omap_mbox2_priv omap2_mbox_dsp_priv = { | 286 | static struct omap_mbox2_priv omap2_mbox_dsp_priv = { |
287 | .tx_fifo = { | 287 | .tx_fifo = { |
@@ -306,7 +306,7 @@ struct omap_mbox mbox_dsp_info = { | |||
306 | }; | 306 | }; |
307 | #endif | 307 | #endif |
308 | 308 | ||
309 | #if defined(CONFIG_ARCH_OMAP3430) | 309 | #if defined(CONFIG_ARCH_OMAP3) |
310 | struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; | 310 | struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL }; |
311 | #endif | 311 | #endif |
312 | 312 | ||
@@ -394,15 +394,19 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) | |||
394 | 394 | ||
395 | if (false) | 395 | if (false) |
396 | ; | 396 | ; |
397 | #if defined(CONFIG_ARCH_OMAP3430) | 397 | #if defined(CONFIG_ARCH_OMAP3) |
398 | else if (cpu_is_omap3430()) { | 398 | else if (cpu_is_omap34xx()) { |
399 | list = omap3_mboxes; | 399 | list = omap3_mboxes; |
400 | 400 | ||
401 | list[0]->irq = platform_get_irq_byname(pdev, "dsp"); | 401 | list[0]->irq = platform_get_irq_byname(pdev, "dsp"); |
402 | } | 402 | } |
403 | #endif | 403 | #endif |
404 | #if defined(CONFIG_ARCH_OMAP2420) | 404 | #if defined(CONFIG_ARCH_OMAP2) |
405 | else if (cpu_is_omap2420()) { | 405 | else if (cpu_is_omap2430()) { |
406 | list = omap2_mboxes; | ||
407 | |||
408 | list[0]->irq = platform_get_irq_byname(pdev, "dsp"); | ||
409 | } else if (cpu_is_omap2420()) { | ||
406 | list = omap2_mboxes; | 410 | list = omap2_mboxes; |
407 | 411 | ||
408 | list[0]->irq = platform_get_irq_byname(pdev, "dsp"); | 412 | list[0]->irq = platform_get_irq_byname(pdev, "dsp"); |
@@ -432,9 +436,8 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) | |||
432 | iounmap(mbox_base); | 436 | iounmap(mbox_base); |
433 | return ret; | 437 | return ret; |
434 | } | 438 | } |
435 | return 0; | ||
436 | 439 | ||
437 | return ret; | 440 | return 0; |
438 | } | 441 | } |
439 | 442 | ||
440 | static int __devexit omap2_mbox_remove(struct platform_device *pdev) | 443 | static int __devexit omap2_mbox_remove(struct platform_device *pdev) |
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index f5a1aad1a5c0..3fc5dc7233da 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c | |||
@@ -33,9 +33,11 @@ static struct iommu_device omap3_devices[] = { | |||
33 | .name = "isp", | 33 | .name = "isp", |
34 | .nr_tlb_entries = 8, | 34 | .nr_tlb_entries = 8, |
35 | .clk_name = "cam_ick", | 35 | .clk_name = "cam_ick", |
36 | .da_start = 0x0, | ||
37 | .da_end = 0xFFFFF000, | ||
36 | }, | 38 | }, |
37 | }, | 39 | }, |
38 | #if defined(CONFIG_MPU_BRIDGE_IOMMU) | 40 | #if defined(CONFIG_OMAP_IOMMU_IVA2) |
39 | { | 41 | { |
40 | .base = 0x5d000000, | 42 | .base = 0x5d000000, |
41 | .irq = 28, | 43 | .irq = 28, |
@@ -43,6 +45,8 @@ static struct iommu_device omap3_devices[] = { | |||
43 | .name = "iva2", | 45 | .name = "iva2", |
44 | .nr_tlb_entries = 32, | 46 | .nr_tlb_entries = 32, |
45 | .clk_name = "iva2_ck", | 47 | .clk_name = "iva2_ck", |
48 | .da_start = 0x11000000, | ||
49 | .da_end = 0xFFFFF000, | ||
46 | }, | 50 | }, |
47 | }, | 51 | }, |
48 | #endif | 52 | #endif |
@@ -64,6 +68,8 @@ static struct iommu_device omap4_devices[] = { | |||
64 | .name = "ducati", | 68 | .name = "ducati", |
65 | .nr_tlb_entries = 32, | 69 | .nr_tlb_entries = 32, |
66 | .clk_name = "ducati_ick", | 70 | .clk_name = "ducati_ick", |
71 | .da_start = 0x0, | ||
72 | .da_end = 0xFFFFF000, | ||
67 | }, | 73 | }, |
68 | }, | 74 | }, |
69 | #if defined(CONFIG_MPU_TESLA_IOMMU) | 75 | #if defined(CONFIG_MPU_TESLA_IOMMU) |
@@ -74,6 +80,8 @@ static struct iommu_device omap4_devices[] = { | |||
74 | .name = "tesla", | 80 | .name = "tesla", |
75 | .nr_tlb_entries = 32, | 81 | .nr_tlb_entries = 32, |
76 | .clk_name = "tesla_ick", | 82 | .clk_name = "tesla_ick", |
83 | .da_start = 0x0, | ||
84 | .da_end = 0xFFFFF000, | ||
77 | }, | 85 | }, |
78 | }, | 86 | }, |
79 | #endif | 87 | #endif |
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 92c5bb7909f5..5e63e5069e0d 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig | |||
@@ -109,6 +109,9 @@ config OMAP_IOMMU_DEBUG | |||
109 | 109 | ||
110 | Say N unless you know you need this. | 110 | Say N unless you know you need this. |
111 | 111 | ||
112 | config OMAP_IOMMU_IVA2 | ||
113 | bool | ||
114 | |||
112 | choice | 115 | choice |
113 | prompt "System timer" | 116 | prompt "System timer" |
114 | default OMAP_32K_TIMER if !ARCH_OMAP15XX | 117 | default OMAP_32K_TIMER if !ARCH_OMAP15XX |
diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h index 33c7d41cb6a5..69230d685538 100644 --- a/arch/arm/plat-omap/include/plat/iommu.h +++ b/arch/arm/plat-omap/include/plat/iommu.h | |||
@@ -50,6 +50,8 @@ struct iommu { | |||
50 | int (*isr)(struct iommu *obj); | 50 | int (*isr)(struct iommu *obj); |
51 | 51 | ||
52 | void *ctx; /* iommu context: registres saved area */ | 52 | void *ctx; /* iommu context: registres saved area */ |
53 | u32 da_start; | ||
54 | u32 da_end; | ||
53 | }; | 55 | }; |
54 | 56 | ||
55 | struct cr_regs { | 57 | struct cr_regs { |
@@ -103,6 +105,8 @@ struct iommu_platform_data { | |||
103 | const char *name; | 105 | const char *name; |
104 | const char *clk_name; | 106 | const char *clk_name; |
105 | const int nr_tlb_entries; | 107 | const int nr_tlb_entries; |
108 | u32 da_start; | ||
109 | u32 da_end; | ||
106 | }; | 110 | }; |
107 | 111 | ||
108 | #if defined(CONFIG_ARCH_OMAP1) | 112 | #if defined(CONFIG_ARCH_OMAP1) |
@@ -152,6 +156,7 @@ extern void flush_iotlb_all(struct iommu *obj); | |||
152 | extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e); | 156 | extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e); |
153 | extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova); | 157 | extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova); |
154 | 158 | ||
159 | extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end); | ||
155 | extern struct iommu *iommu_get(const char *name); | 160 | extern struct iommu *iommu_get(const char *name); |
156 | extern void iommu_put(struct iommu *obj); | 161 | extern void iommu_put(struct iommu *obj); |
157 | 162 | ||
diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h index 997656552109..cc3921e9059c 100644 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ b/arch/arm/plat-omap/include/plat/mailbox.h | |||
@@ -46,8 +46,8 @@ struct omap_mbox_queue { | |||
46 | struct kfifo fifo; | 46 | struct kfifo fifo; |
47 | struct work_struct work; | 47 | struct work_struct work; |
48 | struct tasklet_struct tasklet; | 48 | struct tasklet_struct tasklet; |
49 | int (*callback)(void *); | ||
50 | struct omap_mbox *mbox; | 49 | struct omap_mbox *mbox; |
50 | bool full; | ||
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct omap_mbox { | 53 | struct omap_mbox { |
@@ -57,13 +57,15 @@ struct omap_mbox { | |||
57 | struct omap_mbox_ops *ops; | 57 | struct omap_mbox_ops *ops; |
58 | struct device *dev; | 58 | struct device *dev; |
59 | void *priv; | 59 | void *priv; |
60 | int use_count; | ||
61 | struct blocking_notifier_head notifier; | ||
60 | }; | 62 | }; |
61 | 63 | ||
62 | int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); | 64 | int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); |
63 | void omap_mbox_init_seq(struct omap_mbox *); | 65 | void omap_mbox_init_seq(struct omap_mbox *); |
64 | 66 | ||
65 | struct omap_mbox *omap_mbox_get(const char *); | 67 | struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb); |
66 | void omap_mbox_put(struct omap_mbox *); | 68 | void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb); |
67 | 69 | ||
68 | int omap_mbox_register(struct device *parent, struct omap_mbox **); | 70 | int omap_mbox_register(struct device *parent, struct omap_mbox **); |
69 | int omap_mbox_unregister(void); | 71 | int omap_mbox_unregister(void); |
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 6cd151b31bc5..b1107c08da56 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c | |||
@@ -830,6 +830,28 @@ static int device_match_by_alias(struct device *dev, void *data) | |||
830 | } | 830 | } |
831 | 831 | ||
832 | /** | 832 | /** |
833 | * iommu_set_da_range - Set a valid device address range | ||
834 | * @obj: target iommu | ||
835 | * @start Start of valid range | ||
836 | * @end End of valid range | ||
837 | **/ | ||
838 | int iommu_set_da_range(struct iommu *obj, u32 start, u32 end) | ||
839 | { | ||
840 | |||
841 | if (!obj) | ||
842 | return -EFAULT; | ||
843 | |||
844 | if (end < start || !PAGE_ALIGN(start | end)) | ||
845 | return -EINVAL; | ||
846 | |||
847 | obj->da_start = start; | ||
848 | obj->da_end = end; | ||
849 | |||
850 | return 0; | ||
851 | } | ||
852 | EXPORT_SYMBOL_GPL(iommu_set_da_range); | ||
853 | |||
854 | /** | ||
833 | * iommu_get - Get iommu handler | 855 | * iommu_get - Get iommu handler |
834 | * @name: target iommu name | 856 | * @name: target iommu name |
835 | **/ | 857 | **/ |
@@ -922,6 +944,8 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) | |||
922 | obj->name = pdata->name; | 944 | obj->name = pdata->name; |
923 | obj->dev = &pdev->dev; | 945 | obj->dev = &pdev->dev; |
924 | obj->ctx = (void *)obj + sizeof(*obj); | 946 | obj->ctx = (void *)obj + sizeof(*obj); |
947 | obj->da_start = pdata->da_start; | ||
948 | obj->da_end = pdata->da_end; | ||
925 | 949 | ||
926 | mutex_init(&obj->iommu_lock); | 950 | mutex_init(&obj->iommu_lock); |
927 | mutex_init(&obj->mmap_lock); | 951 | mutex_init(&obj->mmap_lock); |
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index 8ce0de247c71..6dc1296c8c77 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c | |||
@@ -87,35 +87,43 @@ static size_t sgtable_len(const struct sg_table *sgt) | |||
87 | } | 87 | } |
88 | #define sgtable_ok(x) (!!sgtable_len(x)) | 88 | #define sgtable_ok(x) (!!sgtable_len(x)) |
89 | 89 | ||
90 | static unsigned max_alignment(u32 addr) | ||
91 | { | ||
92 | int i; | ||
93 | unsigned pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, }; | ||
94 | for (i = 0; i < ARRAY_SIZE(pagesize) && addr & (pagesize[i] - 1); i++) | ||
95 | ; | ||
96 | return (i < ARRAY_SIZE(pagesize)) ? pagesize[i] : 0; | ||
97 | } | ||
98 | |||
90 | /* | 99 | /* |
91 | * calculate the optimal number sg elements from total bytes based on | 100 | * calculate the optimal number sg elements from total bytes based on |
92 | * iommu superpages | 101 | * iommu superpages |
93 | */ | 102 | */ |
94 | static unsigned int sgtable_nents(size_t bytes) | 103 | static unsigned sgtable_nents(size_t bytes, u32 da, u32 pa) |
95 | { | 104 | { |
96 | int i; | 105 | unsigned nr_entries = 0, ent_sz; |
97 | unsigned int nr_entries; | ||
98 | const unsigned long pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, }; | ||
99 | 106 | ||
100 | if (!IS_ALIGNED(bytes, PAGE_SIZE)) { | 107 | if (!IS_ALIGNED(bytes, PAGE_SIZE)) { |
101 | pr_err("%s: wrong size %08x\n", __func__, bytes); | 108 | pr_err("%s: wrong size %08x\n", __func__, bytes); |
102 | return 0; | 109 | return 0; |
103 | } | 110 | } |
104 | 111 | ||
105 | nr_entries = 0; | 112 | while (bytes) { |
106 | for (i = 0; i < ARRAY_SIZE(pagesize); i++) { | 113 | ent_sz = max_alignment(da | pa); |
107 | if (bytes >= pagesize[i]) { | 114 | ent_sz = min_t(unsigned, ent_sz, iopgsz_max(bytes)); |
108 | nr_entries += (bytes / pagesize[i]); | 115 | nr_entries++; |
109 | bytes %= pagesize[i]; | 116 | da += ent_sz; |
110 | } | 117 | pa += ent_sz; |
118 | bytes -= ent_sz; | ||
111 | } | 119 | } |
112 | BUG_ON(bytes); | ||
113 | 120 | ||
114 | return nr_entries; | 121 | return nr_entries; |
115 | } | 122 | } |
116 | 123 | ||
117 | /* allocate and initialize sg_table header(a kind of 'superblock') */ | 124 | /* allocate and initialize sg_table header(a kind of 'superblock') */ |
118 | static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags) | 125 | static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags, |
126 | u32 da, u32 pa) | ||
119 | { | 127 | { |
120 | unsigned int nr_entries; | 128 | unsigned int nr_entries; |
121 | int err; | 129 | int err; |
@@ -127,9 +135,8 @@ static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags) | |||
127 | if (!IS_ALIGNED(bytes, PAGE_SIZE)) | 135 | if (!IS_ALIGNED(bytes, PAGE_SIZE)) |
128 | return ERR_PTR(-EINVAL); | 136 | return ERR_PTR(-EINVAL); |
129 | 137 | ||
130 | /* FIXME: IOVMF_DA_FIXED should support 'superpages' */ | 138 | if (flags & IOVMF_LINEAR) { |
131 | if ((flags & IOVMF_LINEAR) && (flags & IOVMF_DA_ANON)) { | 139 | nr_entries = sgtable_nents(bytes, da, pa); |
132 | nr_entries = sgtable_nents(bytes); | ||
133 | if (!nr_entries) | 140 | if (!nr_entries) |
134 | return ERR_PTR(-EINVAL); | 141 | return ERR_PTR(-EINVAL); |
135 | } else | 142 | } else |
@@ -273,13 +280,14 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, | |||
273 | alignement = PAGE_SIZE; | 280 | alignement = PAGE_SIZE; |
274 | 281 | ||
275 | if (flags & IOVMF_DA_ANON) { | 282 | if (flags & IOVMF_DA_ANON) { |
276 | /* | 283 | start = obj->da_start; |
277 | * Reserve the first page for NULL | 284 | |
278 | */ | ||
279 | start = PAGE_SIZE; | ||
280 | if (flags & IOVMF_LINEAR) | 285 | if (flags & IOVMF_LINEAR) |
281 | alignement = iopgsz_max(bytes); | 286 | alignement = iopgsz_max(bytes); |
282 | start = roundup(start, alignement); | 287 | start = roundup(start, alignement); |
288 | } else if (start < obj->da_start || start > obj->da_end || | ||
289 | obj->da_end - start < bytes) { | ||
290 | return ERR_PTR(-EINVAL); | ||
283 | } | 291 | } |
284 | 292 | ||
285 | tmp = NULL; | 293 | tmp = NULL; |
@@ -289,19 +297,19 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da, | |||
289 | prev_end = 0; | 297 | prev_end = 0; |
290 | list_for_each_entry(tmp, &obj->mmap, list) { | 298 | list_for_each_entry(tmp, &obj->mmap, list) { |
291 | 299 | ||
292 | if (prev_end >= start) | 300 | if (prev_end > start) |
293 | break; | 301 | break; |
294 | 302 | ||
295 | if (start + bytes < tmp->da_start) | 303 | if (tmp->da_start > start && (tmp->da_start - start) >= bytes) |
296 | goto found; | 304 | goto found; |
297 | 305 | ||
298 | if (flags & IOVMF_DA_ANON) | 306 | if (tmp->da_end >= start && flags & IOVMF_DA_ANON) |
299 | start = roundup(tmp->da_end + 1, alignement); | 307 | start = roundup(tmp->da_end + 1, alignement); |
300 | 308 | ||
301 | prev_end = tmp->da_end; | 309 | prev_end = tmp->da_end; |
302 | } | 310 | } |
303 | 311 | ||
304 | if ((start > prev_end) && (ULONG_MAX - start >= bytes)) | 312 | if ((start >= prev_end) && (obj->da_end - start >= bytes)) |
305 | goto found; | 313 | goto found; |
306 | 314 | ||
307 | dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n", | 315 | 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 | BUG_ON(!sgt); | 417 | BUG_ON(!sgt); |
410 | } | 418 | } |
411 | 419 | ||
412 | static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) | 420 | static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, u32 da, |
421 | size_t len) | ||
413 | { | 422 | { |
414 | unsigned int i; | 423 | unsigned int i; |
415 | struct scatterlist *sg; | 424 | struct scatterlist *sg; |
@@ -418,9 +427,10 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) | |||
418 | va = phys_to_virt(pa); | 427 | va = phys_to_virt(pa); |
419 | 428 | ||
420 | for_each_sg(sgt->sgl, sg, sgt->nents, i) { | 429 | for_each_sg(sgt->sgl, sg, sgt->nents, i) { |
421 | size_t bytes; | 430 | unsigned bytes; |
422 | 431 | ||
423 | bytes = iopgsz_max(len); | 432 | bytes = max_alignment(da | pa); |
433 | bytes = min_t(unsigned, bytes, iopgsz_max(len)); | ||
424 | 434 | ||
425 | BUG_ON(!iopgsz_ok(bytes)); | 435 | BUG_ON(!iopgsz_ok(bytes)); |
426 | 436 | ||
@@ -429,6 +439,7 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len) | |||
429 | * 'pa' is cotinuous(linear). | 439 | * 'pa' is cotinuous(linear). |
430 | */ | 440 | */ |
431 | pa += bytes; | 441 | pa += bytes; |
442 | da += bytes; | ||
432 | len -= bytes; | 443 | len -= bytes; |
433 | } | 444 | } |
434 | BUG_ON(len); | 445 | BUG_ON(len); |
@@ -695,18 +706,18 @@ u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags) | |||
695 | if (!va) | 706 | if (!va) |
696 | return -ENOMEM; | 707 | return -ENOMEM; |
697 | 708 | ||
698 | sgt = sgtable_alloc(bytes, flags); | 709 | flags &= IOVMF_HW_MASK; |
710 | flags |= IOVMF_DISCONT; | ||
711 | flags |= IOVMF_ALLOC; | ||
712 | flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON); | ||
713 | |||
714 | sgt = sgtable_alloc(bytes, flags, da, 0); | ||
699 | if (IS_ERR(sgt)) { | 715 | if (IS_ERR(sgt)) { |
700 | da = PTR_ERR(sgt); | 716 | da = PTR_ERR(sgt); |
701 | goto err_sgt_alloc; | 717 | goto err_sgt_alloc; |
702 | } | 718 | } |
703 | sgtable_fill_vmalloc(sgt, va); | 719 | sgtable_fill_vmalloc(sgt, va); |
704 | 720 | ||
705 | flags &= IOVMF_HW_MASK; | ||
706 | flags |= IOVMF_DISCONT; | ||
707 | flags |= IOVMF_ALLOC; | ||
708 | flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON); | ||
709 | |||
710 | da = __iommu_vmap(obj, da, sgt, va, bytes, flags); | 721 | da = __iommu_vmap(obj, da, sgt, va, bytes, flags); |
711 | if (IS_ERR_VALUE(da)) | 722 | if (IS_ERR_VALUE(da)) |
712 | goto err_iommu_vmap; | 723 | goto err_iommu_vmap; |
@@ -746,11 +757,11 @@ static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va, | |||
746 | { | 757 | { |
747 | struct sg_table *sgt; | 758 | struct sg_table *sgt; |
748 | 759 | ||
749 | sgt = sgtable_alloc(bytes, flags); | 760 | sgt = sgtable_alloc(bytes, flags, da, pa); |
750 | if (IS_ERR(sgt)) | 761 | if (IS_ERR(sgt)) |
751 | return PTR_ERR(sgt); | 762 | return PTR_ERR(sgt); |
752 | 763 | ||
753 | sgtable_fill_kmalloc(sgt, pa, bytes); | 764 | sgtable_fill_kmalloc(sgt, pa, da, bytes); |
754 | 765 | ||
755 | da = map_iommu_region(obj, da, sgt, va, bytes, flags); | 766 | da = map_iommu_region(obj, da, sgt, va, bytes, flags); |
756 | if (IS_ERR_VALUE(da)) { | 767 | if (IS_ERR_VALUE(da)) { |
@@ -811,7 +822,7 @@ void iommu_kunmap(struct iommu *obj, u32 da) | |||
811 | struct sg_table *sgt; | 822 | struct sg_table *sgt; |
812 | typedef void (*func_t)(const void *); | 823 | typedef void (*func_t)(const void *); |
813 | 824 | ||
814 | sgt = unmap_vm_area(obj, da, (func_t)__iounmap, | 825 | sgt = unmap_vm_area(obj, da, (func_t)iounmap, |
815 | IOVMF_LINEAR | IOVMF_MMIO); | 826 | IOVMF_LINEAR | IOVMF_MMIO); |
816 | if (!sgt) | 827 | if (!sgt) |
817 | dev_dbg(obj->dev, "%s: No sgt\n", __func__); | 828 | dev_dbg(obj->dev, "%s: No sgt\n", __func__); |
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index d2fafb892f7f..459b319a9fad 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c | |||
@@ -28,12 +28,12 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/kfifo.h> | 29 | #include <linux/kfifo.h> |
30 | #include <linux/err.h> | 30 | #include <linux/err.h> |
31 | #include <linux/notifier.h> | ||
31 | 32 | ||
32 | #include <plat/mailbox.h> | 33 | #include <plat/mailbox.h> |
33 | 34 | ||
34 | static struct workqueue_struct *mboxd; | 35 | static struct workqueue_struct *mboxd; |
35 | static struct omap_mbox **mboxes; | 36 | static struct omap_mbox **mboxes; |
36 | static bool rq_full; | ||
37 | 37 | ||
38 | static int mbox_configured; | 38 | static int mbox_configured; |
39 | static DEFINE_MUTEX(mbox_configured_lock); | 39 | static DEFINE_MUTEX(mbox_configured_lock); |
@@ -93,20 +93,25 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | |||
93 | struct omap_mbox_queue *mq = mbox->txq; | 93 | struct omap_mbox_queue *mq = mbox->txq; |
94 | int ret = 0, len; | 94 | int ret = 0, len; |
95 | 95 | ||
96 | spin_lock(&mq->lock); | 96 | spin_lock_bh(&mq->lock); |
97 | 97 | ||
98 | if (kfifo_avail(&mq->fifo) < sizeof(msg)) { | 98 | if (kfifo_avail(&mq->fifo) < sizeof(msg)) { |
99 | ret = -ENOMEM; | 99 | ret = -ENOMEM; |
100 | goto out; | 100 | goto out; |
101 | } | 101 | } |
102 | 102 | ||
103 | if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) { | ||
104 | mbox_fifo_write(mbox, msg); | ||
105 | goto out; | ||
106 | } | ||
107 | |||
103 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); | 108 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); |
104 | WARN_ON(len != sizeof(msg)); | 109 | WARN_ON(len != sizeof(msg)); |
105 | 110 | ||
106 | tasklet_schedule(&mbox->txq->tasklet); | 111 | tasklet_schedule(&mbox->txq->tasklet); |
107 | 112 | ||
108 | out: | 113 | out: |
109 | spin_unlock(&mq->lock); | 114 | spin_unlock_bh(&mq->lock); |
110 | return ret; | 115 | return ret; |
111 | } | 116 | } |
112 | EXPORT_SYMBOL(omap_mbox_msg_send); | 117 | EXPORT_SYMBOL(omap_mbox_msg_send); |
@@ -146,8 +151,14 @@ static void mbox_rx_work(struct work_struct *work) | |||
146 | len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); | 151 | len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); |
147 | WARN_ON(len != sizeof(msg)); | 152 | WARN_ON(len != sizeof(msg)); |
148 | 153 | ||
149 | if (mq->callback) | 154 | blocking_notifier_call_chain(&mq->mbox->notifier, len, |
150 | mq->callback((void *)msg); | 155 | (void *)msg); |
156 | spin_lock_irq(&mq->lock); | ||
157 | if (mq->full) { | ||
158 | mq->full = false; | ||
159 | omap_mbox_enable_irq(mq->mbox, IRQ_RX); | ||
160 | } | ||
161 | spin_unlock_irq(&mq->lock); | ||
151 | } | 162 | } |
152 | } | 163 | } |
153 | 164 | ||
@@ -170,7 +181,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) | |||
170 | while (!mbox_fifo_empty(mbox)) { | 181 | while (!mbox_fifo_empty(mbox)) { |
171 | if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { | 182 | if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { |
172 | omap_mbox_disable_irq(mbox, IRQ_RX); | 183 | omap_mbox_disable_irq(mbox, IRQ_RX); |
173 | rq_full = true; | 184 | mq->full = true; |
174 | goto nomem; | 185 | goto nomem; |
175 | } | 186 | } |
176 | 187 | ||
@@ -239,73 +250,77 @@ static int omap_mbox_startup(struct omap_mbox *mbox) | |||
239 | int ret = 0; | 250 | int ret = 0; |
240 | struct omap_mbox_queue *mq; | 251 | struct omap_mbox_queue *mq; |
241 | 252 | ||
242 | if (mbox->ops->startup) { | 253 | mutex_lock(&mbox_configured_lock); |
243 | mutex_lock(&mbox_configured_lock); | 254 | if (!mbox_configured++) { |
244 | if (!mbox_configured) | 255 | if (likely(mbox->ops->startup)) { |
245 | ret = mbox->ops->startup(mbox); | 256 | ret = mbox->ops->startup(mbox); |
246 | 257 | if (unlikely(ret)) | |
247 | if (ret) { | 258 | goto fail_startup; |
248 | mutex_unlock(&mbox_configured_lock); | 259 | } else |
249 | return ret; | 260 | goto fail_startup; |
250 | } | ||
251 | mbox_configured++; | ||
252 | mutex_unlock(&mbox_configured_lock); | ||
253 | } | ||
254 | |||
255 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, | ||
256 | mbox->name, mbox); | ||
257 | if (ret) { | ||
258 | printk(KERN_ERR | ||
259 | "failed to register mailbox interrupt:%d\n", ret); | ||
260 | goto fail_request_irq; | ||
261 | } | 261 | } |
262 | 262 | ||
263 | mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); | 263 | if (!mbox->use_count++) { |
264 | if (!mq) { | 264 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, |
265 | ret = -ENOMEM; | 265 | mbox->name, mbox); |
266 | goto fail_alloc_txq; | 266 | if (unlikely(ret)) { |
267 | } | 267 | pr_err("failed to register mailbox interrupt:%d\n", |
268 | mbox->txq = mq; | 268 | ret); |
269 | goto fail_request_irq; | ||
270 | } | ||
271 | mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); | ||
272 | if (!mq) { | ||
273 | ret = -ENOMEM; | ||
274 | goto fail_alloc_txq; | ||
275 | } | ||
276 | mbox->txq = mq; | ||
269 | 277 | ||
270 | mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); | 278 | mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); |
271 | if (!mq) { | 279 | if (!mq) { |
272 | ret = -ENOMEM; | 280 | ret = -ENOMEM; |
273 | goto fail_alloc_rxq; | 281 | goto fail_alloc_rxq; |
282 | } | ||
283 | mbox->rxq = mq; | ||
284 | mq->mbox = mbox; | ||
274 | } | 285 | } |
275 | mbox->rxq = mq; | 286 | mutex_unlock(&mbox_configured_lock); |
276 | |||
277 | return 0; | 287 | return 0; |
278 | 288 | ||
279 | fail_alloc_rxq: | 289 | fail_alloc_rxq: |
280 | mbox_queue_free(mbox->txq); | 290 | mbox_queue_free(mbox->txq); |
281 | fail_alloc_txq: | 291 | fail_alloc_txq: |
282 | free_irq(mbox->irq, mbox); | 292 | free_irq(mbox->irq, mbox); |
283 | fail_request_irq: | 293 | fail_request_irq: |
284 | if (mbox->ops->shutdown) | 294 | if (mbox->ops->shutdown) |
285 | mbox->ops->shutdown(mbox); | 295 | mbox->ops->shutdown(mbox); |
286 | 296 | mbox->use_count--; | |
297 | fail_startup: | ||
298 | mbox_configured--; | ||
299 | mutex_unlock(&mbox_configured_lock); | ||
287 | return ret; | 300 | return ret; |
288 | } | 301 | } |
289 | 302 | ||
290 | static void omap_mbox_fini(struct omap_mbox *mbox) | 303 | static void omap_mbox_fini(struct omap_mbox *mbox) |
291 | { | 304 | { |
292 | free_irq(mbox->irq, mbox); | 305 | mutex_lock(&mbox_configured_lock); |
293 | tasklet_kill(&mbox->txq->tasklet); | 306 | |
294 | flush_work(&mbox->rxq->work); | 307 | if (!--mbox->use_count) { |
295 | mbox_queue_free(mbox->txq); | 308 | free_irq(mbox->irq, mbox); |
296 | mbox_queue_free(mbox->rxq); | 309 | tasklet_kill(&mbox->txq->tasklet); |
310 | flush_work(&mbox->rxq->work); | ||
311 | mbox_queue_free(mbox->txq); | ||
312 | mbox_queue_free(mbox->rxq); | ||
313 | } | ||
297 | 314 | ||
298 | if (mbox->ops->shutdown) { | 315 | if (likely(mbox->ops->shutdown)) { |
299 | mutex_lock(&mbox_configured_lock); | 316 | if (!--mbox_configured) |
300 | if (mbox_configured > 0) | ||
301 | mbox_configured--; | ||
302 | if (!mbox_configured) | ||
303 | mbox->ops->shutdown(mbox); | 317 | mbox->ops->shutdown(mbox); |
304 | mutex_unlock(&mbox_configured_lock); | ||
305 | } | 318 | } |
319 | |||
320 | mutex_unlock(&mbox_configured_lock); | ||
306 | } | 321 | } |
307 | 322 | ||
308 | struct omap_mbox *omap_mbox_get(const char *name) | 323 | struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) |
309 | { | 324 | { |
310 | struct omap_mbox *mbox; | 325 | struct omap_mbox *mbox; |
311 | int ret; | 326 | int ret; |
@@ -324,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name) | |||
324 | if (ret) | 339 | if (ret) |
325 | return ERR_PTR(-ENODEV); | 340 | return ERR_PTR(-ENODEV); |
326 | 341 | ||
342 | if (nb) | ||
343 | blocking_notifier_chain_register(&mbox->notifier, nb); | ||
344 | |||
327 | return mbox; | 345 | return mbox; |
328 | } | 346 | } |
329 | EXPORT_SYMBOL(omap_mbox_get); | 347 | EXPORT_SYMBOL(omap_mbox_get); |
330 | 348 | ||
331 | void omap_mbox_put(struct omap_mbox *mbox) | 349 | void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) |
332 | { | 350 | { |
351 | blocking_notifier_chain_unregister(&mbox->notifier, nb); | ||
333 | omap_mbox_fini(mbox); | 352 | omap_mbox_fini(mbox); |
334 | } | 353 | } |
335 | EXPORT_SYMBOL(omap_mbox_put); | 354 | EXPORT_SYMBOL(omap_mbox_put); |
@@ -353,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list) | |||
353 | ret = PTR_ERR(mbox->dev); | 372 | ret = PTR_ERR(mbox->dev); |
354 | goto err_out; | 373 | goto err_out; |
355 | } | 374 | } |
375 | |||
376 | BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); | ||
356 | } | 377 | } |
357 | return 0; | 378 | return 0; |
358 | 379 | ||
@@ -391,7 +412,8 @@ static int __init omap_mbox_init(void) | |||
391 | 412 | ||
392 | /* kfifo size sanity check: alignment and minimal size */ | 413 | /* kfifo size sanity check: alignment and minimal size */ |
393 | mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); | 414 | mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); |
394 | mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t)); | 415 | mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, |
416 | sizeof(mbox_msg_t)); | ||
395 | 417 | ||
396 | return 0; | 418 | return 0; |
397 | } | 419 | } |