1 /*
2 *
3 * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * Further, this software is distributed without any warranty that it is
14 * free of the rightful claim of any third person regarding infringement
15 * or the like. Any license provided herein, whether implied or
16 * otherwise, applies only to this software file. Patent licenses, if
17 * any, provided herein do not apply to combinations of this program with
18 * other software, or any other product whatsoever.
19 *
20 * You should have received a copy of the GNU General Public
21 * License along with this program; if not, write the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 *
24 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
25 * Mountain View, CA 94043, or:
26 *
27 * http://www.sgi.com
28 *
29 * For further information regarding this notice, see:
30 *
31 * http://oss.sgi.com/projects/GenInfo/NoticeExplan
32 */
33 #include <linux/config.h>
34 #include <asm/uaccess.h>
35
36 #ifdef CONFIG_PROC_FS
37 #include <linux/proc_fs.h>
38 #include <asm/sn/sn_sal.h>
39 #include <asm/sn/sn_cpuid.h>
40
41
partition_id_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)42 static int partition_id_read_proc(char *page, char **start, off_t off,
43 int count, int *eof, void *data) {
44
45 return sprintf(page, "%d\n", sn_local_partid());
46 }
47
48 static struct proc_dir_entry * sgi_proc_dir;
49
50 void
register_sn_partition_id(void)51 register_sn_partition_id(void) {
52 struct proc_dir_entry *entry;
53
54 if (!sgi_proc_dir) {
55 sgi_proc_dir = proc_mkdir("sgi_sn", 0);
56 }
57 entry = create_proc_entry("partition_id", 0444, sgi_proc_dir);
58 if (entry) {
59 entry->nlink = 1;
60 entry->data = 0;
61 entry->read_proc = partition_id_read_proc;
62 entry->write_proc = NULL;
63 }
64 }
65
66 static int
system_serial_number_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)67 system_serial_number_read_proc(char *page, char **start, off_t off,
68 int count, int *eof, void *data) {
69 return sprintf(page, "%s\n", sn_system_serial_number());
70 }
71
72 static int
licenseID_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)73 licenseID_read_proc(char *page, char **start, off_t off,
74 int count, int *eof, void *data) {
75 return sprintf(page, "0x%lx\n",sn_partition_serial_number_val());
76 }
77
78 void
register_sn_serial_numbers(void)79 register_sn_serial_numbers(void) {
80 struct proc_dir_entry *entry;
81
82 if (!sgi_proc_dir) {
83 sgi_proc_dir = proc_mkdir("sgi_sn", 0);
84 }
85 entry = create_proc_entry("system_serial_number", 0444, sgi_proc_dir);
86 if (entry) {
87 entry->nlink = 1;
88 entry->data = 0;
89 entry->read_proc = system_serial_number_read_proc;
90 entry->write_proc = NULL;
91 }
92 entry = create_proc_entry("licenseID", 0444, sgi_proc_dir);
93 if (entry) {
94 entry->nlink = 1;
95 entry->data = 0;
96 entry->read_proc = licenseID_read_proc;
97 entry->write_proc = NULL;
98 }
99 }
100
101 // Disable forced interrupts, but leave the code in, just in case.
102 int sn_force_interrupt_flag = 0;
103
104 static int
sn_force_interrupt_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)105 sn_force_interrupt_read_proc(char *page, char **start, off_t off,
106 int count, int *eof, void *data) {
107 if (sn_force_interrupt_flag) {
108 return sprintf(page, "Force interrupt is enabled\n");
109 }
110 return sprintf(page, "Force interrupt is disabled\n");
111 }
112
113 static int
sn_force_interrupt_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)114 sn_force_interrupt_write_proc(struct file *file, const char *buffer,
115 unsigned long count, void *data)
116 {
117 if (*buffer == '0') {
118 sn_force_interrupt_flag = 0;
119 } else {
120 sn_force_interrupt_flag = 1;
121 }
122 return 1;
123 }
124
125 void
register_sn_force_interrupt(void)126 register_sn_force_interrupt(void) {
127 struct proc_dir_entry *entry;
128
129 if (!sgi_proc_dir) {
130 sgi_proc_dir = proc_mkdir("sgi_sn", 0);
131 }
132 entry = create_proc_entry("sn_force_interrupt",0444, sgi_proc_dir);
133 if (entry) {
134 entry->nlink = 1;
135 entry->data = 0;
136 entry->read_proc = sn_force_interrupt_read_proc;
137 entry->write_proc = sn_force_interrupt_write_proc;
138 }
139 }
140
141 extern int sn_linkstats_get(char *);
142 extern int sn_linkstats_reset(unsigned long);
143
144 static int
sn_linkstats_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)145 sn_linkstats_read_proc(char *page, char **start, off_t off,
146 int count, int *eof, void *data) {
147
148 return sn_linkstats_get(page);
149 }
150
151 static int
sn_linkstats_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)152 sn_linkstats_write_proc(struct file *file, const char *buffer,
153 unsigned long count, void *data)
154 {
155 char s[64];
156 unsigned long msecs;
157 int e = count;
158
159 if (copy_from_user(s, buffer, count < sizeof(s) ? count : sizeof(s)))
160 e = -EFAULT;
161 else {
162 if (sscanf(s, "%lu", &msecs) != 1 || msecs < 5)
163 /* at least 5 milliseconds between updates */
164 e = -EINVAL;
165 else
166 sn_linkstats_reset(msecs);
167 }
168
169 return e;
170 }
171
172 void
register_sn_linkstats(void)173 register_sn_linkstats(void) {
174 struct proc_dir_entry *entry;
175
176 if (!sgi_proc_dir) {
177 sgi_proc_dir = proc_mkdir("sgi_sn", 0);
178 }
179 entry = create_proc_entry("linkstats", 0444, sgi_proc_dir);
180 if (entry) {
181 entry->nlink = 1;
182 entry->data = 0;
183 entry->read_proc = sn_linkstats_read_proc;
184 entry->write_proc = sn_linkstats_write_proc;
185 }
186 }
187
188 #define SHUB_MAX_VERSION 3
189 static struct proc_dir_entry **proc_entries;
190 static char* shub_revision[SHUB_MAX_VERSION+1] = {
191 "unknown",
192 "1.0",
193 "1.1",
194 "1.2"
195 };
196
197 static int
read_shub_info_entry(char * page,char ** start,off_t off,int count,int * eof,void * data)198 read_shub_info_entry(char* page, char **start, off_t off, int count, int *eof,
199 void* data) {
200 unsigned long id;
201 int rev;
202 int nasid = (long) data; /* Data contains NASID of this node */
203 int len = 0;
204
205 id = REMOTE_HUB_L(nasid, SH_SHUB_ID);
206 rev = (id & SH_SHUB_ID_REVISION_MASK) >> SH_SHUB_ID_REVISION_SHFT;
207 len += sprintf(&page[len], "type : SHub\n");
208 len += sprintf(&page[len], "revision : %s\n",
209 (rev <= SHUB_MAX_VERSION) ? shub_revision[rev] : "unknown");
210 len += sprintf(&page[len], "nasid : %d\n", nasid);
211
212 return len;
213 }
214
215 static void
register_sn_nodes(void)216 register_sn_nodes(void) {
217 struct proc_dir_entry **entp;
218 cnodeid_t cnodeid;
219 nasid_t nasid;
220 char name[11];
221
222 if (!sgi_proc_dir) {
223 sgi_proc_dir = proc_mkdir("sgi_sn", 0);
224 }
225
226 proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *),
227 GFP_KERNEL);
228
229 for (cnodeid = 0, entp = proc_entries;
230 cnodeid < numnodes;
231 cnodeid++, entp++) {
232 sprintf(name, "node%d", cnodeid);
233 *entp = proc_mkdir(name, sgi_proc_dir);
234 nasid = cnodeid_to_nasid(cnodeid);
235 create_proc_read_entry(
236 "hubinfo", 0, *entp, read_shub_info_entry,
237 (void*) (long) nasid);
238 }
239 }
240
241 void
register_sn_procfs(void)242 register_sn_procfs(void) {
243 register_sn_partition_id();
244 register_sn_serial_numbers();
245 register_sn_force_interrupt();
246 register_sn_linkstats();
247 register_sn_nodes();
248 }
249
250 #endif /* CONFIG_PROC_FS */
251