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/sysctl.h> 13#include <linux/proc_fs.h> 14#include <linux/init.h> 15#include <asm/uaccess.h> 16 17static const char frv_cache_wback[] = "wback"; 18static const char frv_cache_wthru[] = "wthru"; 19 20static void frv_change_dcache_mode(unsigned long newmode) 21{ 22 unsigned long flags, hsr0; 23 24 local_irq_save(flags); 25 26 hsr0 = __get_HSR(0); 27 hsr0 &= ~HSR0_DCE; 28 __set_HSR(0, hsr0); 29 30 asm volatile(" dcef @(gr0,gr0),#1 \n" 31 " membar \n" 32 : : : "memory" 33 ); 34 35 hsr0 = (hsr0 & ~HSR0_CBM) | newmode; 36 __set_HSR(0, hsr0); 37 hsr0 |= HSR0_DCE; 38 __set_HSR(0, hsr0); 39 40 local_irq_restore(flags); 41 42 //printk("HSR0 now %08lx\n", hsr0); 43} 44 45/*****************************************************************************/ 46/* 47 * handle requests to dynamically switch the write caching mode delivered by /proc 48 */ 49static int procctl_frv_cachemode(struct ctl_table *table, int write, 50 void __user *buffer, size_t *lenp, 51 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 (*ppos > 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 *ppos = 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(struct ctl_table *table, int write, 125 void __user *buffer, size_t *lenp, 126 loff_t *ppos) 127{ 128 pid_t pid; 129 char buff[16], *p; 130 int len; 131 132 len = *lenp; 133 134 if (write) { 135 /* potential state change */ 136 if (len <= 1 || len > sizeof(buff) - 1) 137 return -EINVAL; 138 139 if (copy_from_user(buff, buffer, len) != 0) 140 return -EFAULT; 141 142 if (buff[len - 1] == '\n') 143 buff[len - 1] = '\0'; 144 else 145 buff[len] = '\0'; 146 147 pid = simple_strtoul(buff, &p, 10); 148 if (*p) 149 return -EINVAL; 150 151 return cxn_pin_by_pid(pid); 152 } 153 154 /* read the currently pinned CXN */ 155 if (*ppos > 0) { 156 *lenp = 0; 157 return 0; 158 } 159 160 len = snprintf(buff, sizeof(buff), "%d\n", cxn_pinned); 161 if (len > *lenp) 162 len = *lenp; 163 164 if (copy_to_user(buffer, buff, len) != 0) 165 return -EFAULT; 166 167 *lenp = len; 168 *ppos = len; 169 return 0; 170 171} /* end procctl_frv_pin_cxnr() */ 172#endif 173 174/* 175 * FR-V specific sysctls 176 */ 177static struct ctl_table frv_table[] = 178{ 179 { 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 .procname = "pin-cxnr", 189 .data = NULL, 190 .maxlen = 0, 191 .mode = 0644, 192 .proc_handler = procctl_frv_pin_cxnr 193 }, 194#endif 195 {} 196}; 197 198/* 199 * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 200 * when all the PM interfaces exist nicely. 201 */ 202static struct ctl_table frv_dir_table[] = 203{ 204 { 205 .procname = "frv", 206 .mode = 0555, 207 .child = frv_table 208 }, 209 {} 210}; 211 212/* 213 * Initialize power interface 214 */ 215static int __init frv_sysctl_init(void) 216{ 217 register_sysctl_table(frv_dir_table); 218 return 0; 219} 220 221__initcall(frv_sysctl_init); 222