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