aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLajos Molnar <molnar@ti.com>2010-06-29 06:23:47 -0400
committerPaolo Pisati <paolo.pisati@canonical.com>2012-08-17 04:18:57 -0400
commite47c00628ac013f55fa36f98779c6582b0a609d2 (patch)
tree8e865a05e3403ac8d23fe7607352f389bb94cda3
parentfe0ae617ff9b61bedc4f8a88289bf5b982aba2ef (diff)
TILER: Added key-id enforcement.
TILER block lookup is now based on key & id. However, it is still possible to look up a block's key & id based on its system space address. Signed-off-by: Lajos Molnar <molnar@ti.com> TILER: Added address space support for mmap. Now each TILER buffer occupies a range of the correct size in TILER's mmap memory space (offset + size). Signed-off-by: Lajos Molnar <molnar@ti.com> TILER: Added support for partial mmaping of TILER buffers Added support for mmapping only a portion of a TILER buffer. Also added helper functions that can be used by other drivers that use TILER to mmap and ioremap portions of TILER blocks. Signed-off-by: Lajos Molnar <molnar@ti.com>
-rw-r--r--arch/arm/mach-omap2/include/mach/tiler.h32
-rw-r--r--drivers/media/video/tiler/tiler.c242
2 files changed, 212 insertions, 62 deletions
diff --git a/arch/arm/mach-omap2/include/mach/tiler.h b/arch/arm/mach-omap2/include/mach/tiler.h
index 6f0757b9b24..be29f3ce3e2 100644
--- a/arch/arm/mach-omap2/include/mach/tiler.h
+++ b/arch/arm/mach-omap2/include/mach/tiler.h
@@ -26,6 +26,8 @@
26 26
27#define TILER_MAX_NUM_BLOCKS 16 27#define TILER_MAX_NUM_BLOCKS 16
28 28
29#include <linux/mm.h>
30
29#define TILIOC_GBLK _IOWR('z', 100, struct tiler_block_info) 31#define TILIOC_GBLK _IOWR('z', 100, struct tiler_block_info)
30#define TILIOC_FBLK _IOW('z', 101, struct tiler_block_info) 32#define TILIOC_FBLK _IOW('z', 101, struct tiler_block_info)
31#define TILIOC_GSSP _IOWR('z', 102, u32) 33#define TILIOC_GSSP _IOWR('z', 102, u32)
@@ -125,6 +127,36 @@ s32 tiler_allocx(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 align,
125 u32 offs, u32 gid, pid_t pid); 127 u32 offs, u32 gid, pid_t pid);
126 128
127/** 129/**
130 * Mmaps a portion of a tiler block to a virtual address. Use this method in
131 * your driver's mmap function to potentially combine multiple tiler blocks as
132 * one virtual buffer.
133 *
134 * @param blk pointer to tiler block data
135 * @param offs offset from where to map (must be page aligned)
136 * @param size size of area to map (must be page aligned)
137 * @param addr virtual address
138 *
139 * @return error status
140 */
141s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
142 struct vm_area_struct *vma, u32 voffs);
143
144/**
145 * Ioremaps a portion of a tiler block. Use this method in your driver instead
146 * of ioremap to potentially combine multiple tiler blocks as one virtual
147 * buffer.
148 *
149 * @param blk pointer to tiler block data
150 * @param offs offset from where to map (must be page aligned)
151 * @param size size of area to map (must be page aligned)
152 * @param addr virtual address
153 *
154 * @return error status
155 */
156s32 tiler_ioremap_blk(struct tiler_block_t *blk, u32 offs, u32 size, u32 addr,
157 u32 mtype);
158
159/**
128 * Maps an existing buffer to a 1D or 2D TILER area for the 160 * Maps an existing buffer to a 1D or 2D TILER area for the
129 * current process with group ID 0. 161 * current process with group ID 0.
130 * 162 *
diff --git a/drivers/media/video/tiler/tiler.c b/drivers/media/video/tiler/tiler.c
index 0d3aa51efa8..903df67b86f 100644
--- a/drivers/media/video/tiler/tiler.c
+++ b/drivers/media/video/tiler/tiler.c
@@ -32,6 +32,7 @@
32#include <linux/pagemap.h> /* page_cache_release() */ 32#include <linux/pagemap.h> /* page_cache_release() */
33#include <linux/slab.h> 33#include <linux/slab.h>
34 34
35#include <asm/mach/map.h> /* for ioremap_page */
35#include <mach/tiler.h> 36#include <mach/tiler.h>
36#include <mach/dmm.h> 37#include <mach/dmm.h>
37#include "../dmm/tmm.h" 38#include "../dmm/tmm.h"
@@ -117,7 +118,6 @@ static s32 tiler_major;
117static s32 tiler_minor; 118static s32 tiler_minor;
118static struct tiler_dev *tiler_device; 119static struct tiler_dev *tiler_device;
119static struct class *tilerdev_class; 120static struct class *tilerdev_class;
120static u32 id;
121static struct mutex mtx; 121static struct mutex mtx;
122static struct tcm *tcm[TILER_FORMATS]; 122static struct tcm *tcm[TILER_FORMATS];
123static struct tmm *tmm[TILER_FORMATS]; 123static struct tmm *tmm[TILER_FORMATS];
@@ -170,7 +170,6 @@ static inline u32 tiler_size(const struct tiler_block_t *b)
170 return b->height * tiler_vstride(b); 170 return b->height * tiler_vstride(b);
171} 171}
172 172
173
174/* get process info, and increment refs for device tracking */ 173/* get process info, and increment refs for device tracking */
175static struct process_info *__get_pi(pid_t pid, bool kernel) 174static struct process_info *__get_pi(pid_t pid, bool kernel)
176{ 175{
@@ -557,6 +556,56 @@ static inline bool _m_try_free(struct mem_info *mi)
557 return _m_chk_ref(mi); 556 return _m_chk_ref(mi);
558} 557}
559 558
559/* check if an id is used */
560static bool _m_id_in_use(u32 id)
561{
562 struct mem_info *mi;
563 list_for_each_entry(mi, &blocks, global)
564 if (mi->blk.id == id)
565 return 1;
566 return 0;
567}
568
569/* check if an offset is used */
570static bool _m_offs_in_use(u32 offs, u32 length, struct process_info *pi)
571{
572 struct __buf_info *_b;
573 list_for_each_entry(_b, &pi->bufs, by_pid)
574 if (_b->buf_info.offset < offs + length &&
575 _b->buf_info.offset + _b->buf_info.length > offs)
576 return 1;
577 return 0;
578}
579
580/* get an id */
581static u32 _m_get_id(void)
582{
583 static u32 id = 0x2d7ae;
584
585 /* ensure noone is using this id */
586 while (_m_id_in_use(id)) {
587 /* Galois LSFR: 32, 22, 2, 1 */
588 id = (id >> 1) ^ (u32)((0 - (id & 1u)) & 0x80200003u);
589 }
590
591 return id;
592}
593
594/* get an offset */
595static u32 _m_get_offs(struct process_info *pi, u32 length)
596{
597 static u32 offs = 0xda7a;
598
599 /* ensure no-one is using this offset */
600 while ((offs << PAGE_SHIFT) + length < length ||
601 _m_offs_in_use(offs << PAGE_SHIFT, length, pi)) {
602 /* Galois LSF: 20, 17 */
603 offs = (offs >> 1) ^ (u32)((0 - (offs & 1u)) & 0x90000);
604 }
605
606 return offs << PAGE_SHIFT;
607}
608
560static s32 register_buf(struct __buf_info *_b, struct process_info *pi) 609static s32 register_buf(struct __buf_info *_b, struct process_info *pi)
561{ 610{
562 struct mem_info *mi = NULL; 611 struct mem_info *mi = NULL;
@@ -570,11 +619,13 @@ static s32 register_buf(struct __buf_info *_b, struct process_info *pi)
570 mutex_lock(&mtx); 619 mutex_lock(&mtx);
571 620
572 /* find each block */ 621 /* find each block */
622 b->length = 0;
573 list_for_each_entry(mi, &blocks, global) { 623 list_for_each_entry(mi, &blocks, global) {
574 for (i = 0; i < num; i++) { 624 for (i = 0; i < num; i++) {
575 if (!_b->mi[i] && mi->blk.phys == b->blocks[i].ssptr) { 625 if (!_b->mi[i] && mi->blk.id == b->blocks[i].id &&
626 mi->blk.key == b->blocks[i].key) {
576 _b->mi[i] = mi; 627 _b->mi[i] = mi;
577 628 b->length += tiler_size(&mi->blk);
578 /* quit if found all*/ 629 /* quit if found all*/
579 if (!--remain) 630 if (!--remain)
580 break; 631 break;
@@ -585,8 +636,7 @@ static s32 register_buf(struct __buf_info *_b, struct process_info *pi)
585 636
586 /* if found all, register buffer */ 637 /* if found all, register buffer */
587 if (!remain) { 638 if (!remain) {
588 b->offset = id; 639 b->offset = _m_get_offs(pi, b->length);
589 id += 0x1000;
590 640
591 list_add(&_b->by_pid, &pi->bufs); 641 list_add(&_b->by_pid, &pi->bufs);
592 642
@@ -821,42 +871,123 @@ static struct mem_info *__get_area(enum tiler_fmt fmt, u32 width, u32 height,
821 return mi; 871 return mi;
822} 872}
823 873
874s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
875 struct vm_area_struct *vma, u32 voffs)
876{
877 u32 v, p;
878 u32 len; /* area to map */
879
880 /* don't allow mremap */
881 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
882
883 /* mapping must fit into vma */
884 if (vma->vm_start > vma->vm_start + voffs ||
885 vma->vm_start + voffs > vma->vm_start + voffs + size ||
886 vma->vm_start + voffs + size > vma->vm_end)
887 BUG();
888
889 /* mapping must fit into block */
890 if (offs > offs + size ||
891 offs + size > tiler_size(blk))
892 BUG();
893
894 v = tiler_vstride(blk);
895 p = tiler_pstride(blk);
896
897 /* remap block portion */
898 len = v - (offs % v); /* initial area to map */
899 while (size) {
900 if (len > size)
901 len = size;
902
903 vma->vm_pgoff = (blk->phys + offs) >> PAGE_SHIFT;
904 if (remap_pfn_range(vma, vma->vm_start + voffs, vma->vm_pgoff,
905 len, vma->vm_page_prot))
906 return -EAGAIN;
907 voffs += len;
908 offs += len + p - v;
909 size -= len;
910 len = v; /* subsequent area to map */
911 }
912 return 0;
913}
914EXPORT_SYMBOL(tiler_mmap_blk);
915
916s32 tiler_ioremap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
917 u32 addr, u32 mtype)
918{
919 u32 v, p;
920 u32 len; /* area to map */
921 const struct mem_type *type = get_mem_type(mtype);
922
923 /* mapping must fit into address space */
924 if (addr > addr + size)
925 BUG();
926
927 /* mapping must fit into block */
928 if (offs > offs + size ||
929 offs + size > tiler_size(blk))
930 BUG();
931
932 v = tiler_vstride(blk);
933 p = tiler_pstride(blk);
934
935 /* move offset and address to end */
936 offs += blk->phys + size;
937 addr += size;
938
939 len = v - (offs % v); /* initial area to map */
940 while (size) {
941 while (len && size) {
942 if (ioremap_page(addr - size, offs - size, type))
943 return -EAGAIN;
944 len -= PAGE_SIZE;
945 size -= PAGE_SIZE;
946 }
947
948 offs += p - v;
949 len = v; /* subsequent area to map */
950 }
951 return 0;
952}
953EXPORT_SYMBOL(tiler_ioremap_blk);
954
824static s32 tiler_mmap(struct file *filp, struct vm_area_struct *vma) 955static s32 tiler_mmap(struct file *filp, struct vm_area_struct *vma)
825{ 956{
826 struct __buf_info *_b = NULL; 957 struct __buf_info *_b = NULL;
827 struct tiler_buf_info *b = NULL; 958 struct tiler_buf_info *b = NULL;
828 s32 i = 0, j = 0, k = 0, m = 0, p = 0; 959 u32 i, map_offs, map_size, blk_offs, blk_size, mapped_size;
829 struct list_head *pos = NULL;
830 struct process_info *pi = filp->private_data; 960 struct process_info *pi = filp->private_data;
961 u32 offs = vma->vm_pgoff << PAGE_SHIFT;
962 u32 size = vma->vm_end - vma->vm_start;
831 963
832 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 964 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
833 965
834 /* don't allow mremap */
835 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
836
837 mutex_lock(&mtx); 966 mutex_lock(&mtx);
838 list_for_each(pos, &pi->bufs) { 967 list_for_each_entry(_b, &pi->bufs, by_pid) {
839 _b = list_entry(pos, struct __buf_info, by_pid); 968 if (offs >= _b->buf_info.offset &&
840 if ((vma->vm_pgoff << PAGE_SHIFT) == _b->buf_info.offset) 969 offs + size <= _b->buf_info.offset + _b->buf_info.length) {
970 b = &_b->buf_info;
841 break; 971 break;
972 }
842 } 973 }
843 mutex_unlock(&mtx); 974 mutex_unlock(&mtx);
844 if (!_b) 975 if (!b)
845 return -ENXIO; 976 return -ENXIO;
846 977
847 b = &_b->buf_info; 978 /* mmap relevant blocks */
848 979 blk_offs = _b->buf_info.offset;
849 for (i = 0; i < b->num_blocks; i++) { 980 mapped_size = 0;
850 p = tiler_vstride(&_b->mi[i]->blk); 981 for (i = 0; i < b->num_blocks; i++, blk_offs += blk_size) {
851 for (m = j = 0; j < _b->mi[i]->blk.height; j++) { 982 blk_size = tiler_size(&_b->mi[i]->blk);
852 /* map each page of the line */ 983 if (offs >= blk_offs + blk_size || offs + size < blk_offs)
853 vma->vm_pgoff = (b->blocks[i].ssptr + m) >> PAGE_SHIFT; 984 continue;
854 if (remap_pfn_range(vma, vma->vm_start + k, 985 map_offs = max(offs, blk_offs) - blk_offs;
855 vma->vm_pgoff, p, vma->vm_page_prot)) 986 map_size = min(size - mapped_size, blk_size);
856 return -EAGAIN; 987 if (tiler_mmap_blk(&_b->mi[i]->blk, map_offs, map_size, vma,
857 k += p; 988 mapped_size))
858 m += tiler_pstride(&_b->mi[i]->blk); 989 return -EAGAIN;
859 } 990 mapped_size += map_size;
860 } 991 }
861 return 0; 992 return 0;
862} 993}
@@ -939,6 +1070,10 @@ static s32 map_block(enum tiler_fmt fmt, u32 width, u32 height,
939 1070
940 mi->blk.width = width; 1071 mi->blk.width = width;
941 mi->blk.height = height; 1072 mi->blk.height = height;
1073 mi->blk.key = key;
1074 mutex_lock(&mtx);
1075 mi->blk.id = _m_get_id();
1076 mutex_unlock(&mtx);
942 mi->usr = usr_addr; 1077 mi->usr = usr_addr;
943 1078
944 /* allocate pages */ 1079 /* allocate pages */
@@ -1047,7 +1182,7 @@ s32 tiler_map(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 usr_addr)
1047} 1182}
1048EXPORT_SYMBOL(tiler_map); 1183EXPORT_SYMBOL(tiler_map);
1049 1184
1050s32 free_block(u32 sys_addr, struct process_info *pi) 1185s32 free_block(u32 key, u32 id, struct process_info *pi)
1051{ 1186{
1052 struct gid_info *gi = NULL; 1187 struct gid_info *gi = NULL;
1053 struct area_info *ai = NULL; 1188 struct area_info *ai = NULL;
@@ -1058,19 +1193,11 @@ s32 free_block(u32 sys_addr, struct process_info *pi)
1058 1193
1059 /* find block in process list and free it */ 1194 /* find block in process list and free it */
1060 list_for_each_entry(gi, &pi->groups, by_pid) { 1195 list_for_each_entry(gi, &pi->groups, by_pid) {
1061 /* currently we know if block is 1D or 2D by the address */ 1196 {
1062 if (TILER_GET_ACC_MODE(sys_addr) == TILFMT_PAGE) {
1063 list_for_each_entry(mi, &gi->onedim, by_area) {
1064 if (mi->blk.phys == sys_addr) {
1065 _m_try_free(mi);
1066 res = 0;
1067 goto done;
1068 }
1069 }
1070 } else {
1071 list_for_each_entry(ai, &gi->areas, by_gid) { 1197 list_for_each_entry(ai, &gi->areas, by_gid) {
1072 list_for_each_entry(mi, &ai->blocks, by_area) { 1198 list_for_each_entry(mi, &ai->blocks, by_area) {
1073 if (mi->blk.phys == sys_addr) { 1199 if (mi->blk.key == key &&
1200 mi->blk.id == id) {
1074 _m_try_free(mi); 1201 _m_try_free(mi);
1075 res = 0; 1202 res = 0;
1076 goto done; 1203 goto done;
@@ -1087,7 +1214,7 @@ done:
1087 return res; 1214 return res;
1088} 1215}
1089 1216
1090s32 free_block_global(u32 ssptr) 1217static s32 free_block_global(u32 key, u32 id)
1091{ 1218{
1092 struct mem_info *mi; 1219 struct mem_info *mi;
1093 s32 res = -ENOENT; 1220 s32 res = -ENOENT;
@@ -1096,7 +1223,7 @@ s32 free_block_global(u32 ssptr)
1096 1223
1097 /* find block in global list and free it */ 1224 /* find block in global list and free it */
1098 list_for_each_entry(mi, &blocks, global) { 1225 list_for_each_entry(mi, &blocks, global) {
1099 if (mi->blk.phys == ssptr) { 1226 if (mi->blk.key == key && mi->blk.id == id) {
1100 _m_try_free(mi); 1227 _m_try_free(mi);
1101 res = 0; 1228 res = 0;
1102 break; 1229 break;
@@ -1110,23 +1237,7 @@ s32 free_block_global(u32 ssptr)
1110 1237
1111s32 tiler_free(struct tiler_block_t *blk) 1238s32 tiler_free(struct tiler_block_t *blk)
1112{ 1239{
1113 struct mem_info *mi; 1240 return free_block_global(blk->key, blk->id);
1114 s32 res = -ENOENT;
1115
1116 mutex_lock(&mtx);
1117
1118 /* find block in global list and free it */
1119 list_for_each_entry(mi, &blocks, global) {
1120 if (mi->blk.phys == blk->phys) {
1121 _m_try_free(mi);
1122 res = 0;
1123 break;
1124 }
1125 }
1126 mutex_unlock(&mtx);
1127
1128 /* for debugging, we can set the PAT entries to DMM_LISA_MAP__0 */
1129 return res;
1130} 1241}
1131EXPORT_SYMBOL(tiler_free); 1242EXPORT_SYMBOL(tiler_free);
1132 1243
@@ -1163,6 +1274,8 @@ found:
1163 blk->dim.area.height = i->blk.height; 1274 blk->dim.area.height = i->blk.height;
1164 blk->group_id = ((struct area_info *) i->parent)->gi->gid; 1275 blk->group_id = ((struct area_info *) i->parent)->gi->gid;
1165 } 1276 }
1277 blk->id = i->blk.id;
1278 blk->key = i->blk.key;
1166 blk->offs = i->blk.phys & ~PAGE_MASK; 1279 blk->offs = i->blk.phys & ~PAGE_MASK;
1167 blk->align = 0; 1280 blk->align = 0;
1168 return 0; 1281 return 0;
@@ -1218,6 +1331,7 @@ static s32 tiler_ioctl(struct inode *ip, struct file *filp, u32 cmd,
1218 } 1331 }
1219 1332
1220 if (mi) { 1333 if (mi) {
1334 block_info.id = mi->blk.id;
1221 block_info.stride = tiler_vstride(&mi->blk); 1335 block_info.stride = tiler_vstride(&mi->blk);
1222 block_info.ssptr = mi->blk.phys; 1336 block_info.ssptr = mi->blk.phys;
1223 } 1337 }
@@ -1232,8 +1346,8 @@ static s32 tiler_ioctl(struct inode *ip, struct file *filp, u32 cmd,
1232 return -EFAULT; 1346 return -EFAULT;
1233 1347
1234 /* search current process first, then all processes */ 1348 /* search current process first, then all processes */
1235 free_block(block_info.ssptr, pi) ? 1349 free_block(block_info.key, block_info.id, pi) ?
1236 free_block_global(block_info.ssptr) : 0; 1350 free_block_global(block_info.key, block_info.id) : 0;
1237 1351
1238 /* free always succeeds */ 1352 /* free always succeeds */
1239 break; 1353 break;
@@ -1270,6 +1384,7 @@ static s32 tiler_ioctl(struct inode *ip, struct file *filp, u32 cmd,
1270 return r; 1384 return r;
1271 1385
1272 if (mi) { 1386 if (mi) {
1387 block_info.id = mi->blk.id;
1273 block_info.stride = tiler_vstride(&mi->blk); 1388 block_info.stride = tiler_vstride(&mi->blk);
1274 block_info.ssptr = mi->blk.phys; 1389 block_info.ssptr = mi->blk.phys;
1275 } 1390 }
@@ -1390,6 +1505,10 @@ s32 alloc_block(enum tiler_fmt fmt, u32 width, u32 height,
1390 1505
1391 mi->blk.width = width; 1506 mi->blk.width = width;
1392 mi->blk.height = height; 1507 mi->blk.height = height;
1508 mi->blk.key = key;
1509 mutex_lock(&mtx);
1510 mi->blk.id = _m_get_id();
1511 mutex_unlock(&mtx);
1393 1512
1394 /* allocate and map if mapping is supported */ 1513 /* allocate and map if mapping is supported */
1395 if (tmm_can_map(TMM(fmt))) { 1514 if (tmm_can_map(TMM(fmt))) {
@@ -1642,7 +1761,6 @@ static s32 __init tiler_init(void)
1642 INIT_LIST_HEAD(&procs); 1761 INIT_LIST_HEAD(&procs);
1643 INIT_LIST_HEAD(&orphan_areas); 1762 INIT_LIST_HEAD(&orphan_areas);
1644 INIT_LIST_HEAD(&orphan_onedim); 1763 INIT_LIST_HEAD(&orphan_onedim);
1645 id = 0xda7a000;
1646 1764
1647error: 1765error:
1648 /* TODO: error handling for device registration */ 1766 /* TODO: error handling for device registration */