summaryrefslogtreecommitdiff
path: root/drivers/video/wmt/wmt-mb.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 20:10:08 +0530
committerSrikant Patnaik2015-01-11 20:10:08 +0530
commit6be9593ee4352c19377a47475fdcd8473897ac42 (patch)
treeb85d6e3d961374d41c446318e2c2598272a8e86c /drivers/video/wmt/wmt-mb.c
parentddd6804ba90290b66ebff05b99752fcdd75fec45 (diff)
downloadFOSSEE-netbook-kernel-source-6be9593ee4352c19377a47475fdcd8473897ac42.tar.gz
FOSSEE-netbook-kernel-source-6be9593ee4352c19377a47475fdcd8473897ac42.tar.bz2
FOSSEE-netbook-kernel-source-6be9593ee4352c19377a47475fdcd8473897ac42.zip
Fix white screen issue during bootup
Signed-off-by: Manish Patel <manish.patel@xzadium.com>
Diffstat (limited to 'drivers/video/wmt/wmt-mb.c')
-rw-r--r--[-rwxr-xr-x]drivers/video/wmt/wmt-mb.c1141
1 files changed, 672 insertions, 469 deletions
diff --git a/drivers/video/wmt/wmt-mb.c b/drivers/video/wmt/wmt-mb.c
index 61bc6855..375d53c8 100755..100644
--- a/drivers/video/wmt/wmt-mb.c
+++ b/drivers/video/wmt/wmt-mb.c
@@ -62,7 +62,7 @@
#define MB_VERSION_MAJOR 1
#define MB_VERSION_MINOR 0
#define MB_VERSION_MICRO 0
-#define MB_VERSION_BUILD 6
+#define MB_VERSION_BUILD 3
#define MB_DEBUG
#define MB_INFO(fmt, args...) \
@@ -312,243 +312,420 @@ static spinlock_t mb_search_lock;
static spinlock_t mb_ioctl_lock;
static spinlock_t mb_task_mm_lock;
static spinlock_t mb_task_lock;
+static struct page *pg_user[12800]; /* 12800 pages = 50 MB */
static char show_mb_buffer[MB_SHOW_BUFSIZE];
static char show_mba_buffer[MBA_SHOW_BUFSIZE];
-static inline uint64_t checkSum(unsigned long phys, int size, int type)
+#define MMU_SEARCH_DONE 1
+typedef int (*mb_page_proc)(void *, dma_addr_t, int);
+
+static inline int mmu_search_pte(
+ pte_t *pte,
+ unsigned long boundary,
+ unsigned long *addr,
+ unsigned long *offset,
+ mb_page_proc proc,
+ void *priv)
{
- char *d = (type) ? __va(phys) : mb_phys_to_virt(phys);
- int i, pageSize, len, offset;
- uint64_t sum, cs = 0;
-
- len = size;
- offset = (unsigned long)d % PAGE_SIZE;
- while (len > 0) {
- sum = 0;
- pageSize = min((int)(PAGE_SIZE - offset), len);
- for (i = 0; i < pageSize; i++)
- sum += d[i];
- MB_WDBG("[CS] addr %#lx ~ %#lx size %#x cs %#llx\n",
- phys, phys + size, size, sum);
- MB_WDBG("[CS:DATA] %02x %02x %02x %02x %02x %02x %02x %02x\n",
- d[0] & 0xff, d[1] & 0xff, d[2] & 0xff, d[3] & 0xff,
- d[4] & 0xff, d[5] & 0xff, d[6] & 0xff, d[7] & 0xff);
- d += pageSize;
- len -= pageSize;
- cs += sum;
- }
-
- return cs;
+ int ret = 0, index = 0;
+
+ /* for each pte */
+ while (pte && (*addr < boundary)) {
+ unsigned long pfn = pte_pfn(*pte);
+ struct page *pg = pfn_to_page(pfn);
+ void *virt = page_address(pg);
+ dma_addr_t phys = virt_to_phys(virt);
+
+ MB_WDBG("\t\t[PTE%3d] PTE[%p]=%x n %lx V %p P %x U %lx[%lx]\n",
+ index++, pte, pte_val(*pte), pfn,
+ virt, phys, *addr, *offset);
+ if (!pfn_valid(pfn)) {
+ MB_WARN("invalid pfn %ld of addr %lx\n", pfn, *addr);
+ return -1;
+ }
+ if (*offset < PAGE_SIZE) {
+ ret = proc(priv, phys, *offset);
+ if (ret)
+ break;
+ *offset = 0;
+ } else
+ *offset -= PAGE_SIZE;
+ *addr += PAGE_SIZE;
+ pte++;
+#ifdef MB_WORDY
+ msleep(30);
+#endif
+ };
+ return ret;
}
-unsigned long user_to_phys(unsigned long user)
+static inline int mmu_search_pmd(
+ pmd_t *pmd,
+ unsigned long boundary,
+ unsigned long *addr,
+ unsigned long *offset,
+ mb_page_proc proc,
+ void *priv)
{
- unsigned long par, phys, offset;
- offset = user % PAGE_SIZE;
-
- asm volatile(
- "mcr p15, 0, %[user], c7, c8, 0\n"
- "isb\n"
- "mrc p15, 0, %[par], c7, c4, 0\n"
- : [par] "=r" (par)
- : [user] "r" (user));
-
- phys = (par & PAGE_MASK) + offset;
- MB_DBG("%s: user %lx par %lx phys %lx\n",
- __func__, user, par, phys);
-
- return (par & 0x1) ? 0 : phys;
+ int ret = 0, index = 0;
+ unsigned long end;
+ pte_t *pte;
+
+ /* for each pmd */
+ while (pmd && (*addr < boundary)) {
+ /* from start to PMD alignment */
+ end = (*addr + PMD_SIZE) & PMD_MASK;
+ end = min(end, boundary);
+ pte = pte_offset_map(pmd, *addr);
+ if (pte == NULL) {
+ MB_WARN("[%08lx] *pmd=%08llx unknown pte\n",
+ *addr, (long long)pmd_val(*pmd));
+ return -1;
+ }
+ MB_WDBG("\t[PMD%3d, %lx, %lx] *(%p)=%x addr %lx\n", index++,
+ end - PMD_SIZE, end, pmd, pmd_val(*pmd), *addr);
+ ret = mmu_search_pte(pte, end, addr, offset, proc, priv);
+ if (ret)
+ break;
+ pmd++;
+ };
+ return ret;
}
-EXPORT_SYMBOL(user_to_phys);
-/* return address is guaranteeed only under page alignment */
-void *user_to_virt(unsigned long user)
+static inline int mmu_search_pgd(
+ pgd_t *pgd,
+ unsigned long boundary,
+ unsigned long *addr,
+ unsigned long *offset,
+ mb_page_proc proc,
+ void *priv)
{
- unsigned long phys;
-
- phys = user_to_phys(user);
- if (!phys) {
- MB_WARN("user 0x%lx to virt fail.\n", user);
- return 0;
- }
+ int ret = 0, index = 0;
+ unsigned long end;
+ pmd_t *pmd;
+ pud_t *pud;
+
+ /* for each pgd */
+ while (pgd && (*addr < boundary)) {
+ /* from start to PGDIR alignment */
+ end = (*addr + PGDIR_SIZE) & PGDIR_MASK;
+ end = min(end, boundary);
+ MB_WDBG("[PGD%3d, %lx, %lx] *(%p)=%x addr %lx\n", index++,
+ end - PGDIR_SIZE, end, pgd, pgd_val(*pgd), *addr);
+ pud = pud_offset(pgd, *addr);
+ if (pud_none(*pud) || pud_bad(*pud)) {
+ MB_WARN("[%08lx] *pgd=%08llx %s pud\n",
+ *addr, (long long)pgd_val(*pgd),
+ pud_none(*pud) ? "(None)" : "(Bad)");
+ return -1;
+ }
+ pmd = pmd_offset(pud, *addr);
+ if (pmd == NULL) {
+ MB_WARN("[%08lx] *pgd=%08llx unknown pmd\n",
+ *addr, (long long)pgd_val(*pgd));
+ return -1;
+ }
+ ret = mmu_search_pmd(pmd, end, addr, offset, proc, priv);
+ if (ret)
+ break;
+ pgd++;
+ };
- return __va(phys);
+ return ret;
}
-EXPORT_SYMBOL(user_to_virt);
-struct prdt_info {
+struct prdt_search_info {
int index;
int items;
- int offset;
- int size;
- struct prdt_struct *prdt;
- struct prdt_struct *last;
+ unsigned int size;
+ struct prdt_struct *prev;
+ struct prdt_struct *next;
};
-static int prdt_proc(struct prdt_info *info, unsigned long phys)
+static int __user_to_prdt_proc(void *priv, dma_addr_t phys, int offset)
{
- int len;
+ struct prdt_search_info *info = (struct prdt_search_info *)priv;
+ struct prdt_struct *prev = info->prev, *next = info->next;
+ int len = PAGE_SIZE - offset;
- if (!info) {
- MB_WARN("PRDT process fail. (NULL info)\n");
- return -1;
- }
-
- /* PRDT has done or no PRDT space */
- if (info->size <= 0 ||
- (info->last && info->last->EDT))
- return 0;
-
- len = PAGE_SIZE - info->offset;
- if (len > info->size) /* last page */
+ if (len > info->size)
len = info->size;
/* Check it could combind with previous one */
- if (info->last &&
- /* prd size boundary check, MAX 60K */
- (info->last->size <= ((1 << 16) - (2 * PAGE_SIZE))) &&
- /* page continuity check */
- ((info->last->addr + info->last->size) == phys))
- info->last->size += len;
+ if (prev &&
+ /* prd size boundary check, MAX 60K */
+ (prev->size <= ((1 << 16) - (2 * PAGE_SIZE))) &&
+ /* page continuity check */
+ ((prev->addr + prev->size) == phys))
+ prev->size += len;
else { /* create new one */
+ info->prev = prev = next;
+ info->next = next + 1;
+ prev->addr = phys + offset;
+ prev->size = len;
+ info->index++;
+ info->items--;
if (!info->items) {
MB_WARN("PRD table full (ptr %p # %d left %d).\n",
- info->last+1, info->index+1, info->size);
- if (info->last)
- info->last->EDT = 1;
+ next, info->index, info->size);
+ prev->EDT = 1;
return -1;
}
- if (info->last == NULL)
- info->last = info->prdt;
- else
- info->last++;
- info->last->addr = phys + info->offset;
- info->last->size = len;
- info->index++;
- info->items--;
- info->offset = 0;
}
info->size -= len;
- info->last->reserve = 0;
- info->last->EDT = (info->size) ? 0 : 1;
- MB_WDBG("\t[PRD %3d] %p (0x%x ~ 0x%x, 0x%x, %x) phys 0x%lx offset 0x%x len 0x%x left %x\n",
- info->index, info->last, info->last->addr, info->last->addr + info->last->size,
- info->last->size, info->last->EDT, phys, info->offset, len, info->size);
+ prev->reserve = 0;
+ prev->EDT = (info->size) ? 0 : 1;
+ MB_WDBG("\t\t\t[PRD %3d] %p start %x(%x + %d) size %x edt %x left %x\n",
+ info->index, prev, prev->addr, phys, offset,
+ prev->size, prev->EDT, info->size);
- return 0;
-}
-
-static inline void show_prdt(struct prdt_struct *next)
-{
- int idx = 1;
+ if (prev->EDT)
+ return MMU_SEARCH_DONE;
- while (!next->EDT) {
- MB_INFO("PRDT %d-th item: addr %x size %d EDT %d\n",
- idx, next->addr, next->size, next->EDT);
- idx++;
- next++;
- }
- MB_INFO("PRDT last(%d-th) item: addr %x size %d EDT %d\n",
- idx, next->addr, next->size, next->EDT);
+ return 0;
}
-int user_to_prdt(
+static int __user_to_prdt(
unsigned long user,
unsigned int size,
struct prdt_struct *prdt,
unsigned int items)
{
- struct prdt_info info = {0};
- unsigned long addr;
- int idx;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long addr, end, offset;
+ struct prdt_search_info info = {0};
+ unsigned int idx;
+ pgd_t *pgd;
+ int ret;
if (!prdt || ((size / PAGE_SIZE) + 2) > items) {
- MB_WARN("PRD table space not enough (ptr %p at least %lu but %d).\n",
- prdt, (size/PAGE_SIZE)+2, items);
+ MB_WARN("PRD table space not enough (ptr %p at least %lu).\n",
+ prdt, (size/PAGE_SIZE)+2);
return -EINVAL;
}
- MB_DBG("Memory(%#lx,%#x) PRDT(%p,%d)\n", user, size, prdt, items);
- info.items = items;
- info.offset = user % PAGE_SIZE;
+ MB_DBG("Memory(%#lx,%d) PRDT(%p,%d)\n", user, size, prdt, items);
info.size = size;
- info.prdt = prdt;
- addr = user & PAGE_MASK;
+ info.next = prdt;
+ info.items = items;
+ addr = user;
+
+ down_read(&mm->mmap_sem);
while (info.size > 0) {
- unsigned long phys = user_to_phys(addr);
- if (!phys) {
- MB_WARN("user to prdt fail: unknown addr %lx (%lx, %x)\n",
- addr, user, size);
- return -EINVAL;
+ vma = find_vma(mm, addr);
+ if (vma == NULL) {
+ MB_WARN("user addr %lx not found in task %s\n",
+ addr, current->comm);
+ info.next->EDT = 1;
+ goto fault;
}
- prdt_proc(&info, phys);
- addr += PAGE_SIZE;
+
+ MB_WDBG("VMA found: mm %p start %lx end %lx flags %lx\n",
+ mm, vma->vm_start, vma->vm_end, vma->vm_flags);
+ end = PAGE_ALIGN(vma->vm_end);
+ offset = addr - vma->vm_start;
+ addr = vma->vm_start;
+ pgd = pgd_offset(mm, vma->vm_start);
+ ret = mmu_search_pgd(pgd, end, &addr, &offset,
+ __user_to_prdt_proc, &info);
+ if (ret == MMU_SEARCH_DONE)
+ break;
+ if (ret)
+ goto fault;
}
- /* flush cache */
- MB_WDBG("flush PRDT %p, from %lx size %d\n", prdt, user, size);
- dmac_flush_range((const void *)user, (const void *)(user + size));
+ MB_WDBG("PRDT %p, from %lx size %d\n", prdt, user, size);
for (idx = 0;; idx++) {
- MB_WDBG("PRDT[%d] %p addr %x( ~ %x) size %d EDT %d (%p ~ %p)\n",
- idx, &prdt[idx], prdt[idx].addr, prdt[idx].addr + prdt[idx].size, prdt[idx].size,
- prdt[idx].EDT, __va(prdt[idx].addr), __va(prdt[idx].addr + prdt[idx].size));
+ MB_WDBG("PRDT[%d] adddr %x size %d EDT %d\n",
+ idx, prdt[idx].addr, prdt[idx].size, prdt[idx].EDT);
+ dmac_flush_range(__va(prdt[idx].addr),
+ __va(prdt[idx].addr + prdt[idx].size));
outer_flush_range(prdt[idx].addr,
prdt[idx].addr + prdt[idx].size);
if (prdt[idx].EDT)
break;
}
-
- /* show_prdt(prdt); */
+ up_read(&mm->mmap_sem);
return 0;
+fault:
+ MB_WARN("USER TO PRDT unfinished, remain size %d\n", info.size);
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
}
-EXPORT_SYMBOL(user_to_prdt);
-int mb_to_prdt(
- unsigned long phys,
+static int __user_to_prdt1(
+ unsigned long user,
unsigned int size,
- struct prdt_struct *prdt,
+ struct prdt_struct *next,
unsigned int items)
{
- struct prdt_info info = {0};
- unsigned long addr;
- void *virt = NULL;
- int idx;
+ void *ptr_start, *ptr_end, *ptr, *virt = NULL;
+ int res, pg_size, pg_idx = 0, nr_pages = 0;
+ struct vm_area_struct *vma;
+
+ ptr_start = ptr = (void *)user;
+ ptr_end = ptr_start + size;
+ MB_DBG("Memory(%#lx,%d) PRDT(%p,%d)\n", user, size, next, items);
+
+ down_read(&current->mm->mmap_sem);
+ vma = find_vma(current->mm, user);
+ up_read(&current->mm->mmap_sem);
+ /* For kernel direct-mapped memory, take the easy way */
+ if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
+ unsigned long phys = 0;
+ /* kernel-allocated, mmaped-to-usermode addresses */
+ phys = (vma->vm_pgoff << PAGE_SHIFT) + (user - vma->vm_start);
+ virt = __va(phys);
+ MB_INFO("kernel-alloc, mmaped-to-user addr U %lx V %p P %lx",
+ user, virt, phys);
+ BUG_ON(1);
+ return -EFAULT;
+ }
+ MB_WDBG("VMA found: mm %p start %lx end %lx flags %lx\n",
+ current->mm, vma->vm_start, vma->vm_end, vma->vm_flags);
- if (!prdt || ((size / PAGE_SIZE) + 2) > items) {
- MB_WARN("PRD table space not enough (ptr %p at least %lu but %d).\n",
- prdt, (size/PAGE_SIZE)+2, items);
+ nr_pages = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
+ if (!next || ((size/PAGE_SIZE)+2) > items || nr_pages > 2560) {
+ MB_WARN("PRD table space full (ptr %p pages %d prdt %d/%lu).\n",
+ next, nr_pages, items, (size/PAGE_SIZE)+2);
return -EINVAL;
}
- MB_DBG("Memory(%#lx,%#x) PRDT(%p,%d)\n", phys, size, prdt, items);
- info.items = items;
- info.offset = phys % PAGE_SIZE;
- info.size = size;
- info.prdt = prdt;
- addr = phys & PAGE_MASK;
- while (info.size > 0) {
- prdt_proc(&info, addr);
- addr += PAGE_SIZE;
+ memset(pg_user, 0x0, sizeof(struct page *)*2560);
+ down_read(&current->mm->mmap_sem);
+ res = get_user_pages(current, current->mm,
+ (unsigned long)ptr, nr_pages, 1, 0, pg_user, NULL);
+ while (res > 0 && size > 0) {
+ pg_size = PAGE_SIZE - ((unsigned long)ptr & ~PAGE_MASK);
+ virt = page_address(pg_user[pg_idx]) +
+ ((unsigned long)ptr & ~PAGE_MASK);
+ if (pg_size > size)
+ pg_size = size;
+ MB_DBG("Get %d-th user page s %d/%d u %p v %p p %lx\n",
+ pg_idx, pg_size, size, ptr, virt, __pa(virt));
+ if ((next->addr + next->size) != __pa(virt) ||
+ (next->size + pg_size) >= 65536 || !pg_idx) {
+ if (pg_idx) {
+ next->EDT = 0;
+ next++;
+ }
+ memset(next, 0x0, sizeof(struct prdt_struct));
+ next->addr = __pa(virt);
+ }
+ next->size += pg_size;
+ next->EDT = 1;
+ size -= pg_size;
+ ptr += pg_size;
+ pg_idx++;
+ }
+ next->EDT = 1;
+ up_read(&current->mm->mmap_sem);
+ return size;
+}
+
+static int __user_to_prdt2(
+ unsigned long user,
+ unsigned int size,
+ struct prdt_struct *next,
+ unsigned int items)
+{
+ void *ptr_start, *ptr_end, *ptr, *virt = NULL;
+ int res, pg_size, pg_idx = 0, ret = 0;
+ struct vm_area_struct *vma;
+ struct page *pages = NULL;
+
+ ptr_start = ptr = (void *)user;
+ ptr_end = ptr_start + size;
+ MB_DBG("Memory(%#lx,%d) PRDT(%p,%d)\n", user, size, next, items);
+
+ down_read(&current->mm->mmap_sem);
+ vma = find_vma(current->mm, user);
+ up_read(&current->mm->mmap_sem);
+ /* For kernel direct-mapped memory, take the easy way */
+ if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
+ unsigned long phys = 0;
+ /* kernel-allocated, mmaped-to-usermode addresses */
+ phys = (vma->vm_pgoff << PAGE_SHIFT) + (user - vma->vm_start);
+ virt = __va(phys);
+ MB_INFO("kernel-alloc, user-mmaped addr U %lx V %p P %lx",
+ user, virt, phys);
+ BUG_ON(1);
+ return -EFAULT;
}
- /* flush cache */
- MB_WDBG("PRDT %p, from %lx size %d\n", prdt, phys, size);
- virt = mb_phys_to_virt(phys);
- dmac_flush_range(virt, virt + size);
- for (idx = 0;; idx++) {
- MB_WDBG("PRDT[%d] addr %x size %d EDT %d\n",
- idx, prdt[idx].addr, prdt[idx].size, prdt[idx].EDT);
- outer_flush_range(prdt[idx].addr,
- prdt[idx].addr + prdt[idx].size);
- if (prdt[idx].EDT)
+ if (!next || ((size/PAGE_SIZE)+2) > items) {
+ MB_WARN("PRD table space full (ptr %p at least %lu)\n",
+ next, (size/PAGE_SIZE)+2);
+ return -EINVAL;
+ }
+
+ MB_WDBG("VMA found: mm %p start %lx end %lx flags %lx\n",
+ current->mm, vma->vm_start, vma->vm_end, vma->vm_flags);
+
+ while (size) {
+ down_read(&current->mm->mmap_sem);
+ res = get_user_pages(current, current->mm,
+ (unsigned long)ptr, 1, 1, 0, &pages, NULL);
+ up_read(&current->mm->mmap_sem);
+ pg_size = PAGE_SIZE - ((unsigned long)ptr & ~PAGE_MASK);
+ if (res != 1) {
+ MB_ERROR("Get %d-th user pages (a %p s %d/%d) fail\n",
+ pg_idx, ptr, pg_size, size);
+ next->EDT = 1;
+ ret = -EFAULT;
break;
+ }
+ virt = page_address(&pages[0]) +
+ ((unsigned long)ptr & ~PAGE_MASK);
+ pg_size = (pg_size > size) ? size : pg_size;
+ MB_DBG("Get %d-th user page s %d/%d u %p v %p p %lx\n",
+ pg_idx, pg_size, size, ptr, virt, __pa(virt));
+ if ((next->addr + next->size) != __pa(virt) ||
+ (next->size + pg_size) >= 65536 || !pg_idx) {
+ if (pg_idx) {
+ next->EDT = 0;
+ next++;
+ }
+ memset(next, 0x0, sizeof(struct prdt_struct));
+ next->addr = __pa(virt);
+ }
+ next->size += pg_size;
+ next->EDT = 1;
+ size -= pg_size;
+ ptr += pg_size;
+ pg_idx++;
}
+ return ret;
+}
- /* show_prdt(prdt); */
- return 0;
+static void show_prdt(struct prdt_struct *next)
+{
+ int idx = 1;
+ while (!next->EDT) {
+ MB_INFO("PRDT %d-th item: addr %x size %d EDT %d\n",
+ idx, next->addr, next->size, next->EDT);
+ idx++;
+ next++;
+ }
+ MB_INFO("PRDT last(%d-th) item: addr %x size %d EDT %d\n",
+ idx, next->addr, next->size, next->EDT);
}
-EXPORT_SYMBOL(mb_to_prdt);
+/*!*************************************************************************
+* wmt_mmu_table_size
+*
+* Public Function
+*/
+/*!
+* \brief
+* estimate request mmu table size for input size
+*
+* \parameter
+* size [IN] convert size
+*
+* \retval size of needed mmu table
+*/
unsigned int wmt_mmu_table_size(unsigned int size)
{
unsigned int nPte, nPde, need;
@@ -556,42 +733,65 @@ unsigned int wmt_mmu_table_size(unsigned int size)
if (!size)
return 0;
- nPte = (size / PAGE_SIZE) + 2; /* maybe cross page up and down boundary */
- nPde = PAGE_ALIGN(nPte * 4) / PAGE_SIZE;
- need = PAGE_ALIGN(nPde * 4);
+ nPte = ((PAGE_ALIGN(size)) / PAGE_SIZE) + 1;
+ nPde = ALIGN(nPte, 1024) / 1024;
+
+ need = (ALIGN(nPde, 1024) / 1024) * PAGE_SIZE;
need += nPte * 4;
- MB_DBG("PDE %d PTE %d RequestSize %d\n", nPde, nPte, need);
+ printk(KERN_DEBUG "PDE %d PTE %d RequestSize %d\n", nPde, nPte, need);
return need;
}
EXPORT_SYMBOL(wmt_mmu_table_size);
+/*!*************************************************************************
+* wmt_mmu_table_check
+*
+* Public Function
+*/
+/*!
+* \brief
+* check pre-allocated mmu table is valid for input size
+*
+* \parameter
+* mmu_addr [IN] mmu table address
+* mmu_size [IN] mmu table size
+* size [IN] convert size
+*
+* \retval 1 if success
+*/
int wmt_mmu_table_check(
- unsigned int mmuPhys,
- unsigned int mmuSize,
+ unsigned int *mmu_addr,
+ unsigned int mmu_size,
unsigned int size)
{
- int request;
+ unsigned int nPte, nPde, request;
if (!size) {
- MB_WARN("mmu table failure. NULL size\n");
+ printk(KERN_WARNING "mmu create failure. NULL size\n");
return 0;
}
- if (!mmuSize) {
- MB_WARN("mmu table failure. NULL mmu size\n");
+ if (!mmu_size) {
+ printk(KERN_WARNING "mmu create failure. NULL mmu size\n");
return 0;
}
- if (mmuPhys % PAGE_SIZE) {
- MB_WARN("mmu table failure. PDE Table not align\n");
+ if ((unsigned int)mmu_addr % PAGE_SIZE) {
+ printk(KERN_WARNING "mmu create fail. PDE Table not align\n");
return 0;
}
- request = wmt_mmu_table_size(size);
- if (mmuSize < request) {
- MB_WARN("mmu table failure. size %d < %d (request)\n",
- mmuSize, request);
+ nPte = ((PAGE_ALIGN(size)) / PAGE_SIZE) + 1;
+ nPde = ALIGN(nPte, 1024) / 1024;
+
+ request = (ALIGN(nPde, 1024) / 1024) * PAGE_SIZE;
+ request += nPte * 4;
+
+ if (mmu_size < request) {
+ printk(KERN_WARNING "mmu create fail. out of mmu size\n");
+ printk(KERN_WARNING "(pde %d pte %d request %d but %d)\n",
+ nPde, nPte, request, mmu_size);
return 0;
}
@@ -599,254 +799,398 @@ int wmt_mmu_table_check(
}
EXPORT_SYMBOL(wmt_mmu_table_check);
+/*!*************************************************************************
+* wmt_mmu_table_dump
+*
+* Public Function
+*/
+/*!
+* \brief
+* dump mmu table
+*
+* \parameter
+* mmu_addr [IN] mmu table address
+* size [IN] convert size
+* virBufAddr [IN] offset combination of PDE, PTE, and ADDRESS
+*
+* \retval none
+*/
void wmt_mmu_table_dump(struct mmu_table_info *info)
{
- unsigned int size, iPde, iPte, addrOffset;
- unsigned int *mmuVirt, *pte = NULL, *pde = NULL;
+ unsigned int *mmu_addr;
+ unsigned int size;
+ unsigned int virBufAddr;
+ unsigned int *pte = NULL, *pde = NULL;
+ unsigned int pdeOffset, pteOffset, addrOffset, i = 0;
if (info == 0) {
- MB_ERROR("[WMT_MMU_TABLE] Null input pointer\n");
+ printk(KERN_ERR "[WMT_MMU_TABLE] Null input pointer\n");
return;
}
- mmuVirt = (unsigned int *)mb_phys_to_virt(info->addr);
+ mmu_addr = (unsigned int *)mb_phys_to_virt(info->addr);
size = info->size;
- iPte = (info->offset >> 12) % 1024;
- iPde = (info->offset >> 22) % 1024;
- addrOffset = info->offset % PAGE_SIZE;
+ virBufAddr = info->offset;
+
+ addrOffset = virBufAddr % PAGE_SIZE;
+ pteOffset = (virBufAddr >> 12) % 1024;
+ pdeOffset = (virBufAddr >> 22) % 1024;
- MB_INFO("MMU (%x): offset pde %x pte %x addr %x\n",
- info->offset, iPde, iPte, addrOffset);
+ printk(KERN_INFO "MMU (%x): offset pde %x pte %x addr %x\n",
+ virBufAddr, pdeOffset, pteOffset, addrOffset);
+
+ pde = mmu_addr;
+ pde += pdeOffset;
+ pte = mb_phys_to_virt(*pde);
+ pte += pteOffset;
- pde = mmuVirt;
- pte = mb_phys_to_virt(pde[iPde]);
while (size > 0) {
- int pageSize = min((unsigned int)(PAGE_SIZE - addrOffset), size);
- MB_INFO("PDE(%p/%#x @ %d) -> PTE(%p/%#x @ %d) -> %#x, s %#x # %#x\n",
- pde + iPde, info->addr + iPde * sizeof(pde), iPde,
- pte + iPte, pde[iPde] + iPte * sizeof(pte), iPte,
- pte[iPte] + addrOffset, pageSize, size);
- iPte++;
+ printk(KERN_INFO "[%5d] PDE(%p/%lx) -> PTE(%p/%lx) -> addr %x\n",
+ i, pde, mb_virt_to_phys(pde), pte, mb_virt_to_phys(pte),
+ *pte + addrOffset);
+ if ((size + addrOffset) < PAGE_SIZE)
+ break;
+ size -= PAGE_SIZE - addrOffset;
addrOffset = 0;
- size -= pageSize;
- if (!(iPte % 1024)) {
- iPde++;
- iPte = 0;
- pte = mb_phys_to_virt(pde[iPde]);
- }
+ i++;
+ pte++;
+ if (!(i % 1024))
+ pde++;
}
}
EXPORT_SYMBOL(wmt_mmu_table_dump);
-/* parameter:
- mmuPhys [IN] mmu table phys address
- mmuSize [IN] mmu table size
- addr [IN] physical address of convert data
- size [IN] convert size */
+/*!*************************************************************************
+* wmt_mmu_table_from_phys
+*
+* Public Function
+*/
+/*!
+* \brief
+* make up mmu table for physical memory
+*
+* \parameter
+* mmu_addr [IN] mmu table address
+* mmu_size [IN] mmu table size
+* addr [IN] physical address of convert data
+* size [IN] convert size
+*
+* \retval 0xFFFFFFFF if fail
+* offset combination of PDE, PTE, and ADDRESS if success
+*/
unsigned int wmt_mmu_table_from_phys(
- unsigned int mmuPhys,
- unsigned int mmuSize,
+ unsigned int *mmu_addr,
+ unsigned int mmu_size,
unsigned int addr,
unsigned int size)
{
- unsigned int iPde, iPte, nPte, nPde, virBufAddr;
- unsigned int *pte, *pde, *mmuVirt;
- int64_t len = size;
- void *virt = NULL;
+ unsigned int iPte, nPte, nPde, gPde, virBufAddr;
+ unsigned int *pte = NULL, *pde = NULL;
- iPde = iPte = nPte = nPde = 0;
- if (!wmt_mmu_table_check(mmuPhys, mmuSize, size)) {
- MB_WARN("phys %x (size %d) to mmu fail\n", addr, size);
+ iPte = gPde = nPte = nPde = 0;
+ if (!wmt_mmu_table_check(mmu_addr, mmu_size, size)) {
+ printk(KERN_WARNING
+ "phys %x (size %d) to mmu fail\n", addr, size);
return 0xFFFFFFFF;
}
- virt = mb_phys_to_virt(addr);
virBufAddr = addr % PAGE_SIZE;
- nPte = size / PAGE_SIZE + 2;
- nPde = PAGE_ALIGN(nPte * 4) / PAGE_SIZE;
- pde = mmuVirt = mb_phys_to_virt(mmuPhys);
- pte = pde + nPde * 1024;
- *pde = mmuPhys + nPde * PAGE_SIZE;
- MB_DBG("[%s] pde %p/%x # %d pte %p/%x # %d\n",
- __func__, pde, mmuPhys, nPde, pte, *pde, nPte);
-
- while (len > 0) {
- pte[iPte] = addr & PAGE_MASK;
- iPte++;
+ nPte = ((PAGE_ALIGN(size)) / PAGE_SIZE);
+ if (virBufAddr)
+ nPte++;
+ nPde = ALIGN(nPte, 1024) / 1024;
+ gPde = ALIGN(nPde, 1024) / 1024;
+
+ pde = mmu_addr;
+ pte = pde + (gPde * PAGE_SIZE / sizeof(pte));
+ *pde = mb_virt_to_phys(pte);
+ pde++;
+
+ size += virBufAddr;
+ while (size > 0) {
+ *pte = addr & PAGE_MASK;
+ pte++; iPte++;
if (!(iPte % 1024)) {
- pde[iPte + 1] = pde[iPte] + PAGE_SIZE;
- iPte++;
+ *pde = mb_virt_to_phys(pte);
+ pde++;
}
+ if (size < PAGE_SIZE)
+ break;
+ size -= PAGE_SIZE;
addr += PAGE_SIZE;
- len -= PAGE_SIZE;
}
- dmac_flush_range(virt, virt + size);
- outer_flush_range(addr, addr + size);
-
return virBufAddr;
}
EXPORT_SYMBOL(wmt_mmu_table_from_phys);
-struct mmu_info {
+
+struct mmu_search_info {
+ int iPte;
+ unsigned *pte;
+ unsigned *pde;
unsigned int size;
- unsigned int iPte;
- unsigned int *pte;
- unsigned int *pde;
};
-static inline int wmt_mmu_table_proc(struct mmu_info *info, unsigned long phys)
+static int wmt_mmu_table_from_user_proc(
+ void *priv, dma_addr_t phys, int offset)
{
- int pageSize, offset;
- if (!info) {
- MB_WARN("WMT MMU process fail. (NULL info)\n");
- return -1;
- }
-
- if (info->size <= 0) {
- MB_WARN("WMT MMU process fail. (size %d)\n", info->size);
- return -1;
- }
+ struct mmu_search_info *info = (struct mmu_search_info *)priv;
- offset = phys % PAGE_SIZE;
- pageSize = min((unsigned int)(PAGE_SIZE - offset), info->size);
*info->pte = phys & PAGE_MASK;
- info->size -= pageSize;
- MB_WDBG("\t[PTE] PDE[%d](%p)=%x PTE[%d](%p)=%x size %#x left %#x\n",
- info->iPte/1024, info->pde, *info->pde, info->iPte,
- info->pte, *info->pte, pageSize, info->size);
- info->pte++;
+ printk(KERN_DEBUG
+ "\t\t\t[PTE] PDE[%d](%p)=%x PTE[%d](%p)=%x left %d\n",
+ info->iPte/1024, info->pde, *info->pde,
+ info->iPte, info->pte, *info->pte, info->size);
+ info->size -= PAGE_SIZE;
+ if (info->size < PAGE_SIZE)
+ return MMU_SEARCH_DONE;
info->iPte++;
+ info->pte++;
if (!(info->iPte % 1024)) {
*info->pde = mb_virt_to_phys(info->pte);
info->pde++;
}
-
return 0;
}
-/* parameter:
- mmuPhys [IN] mmu table phys address
- mmuSize [IN] mmu table size
- addr [IN] physical address of convert data
- size [IN] convert size */
+/*!*************************************************************************
+* wmt_mmu_table_from_user
+*
+* Public Function
+*/
+/*!
+* \brief
+* make up mmu table for user memory
+*
+* \parameter
+* mmu_addr [IN] mmu table address
+* mmu_size [IN] mmu table size
+* addr [IN] physical address of convert data
+* size [IN] convert size
+*
+* \retval 0xFFFFFFFF if fail
+* offset combination of PDE, PTE, and ADDRESS if success
+*/
unsigned int wmt_mmu_table_from_user(
- unsigned int mmuPhys,
- unsigned int mmuSize,
+ unsigned int *mmu_addr,
+ unsigned int mmu_size,
unsigned int user,
unsigned int size)
{
#ifndef __KERNEL__
- return wmt_mmu_table_from_phys(mmuPhys, mmuSize, user, size);
+ return wmt_mmu_table_from_phys(mmu_addr, mmu_size, user, size);
#else
- struct mmu_info info = {0};
- unsigned int nPte, nPde;
- unsigned long addr = user;
- int offset = user % PAGE_SIZE;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long addr, end, offset;
+ unsigned int nPte, nPde, virBufAddr;
+ struct mmu_search_info info = {0};
+ pgd_t *pgd;
+ int ret;
- if (!wmt_mmu_table_check(mmuPhys, mmuSize, size)) {
- printk(KERN_WARNING "user %x (size %d) to mmu fail\n",
+ nPte = nPde = 0;
+ if (!wmt_mmu_table_check(mmu_addr, mmu_size, size)) {
+ printk(KERN_WARNING "phys %x (size %d) to mmu fail\n",
user, size);
return 0xFFFFFFFF;
}
- MB_DBG("[%s] Memory(%#x,%#x) MMU(%#x,%d)\n",
- __func__, user, size, mmuPhys, mmuSize);
- nPte = size / PAGE_SIZE + 2;
- nPde = PAGE_ALIGN(nPte * 4) / PAGE_SIZE;
- info.size = size;
- info.pde = mb_phys_to_virt(mmuPhys);
- info.pte = info.pde + nPde * 1024;
- *info.pde = mmuPhys + nPde * PAGE_SIZE;
- dmac_flush_range((const void *)user, (const void *)(user + size));
+ virBufAddr = user % PAGE_SIZE;
+ nPte = ((PAGE_ALIGN(size)) / PAGE_SIZE);
+ if (virBufAddr)
+ nPte++;
+ nPde = ALIGN(ALIGN(nPte, 1024) / 1024, 1024) / 1024;
+
+ info.pde = mmu_addr;
+ info.pte = info.pde + (nPde * PAGE_SIZE / sizeof(info.pte));
+ *info.pde = mb_virt_to_phys(info.pte);
+ info.pde++;
+
+ printk(KERN_DEBUG "Memory(%#x,%d)\n", user, size);
+ down_read(&mm->mmap_sem);
+ info.size = size + virBufAddr;
+ addr = (unsigned long)user;
while (info.size > 0) {
- unsigned long phys = user_to_phys(addr);
- int pageSize = min((unsigned int)(PAGE_SIZE - offset), info.size);
- if (!phys) {
- MB_WARN("user to mmu fail: unknown addr %lx (%x # %x)\n",
- addr, user, size);
- return -EINVAL;
+ vma = find_vma(mm, addr);
+ if (vma == NULL) {
+ printk(KERN_WARNING
+ "user addr %lx not found in task %s\n",
+ addr, current->comm);
+ goto fault;
}
- outer_flush_range(phys, phys + pageSize);
- wmt_mmu_table_proc(&info, phys);
- addr += pageSize;
- offset = 0;
+ printk(KERN_DEBUG
+ "VMA found: start %lx end %lx\n",
+ vma->vm_start, vma->vm_end);
+ offset = addr - vma->vm_start;
+ addr = vma->vm_start;
+ end = PAGE_ALIGN(vma->vm_end);
+ pgd = pgd_offset(mm, vma->vm_start);
+ ret = mmu_search_pgd(pgd, end, &addr, &offset,
+ wmt_mmu_table_from_user_proc, &info);
+ if (ret == MMU_SEARCH_DONE)
+ break;
+ if (ret)
+ goto fault;
}
-
- return user % PAGE_SIZE;
+ up_read(&mm->mmap_sem);
+ return virBufAddr;
+fault:
+ printk(KERN_WARNING "USER TO PRDT unfinished, remain size %d\n", size);
+ up_read(&mm->mmap_sem);
+ return 0xFFFFFFFF;
#endif
}
EXPORT_SYMBOL(wmt_mmu_table_from_user);
-/* parameter:
- addr [IN] start address (user or phys depends on addr_type)
- size [IN] size of memory
- addrType [IN] address type (0: phys 1: user)
- info [out] pointer of mmu table info */
+/*!*************************************************************************
+* wmt_mmu_table_create
+*
+* Public Function
+*/
+/*!
+* \brief
+* automatically make up mmu table from giving address
+*
+* \parameter
+* addr [IN] start address (user of phys depends on addr_type)
+* size [IN] size of memory
+* addr_type [IN] address type (0: phys 1: user)
+* info [out] pointer of mmu table info
+*
+* \retval 0 if success, otherwise error code
+*/
unsigned int wmt_mmu_table_create(
unsigned int addr,
unsigned int size,
- unsigned int addrType,
+ unsigned int addr_type,
struct mmu_table_info *info)
{
- int i, nPde, nPte, *pde, mmuSize;
+ unsigned int mmuSize = 0;
unsigned int *mmuAddr = NULL;
- if (!addr || !size || !info || addrType > 1) {
- MB_ERROR("[WMT_MMU_TABLE] invalid args:\n");
- MB_ERROR("\t addr %x # %x type %x info %p\n",
- addr, size, addrType, info);
+ if (!addr || !size || !info || addr_type > 1) {
+ printk(KERN_ERR "[WMT_MMU_TABLE] invalid args:\n");
+ printk(KERN_ERR "\t addr %x # %x type %x info %p\n",
+ addr, size, addr_type, info);
return -EINVAL;
}
mmuSize = wmt_mmu_table_size(size);
+
info->addr = mb_alloc(mmuSize);
- info->size = size;
- MB_DBG("[%s] mmu table (%#x # %#x) addr %#x size %#x type %d\n",
- __func__, info->addr, mmuSize, addr, size, addrType);
if (!info->addr) {
- MB_ERROR("[%s] fail. Out of MB (%d)\n", __func__, mmuSize);
+ printk(KERN_ERR "[WMT_MMU_TABLE] create fail. Out of MB (%d)\n",
+ mmuSize);
return -ENOMEM;
}
+ info->size = size;
+ mmuAddr = (unsigned int *)mb_phys_to_virt(info->addr);
- pde = mmuAddr = (unsigned int *)mb_phys_to_virt((unsigned long)info->addr);
- memset(mmuAddr, 0x0, mmuSize);
- nPte = (size / PAGE_SIZE) + 2; /* maybe cross page up and down boundary */
- nPde = PAGE_ALIGN(nPte * 4) / PAGE_SIZE;
- for (i = 1; i <= nPde; i++, pde++)
- *pde = info->addr + i * PAGE_SIZE;
- info->offset = (addrType) ?
- wmt_mmu_table_from_user(info->addr, mmuSize, addr, size) :
- wmt_mmu_table_from_phys(info->addr, mmuSize, addr, size);
+ info->offset = (addr_type) ?
+ wmt_mmu_table_from_user(mmuAddr, mmuSize, addr, size) :
+ wmt_mmu_table_from_phys(mmuAddr, mmuSize, addr, size);
if (info->offset == 0xFFFFFFFF) {
- MB_ERROR("[WMT_MMU_TABLE] create fail:");
- MB_ERROR("\ttype %x addr %x # %x mmuAddr %p/%x # %d\n",
- addrType, addr, size, mmuAddr, info->addr, info->size);
- mb_free(info->addr);
+ printk(KERN_ERR "[WMT_MMU_TABLE] create fail:");
+ printk(KERN_ERR "\ttype %x addr %x # %x mmuAddr %p/%x # %d\n",
+ addr_type, addr, size, mmuAddr, info->addr, mmuSize);
return -EFAULT;
}
- MB_DBG("[%s] success! (addr %#x size %#x offset %#x)\n",
- __func__, info->addr, info->size, info->offset);
return 0;
}
EXPORT_SYMBOL(wmt_mmu_table_create);
+/*!*************************************************************************
+* wmt_mmu_table_destroy
+*
+* Public Function
+*/
+/*!
+* \brief
+* automatically make up mmu table from giving address
+*
+* \parameter
+* info [IN] start address (user of phys depends on addr_type)
+*
+* \retval 1 if success
+*/
unsigned int wmt_mmu_table_destroy(struct mmu_table_info *info)
{
if (!info) {
- MB_ERROR("[WMT_MMU_TABLE] destroy fail. NULL mmu table info");
+ printk(KERN_ERR "[WMT_MMU_TABLE] destroy fail. NULL mmu table info");
return -EINVAL;
}
- MB_DBG("[%s] success! addr %#x\n", __func__, info->addr);
mb_free(info->addr);
return 0;
}
EXPORT_SYMBOL(wmt_mmu_table_destroy);
+/* return address is guaranteeed only under page alignment */
+void *user_to_virt(unsigned long user)
+{
+ struct vm_area_struct *vma;
+ unsigned long flags;
+ void *virt = NULL;
+
+ spin_lock_irqsave(&mb_task_mm_lock, flags);
+ vma = find_vma(current->mm, user);
+ /* For kernel direct-mapped memory, take the easy way */
+ if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
+ unsigned long phys = 0;
+ /* kernel-allocated, mmaped-to-usermode addresses */
+ phys = (vma->vm_pgoff << PAGE_SHIFT) + (user - vma->vm_start);
+ virt = __va(phys);
+ MB_INFO("%s kernel-alloc, user-mmaped addr U %lx V %p P %lx",
+ __func__, user, virt, phys);
+ } else {
+ /* otherwise, use get_user_pages() for general userland pages */
+ int res, nr_pages = 1;
+ struct page *pages;
+ down_read(&current->mm->mmap_sem);
+ res = get_user_pages(current, current->mm,
+ user, nr_pages, 1, 0, &pages, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (res == nr_pages)
+ virt = page_address(&pages[0]) + (user & ~PAGE_MASK);
+ MB_INFO("%s userland addr U %lx V %p", __func__, user, virt);
+ }
+ spin_unlock_irqrestore(&mb_task_mm_lock, flags);
+
+ return virt;
+}
+EXPORT_SYMBOL(user_to_virt);
+
+int user_to_prdt(
+ unsigned long user,
+ unsigned int size,
+ struct prdt_struct *next,
+ unsigned int items)
+{
+ int ret;
+
+ switch (USR2PRDT_METHOD) {
+ case 1:
+ ret = __user_to_prdt1(user, size, next, items);
+ break;
+ case 2:
+ ret = __user_to_prdt2(user, size, next, items);
+ break;
+ default:
+ ret = __user_to_prdt(user, size, next, items);
+ break;
+ }
+
+ if (MBMSG_LEVEL > 1)
+ show_prdt(next);
+
+ return ret;
+}
+EXPORT_SYMBOL(user_to_prdt);
+
static int mb_show_mb(
struct mb_struct *mb,
char *msg,
@@ -2510,147 +2854,6 @@ RESCAN_MBA:
spin_unlock_irqrestore(&mb_ioctl_lock, flags);
return 0;
- /* _IOW(MB_IOC_MAGIC, 19, unsigned long) // I: phys address */
- case MBIO_STATIC_GET:
- get_user(value, (unsigned long *)arg);
- if (!value || !mbti->task_name || tgid == MB_DEF_TGID) {
- MB_WARN("GET(STATIC): invalid args %lx/%d/%s\n",
- value, tgid, mbti->task_name);
- return -EINVAL;
- }
-
- ret = mb_do_get(value, MB_DEF_TGID, mbti->task_name);
- if (ret != 0)
- MB_WARN("GET(STATIC): fail (args %lx/%d/%s). ret %d\n",
- value, tgid, mbti->task_name, ret);
- MB_OPDBG("GET(STATIC): phys %8lx done\n\n", value);
- break;
-
- /* _IOW(MB_IOC_MAGIC, 20, unsigned long) // I: phys address */
- case MBIO_STATIC_PUT:
- get_user(value, (unsigned long *)arg);
- if (!value || !mbti->task_name || tgid == MB_DEF_TGID) {
- MB_WARN("PUT(STATIC): invalid args %lx/%d/%s\n",
- value, tgid, mbti->task_name);
- return -EINVAL;
- }
-
- ret = mb_do_put(value, MB_DEF_TGID, mbti->task_name);
- if (ret != 0)
- MB_WARN("PUT(STATIC): fail (args %lx/%d/%s). ret %d\n",
- value, tgid, mbti->task_name, ret);
- MB_OPDBG("PUT(STATIC): phys %8lx done\n\n", value);
- break;
-
- /* _IOWR(MB_IOC_MAGIC, 100, unsigned long)
- I: user address O: physical address */
- case MBIO_TEST_USER2PHYS:
- get_user(value, (unsigned long *)arg);
- if (!value) {
- MB_WARN("USER2PHYS: invalid args %lx/%d/%s\n",
- value, tgid, mbti->task_name);
- return -EINVAL;
- }
- phys = user_to_phys(value);
- put_user(phys, (unsigned long *)arg);
- if (!phys)
- MB_WARN("USER2PHYS fail: value %#lx phys %#lx\n", value, phys);
- break;
-
- /* _IOWR(MB_IOC_MAGIC, 101, unsigned long)
- I: user address, size, prdt addr, and prdt size */
- case MBIO_TEST_USER2PRDT:
- /* _IOW(MB_IOC_MAGIC, 103, unsigned long)
- * I: user address, size, prdt addr, and prdt size */
- case MBIO_TEST_MB2PRDT: {
- int items, type = (cmd == MBIO_TEST_MB2PRDT) ? 0 : 1;
- unsigned long size, data[4] = {0};
- struct prdt_struct *prdt;
- copy_from_user(data, (const void *)arg, 4 * sizeof(unsigned long));
- if (!data[0] || !data[1] || !data[2] || !data[3]) {
- MB_WARN("%s: invalid args [%#lx, %#lx, %#lx, %#lx]\n",
- type ? "MB2PRDT" : "USER2PRDT",
- data[0], data[1], data[2], data[3]);
- return -EINVAL;
- }
- items = data[1] / PAGE_SIZE + 2;
- size = items * sizeof(struct prdt_struct);
- if (data[3] < size) {
- MB_WARN("%s: invalid args. prdt size %#lx < %#lx\n",
- type ? "MB2PRDT" : "USER2PRDT", data[3], size);
- return -EINVAL;
- }
- prdt = kmalloc(size, GFP_ATOMIC);
- if (prdt == NULL) {
- MB_WARN("%s: fail, no prdt space %d for size %ld\n",
- type ? "MB2PRDT" : "USER2PRDT",
- items * sizeof(struct prdt_struct), data[1]);
- return -EINVAL;
- }
- MB_DBG("%s: IN %#lx, %#lx, %#lx, %#lx\n",
- type ? "MB2PRDT" : "USER2PRDT",
- data[0], data[1], data[2], data[3]);
- memset(prdt, 0x0, items * sizeof(struct prdt_struct));
- if ((!type && !mb_to_prdt(data[0], data[1], prdt, items)) ||
- (!user_to_prdt(data[0], data[1], prdt, items))) {
- if (MBMSG_LEVEL)
- show_prdt(prdt);
- copy_to_user((void __user *)data[2], prdt, size);
- MB_INFO("%s: Done %#lx, %#lx, %#lx, %#lx\n",
- type ? "MB2PRDT" : "USER2PRDT",
- data[0], data[1], data[2], data[3]);
- } else {
- MB_WARN("%s: fail.\n", type ? "MB2PRDT" : "USER2PRDT");
- ret = -EINVAL;
- }
- kfree(prdt);
- break;
- }
-
- /* _IOWR(MB_IOC_MAGIC, 102, unsigned long)
- I: user address, size, mmu addr, and mmu size O: mmu physical addr */
- case MBIO_TEST_USER2MMUT:
- /* _IOWR(MB_IOC_MAGIC, 104, unsigned long)
- I: user address, size, mmu addr, and mmu size O: mmu physical addr */
- case MBIO_TEST_MB2MMUT: {
- int type = (cmd == MBIO_TEST_MB2MMUT) ? 0 : 1;
- unsigned long mmuSize, data[4] = {0};
- struct mmu_table_info info = {0};
- copy_from_user(data, (const void *)arg, 4 * sizeof(unsigned long));
- if (!data[0] || !data[1] || !data[2] || !data[3]) {
- MB_WARN("%s: invalid args [%#lx, %#lx, %#lx, %#lx]\n",
- type ? "USER2MMUT" : "PHYS2MMUT",
- data[0], data[1], data[2], data[3]);
- return -EINVAL;
- }
- mmuSize = wmt_mmu_table_size(data[1]);
- if (data[3] < mmuSize) {
- MB_WARN("%s: invalid args. mmu size %#lx < %#lx\n",
- type ? "MB2PRDT" : "USER2PRDT", data[3], mmuSize);
- return -EINVAL;
- }
- MB_DBG("%s: IN %#lx, %#lx, %#lx, %#lx(req %#lx)\n",
- type ? "USER2MMUT" : "PHYS2MMUT",
- data[0], data[1], data[2], data[3], mmuSize);
- if (wmt_mmu_table_create(data[0], data[1], type, &info) == 0) {
- void *mmuAddr = mb_phys_to_virt((unsigned long)info.addr);
- if (MBMSG_LEVEL)
- wmt_mmu_table_dump(&info);
- copy_to_user((void __user *)data[2], mmuAddr, mmuSize);
- put_user(info.addr, (unsigned long *)arg);
- ret = mb_do_get(info.addr, MB_DEF_TGID, mbti->task_name);
- wmt_mmu_table_destroy(&info);
- MB_INFO("%s: Done %#lx, %#lx, %#lx, %#lx\n",
- type ? "USER2MMUT" : "PHYS2MMUT",
- data[0], data[1], data[2], data[3]);
- } else {
- MB_WARN("%s: fail. no mmu table space for size %ld\n",
- type ? "USER2MMUT" : "PHYS2MMUT", data[1]);
- return -EINVAL;
- }
- break;
- }
-
default:
ret = -ENOTTY;
break;