1*188917e1SBenjamin Herrenschmidt /* 2*188917e1SBenjamin Herrenschmidt * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation 3*188917e1SBenjamin Herrenschmidt * 4*188917e1SBenjamin Herrenschmidt * This program is free software; you can redistribute it and/or modify 5*188917e1SBenjamin Herrenschmidt * it under the terms of the GNU General Public License as published by 6*188917e1SBenjamin Herrenschmidt * the Free Software Foundation; either version 2 of the License, or 7*188917e1SBenjamin Herrenschmidt * (at your option) any later version. 8*188917e1SBenjamin Herrenschmidt * 9*188917e1SBenjamin Herrenschmidt * This program is distributed in the hope that it will be useful, 10*188917e1SBenjamin Herrenschmidt * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*188917e1SBenjamin Herrenschmidt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*188917e1SBenjamin Herrenschmidt * GNU General Public License for more details. 13*188917e1SBenjamin Herrenschmidt * 14*188917e1SBenjamin Herrenschmidt * You should have received a copy of the GNU General Public License 15*188917e1SBenjamin Herrenschmidt * along with this program; if not, write to the Free Software 16*188917e1SBenjamin Herrenschmidt * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17*188917e1SBenjamin Herrenschmidt */ 18*188917e1SBenjamin Herrenschmidt 19*188917e1SBenjamin Herrenschmidt #include <linux/init.h> 20*188917e1SBenjamin Herrenschmidt #include <linux/mm.h> 21*188917e1SBenjamin Herrenschmidt #include <linux/proc_fs.h> 22*188917e1SBenjamin Herrenschmidt #include <linux/slab.h> 23*188917e1SBenjamin Herrenschmidt #include <linux/kernel.h> 24*188917e1SBenjamin Herrenschmidt 25*188917e1SBenjamin Herrenschmidt #include <asm/machdep.h> 26*188917e1SBenjamin Herrenschmidt #include <asm/vdso_datapage.h> 27*188917e1SBenjamin Herrenschmidt #include <asm/rtas.h> 28*188917e1SBenjamin Herrenschmidt #include <asm/uaccess.h> 29*188917e1SBenjamin Herrenschmidt #include <asm/prom.h> 30*188917e1SBenjamin Herrenschmidt 31*188917e1SBenjamin Herrenschmidt #ifdef CONFIG_PPC64 32*188917e1SBenjamin Herrenschmidt 33*188917e1SBenjamin Herrenschmidt static loff_t page_map_seek( struct file *file, loff_t off, int whence) 34*188917e1SBenjamin Herrenschmidt { 35*188917e1SBenjamin Herrenschmidt loff_t new; 36*188917e1SBenjamin Herrenschmidt struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); 37*188917e1SBenjamin Herrenschmidt 38*188917e1SBenjamin Herrenschmidt switch(whence) { 39*188917e1SBenjamin Herrenschmidt case 0: 40*188917e1SBenjamin Herrenschmidt new = off; 41*188917e1SBenjamin Herrenschmidt break; 42*188917e1SBenjamin Herrenschmidt case 1: 43*188917e1SBenjamin Herrenschmidt new = file->f_pos + off; 44*188917e1SBenjamin Herrenschmidt break; 45*188917e1SBenjamin Herrenschmidt case 2: 46*188917e1SBenjamin Herrenschmidt new = dp->size + off; 47*188917e1SBenjamin Herrenschmidt break; 48*188917e1SBenjamin Herrenschmidt default: 49*188917e1SBenjamin Herrenschmidt return -EINVAL; 50*188917e1SBenjamin Herrenschmidt } 51*188917e1SBenjamin Herrenschmidt if ( new < 0 || new > dp->size ) 52*188917e1SBenjamin Herrenschmidt return -EINVAL; 53*188917e1SBenjamin Herrenschmidt return (file->f_pos = new); 54*188917e1SBenjamin Herrenschmidt } 55*188917e1SBenjamin Herrenschmidt 56*188917e1SBenjamin Herrenschmidt static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, 57*188917e1SBenjamin Herrenschmidt loff_t *ppos) 58*188917e1SBenjamin Herrenschmidt { 59*188917e1SBenjamin Herrenschmidt struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); 60*188917e1SBenjamin Herrenschmidt return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size); 61*188917e1SBenjamin Herrenschmidt } 62*188917e1SBenjamin Herrenschmidt 63*188917e1SBenjamin Herrenschmidt static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) 64*188917e1SBenjamin Herrenschmidt { 65*188917e1SBenjamin Herrenschmidt struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); 66*188917e1SBenjamin Herrenschmidt 67*188917e1SBenjamin Herrenschmidt if ((vma->vm_end - vma->vm_start) > dp->size) 68*188917e1SBenjamin Herrenschmidt return -EINVAL; 69*188917e1SBenjamin Herrenschmidt 70*188917e1SBenjamin Herrenschmidt remap_pfn_range(vma, vma->vm_start, __pa(dp->data) >> PAGE_SHIFT, 71*188917e1SBenjamin Herrenschmidt dp->size, vma->vm_page_prot); 72*188917e1SBenjamin Herrenschmidt return 0; 73*188917e1SBenjamin Herrenschmidt } 74*188917e1SBenjamin Herrenschmidt 75*188917e1SBenjamin Herrenschmidt static const struct file_operations page_map_fops = { 76*188917e1SBenjamin Herrenschmidt .llseek = page_map_seek, 77*188917e1SBenjamin Herrenschmidt .read = page_map_read, 78*188917e1SBenjamin Herrenschmidt .mmap = page_map_mmap 79*188917e1SBenjamin Herrenschmidt }; 80*188917e1SBenjamin Herrenschmidt 81*188917e1SBenjamin Herrenschmidt 82*188917e1SBenjamin Herrenschmidt static int __init proc_ppc64_init(void) 83*188917e1SBenjamin Herrenschmidt { 84*188917e1SBenjamin Herrenschmidt struct proc_dir_entry *pde; 85*188917e1SBenjamin Herrenschmidt 86*188917e1SBenjamin Herrenschmidt pde = proc_create_data("powerpc/systemcfg", S_IFREG|S_IRUGO, NULL, 87*188917e1SBenjamin Herrenschmidt &page_map_fops, vdso_data); 88*188917e1SBenjamin Herrenschmidt if (!pde) 89*188917e1SBenjamin Herrenschmidt return 1; 90*188917e1SBenjamin Herrenschmidt pde->size = PAGE_SIZE; 91*188917e1SBenjamin Herrenschmidt 92*188917e1SBenjamin Herrenschmidt return 0; 93*188917e1SBenjamin Herrenschmidt } 94*188917e1SBenjamin Herrenschmidt __initcall(proc_ppc64_init); 95*188917e1SBenjamin Herrenschmidt 96*188917e1SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */ 97*188917e1SBenjamin Herrenschmidt 98*188917e1SBenjamin Herrenschmidt /* 99*188917e1SBenjamin Herrenschmidt * Create the ppc64 and ppc64/rtas directories early. This allows us to 100*188917e1SBenjamin Herrenschmidt * assume that they have been previously created in drivers. 101*188917e1SBenjamin Herrenschmidt */ 102*188917e1SBenjamin Herrenschmidt static int __init proc_ppc64_create(void) 103*188917e1SBenjamin Herrenschmidt { 104*188917e1SBenjamin Herrenschmidt struct proc_dir_entry *root; 105*188917e1SBenjamin Herrenschmidt 106*188917e1SBenjamin Herrenschmidt root = proc_mkdir("powerpc", NULL); 107*188917e1SBenjamin Herrenschmidt if (!root) 108*188917e1SBenjamin Herrenschmidt return 1; 109*188917e1SBenjamin Herrenschmidt 110*188917e1SBenjamin Herrenschmidt #ifdef CONFIG_PPC64 111*188917e1SBenjamin Herrenschmidt if (!proc_symlink("ppc64", NULL, "powerpc")) 112*188917e1SBenjamin Herrenschmidt pr_err("Failed to create link /proc/ppc64 -> /proc/powerpc\n"); 113*188917e1SBenjamin Herrenschmidt #endif 114*188917e1SBenjamin Herrenschmidt 115*188917e1SBenjamin Herrenschmidt if (!of_find_node_by_path("/rtas")) 116*188917e1SBenjamin Herrenschmidt return 0; 117*188917e1SBenjamin Herrenschmidt 118*188917e1SBenjamin Herrenschmidt if (!proc_mkdir("rtas", root)) 119*188917e1SBenjamin Herrenschmidt return 1; 120*188917e1SBenjamin Herrenschmidt 121*188917e1SBenjamin Herrenschmidt if (!proc_symlink("rtas", NULL, "powerpc/rtas")) 122*188917e1SBenjamin Herrenschmidt return 1; 123*188917e1SBenjamin Herrenschmidt 124*188917e1SBenjamin Herrenschmidt return 0; 125*188917e1SBenjamin Herrenschmidt } 126*188917e1SBenjamin Herrenschmidt core_initcall(proc_ppc64_create); 127