16d7d7433SHuang, Ying /* 26d7d7433SHuang, Ying * Architecture specific debugfs files 36d7d7433SHuang, Ying * 46d7d7433SHuang, Ying * Copyright (C) 2007, Intel Corp. 56d7d7433SHuang, Ying * Huang Ying <ying.huang@intel.com> 66d7d7433SHuang, Ying * 76d7d7433SHuang, Ying * This file is released under the GPLv2. 86d7d7433SHuang, Ying */ 96d7d7433SHuang, Ying #include <linux/debugfs.h> 10c14b2adfSHuang, Ying #include <linux/uaccess.h> 116d7d7433SHuang, Ying #include <linux/stat.h> 126d7d7433SHuang, Ying #include <linux/init.h> 13c14b2adfSHuang, Ying #include <linux/io.h> 14c14b2adfSHuang, Ying #include <linux/mm.h> 15*ae79cdaaSvenkatesh.pallipadi@intel.com #include <linux/module.h> 166d7d7433SHuang, Ying 176d7d7433SHuang, Ying #include <asm/setup.h> 186d7d7433SHuang, Ying 19*ae79cdaaSvenkatesh.pallipadi@intel.com struct dentry *arch_debugfs_dir; 20*ae79cdaaSvenkatesh.pallipadi@intel.com EXPORT_SYMBOL(arch_debugfs_dir); 21*ae79cdaaSvenkatesh.pallipadi@intel.com 226d7d7433SHuang, Ying #ifdef CONFIG_DEBUG_BOOT_PARAMS 23c14b2adfSHuang, Ying struct setup_data_node { 24c14b2adfSHuang, Ying u64 paddr; 25c14b2adfSHuang, Ying u32 type; 26c14b2adfSHuang, Ying u32 len; 27c14b2adfSHuang, Ying }; 28c14b2adfSHuang, Ying 29c14b2adfSHuang, Ying static ssize_t 30c14b2adfSHuang, Ying setup_data_read(struct file *file, char __user *user_buf, size_t count, 31c14b2adfSHuang, Ying loff_t *ppos) 32c14b2adfSHuang, Ying { 33c14b2adfSHuang, Ying struct setup_data_node *node = file->private_data; 34c14b2adfSHuang, Ying unsigned long remain; 35c14b2adfSHuang, Ying loff_t pos = *ppos; 36c14b2adfSHuang, Ying struct page *pg; 37c14b2adfSHuang, Ying void *p; 38c14b2adfSHuang, Ying u64 pa; 39c14b2adfSHuang, Ying 40c14b2adfSHuang, Ying if (pos < 0) 41c14b2adfSHuang, Ying return -EINVAL; 42c14b2adfSHuang, Ying if (pos >= node->len) 43c14b2adfSHuang, Ying return 0; 44c14b2adfSHuang, Ying 45c14b2adfSHuang, Ying if (count > node->len - pos) 46c14b2adfSHuang, Ying count = node->len - pos; 47c14b2adfSHuang, Ying pa = node->paddr + sizeof(struct setup_data) + pos; 48c14b2adfSHuang, Ying pg = pfn_to_page((pa + count - 1) >> PAGE_SHIFT); 49c14b2adfSHuang, Ying if (PageHighMem(pg)) { 50c14b2adfSHuang, Ying p = ioremap_cache(pa, count); 51c14b2adfSHuang, Ying if (!p) 52c14b2adfSHuang, Ying return -ENXIO; 53c14b2adfSHuang, Ying } else { 54c14b2adfSHuang, Ying p = __va(pa); 55c14b2adfSHuang, Ying } 56c14b2adfSHuang, Ying 57c14b2adfSHuang, Ying remain = copy_to_user(user_buf, p, count); 58c14b2adfSHuang, Ying 59c14b2adfSHuang, Ying if (PageHighMem(pg)) 60c14b2adfSHuang, Ying iounmap(p); 61c14b2adfSHuang, Ying 62c14b2adfSHuang, Ying if (remain) 63c14b2adfSHuang, Ying return -EFAULT; 64c14b2adfSHuang, Ying 65c14b2adfSHuang, Ying *ppos = pos + count; 66c14b2adfSHuang, Ying 67c14b2adfSHuang, Ying return count; 68c14b2adfSHuang, Ying } 69c14b2adfSHuang, Ying 70c14b2adfSHuang, Ying static int setup_data_open(struct inode *inode, struct file *file) 71c14b2adfSHuang, Ying { 72c14b2adfSHuang, Ying file->private_data = inode->i_private; 73c14b2adfSHuang, Ying return 0; 74c14b2adfSHuang, Ying } 75c14b2adfSHuang, Ying 76c14b2adfSHuang, Ying static const struct file_operations fops_setup_data = { 77c14b2adfSHuang, Ying .read = setup_data_read, 78c14b2adfSHuang, Ying .open = setup_data_open, 79c14b2adfSHuang, Ying }; 80c14b2adfSHuang, Ying 81c14b2adfSHuang, Ying static int __init 82c14b2adfSHuang, Ying create_setup_data_node(struct dentry *parent, int no, 83c14b2adfSHuang, Ying struct setup_data_node *node) 84c14b2adfSHuang, Ying { 85c14b2adfSHuang, Ying struct dentry *d, *type, *data; 86c14b2adfSHuang, Ying char buf[16]; 87c14b2adfSHuang, Ying int error; 88c14b2adfSHuang, Ying 89c14b2adfSHuang, Ying sprintf(buf, "%d", no); 90c14b2adfSHuang, Ying d = debugfs_create_dir(buf, parent); 91c14b2adfSHuang, Ying if (!d) { 92c14b2adfSHuang, Ying error = -ENOMEM; 93c14b2adfSHuang, Ying goto err_return; 94c14b2adfSHuang, Ying } 95c14b2adfSHuang, Ying type = debugfs_create_x32("type", S_IRUGO, d, &node->type); 96c14b2adfSHuang, Ying if (!type) { 97c14b2adfSHuang, Ying error = -ENOMEM; 98c14b2adfSHuang, Ying goto err_dir; 99c14b2adfSHuang, Ying } 100c14b2adfSHuang, Ying data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data); 101c14b2adfSHuang, Ying if (!data) { 102c14b2adfSHuang, Ying error = -ENOMEM; 103c14b2adfSHuang, Ying goto err_type; 104c14b2adfSHuang, Ying } 105c14b2adfSHuang, Ying return 0; 106c14b2adfSHuang, Ying 107c14b2adfSHuang, Ying err_type: 108c14b2adfSHuang, Ying debugfs_remove(type); 109c14b2adfSHuang, Ying err_dir: 110c14b2adfSHuang, Ying debugfs_remove(d); 111c14b2adfSHuang, Ying err_return: 112c14b2adfSHuang, Ying return error; 113c14b2adfSHuang, Ying } 114c14b2adfSHuang, Ying 115c14b2adfSHuang, Ying static int __init create_setup_data_nodes(struct dentry *parent) 116c14b2adfSHuang, Ying { 117c14b2adfSHuang, Ying struct setup_data_node *node; 118c14b2adfSHuang, Ying struct setup_data *data; 119c14b2adfSHuang, Ying int error, no = 0; 120c14b2adfSHuang, Ying struct dentry *d; 121c14b2adfSHuang, Ying struct page *pg; 122c14b2adfSHuang, Ying u64 pa_data; 123c14b2adfSHuang, Ying 124c14b2adfSHuang, Ying d = debugfs_create_dir("setup_data", parent); 125c14b2adfSHuang, Ying if (!d) { 126c14b2adfSHuang, Ying error = -ENOMEM; 127c14b2adfSHuang, Ying goto err_return; 128c14b2adfSHuang, Ying } 129c14b2adfSHuang, Ying 130c14b2adfSHuang, Ying pa_data = boot_params.hdr.setup_data; 131c14b2adfSHuang, Ying 132c14b2adfSHuang, Ying while (pa_data) { 133c14b2adfSHuang, Ying node = kmalloc(sizeof(*node), GFP_KERNEL); 134c14b2adfSHuang, Ying if (!node) { 135c14b2adfSHuang, Ying error = -ENOMEM; 136c14b2adfSHuang, Ying goto err_dir; 137c14b2adfSHuang, Ying } 138c14b2adfSHuang, Ying pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT); 139c14b2adfSHuang, Ying if (PageHighMem(pg)) { 140c14b2adfSHuang, Ying data = ioremap_cache(pa_data, sizeof(*data)); 141c14b2adfSHuang, Ying if (!data) { 142c14b2adfSHuang, Ying error = -ENXIO; 143c14b2adfSHuang, Ying goto err_dir; 144c14b2adfSHuang, Ying } 145c14b2adfSHuang, Ying } else { 146c14b2adfSHuang, Ying data = __va(pa_data); 147c14b2adfSHuang, Ying } 148c14b2adfSHuang, Ying 149c14b2adfSHuang, Ying node->paddr = pa_data; 150c14b2adfSHuang, Ying node->type = data->type; 151c14b2adfSHuang, Ying node->len = data->len; 152c14b2adfSHuang, Ying error = create_setup_data_node(d, no, node); 153c14b2adfSHuang, Ying pa_data = data->next; 154c14b2adfSHuang, Ying 155c14b2adfSHuang, Ying if (PageHighMem(pg)) 156c14b2adfSHuang, Ying iounmap(data); 157c14b2adfSHuang, Ying if (error) 158c14b2adfSHuang, Ying goto err_dir; 159c14b2adfSHuang, Ying no++; 160c14b2adfSHuang, Ying } 161c14b2adfSHuang, Ying return 0; 162c14b2adfSHuang, Ying 163c14b2adfSHuang, Ying err_dir: 164c14b2adfSHuang, Ying debugfs_remove(d); 165c14b2adfSHuang, Ying err_return: 166c14b2adfSHuang, Ying return error; 167c14b2adfSHuang, Ying } 168c14b2adfSHuang, Ying 1696d7d7433SHuang, Ying static struct debugfs_blob_wrapper boot_params_blob = { 1706d7d7433SHuang, Ying .data = &boot_params, 1716d7d7433SHuang, Ying .size = sizeof(boot_params), 1726d7d7433SHuang, Ying }; 1736d7d7433SHuang, Ying 1746d7d7433SHuang, Ying static int __init boot_params_kdebugfs_init(void) 1756d7d7433SHuang, Ying { 1766d7d7433SHuang, Ying struct dentry *dbp, *version, *data; 177c14b2adfSHuang, Ying int error; 1786d7d7433SHuang, Ying 1796d7d7433SHuang, Ying dbp = debugfs_create_dir("boot_params", NULL); 1806d7d7433SHuang, Ying if (!dbp) { 1816d7d7433SHuang, Ying error = -ENOMEM; 1826d7d7433SHuang, Ying goto err_return; 1836d7d7433SHuang, Ying } 1846d7d7433SHuang, Ying version = debugfs_create_x16("version", S_IRUGO, dbp, 1856d7d7433SHuang, Ying &boot_params.hdr.version); 1866d7d7433SHuang, Ying if (!version) { 1876d7d7433SHuang, Ying error = -ENOMEM; 1886d7d7433SHuang, Ying goto err_dir; 1896d7d7433SHuang, Ying } 1906d7d7433SHuang, Ying data = debugfs_create_blob("data", S_IRUGO, dbp, 1916d7d7433SHuang, Ying &boot_params_blob); 1926d7d7433SHuang, Ying if (!data) { 1936d7d7433SHuang, Ying error = -ENOMEM; 1946d7d7433SHuang, Ying goto err_version; 1956d7d7433SHuang, Ying } 196c14b2adfSHuang, Ying error = create_setup_data_nodes(dbp); 197c14b2adfSHuang, Ying if (error) 198c14b2adfSHuang, Ying goto err_data; 1996d7d7433SHuang, Ying return 0; 200c14b2adfSHuang, Ying 201c14b2adfSHuang, Ying err_data: 202c14b2adfSHuang, Ying debugfs_remove(data); 2036d7d7433SHuang, Ying err_version: 2046d7d7433SHuang, Ying debugfs_remove(version); 2056d7d7433SHuang, Ying err_dir: 2066d7d7433SHuang, Ying debugfs_remove(dbp); 2076d7d7433SHuang, Ying err_return: 2086d7d7433SHuang, Ying return error; 2096d7d7433SHuang, Ying } 2106d7d7433SHuang, Ying #endif 2116d7d7433SHuang, Ying 2126d7d7433SHuang, Ying static int __init arch_kdebugfs_init(void) 2136d7d7433SHuang, Ying { 2146d7d7433SHuang, Ying int error = 0; 2156d7d7433SHuang, Ying 216*ae79cdaaSvenkatesh.pallipadi@intel.com arch_debugfs_dir = debugfs_create_dir("x86", NULL); 217*ae79cdaaSvenkatesh.pallipadi@intel.com if (!arch_debugfs_dir) 218*ae79cdaaSvenkatesh.pallipadi@intel.com return -ENOMEM; 219*ae79cdaaSvenkatesh.pallipadi@intel.com 2206d7d7433SHuang, Ying #ifdef CONFIG_DEBUG_BOOT_PARAMS 2216d7d7433SHuang, Ying error = boot_params_kdebugfs_init(); 2226d7d7433SHuang, Ying #endif 2236d7d7433SHuang, Ying 2246d7d7433SHuang, Ying return error; 2256d7d7433SHuang, Ying } 2266d7d7433SHuang, Ying arch_initcall(arch_kdebugfs_init); 227