File: /usr/src/linux/drivers/net/sk98lin/skproc.c
1 /******************************************************************************
2 *
3 * Name: skproc.c
4 * Project: GEnesis, PCI Gigabit Ethernet Adapter
5 * Version: $Revision: 1.2.2.2 $
6 * Date: $Date: 2001/03/15 12:50:13 $
7 * Purpose: Funktions to display statictic data
8 *
9 ******************************************************************************/
10
11 /******************************************************************************
12 *
13 * (C)Copyright 1998-2001 SysKonnect GmbH.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * Created 22-Nov-2000
21 * Author: Mirko Lindner (mlindner@syskonnect.de)
22 *
23 * The information in this file is provided "AS IS" without warranty.
24 *
25 ******************************************************************************/
26 /******************************************************************************
27 *
28 * History:
29 *
30 * $Log: skproc.c,v $
31 * Revision 1.2.2.2 2001/03/15 12:50:13 mlindner
32 * fix: ProcFS owner protection
33 *
34 * Revision 1.2.2.1 2001/03/12 16:43:48 mlindner
35 * chg: 2.4 requirements for procfs
36 *
37 * Revision 1.1 2001/01/22 14:15:31 mlindner
38 * added ProcFs functionality
39 * Dual Net functionality integrated
40 * Rlmt networks added
41 *
42 *
43 ******************************************************************************/
44
45 #include <linux/proc_fs.h>
46
47 #include "h/skdrv1st.h"
48 #include "h/skdrv2nd.h"
49 #define ZEROPAD 1 /* pad with zero */
50 #define SIGN 2 /* unsigned/signed long */
51 #define PLUS 4 /* show plus */
52 #define SPACE 8 /* space if plus */
53 #define LEFT 16 /* left justified */
54 //#define SPECIAL 32 /* 0x */
55 #define LARGE 64
56
57 extern void proc_fill_inode(struct inode *inode, int fill);
58 extern char * SkNumber(char * str, long long num, int base, int size,
59 int precision ,int type);
60 int proc_read(char *buffer,
61 char **buffer_location,
62 off_t offset,
63 int buffer_length,
64 int *eof,
65 void *data);
66
67 static const char SK_Root_Dir_entry[] = "sk98lin";
68 extern struct net_device *sk98lin_root_dev;
69
70
71 struct proc_dir_entry pSkRootDir = {
72 0,
73 sizeof(SK_Root_Dir_entry)-1,
74 (const char*)SK_Root_Dir_entry,
75 S_IFDIR | S_IRUGO,
76 2, 0, 0, 0, NULL,
77 NULL
78 };
79
80
81 /*****************************************************************************
82 *
83 * proc_read - print "summaries" entry
84 *
85 * Description:
86 * This function fills the proc entry with statistic data about
87 * the ethernet device.
88 *
89 *
90 * Returns: buffer with statistic data
91 *
92 */
93 int proc_read(char *buffer,
94 char **buffer_location,
95 off_t offset,
96 int buffer_length,
97 int *eof,
98 void *data)
99 {
100 int len = 0;
101 int t;
102 int i;
103 DEV_NET *pNet;
104 SK_AC *pAC;
105 char test_buf[100];
106 unsigned long Flags;
107 unsigned int Size;
108 struct net_device *next;
109 struct net_device *SkgeProcDev = sk98lin_root_dev;
110
111 SK_PNMI_STRUCT_DATA *pPnmiStruct;
112 SK_PNMI_STAT *pPnmiStat;
113 struct proc_dir_entry *file = (struct proc_dir_entry*) data;
114
115 while (SkgeProcDev) {
116 pNet = (DEV_NET*) SkgeProcDev->priv;
117 pAC = pNet->pAC;
118 next = pAC->Next;
119 pPnmiStruct = &pAC->PnmiStruct;
120 /* NetIndex in GetStruct is now required, zero is only dummy */
121
122 for (t=pAC->GIni.GIMacsFound; t > 0; t--) {
123 if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1)
124 t--;
125
126 spin_lock_irqsave(&pAC->SlowPathLock, Flags);
127 Size = SK_PNMI_STRUCT_SIZE;
128 SkPnmiGetStruct(pAC, pAC->IoBase,
129 pPnmiStruct, &Size, t-1);
130 spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
131
132 if (strcmp(pAC->dev[t-1]->name, file->name) == 0) {
133 pPnmiStat = &pPnmiStruct->Stat[0];
134 len = sprintf(buffer,
135 "\nDetailed statistic for device %s\n",
136 pAC->dev[t-1]->name);
137 len += sprintf(buffer + len,
138 "==================================\n");
139
140 /* Board statistics */
141 len += sprintf(buffer + len,
142 "\nBoard statistics\n\n");
143 len += sprintf(buffer + len,
144 "Active Port %c\n",
145 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
146 Net[t-1].PrefPort]->PortNumber);
147 len += sprintf(buffer + len,
148 "Preferred Port %c\n",
149 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
150 Net[t-1].PrefPort]->PortNumber);
151
152 len += sprintf(buffer + len,
153 "Bus speed (Mhz) %d\n",
154 pPnmiStruct->BusSpeed);
155
156 len += sprintf(buffer + len,
157 "Bus width (Bit) %d\n",
158 pPnmiStruct->BusWidth);
159
160 for (i=0; i < SK_MAX_SENSORS; i ++) {
161 if (strcmp(pAC->I2c.SenTable[i].SenDesc,
162 "Temperature") == 0 ) {
163 len += sprintf(buffer + len,
164 "Temperature (C) %d.%d\n",
165 pAC->I2c.SenTable[i].SenValue / 10,
166 pAC->I2c.SenTable[i].SenValue % 10);
167 len += sprintf(buffer + len,
168 "Temperature (F) %d.%d\n",
169 ((((pAC->I2c.SenTable[i].SenValue)
170 *10)*9)/5 + 3200)/100,
171 ((((pAC->I2c.SenTable[i].SenValue)
172 *10)*9)/5 + 3200) % 10);
173 } else if (strcmp(pAC->I2c.SenTable[i].SenDesc,
174 "Speed Fan") == 0 ) {
175 len += sprintf(buffer + len,
176 "Speed Fan %d\n",
177 pAC->I2c.SenTable[i].SenValue);
178 } else {
179 len += sprintf(buffer + len,
180 "%-20s %d.%d\n",
181 pAC->I2c.SenTable[i].SenDesc,
182 pAC->I2c.SenTable[i].SenValue / 1000,
183 pAC->I2c.SenTable[i].SenValue % 1000);
184 }
185 }
186
187 /*Receive statistics */
188
189 len += sprintf(buffer + len,
190 "\nReceive statistics\n\n");
191
192 len += sprintf(buffer + len,
193 "Received bytes %s\n",
194 SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts,
195 10,0,-1,0));
196 len += sprintf(buffer + len,
197 "Received packets %s\n",
198 SkNumber(test_buf, pPnmiStat->StatRxOkCts,
199 10,0,-1,0));
200 len += sprintf(buffer + len,
201 "Received errors %s\n",
202 SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
203 10,0,-1,0));
204 len += sprintf(buffer + len,
205 "Received dropped %s\n",
206 SkNumber(test_buf, pPnmiStruct->RxNoBufCts,
207 10,0,-1,0));
208 len += sprintf(buffer + len,
209 "Received multicast %s\n",
210 SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts,
211 10,0,-1,0));
212 len += sprintf(buffer + len,
213 "Received errors types\n");
214 len += sprintf(buffer + len,
215 " length errors %s\n",
216 SkNumber(test_buf, pPnmiStat->StatRxRuntCts,
217 10, 0, -1, 0));
218 len += sprintf(buffer + len,
219 " over errors %s\n",
220 SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
221 10, 0, -1, 0));
222 len += sprintf(buffer + len,
223 " crc errors %s\n",
224 SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
225 10, 0, -1, 0));
226 len += sprintf(buffer + len,
227 " frame errors %s\n",
228 SkNumber(test_buf, pPnmiStat->StatRxFramingCts,
229 10, 0, -1, 0));
230 len += sprintf(buffer + len,
231 " fifo errors %s\n",
232 SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
233 10, 0, -1, 0));
234 len += sprintf(buffer + len,
235 " missed errors %s\n",
236 SkNumber(test_buf, pPnmiStat->StatRxMissedCts,
237 10, 0, -1, 0));
238
239 /*Transmit statistics */
240 len += sprintf(buffer + len,
241 "\nTransmit statistics\n\n");
242
243 len += sprintf(buffer + len,
244 "Transmit bytes %s\n",
245 SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts,
246 10,0,-1,0));
247 len += sprintf(buffer + len,
248 "Transmit packets %s\n",
249 SkNumber(test_buf, pPnmiStat->StatTxOkCts,
250 10,0,-1,0));
251 len += sprintf(buffer + len,
252 "Transmit errors %s\n",
253 SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
254 10,0,-1,0));
255 len += sprintf(buffer + len,
256 "Transmit dropped %s\n",
257 SkNumber(test_buf, pPnmiStruct->TxNoBufCts,
258 10,0,-1,0));
259 len += sprintf(buffer + len,
260 "Transmit collisions %s\n",
261 SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
262 10,0,-1,0));
263 len += sprintf(buffer + len,
264 "Transmited errors types\n");
265 len += sprintf(buffer + len,
266 " aborted errors %ld\n",
267 pAC->stats.tx_aborted_errors);
268 len += sprintf(buffer + len,
269 " carrier errors %s\n",
270 SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
271 10, 0, -1, 0));
272 len += sprintf(buffer + len,
273 " fifo errors %s\n",
274 SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts,
275 10, 0, -1, 0));
276 len += sprintf(buffer + len,
277 " heartbeat errors %s\n",
278 SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
279 10, 0, -1, 0));
280 len += sprintf(buffer + len,
281 " window errors %ld\n",
282 pAC->stats.tx_window_errors);
283 }
284 }
285 SkgeProcDev = next;
286 }
287 if (offset >= len) {
288 *eof = 1;
289 return 0;
290 }
291
292 *buffer_location = buffer + offset;
293 if (buffer_length >= len - offset) {
294 *eof = 1;
295 }
296 return (min_t(int, buffer_length, len - offset));
297 }
298
299
300
301
302
303 /*****************************************************************************
304 *
305 * SkDoDiv - convert 64bit number
306 *
307 * Description:
308 * This function "converts" a long long number.
309 *
310 * Returns:
311 * remainder of division
312 */
313 static long SkDoDiv (long long Dividend, int Divisor, long long *pErg)
314 {
315 long Rest;
316 long long Ergebnis;
317 long Akku;
318
319
320 Akku = Dividend >> 32;
321
322 Ergebnis = ((long long) (Akku / Divisor)) << 32;
323 Rest = Akku % Divisor ;
324
325 Akku = Rest << 16;
326 Akku |= ((Dividend & 0xFFFF0000) >> 16);
327
328
329 Ergebnis += ((long long) (Akku / Divisor)) << 16;
330 Rest = Akku % Divisor ;
331
332 Akku = Rest << 16;
333 Akku |= (Dividend & 0xFFFF);
334
335 Ergebnis += (Akku / Divisor);
336 Rest = Akku % Divisor ;
337
338 *pErg = Ergebnis;
339 return (Rest);
340 }
341
342
343 #if 0
344 #define do_div(n,base) ({ \
345 long long __res; \
346 __res = ((unsigned long long) n) % (unsigned) base; \
347 n = ((unsigned long long) n) / (unsigned) base; \
348 __res; })
349
350 #endif
351
352
353 /*****************************************************************************
354 *
355 * SkNumber - Print results
356 *
357 * Description:
358 * This function converts a long long number into a string.
359 *
360 * Returns:
361 * number as string
362 */
363 char * SkNumber(char * str, long long num, int base, int size, int precision
364 ,int type)
365 {
366 char c,sign,tmp[66], *strorg = str;
367 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
368 int i;
369
370 if (type & LARGE)
371 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
372 if (type & LEFT)
373 type &= ~ZEROPAD;
374 if (base < 2 || base > 36)
375 return 0;
376 c = (type & ZEROPAD) ? '0' : ' ';
377 sign = 0;
378 if (type & SIGN) {
379 if (num < 0) {
380 sign = '-';
381 num = -num;
382 size--;
383 } else if (type & PLUS) {
384 sign = '+';
385 size--;
386 } else if (type & SPACE) {
387 sign = ' ';
388 size--;
389 }
390 }
391 if (type & SPECIAL) {
392 if (base == 16)
393 size -= 2;
394 else if (base == 8)
395 size--;
396 }
397 i = 0;
398 if (num == 0)
399 tmp[i++]='0';
400 else while (num != 0)
401 tmp[i++] = digits[SkDoDiv(num,base, &num)];
402
403 if (i > precision)
404 precision = i;
405 size -= precision;
406 if (!(type&(ZEROPAD+LEFT)))
407 while(size-->0)
408 *str++ = ' ';
409 if (sign)
410 *str++ = sign;
411 if (type & SPECIAL) {
412 if (base==8)
413 *str++ = '0';
414 else if (base==16) {
415 *str++ = '0';
416 *str++ = digits[33];
417 }
418 }
419 if (!(type & LEFT))
420 while (size-- > 0)
421 *str++ = c;
422 while (i < precision--)
423 *str++ = '0';
424 while (i-- > 0)
425 *str++ = tmp[i];
426 while (size-- > 0)
427 *str++ = ' ';
428
429 str[0] = '\0';
430
431 return strorg;
432 }
433
434
435
436