/****************************************************************************** * * Name: skproc.c * Project: GEnesis, PCI Gigabit Ethernet Adapter * Version: $Revision: 1.2.2.2 $ * Date: $Date: 2001/03/15 12:50:13 $ * Purpose: Funktions to display statictic data * ******************************************************************************/ /****************************************************************************** * * (C)Copyright 1998-2001 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.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 #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 SPECIAL 32 /* 0x */ #define LARGE 64 extern void proc_fill_inode(struct inode *inode, int fill); extern char * SkNumber(char * str, long long num, int base, int size, int precision ,int type); int proc_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data); static const char SK_Root_Dir_entry[] = "sk98lin"; extern struct net_device *sk98lin_root_dev; struct proc_dir_entry pSkRootDir = { 0, sizeof(SK_Root_Dir_entry)-1, (const char*)SK_Root_Dir_entry, S_IFDIR | S_IRUGO, 2, 0, 0, 0, NULL, NULL }; /***************************************************************************** * * 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]; unsigned long Flags; unsigned int Size; struct net_device *next; struct net_device *SkgeProcDev = sk98lin_root_dev; 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); for (i=0; i < SK_MAX_SENSORS; i ++) { if (strcmp(pAC->I2c.SenTable[i].SenDesc, "Temperature") == 0 ) { len += sprintf(buffer + len, "Temperature (C) %d.%d\n", pAC->I2c.SenTable[i].SenValue / 10, pAC->I2c.SenTable[i].SenValue % 10); len += sprintf(buffer + len, "Temperature (F) %d.%d\n", ((((pAC->I2c.SenTable[i].SenValue) *10)*9)/5 + 3200)/100, ((((pAC->I2c.SenTable[i].SenValue) *10)*9)/5 + 3200) % 10); } else if (strcmp(pAC->I2c.SenTable[i].SenDesc, "Speed Fan") == 0 ) { len += sprintf(buffer + len, "Speed Fan %d\n", pAC->I2c.SenTable[i].SenValue); } else { len += sprintf(buffer + len, "%-20s %d.%d\n", pAC->I2c.SenTable[i].SenDesc, pAC->I2c.SenTable[i].SenValue / 1000, pAC->I2c.SenTable[i].SenValue % 1000); } } /*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)); len += sprintf(buffer + len, "Received errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxFcsCts, 10,0,-1,0)); len += sprintf(buffer + len, "Received dropped %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, "Received errors types\n"); len += sprintf(buffer + len, " length errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxRuntCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " over errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " crc errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxFcsCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " frame errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxFramingCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " fifo errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " missed errors %s\n", SkNumber(test_buf, pPnmiStat->StatRxMissedCts, 10, 0, -1, 0)); /*Transmit statistics */ len += sprintf(buffer + len, "\nTransmit statistics\n\n"); len += sprintf(buffer + len, "Transmit bytes %s\n", SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts, 10,0,-1,0)); len += sprintf(buffer + len, "Transmit 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, "Transmited errors types\n"); len += sprintf(buffer + len, " aborted errors %ld\n", pAC->stats.tx_aborted_errors); len += sprintf(buffer + len, " carrier errors %s\n", SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " fifo errors %s\n", SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " heartbeat errors %s\n", SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, 10, 0, -1, 0)); len += sprintf(buffer + len, " window errors %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 & SPECIAL) { 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 & SPECIAL) { 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; }