blob: a23e55c504a9a56f835f13c57b500986465b39d0 [file] [log] [blame]
/******************************************************************************
*
* Name: skproc.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 1.4 $
* Date: $Date: 2003/02/25 14:16:37 $
* Purpose: Funktions to display statictic data
*
******************************************************************************/
/******************************************************************************
*
* (C)Copyright 1998-2003 SysKonnect GmbH.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Created 22-Nov-2000
* Author: Mirko Lindner (mlindner@syskonnect.de)
*
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
/******************************************************************************
*
* History:
*
* $Log: skproc.c,v $
* Revision 1.4 2003/02/25 14:16:37 mlindner
* Fix: Copyright statement
*
* Revision 1.3 2002/10/02 12:59:51 mlindner
* Add: Support for Yukon
* Add: Speed check and setup
* Add: Merge source for kernel 2.2.x and 2.4.x
* Add: Read sensor names directly from VPD
* Fix: Volt values
*
* Revision 1.2.2.7 2002/01/14 12:45:15 mlindner
* Fix: Editorial changes
*
* Revision 1.2.2.6 2001/12/06 15:26:07 mlindner
* Fix: Return value of proc_read
*
* Revision 1.2.2.5 2001/12/06 09:57:39 mlindner
* New ProcFs entries
*
* Revision 1.2.2.4 2001/09/05 12:16:02 mlindner
* Add: New ProcFs entries
* Fix: Counter Errors (Jumbo == to long errors)
* Fix: Kernel error compilation
* Fix: too short counters
*
* Revision 1.2.2.3 2001/06/25 07:26:26 mlindner
* Add: More error messages
*
* Revision 1.2.2.2 2001/03/15 12:50:13 mlindner
* fix: ProcFS owner protection
*
* Revision 1.2.2.1 2001/03/12 16:43:48 mlindner
* chg: 2.4 requirements for procfs
*
* Revision 1.1 2001/01/22 14:15:31 mlindner
* added ProcFs functionality
* Dual Net functionality integrated
* Rlmt networks added
*
*
******************************************************************************/
#include <linux/proc_fs.h>
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIALX 32 /* 0x */
#define LARGE 64
extern SK_AC *pACList;
extern struct net_device *SkGeRootDev;
extern char * SkNumber(
char * str,
long long num,
int base,
int size,
int precision,
int type);
/*****************************************************************************
*
* proc_read - print "summaries" entry
*
* Description:
* This function fills the proc entry with statistic data about
* the ethernet device.
*
*
* Returns: buffer with statistic data
*
*/
int proc_read(char *buffer,
char **buffer_location,
off_t offset,
int buffer_length,
int *eof,
void *data)
{
int len = 0;
int t;
int i;
DEV_NET *pNet;
SK_AC *pAC;
char test_buf[100];
char sens_msg[50];
unsigned long Flags;
unsigned int Size;
struct SK_NET_DEVICE *next;
struct SK_NET_DEVICE *SkgeProcDev = SkGeRootDev;
SK_PNMI_STRUCT_DATA *pPnmiStruct;
SK_PNMI_STAT *pPnmiStat;
struct proc_dir_entry *file = (struct proc_dir_entry*) data;
while (SkgeProcDev) {
pNet = (DEV_NET*) SkgeProcDev->priv;
pAC = pNet->pAC;
next = pAC->Next;
pPnmiStruct = &pAC->PnmiStruct;
/* NetIndex in GetStruct is now required, zero is only dummy */
for (t=pAC->GIni.GIMacsFound; t > 0; t--) {
if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1)
t--;
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
Size = SK_PNMI_STRUCT_SIZE;
SkPnmiGetStruct(pAC, pAC->IoBase,
pPnmiStruct, &Size, t-1);
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
if (strcmp(pAC->dev[t-1]->name, file->name) == 0) {
pPnmiStat = &pPnmiStruct->Stat[0];
len = sprintf(buffer,
"\nDetailed statistic for device %s\n",
pAC->dev[t-1]->name);
len += sprintf(buffer + len,
"=======================================\n");
/* Board statistics */
len += sprintf(buffer + len,
"\nBoard statistics\n\n");
len += sprintf(buffer + len,
"Active Port %c\n",
'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
Net[t-1].PrefPort]->PortNumber);
len += sprintf(buffer + len,
"Preferred Port %c\n",
'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt.
Net[t-1].PrefPort]->PortNumber);
len += sprintf(buffer + len,
"Bus speed (MHz) %d\n",
pPnmiStruct->BusSpeed);
len += sprintf(buffer + len,
"Bus width (Bit) %d\n",
pPnmiStruct->BusWidth);
len += sprintf(buffer + len,
"Hardware revision v%d.%d\n",
(pAC->GIni.GIPciHwRev >> 4) & 0x0F,
pAC->GIni.GIPciHwRev & 0x0F);
/* Print sensor informations */
for (i=0; i < pAC->I2c.MaxSens; i ++) {
/* Check type */
switch (pAC->I2c.SenTable[i].SenType) {
case 1:
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (C)");
len += sprintf(buffer + len,
"%-25s %d.%02d\n",
sens_msg,
pAC->I2c.SenTable[i].SenValue / 10,
pAC->I2c.SenTable[i].SenValue % 10);
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (F)");
len += sprintf(buffer + len,
"%-25s %d.%02d\n",
sens_msg,
((((pAC->I2c.SenTable[i].SenValue)
*10)*9)/5 + 3200)/100,
((((pAC->I2c.SenTable[i].SenValue)
*10)*9)/5 + 3200) % 10);
break;
case 2:
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (V)");
len += sprintf(buffer + len,
"%-25s %d.%03d\n",
sens_msg,
pAC->I2c.SenTable[i].SenValue / 1000,
pAC->I2c.SenTable[i].SenValue % 1000);
break;
case 3:
strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
strcat(sens_msg, " (rpm)");
len += sprintf(buffer + len,
"%-25s %d\n",
sens_msg,
pAC->I2c.SenTable[i].SenValue);
break;
default:
break;
}
}
/*Receive statistics */
len += sprintf(buffer + len,
"\nReceive statistics\n\n");
len += sprintf(buffer + len,
"Received bytes %s\n",
SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Received packets %s\n",
SkNumber(test_buf, pPnmiStat->StatRxOkCts,
10,0,-1,0));
#if 0
if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC &&
pAC->HWRevision < 12) {
pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
pPnmiStat->StatRxShortsCts;
pPnmiStat->StatRxShortsCts = 0;
}
#endif
if (pNet->Mtu > 1500)
pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
pPnmiStat->StatRxTooLongCts;
len += sprintf(buffer + len,
"Receive errors %s\n",
SkNumber(test_buf, pPnmiStruct->InErrorsCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Receive drops %s\n",
SkNumber(test_buf, pPnmiStruct->RxNoBufCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Received multicast %s\n",
SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Receive error types\n");
len += sprintf(buffer + len,
" length %s\n",
SkNumber(test_buf, pPnmiStat->StatRxRuntCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" buffer overflow %s\n",
SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" bad crc %s\n",
SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" framing %s\n",
SkNumber(test_buf, pPnmiStat->StatRxFramingCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" missed frames %s\n",
SkNumber(test_buf, pPnmiStat->StatRxMissedCts,
10, 0, -1, 0));
if (pNet->Mtu > 1500)
pPnmiStat->StatRxTooLongCts = 0;
len += sprintf(buffer + len,
" too long %s\n",
SkNumber(test_buf, pPnmiStat->StatRxTooLongCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" carrier extension %s\n",
SkNumber(test_buf, pPnmiStat->StatRxCextCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" too short %s\n",
SkNumber(test_buf, pPnmiStat->StatRxShortsCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" symbol %s\n",
SkNumber(test_buf, pPnmiStat->StatRxSymbolCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" LLC MAC size %s\n",
SkNumber(test_buf, pPnmiStat->StatRxIRLengthCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" carrier event %s\n",
SkNumber(test_buf, pPnmiStat->StatRxCarrierCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" jabber %s\n",
SkNumber(test_buf, pPnmiStat->StatRxJabberCts,
10, 0, -1, 0));
/*Transmit statistics */
len += sprintf(buffer + len,
"\nTransmit statistics\n\n");
len += sprintf(buffer + len,
"Transmited bytes %s\n",
SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Transmited packets %s\n",
SkNumber(test_buf, pPnmiStat->StatTxOkCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Transmit errors %s\n",
SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Transmit dropped %s\n",
SkNumber(test_buf, pPnmiStruct->TxNoBufCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Transmit collisions %s\n",
SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
10,0,-1,0));
len += sprintf(buffer + len,
"Transmit errors types\n");
len += sprintf(buffer + len,
" excessive collision %ld\n",
pAC->stats.tx_aborted_errors);
len += sprintf(buffer + len,
" carrier %s\n",
SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" fifo underrun %s\n",
SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" heartbeat %s\n",
SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
10, 0, -1, 0));
len += sprintf(buffer + len,
" window %ld\n",
pAC->stats.tx_window_errors);
}
}
SkgeProcDev = next;
}
if (offset >= len) {
*eof = 1;
return 0;
}
*buffer_location = buffer + offset;
if (buffer_length >= len - offset) {
*eof = 1;
}
return (min_t(int, buffer_length, len - offset));
}
/*****************************************************************************
*
* SkDoDiv - convert 64bit number
*
* Description:
* This function "converts" a long long number.
*
* Returns:
* remainder of division
*/
static long SkDoDiv (long long Dividend, int Divisor, long long *pErg)
{
long Rest;
long long Ergebnis;
long Akku;
Akku = Dividend >> 32;
Ergebnis = ((long long) (Akku / Divisor)) << 32;
Rest = Akku % Divisor ;
Akku = Rest << 16;
Akku |= ((Dividend & 0xFFFF0000) >> 16);
Ergebnis += ((long long) (Akku / Divisor)) << 16;
Rest = Akku % Divisor ;
Akku = Rest << 16;
Akku |= (Dividend & 0xFFFF);
Ergebnis += (Akku / Divisor);
Rest = Akku % Divisor ;
*pErg = Ergebnis;
return (Rest);
}
#if 0
#define do_div(n,base) ({ \
long long __res; \
__res = ((unsigned long long) n) % (unsigned) base; \
n = ((unsigned long long) n) / (unsigned) base; \
__res; })
#endif
/*****************************************************************************
*
* SkNumber - Print results
*
* Description:
* This function converts a long long number into a string.
*
* Returns:
* number as string
*/
char * SkNumber(char * str, long long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[66], *strorg = str;
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIALX) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[SkDoDiv(num,base, &num)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (type & SPECIALX) {
if (base==8)
*str++ = '0';
else if (base==16) {
*str++ = '0';
*str++ = digits[33];
}
}
if (!(type & LEFT))
while (size-- > 0)
*str++ = c;
while (i < precision--)
*str++ = '0';
while (i-- > 0)
*str++ = tmp[i];
while (size-- > 0)
*str++ = ' ';
str[0] = '\0';
return strorg;
}