* Add support for SK98xx driver

* Add PCI support for SL8245 board

* Support IceCube board configurations with 1 x AMD AM29LV065 (8 MB)
  or 1 x AM29LV652 (two LV065 in one chip = 16 MB);
  Run IPB at 133 Mhz; adjust the MII clock frequency accordingly

* Set BRG_CLK on PM825/826 to 64MHz (VCO_OUT / 4, instead of 16  MHz)
  to allow for more accurate baudrate settings
  (error now 0.7% at 115 kbps, instead of 3.5% before)

* Patch by Andreas Mohr, 4 Sep 2003:
  Fix a lot of spelling errors
diff --git a/drivers/sk98lin/skproc.c b/drivers/sk98lin/skproc.c
new file mode 100644
index 0000000..a23e55c
--- /dev/null
+++ b/drivers/sk98lin/skproc.c
@@ -0,0 +1,515 @@
+/******************************************************************************
+ *
+ * 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;
+}
+
+
+