};
static void ion_iommu_force_unmap(struct ion_buffer *buffer);
+extern char *rockchip_ion_snapshot_get(unsigned *size);
+extern int rockchip_ion_snapshot_debugfs(struct dentry* root);
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
{
if (!idev->clients_debug_root)
pr_err("ion: failed to create debugfs clients directory.\n");
+#ifdef CONFIG_ION_ROCKCHIP_SNAPSHOT
+ rockchip_ion_snapshot_debugfs(idev->debug_root);
+#endif
+
debugfs_done:
idev->custom_ioctl = custom_ioctl;
}
}
-#define ION_SNAPSHOT_BUFFER_LEN 1<<18
+#ifdef CONFIG_ION_ROCKCHIP_SNAPSHOT
int ion_snapshot_save(struct ion_device *idev)
{
static struct seq_file seqf;
struct rb_node *n;
if (!seqf.buf) {
- seqf.size = ION_SNAPSHOT_BUFFER_LEN;
- seqf.buf = kmalloc(seqf.size, GFP_KERNEL);
+ seqf.buf = rockchip_ion_snapshot_get(&seqf.size);
if (!seqf.buf)
return -ENOMEM;
- printk("%s: create snapshot 0x%x@0x%lx\n", __func__, seqf.size,
- __pa(seqf.buf));
- } else {
- printk("%s: save snapshot 0x%x@0x%lx\n", __func__, seqf.size,
- __pa(seqf.buf));
- memset(seqf.buf, 0, seqf.size);
- seqf.count = 0;
}
+ memset(seqf.buf, 0, seqf.size);
+ seqf.count = 0;
+ pr_info("%s: save snapshot 0x%x@0x%lx\n", __func__, seqf.size,
+ __pa(seqf.buf));
down_read(&idev->lock);
return 0;
}
+#else
+int ion_snapshot_save(struct ion_device *idev)
+{
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ * drivers/staging/android/ion/rockchip/rockchip_ion_snapshot.c
+ *
+ * Copyright (C) 2011-2014 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "ion_snapshot: " fmt
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <linux/debugfs.h>
+
+#define LOG_BUF_LEN (1 << CONFIG_ION_SNAPSHOT_BUF_SHIFT)
+#define LOG_BUF_PAGE_ORDER (CONFIG_ION_SNAPSHOT_BUF_SHIFT - PAGE_SHIFT)
+// snapshot for last
+static char last_ion_buf[LOG_BUF_LEN];
+// snapshot for current
+static char* ion_snapshot_buf;
+
+static ssize_t last_ion_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ loff_t pos = *offset;
+ ssize_t count;
+
+ if (pos >= LOG_BUF_LEN || last_ion_buf[0]==0)
+ return 0;
+
+ count = min(len, (size_t)(LOG_BUF_LEN - pos));
+ if (copy_to_user(buf, &last_ion_buf[pos], count))
+ return -EFAULT;
+
+ *offset += count;
+ return count;
+}
+
+static const struct file_operations last_ion_fops = {
+ .owner = THIS_MODULE,
+ .read = last_ion_read,
+};
+
+static ssize_t ion_snapshot_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ loff_t pos = *offset;
+ ssize_t count;
+
+ if (pos >= LOG_BUF_LEN || ion_snapshot_buf[0]==0)
+ return 0;
+
+ count = min(len, (size_t)(LOG_BUF_LEN - pos));
+ if (copy_to_user(buf, &ion_snapshot_buf[pos], count))
+ return -EFAULT;
+
+ *offset += count;
+ return count;
+}
+
+static const struct file_operations ion_snapshot_fops = {
+ .owner = THIS_MODULE,
+ .read = ion_snapshot_read,
+};
+
+char *rockchip_ion_snapshot_get(unsigned *size)
+{
+ *size = LOG_BUF_LEN;
+ return ion_snapshot_buf;
+}
+
+int rockchip_ion_snapshot_debugfs(struct dentry* root)
+{
+ struct dentry* last_ion_dentry;
+ struct dentry* ion_snapshot_dentry;
+
+ last_ion_dentry = debugfs_create_file("last_ion", S_IRUSR,
+ root,
+ NULL, &last_ion_fops);
+ if (!last_ion_dentry) {
+ char buf[256], *path;
+ path = dentry_path(root, buf, 256);
+ pr_err("Failed to create client debugfs at %s/%s\n",
+ path, "last_ion");
+ }
+
+ ion_snapshot_dentry = debugfs_create_file("ion_snapshot", S_IRUSR,
+ root,
+ NULL, &ion_snapshot_fops);
+ if (!ion_snapshot_dentry) {
+ char buf[256], *path;
+ path = dentry_path(root, buf, 256);
+ pr_err("Failed to create client debugfs at %s/%s\n",
+ path, "ion_snapshot");
+ }
+
+ return 0;
+}
+
+static void * __init last_ion_vmap(phys_addr_t start, unsigned int page_count)
+{
+ struct page *pages[page_count + 1];
+ unsigned int i;
+
+ for (i = 0; i < page_count; i++) {
+ phys_addr_t addr = start + i * PAGE_SIZE;
+ pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
+ }
+ pages[page_count] = pfn_to_page(start >> PAGE_SHIFT);
+ return vmap(pages, page_count + 1, VM_MAP, pgprot_noncached(PAGE_KERNEL));
+}
+
+static int __init rockchip_ion_snapshot_init(void)
+{
+ char *log_buf;
+
+ log_buf = (char *)__get_free_pages(GFP_KERNEL, LOG_BUF_PAGE_ORDER);
+ if (!log_buf) {
+ pr_err("failed to __get_free_pages(%d)\n", LOG_BUF_PAGE_ORDER);
+ return 0;
+ }
+
+ ion_snapshot_buf = last_ion_vmap(virt_to_phys(log_buf), 1 << LOG_BUF_PAGE_ORDER);
+ if (!ion_snapshot_buf) {
+ pr_err("failed to map %d pages at 0x%08x\n", 1 << LOG_BUF_PAGE_ORDER, virt_to_phys(log_buf));
+ return 0;
+ }
+
+ pr_info("0x%08x map to 0x%p and copy to 0x%p (version 0.1)\n",
+ virt_to_phys(log_buf), ion_snapshot_buf, last_ion_buf);
+
+ memcpy(last_ion_buf, ion_snapshot_buf, LOG_BUF_LEN);
+ memset(ion_snapshot_buf, 0, LOG_BUF_LEN);
+
+ return 0;
+}
+
+postcore_initcall(rockchip_ion_snapshot_init);