From 879568111df7776848beb70468c78b9aa09092a8 Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 26 Nov 2012 19:05:00 +0200 Subject: [PATCH] support section mmap, update test --- module/warm_main.c | 84 ++++++++++++++++++++ test.c | 185 ++++++++++++++++++++++++++++++++++++++++----- warm.c | 51 ++++++++++++- warm.h | 14 ++++ 4 files changed, 313 insertions(+), 21 deletions(-) diff --git a/module/warm_main.c b/module/warm_main.c index 18e9762..3b3a148 100644 --- a/module/warm_main.c +++ b/module/warm_main.c @@ -337,6 +337,81 @@ static int do_cache_ops(int ops, u32 addr, u32 size) return 0; } +static int do_map_op(u32 vaddr, u32 paddr, u32 size, int cb, int is_unmap) +{ + int count = 0, retval = 0; + u32 pstart, start, end; + u32 desc1, apcb_bits; + u32 *pgtable; + u32 v, mask; + + apcb_bits = (3 << 10) | (1 << 5); /* r/w, dom 1 */ + if (cb & WCB_C_BIT) + apcb_bits |= 8; + if (cb & WCB_B_BIT) + apcb_bits |= 4; + // spinlock + + mask = SECTION_SIZE - 1; + size = (size + mask) & ~mask; + + pstart = paddr; + start = vaddr; + end = start + size; + + /* check for overflows */ + if (end - 1 < start) + return -EINVAL; + if (pstart + size - 1 < pstart) + return -EINVAL; + + pgtable = get_pgtable(); + + for (; vaddr < end; vaddr += SECTION_SIZE, paddr += SECTION_SIZE) + { + desc1 = pgtable[vaddr >> 20]; + + if (is_unmap) { + if ((desc1 & 3) != 2) { + printk(KERN_WARNING PFX "vaddr %08x is not a section? (%08x)\n", + vaddr, desc1); + return -EINVAL; + } + v = 0; + } else { + if ((desc1 & 3) != 0) { + printk(KERN_WARNING PFX "vaddr %08x already mapped? (%08x)\n", + vaddr, desc1); + retval = -EINVAL; + break; + } + v = (paddr & ~mask) | apcb_bits | 0x12; + } + + pgtable[vaddr >> 20] = v; + count++; + } + + if (retval != 0) { + /* undo mappings */ + vaddr = start; + + for (; vaddr < end && count > 0; vaddr += SECTION_SIZE, count--) + pgtable[vaddr >> 20] = 0; + } + + warm_cop_clean_d(); + warm_drain_wb_inval_tlb(); + + if (retval == 0 && !is_unmap) { + WARM_INFO("mapped %08x to %08x with %c%c bit(s) (%d section(s))\n", + start, pstart, apcb_bits & 8 ? 'c' : ' ', + apcb_bits & 4 ? 'b' : ' ', count); + } + + return retval; +} + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) static long warm_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) #else @@ -348,6 +423,7 @@ static int warm_ioctl(struct inode *inode, struct file *file, union { struct warm_cache_op wcop; struct warm_change_cb ccb; + struct warm_map_op mop; unsigned long addr; } u; long ret; @@ -381,6 +457,14 @@ static int warm_ioctl(struct inode *inode, struct file *file, if (copy_to_user(arg, &u.addr, sizeof(u.addr))) return -EFAULT; break; + case WARMC_MMAP: + if (copy_from_user(&u.mop, arg, sizeof(u.mop))) + return -EFAULT; + if (u.mop.cb & ~(WCB_C_BIT|WCB_B_BIT)) + return -EINVAL; + ret = do_map_op(u.mop.virt_addr, u.mop.phys_addr, u.mop.size, + u.mop.cb, u.mop.is_unmap); + break; default: ret = -ENOTTY; break; diff --git a/test.c b/test.c index 55dfe7b..8a9fd90 100644 --- a/test.c +++ b/test.c @@ -11,6 +11,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #if 1 #include "warm.h" @@ -24,8 +30,10 @@ typedef unsigned long long u64; static u64 start_time, end_time; -static unsigned char buff[8 * 1024 * 1024] __attribute__((aligned(32))); -static unsigned char *buff_mid = &buff[8 * 1024 * 1024 / 2]; +static unsigned char buff[2 * 1024 * 1024] __attribute__((aligned(32))); +static unsigned char *buff_mid = &buff[sizeof(buff) / 2]; + +#define REP 32 static u64 xtime(void) { @@ -71,6 +79,18 @@ static void word_fill(void) *p++ = 0; } +static void cached_byte_fill(void) +{ + char *p = (void *)buff; + int i, j, v; + + for (i = sizeof(buff) / 32; i > 0; i--) { + v += *p; + for (j = 32; j > 0; j--) + *p++ = v; + } +} + static void do_memcpy(void) { memcpy(buff, buff_mid, sizeof(buff) / 2); @@ -105,40 +125,96 @@ static void word_inc(void) } } +#define TEST_PAGE 4096 + +static void page_writes_ref(void *buf) +{ + long *d = buf; + int i, j; + + for (j = 0; j < 0x100000 / TEST_PAGE; j++) + for (i = 0; i < TEST_PAGE / 4; i++) + d[j * TEST_PAGE / 4 + i] = 0; +} + +static void page_inc_ref(void *buf) +{ + long *d = buf; + int i, j; + + for (j = 0; j < 0x100000 / TEST_PAGE; j++) + for (i = 0; i < TEST_PAGE / 4; i++) + d[j * TEST_PAGE / 4 + i]++; +} + +static void page_writes(void *buf) +{ + long *d = buf; + int i, j; + + for (i = 0; i < TEST_PAGE / 4; i++) + for (j = 0; j < 0x100000 / TEST_PAGE; j++) + d[j * TEST_PAGE / 4 + i] = 0; +} + +static void page_inc(void *buf) +{ + long *d = buf; + int i, j; + + for (i = 0; i < TEST_PAGE / 4; i++) + for (j = 0; j < 0x100000 / TEST_PAGE; j++) + d[j * TEST_PAGE / 4 + i]++; +} + #define ONE_TEST(count, func) \ test_start(); \ for (i = count; i > 0; i--) \ - func(); \ + func; \ test_end() static void tests(void) { int i; - ONE_TEST(64, do_memset); - show_result("memset", sizeof(buff) * 64); + ONE_TEST(REP, do_memset()); + show_result("memset", sizeof(buff) * REP); + + ONE_TEST(REP, byte_fill()); + show_result("byte fill", sizeof(buff) * REP); - ONE_TEST(64, byte_fill); - show_result("byte fill", sizeof(buff) * 64); + ONE_TEST(REP, word_fill()); + show_result("word fill", sizeof(buff) * REP); - ONE_TEST(64, word_fill); - show_result("word fill", sizeof(buff) * 64); + ONE_TEST(REP, cached_byte_fill()); + show_result("c. byte fill", sizeof(buff) * REP); - ONE_TEST(128, do_memcpy); - show_result("memcpy", sizeof(buff) * 128 / 2); + ONE_TEST(REP * 2, do_memcpy()); + show_result("memcpy", sizeof(buff) * REP); - ONE_TEST(128, byte_cpy); - show_result("byte copy", sizeof(buff) * 128 / 2); + ONE_TEST(REP * 2, byte_cpy()); + show_result("byte copy", sizeof(buff) * REP); - ONE_TEST(128, word_cpy); - show_result("word copy", sizeof(buff) * 128 / 2); + ONE_TEST(REP * 2, word_cpy()); + show_result("word copy", sizeof(buff) * REP); - ONE_TEST(64, word_inc); - show_result("word inc", sizeof(buff) * 64); + ONE_TEST(REP, word_inc()); + show_result("word inc", sizeof(buff) * REP); usleep(200000); } +static void page_tests(void *buf) +{ + int i; + + ONE_TEST(REP, page_writes(buf)); + show_result("page_writes", 0x100000 * REP); + + ONE_TEST(REP, page_inc(buf)); + show_result("page_inc", 0x100000 * REP); +} + #if 1 #include #include @@ -225,7 +301,11 @@ void coherency_test(void) int main() { - int ret; + struct fb_fix_screeninfo fbfix; + void *mmap_mem; + void *section_mem; + int fbdev; + int i, ret; ret = warm_init(); if (ret != 0) @@ -236,6 +316,9 @@ int main() printf("buff: %p - %p\n", buff, buff + sizeof(buff) - 1); + // prefault + do_memset(); + printf("-- default --\n"); tests(); @@ -252,9 +335,75 @@ int main() warm_change_cb_range(WCB_B_BIT, 0, buff, sizeof(buff)); tests(); + //printf("-- c b --\n"); warm_change_cb_range(WCB_C_BIT|WCB_B_BIT, 1, buff, sizeof(buff)); + //tests(); + coherency_test(); + mmap_mem = mmap((void *)0x60000000, 0x100000, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + // find safe location for section map, we'll use fb + fbdev = open("/dev/fb0", O_RDWR); + if (fbdev == -1) { + perror("fb open"); + goto out; + } + + ret = ioctl(fbdev, FBIOGET_FSCREENINFO, &fbfix); + if (ret == -1) { + perror("ioctl(fbdev)"); + goto out; + } + + section_mem = (void *)0x70000000; + ret = warm_mmap_section(section_mem, fbfix.smem_start, 0x100000, + WCB_C_BIT|WCB_B_BIT); + if (ret != 0) { + fprintf(stderr, "section map failed\n"); + goto out; + } + + // prefault + memset(mmap_mem, 0, 0x100000); + memset(section_mem, 0, 0x100000); + + ONE_TEST(REP, page_writes_ref(mmap_mem)); + show_result("page_wr_ref_m", 0x100000 * REP); + + ONE_TEST(REP, page_inc_ref(mmap_mem)); + show_result("page_inc_ref_m", 0x100000 * REP); + + ONE_TEST(REP, page_writes_ref(section_mem)); + show_result("page_wr_ref_s", 0x100000 * REP); + + ONE_TEST(REP, page_inc_ref(section_mem)); + show_result("page_inc_ref_s", 0x100000 * REP); + + printf("== pages ==\n"); + page_tests(mmap_mem); + + printf("== section ==\n"); + printf("-- default --\n"); + page_tests(section_mem); + + printf("-- ncnb --\n"); + warm_change_cb_range(WCB_C_BIT|WCB_B_BIT, 0, section_mem, 0x100000); + page_tests(section_mem); + + printf("-- nc b --\n"); + warm_change_cb_range(WCB_B_BIT, 1, section_mem, 0x100000); + page_tests(section_mem); + + printf("-- cnb --\n"); + warm_change_cb_range(WCB_C_BIT, 1, section_mem, 0x100000); + warm_change_cb_range(WCB_B_BIT, 0, section_mem, 0x100000); + page_tests(section_mem); + + warm_munmap_section(section_mem, 0x100000); + +out: warm_finish(); return 0; diff --git a/warm.c b/warm.c index c79c63e..d17b122 100644 --- a/warm.c +++ b/warm.c @@ -205,7 +205,7 @@ int warm_cache_op_range(int op, void *addr, unsigned long size) ret = ioctl(warm_fd, WARMC_CACHE_OP, &wop); if (ret != 0) { - perror("WARMC_CACHE_OP failed"); + perror(PFX "WARMC_CACHE_OP failed"); return -1; } @@ -232,7 +232,7 @@ int warm_change_cb_range(int cb, int is_set, void *addr, unsigned long size) ret = ioctl(warm_fd, WARMC_CHANGE_CB, &ccb); if (ret != 0) { - perror("WARMC_CHANGE_CB failed"); + perror(PFX "WARMC_CHANGE_CB failed"); return -1; } @@ -252,10 +252,55 @@ unsigned long warm_virt2phys(const void *ptr) ptrio = (unsigned long)ptr; ret = ioctl(warm_fd, WARMC_VIRT2PHYS, &ptrio); if (ret != 0) { - perror("WARMC_VIRT2PHYS failed"); + perror(PFX "WARMC_VIRT2PHYS failed"); return (unsigned long)-1; } return ptrio; } +int warm_do_section(void *virt_addr, unsigned long phys_addr, + unsigned long size, int cb, int is_unmap) +{ + struct warm_map_op mop; + unsigned long vaddr; + int ret; + + if (warm_fd < 0) + return -1; + + vaddr = (unsigned long)virt_addr; + if (vaddr & 0xfffff) { + fprintf(stderr, PFX "virt_addr is unaligned\n"); + return -1; + } + if (phys_addr & 0xfffff) { + fprintf(stderr, PFX "phys_addr is unaligned\n"); + return -1; + } + + mop.virt_addr = vaddr; + mop.phys_addr = phys_addr; + mop.size = size; + mop.cb = cb; + mop.is_unmap = is_unmap; + + ret = ioctl(warm_fd, WARMC_MMAP, &mop); + if (ret != 0) { + perror(PFX "WARMC_MMAP failed"); + return -1; + } + + return 0; +} + +int warm_mmap_section(void *virt_addr, unsigned long phys_addr, + unsigned long size, int cb) +{ + return warm_do_section(virt_addr, phys_addr, size, cb, 0); +} + +int warm_munmap_section(void *virt_addr, unsigned long size) +{ + return warm_do_section(virt_addr, 0, size, 0, 1); +} diff --git a/warm.h b/warm.h index 1ef5df2..c36d750 100644 --- a/warm.h +++ b/warm.h @@ -63,6 +63,10 @@ int warm_change_cb_range(int cb, int is_set, void *virt_addr, unsigned long size unsigned long warm_virt2phys(const void *ptr); +int warm_mmap_section(void *virt_addr, unsigned long phys_addr, + unsigned long size, int cb); +int warm_munmap_section(void *virt_addr, unsigned long size); + void warm_finish(void); #ifdef __cplusplus @@ -91,9 +95,19 @@ struct warm_change_cb int is_set; /* set (1) or clear (0) */ }; +struct warm_map_op +{ + unsigned long virt_addr; + unsigned long phys_addr; + unsigned long size; + int cb; + int is_unmap; +}; + #define WARMC_CACHE_OP _IOW(WARM_IOCTL_BASE, 0, struct warm_cache_op) #define WARMC_CHANGE_CB _IOW(WARM_IOCTL_BASE, 1, struct warm_change_cb) #define WARMC_VIRT2PHYS _IOWR(WARM_IOCTL_BASE, 2, unsigned long) +#define WARMC_MMAP _IOW(WARM_IOCTL_BASE, 3, struct warm_map_op) #endif /* WARM_CODE */ #endif /* !__ASSEMBLER__ */ -- 2.39.2