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
union {
struct warm_cache_op wcop;
struct warm_change_cb ccb;
+ struct warm_map_op mop;
unsigned long addr;
} u;
long ret;
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;
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/fb.h>
#if 1
#include "warm.h"
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)
{
*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);
}
}
+#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 <sys/types.h>
#include <sys/stat.h>
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)
printf("buff: %p - %p\n", buff, buff + sizeof(buff) - 1);
+ // prefault
+ do_memset();
+
printf("-- default --\n");
tests();
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;
ret = ioctl(warm_fd, WARMC_CACHE_OP, &wop);
if (ret != 0) {
- perror("WARMC_CACHE_OP failed");
+ perror(PFX "WARMC_CACHE_OP failed");
return -1;
}
ret = ioctl(warm_fd, WARMC_CHANGE_CB, &ccb);
if (ret != 0) {
- perror("WARMC_CHANGE_CB failed");
+ perror(PFX "WARMC_CHANGE_CB failed");
return -1;
}
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);
+}