1/* sysctl.c: implementation of /proc/sys files relating to FRV specifically 2 * 3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/slab.h> 13#include <linux/sysctl.h> 14#include <linux/proc_fs.h> 15#include <linux/init.h> 16#include <asm/uaccess.h> 17 18static const char frv_cache_wback[] = "wback"; 19static const char frv_cache_wthru[] = "wthru"; 20 21static void frv_change_dcache_mode(unsigned long newmode) 22{ 23 unsigned long flags, hsr0; 24 25 local_irq_save(flags); 26 27 hsr0 = __get_HSR(0); 28 hsr0 &= ~HSR0_DCE; 29 __set_HSR(0, hsr0); 30 31 asm volatile(" dcef @(gr0,gr0),#1 \n" 32 " membar \n" 33 : : : "memory" 34 ); 35 36 hsr0 = (hsr0 & ~HSR0_CBM) | newmode; 37 __set_HSR(0, hsr0); 38 hsr0 |= HSR0_DCE; 39 __set_HSR(0, hsr0); 40 41 local_irq_restore(flags); 42 43 //printk("HSR0 now %08lx\n", hsr0); 44} 45 46/*****************************************************************************/ 47/* 48 * handle requests to dynamically switch the write caching mode delivered by /proc 49 */ 50static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp, 51 void __user *buffer, size_t *lenp, loff_t *ppos) 52{ 53 unsigned long hsr0; 54 char buff[8]; 55 int len; 56 57 len = *lenp; 58 59 if (write) { 60 /* potential state change */ 61 if (len <= 1 || len > sizeof(buff) - 1) 62 return -EINVAL; 63 64 if (copy_from_user(buff, buffer, len) != 0) 65 return -EFAULT; 66 67 if (buff[len - 1] == '\n') 68 buff[len - 1] = '\0'; 69 else 70 buff[len] = '\0'; 71 72 if (strcmp(buff, frv_cache_wback) == 0) { 73 /* switch dcache into write-back mode */ 74 frv_change_dcache_mode(HSR0_CBM_COPY_BACK); 75 return 0; 76 } 77 78 if (strcmp(buff, frv_cache_wthru) == 0) { 79 /* switch dcache into write-through mode */ 80 frv_change_dcache_mode(HSR0_CBM_WRITE_THRU); 81 return 0; 82 } 83 84 return -EINVAL; 85 } 86 87 /* read the state */ 88 if (filp->f_pos > 0) { 89 *lenp = 0; 90 return 0; 91 } 92 93 hsr0 = __get_HSR(0); 94 switch (hsr0 & HSR0_CBM) { 95 case HSR0_CBM_WRITE_THRU: 96 memcpy(buff, frv_cache_wthru, sizeof(frv_cache_wthru) - 1); 97 buff[sizeof(frv_cache_wthru) - 1] = '\n'; 98 len = sizeof(frv_cache_wthru); 99 break; 100 default: 101 memcpy(buff, frv_cache_wback, sizeof(frv_cache_wback) - 1); 102 buff[sizeof(frv_cache_wback) - 1] = '\n'; 103 len = sizeof(frv_cache_wback); 104 break; 105 } 106 107 if (len > *lenp) 108 len = *lenp; 109 110 if (copy_to_user(buffer, buff, len) != 0) 111 return -EFAULT; 112 113 *lenp = len; 114 filp->f_pos = len; 115 return 0; 116 117} /* end procctl_frv_cachemode() */ 118 119/*****************************************************************************/ 120/* 121 * permit the mm_struct the nominated process is using have its MMU context ID pinned 122 */ 123#ifdef CONFIG_MMU 124static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp, 125 void __user *buffer, size_t *lenp, loff_t *ppos) 126{ 127 pid_t pid; 128 char buff[16], *p; 129 int len; 130 131 len = *lenp; 132 133 if (write) { 134 /* potential state change */ 135 if (len <= 1 || len > sizeof(buff) - 1) 136 return -EINVAL; 137 138 if (copy_from_user(buff, buffer, len) != 0) 139 return -EFAULT; 140 141 if (buff[len - 1] == '\n') 142 buff[len - 1] = '\0'; 143 else 144 buff[len] = '\0'; 145 146 pid = simple_strtoul(buff, &p, 10); 147 if (*p) 148 return -EINVAL; 149 150 return cxn_pin_by_pid(pid); 151 } 152 153 /* read the currently pinned CXN */ 154 if (filp->f_pos > 0) { 155 *lenp = 0; 156 return 0; 157 } 158 159 len = snprintf(buff, sizeof(buff), "%d\n", cxn_pinned); 160 if (len > *lenp) 161 len = *lenp; 162 163 if (copy_to_user(buffer, buff, len) != 0) 164 return -EFAULT; 165 166 *lenp = len; 167 filp->f_pos = len; 168 return 0; 169 170} /* end procctl_frv_pin_cxnr() */ 171#endif 172 173/* 174 * FR-V specific sysctls 175 */ 176static struct ctl_table frv_table[] = 177{ 178 { 179 .ctl_name = 1, 180 .procname = "cache-mode", 181 .data = NULL, 182 .maxlen = 0, 183 .mode = 0644, 184 .proc_handler = &procctl_frv_cachemode, 185 }, 186#ifdef CONFIG_MMU 187 { 188 .ctl_name = 2, 189 .procname = "pin-cxnr", 190 .data = NULL, 191 .maxlen = 0, 192 .mode = 0644, 193 .proc_handler = &procctl_frv_pin_cxnr 194 }, 195#endif 196 {} 197}; 198 199/* 200 * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 201 * when all the PM interfaces exist nicely. 202 */ 203static struct ctl_table frv_dir_table[] = 204{ 205 { 206 .ctl_name = CTL_FRV, 207 .procname = "frv", 208 .mode = 0555, 209 .child = frv_table 210 }, 211 {} 212}; 213 214/* 215 * Initialize power interface 216 */ 217static int __init frv_sysctl_init(void) 218{ 219 register_sysctl_table(frv_dir_table); 220 return 0; 221} 222 223__initcall(frv_sysctl_init); 224