summaryrefslogtreecommitdiffstats
path: root/drivers/net/wan/lmc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/wan/lmc
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/net/wan/lmc')
-rw-r--r--drivers/net/wan/lmc/Makefile17
-rw-r--r--drivers/net/wan/lmc/lmc.h33
-rw-r--r--drivers/net/wan/lmc/lmc_debug.c85
-rw-r--r--drivers/net/wan/lmc/lmc_debug.h52
-rw-r--r--drivers/net/wan/lmc/lmc_ioctl.h257
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2201
-rw-r--r--drivers/net/wan/lmc/lmc_media.c1246
-rw-r--r--drivers/net/wan/lmc/lmc_media.h65
-rw-r--r--drivers/net/wan/lmc/lmc_prot.h15
-rw-r--r--drivers/net/wan/lmc/lmc_proto.c249
-rw-r--r--drivers/net/wan/lmc/lmc_proto.h16
-rw-r--r--drivers/net/wan/lmc/lmc_var.h570
12 files changed, 4806 insertions, 0 deletions
diff --git a/drivers/net/wan/lmc/Makefile b/drivers/net/wan/lmc/Makefile
new file mode 100644
index 00000000000..dabdcfed4ef
--- /dev/null
+++ b/drivers/net/wan/lmc/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for the Lan Media 21140 based WAN cards
+# Specifically the 1000,1200,5200,5245
+#
+
+obj-$(CONFIG_LANMEDIA) += lmc.o
+
+lmc-objs := lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
+
+# Like above except every packet gets echoed to KERN_DEBUG
+# in hex
+#
+# DBDEF = \
+# -DDEBUG \
+# -DLMC_PACKET_LOG
+
+EXTRA_CFLAGS += -I. $(DBGDEF)
diff --git a/drivers/net/wan/lmc/lmc.h b/drivers/net/wan/lmc/lmc.h
new file mode 100644
index 00000000000..882e58c1bfd
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc.h
@@ -0,0 +1,33 @@
+#ifndef _LMC_H_
+#define _LMC_H_
+
+#include "lmc_var.h"
+
+/*
+ * prototypes for everyone
+ */
+int lmc_probe(struct net_device * dev);
+unsigned lmc_mii_readreg(lmc_softc_t * const sc, unsigned
+ devaddr, unsigned regno);
+void lmc_mii_writereg(lmc_softc_t * const sc, unsigned devaddr,
+ unsigned regno, unsigned data);
+void lmc_led_on(lmc_softc_t * const, u_int32_t);
+void lmc_led_off(lmc_softc_t * const, u_int32_t);
+unsigned lmc_mii_readreg(lmc_softc_t * const, unsigned, unsigned);
+void lmc_mii_writereg(lmc_softc_t * const, unsigned, unsigned, unsigned);
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits);
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits);
+
+int lmc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+extern lmc_media_t lmc_ds3_media;
+extern lmc_media_t lmc_ssi_media;
+extern lmc_media_t lmc_t1_media;
+extern lmc_media_t lmc_hssi_media;
+
+#ifdef _DBG_EVENTLOG
+static void lmcEventLog( u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3 );
+#endif
+
+#endif
+
diff --git a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c
new file mode 100644
index 00000000000..9dccd9546a1
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_debug.c
@@ -0,0 +1,85 @@
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+
+#include "lmc_debug.h"
+
+/*
+ * Prints out len, max to 80 octets using printk, 20 per line
+ */
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
+{
+#ifdef DEBUG
+#ifdef LMC_PACKET_LOG
+ int iNewLine = 1;
+ char str[80], *pstr;
+
+ sprintf(str, KERN_DEBUG "lmc: %s: ", type);
+ pstr = str+strlen(str);
+
+ if(iLen > 240){
+ printk(KERN_DEBUG "lmc: Printing 240 chars... out of: %d\n", iLen);
+ iLen = 240;
+ }
+ else{
+ printk(KERN_DEBUG "lmc: Printing %d chars\n", iLen);
+ }
+
+ while(iLen > 0)
+ {
+ sprintf(pstr, "%02x ", *ucData);
+ pstr+=3;
+ ucData++;
+ if( !(iNewLine % 20))
+ {
+ sprintf(pstr, "\n");
+ printk(str);
+ sprintf(str, KERN_DEBUG "lmc: %s: ", type);
+ pstr=str+strlen(str);
+ }
+ iNewLine++;
+ iLen--;
+ }
+ sprintf(pstr, "\n");
+ printk(str);
+#endif
+#endif
+}
+
+#ifdef DEBUG
+u_int32_t lmcEventLogIndex = 0;
+u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
+#endif
+
+void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3)
+{
+#ifdef DEBUG
+ lmcEventLogBuf[lmcEventLogIndex++] = EventNum;
+ lmcEventLogBuf[lmcEventLogIndex++] = arg2;
+ lmcEventLogBuf[lmcEventLogIndex++] = arg3;
+ lmcEventLogBuf[lmcEventLogIndex++] = jiffies;
+
+ lmcEventLogIndex &= (LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS) - 1;
+#endif
+}
+
+void lmc_trace(struct net_device *dev, char *msg){
+#ifdef LMC_TRACE
+ unsigned long j = jiffies + 3; /* Wait for 50 ms */
+
+ if(in_interrupt()){
+ printk("%s: * %s\n", dev->name, msg);
+// while(time_before(jiffies, j+10))
+// ;
+ }
+ else {
+ printk("%s: %s\n", dev->name, msg);
+ while(time_before(jiffies, j))
+ schedule();
+ }
+#endif
+}
+
+
+/* --------------------------- end if_lmc_linux.c ------------------------ */
diff --git a/drivers/net/wan/lmc/lmc_debug.h b/drivers/net/wan/lmc/lmc_debug.h
new file mode 100644
index 00000000000..cf3563859bf
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_debug.h
@@ -0,0 +1,52 @@
+#ifndef _LMC_DEBUG_H_
+#define _LMC_DEBUG_H_
+
+#ifdef DEBUG
+#ifdef LMC_PACKET_LOG
+#define LMC_CONSOLE_LOG(x,y,z) lmcConsoleLog((x), (y), (z))
+#else
+#define LMC_CONSOLE_LOG(x,y,z)
+#endif
+#else
+#define LMC_CONSOLE_LOG(x,y,z)
+#endif
+
+
+
+/* Debug --- Event log definitions --- */
+/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */
+#define LMC_EVENTLOGSIZE 1024 /* number of events in eventlog */
+#define LMC_EVENTLOGARGS 4 /* number of args for each event */
+
+/* event indicators */
+#define LMC_EVENT_XMT 1
+#define LMC_EVENT_XMTEND 2
+#define LMC_EVENT_XMTINT 3
+#define LMC_EVENT_RCVINT 4
+#define LMC_EVENT_RCVEND 5
+#define LMC_EVENT_INT 6
+#define LMC_EVENT_XMTINTTMO 7
+#define LMC_EVENT_XMTPRCTMO 8
+#define LMC_EVENT_INTEND 9
+#define LMC_EVENT_RESET1 10
+#define LMC_EVENT_RESET2 11
+#define LMC_EVENT_FORCEDRESET 12
+#define LMC_EVENT_WATCHDOG 13
+#define LMC_EVENT_BADPKTSURGE 14
+#define LMC_EVENT_TBUSY0 15
+#define LMC_EVENT_TBUSY1 16
+
+
+#ifdef DEBUG
+extern u_int32_t lmcEventLogIndex;
+extern u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
+#define LMC_EVENT_LOG(x, y, z) lmcEventLog((x), (y), (z))
+#else
+#define LMC_EVENT_LOG(x,y,z)
+#endif /* end ifdef _DBG_EVENTLOG */
+
+void lmcConsoleLog(char *type, unsigned char *ucData, int iLen);
+void lmcEventLog (u_int32_t EventNum, u_int32_t arg2, u_int32_t arg3);
+void lmc_trace(struct net_device *dev, char *msg);
+
+#endif
diff --git a/drivers/net/wan/lmc/lmc_ioctl.h b/drivers/net/wan/lmc/lmc_ioctl.h
new file mode 100644
index 00000000000..57dd861cd3d
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_ioctl.h
@@ -0,0 +1,257 @@
+#ifndef _LMC_IOCTL_H_
+#define _LMC_IOCTL_H_
+/* $Id: lmc_ioctl.h,v 1.15 2000/04/06 12:16:43 asj Exp $ */
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License version 2, incorporated herein by reference.
+ */
+
+#define LMCIOCGINFO SIOCDEVPRIVATE+3 /* get current state */
+#define LMCIOCSINFO SIOCDEVPRIVATE+4 /* set state to user values */
+#define LMCIOCGETLMCSTATS SIOCDEVPRIVATE+5
+#define LMCIOCCLEARLMCSTATS SIOCDEVPRIVATE+6
+#define LMCIOCDUMPEVENTLOG SIOCDEVPRIVATE+7
+#define LMCIOCGETXINFO SIOCDEVPRIVATE+8
+#define LMCIOCSETCIRCUIT SIOCDEVPRIVATE+9
+#define LMCIOCUNUSEDATM SIOCDEVPRIVATE+10
+#define LMCIOCRESET SIOCDEVPRIVATE+11
+#define LMCIOCT1CONTROL SIOCDEVPRIVATE+12
+#define LMCIOCIFTYPE SIOCDEVPRIVATE+13
+#define LMCIOCXILINX SIOCDEVPRIVATE+14
+
+#define LMC_CARDTYPE_UNKNOWN -1
+#define LMC_CARDTYPE_HSSI 1 /* probed card is a HSSI card */
+#define LMC_CARDTYPE_DS3 2 /* probed card is a DS3 card */
+#define LMC_CARDTYPE_SSI 3 /* probed card is a SSI card */
+#define LMC_CARDTYPE_T1 4 /* probed card is a T1 card */
+
+#define LMC_CTL_CARDTYPE_LMC5200 0 /* HSSI */
+#define LMC_CTL_CARDTYPE_LMC5245 1 /* DS3 */
+#define LMC_CTL_CARDTYPE_LMC1000 2 /* SSI, V.35 */
+#define LMC_CTL_CARDTYPE_LMC1200 3 /* DS1 */
+
+#define LMC_CTL_OFF 0 /* generic OFF value */
+#define LMC_CTL_ON 1 /* generic ON value */
+
+#define LMC_CTL_CLOCK_SOURCE_EXT 0 /* clock off line */
+#define LMC_CTL_CLOCK_SOURCE_INT 1 /* internal clock */
+
+#define LMC_CTL_CRC_LENGTH_16 16
+#define LMC_CTL_CRC_LENGTH_32 32
+#define LMC_CTL_CRC_BYTESIZE_2 2
+#define LMC_CTL_CRC_BYTESIZE_4 4
+
+
+#define LMC_CTL_CABLE_LENGTH_LT_100FT 0 /* DS3 cable < 100 feet */
+#define LMC_CTL_CABLE_LENGTH_GT_100FT 1 /* DS3 cable >= 100 feet */
+
+#define LMC_CTL_CIRCUIT_TYPE_E1 0
+#define LMC_CTL_CIRCUIT_TYPE_T1 1
+
+/*
+ * IFTYPE defines
+ */
+#define LMC_PPP 1 /* use sppp interface */
+#define LMC_NET 2 /* use direct net interface */
+#define LMC_RAW 3 /* use direct net interface */
+
+/*
+ * These are not in the least IOCTL related, but I want them common.
+ */
+/*
+ * assignments for the GPIO register on the DEC chip (common)
+ */
+#define LMC_GEP_INIT 0x01 /* 0: */
+#define LMC_GEP_RESET 0x02 /* 1: */
+#define LMC_GEP_MODE 0x10 /* 4: */
+#define LMC_GEP_DP 0x20 /* 5: */
+#define LMC_GEP_DATA 0x40 /* 6: serial out */
+#define LMC_GEP_CLK 0x80 /* 7: serial clock */
+
+/*
+ * HSSI GPIO assignments
+ */
+#define LMC_GEP_HSSI_ST 0x04 /* 2: receive timing sense (deprecated) */
+#define LMC_GEP_HSSI_CLOCK 0x08 /* 3: clock source */
+
+/*
+ * T1 GPIO assignments
+ */
+#define LMC_GEP_SSI_GENERATOR 0x04 /* 2: enable prog freq gen serial i/f */
+#define LMC_GEP_SSI_TXCLOCK 0x08 /* 3: provide clock on TXCLOCK output */
+
+/*
+ * Common MII16 bits
+ */
+#define LMC_MII16_LED0 0x0080
+#define LMC_MII16_LED1 0x0100
+#define LMC_MII16_LED2 0x0200
+#define LMC_MII16_LED3 0x0400 /* Error, and the red one */
+#define LMC_MII16_LED_ALL 0x0780 /* LED bit mask */
+#define LMC_MII16_FIFO_RESET 0x0800
+
+/*
+ * definitions for HSSI
+ */
+#define LMC_MII16_HSSI_TA 0x0001
+#define LMC_MII16_HSSI_CA 0x0002
+#define LMC_MII16_HSSI_LA 0x0004
+#define LMC_MII16_HSSI_LB 0x0008
+#define LMC_MII16_HSSI_LC 0x0010
+#define LMC_MII16_HSSI_TM 0x0020
+#define LMC_MII16_HSSI_CRC 0x0040
+
+/*
+ * assignments for the MII register 16 (DS3)
+ */
+#define LMC_MII16_DS3_ZERO 0x0001
+#define LMC_MII16_DS3_TRLBK 0x0002
+#define LMC_MII16_DS3_LNLBK 0x0004
+#define LMC_MII16_DS3_RAIS 0x0008
+#define LMC_MII16_DS3_TAIS 0x0010
+#define LMC_MII16_DS3_BIST 0x0020
+#define LMC_MII16_DS3_DLOS 0x0040
+#define LMC_MII16_DS3_CRC 0x1000
+#define LMC_MII16_DS3_SCRAM 0x2000
+#define LMC_MII16_DS3_SCRAM_LARS 0x4000
+
+/* Note: 2 pairs of LEDs where swapped by mistake
+ * in Xilinx code for DS3 & DS1 adapters */
+#define LMC_DS3_LED0 0x0100 /* bit 08 yellow */
+#define LMC_DS3_LED1 0x0080 /* bit 07 blue */
+#define LMC_DS3_LED2 0x0400 /* bit 10 green */
+#define LMC_DS3_LED3 0x0200 /* bit 09 red */
+
+/*
+ * framer register 0 and 7 (7 is latched and reset on read)
+ */
+#define LMC_FRAMER_REG0_DLOS 0x80 /* digital loss of service */
+#define LMC_FRAMER_REG0_OOFS 0x40 /* out of frame sync */
+#define LMC_FRAMER_REG0_AIS 0x20 /* alarm indication signal */
+#define LMC_FRAMER_REG0_CIS 0x10 /* channel idle */
+#define LMC_FRAMER_REG0_LOC 0x08 /* loss of clock */
+
+/*
+ * Framer register 9 contains the blue alarm signal
+ */
+#define LMC_FRAMER_REG9_RBLUE 0x02 /* Blue alarm failure */
+
+/*
+ * Framer register 0x10 contains xbit error
+ */
+#define LMC_FRAMER_REG10_XBIT 0x01 /* X bit error alarm failure */
+
+/*
+ * And SSI, LMC1000
+ */
+#define LMC_MII16_SSI_DTR 0x0001 /* DTR output RW */
+#define LMC_MII16_SSI_DSR 0x0002 /* DSR input RO */
+#define LMC_MII16_SSI_RTS 0x0004 /* RTS output RW */
+#define LMC_MII16_SSI_CTS 0x0008 /* CTS input RO */
+#define LMC_MII16_SSI_DCD 0x0010 /* DCD input RO */
+#define LMC_MII16_SSI_RI 0x0020 /* RI input RO */
+#define LMC_MII16_SSI_CRC 0x1000 /* CRC select - RW */
+
+/*
+ * bits 0x0080 through 0x0800 are generic, and described
+ * above with LMC_MII16_LED[0123] _LED_ALL, and _FIFO_RESET
+ */
+#define LMC_MII16_SSI_LL 0x1000 /* LL output RW */
+#define LMC_MII16_SSI_RL 0x2000 /* RL output RW */
+#define LMC_MII16_SSI_TM 0x4000 /* TM input RO */
+#define LMC_MII16_SSI_LOOP 0x8000 /* loopback enable RW */
+
+/*
+ * Some of the MII16 bits are mirrored in the MII17 register as well,
+ * but let's keep thing separate for now, and get only the cable from
+ * the MII17.
+ */
+#define LMC_MII17_SSI_CABLE_MASK 0x0038 /* mask to extract the cable type */
+#define LMC_MII17_SSI_CABLE_SHIFT 3 /* shift to extract the cable type */
+
+/*
+ * And T1, LMC1200
+ */
+#define LMC_MII16_T1_UNUSED1 0x0003
+#define LMC_MII16_T1_XOE 0x0004
+#define LMC_MII16_T1_RST 0x0008 /* T1 chip reset - RW */
+#define LMC_MII16_T1_Z 0x0010 /* output impedance T1=1, E1=0 output - RW */
+#define LMC_MII16_T1_INTR 0x0020 /* interrupt from 8370 - RO */
+#define LMC_MII16_T1_ONESEC 0x0040 /* one second square wave - ro */
+
+#define LMC_MII16_T1_LED0 0x0100
+#define LMC_MII16_T1_LED1 0x0080
+#define LMC_MII16_T1_LED2 0x0400
+#define LMC_MII16_T1_LED3 0x0200
+#define LMC_MII16_T1_FIFO_RESET 0x0800
+
+#define LMC_MII16_T1_CRC 0x1000 /* CRC select - RW */
+#define LMC_MII16_T1_UNUSED2 0xe000
+
+
+/* 8370 framer registers */
+
+#define T1FRAMER_ALARM1_STATUS 0x47
+#define T1FRAMER_ALARM2_STATUS 0x48
+#define T1FRAMER_FERR_LSB 0x50
+#define T1FRAMER_FERR_MSB 0x51 /* framing bit error counter */
+#define T1FRAMER_LCV_LSB 0x54
+#define T1FRAMER_LCV_MSB 0x55 /* line code violation counter */
+#define T1FRAMER_AERR 0x5A
+
+/* mask for the above AERR register */
+#define T1FRAMER_LOF_MASK (0x0f0) /* receive loss of frame */
+#define T1FRAMER_COFA_MASK (0x0c0) /* change of frame alignment */
+#define T1FRAMER_SEF_MASK (0x03) /* severely errored frame */
+
+/* 8370 framer register ALM1 (0x47) values
+ * used to determine link status
+ */
+
+#define T1F_SIGFRZ 0x01 /* signaling freeze */
+#define T1F_RLOF 0x02 /* receive loss of frame alignment */
+#define T1F_RLOS 0x04 /* receive loss of signal */
+#define T1F_RALOS 0x08 /* receive analog loss of signal or RCKI loss of clock */
+#define T1F_RAIS 0x10 /* receive alarm indication signal */
+#define T1F_UNUSED 0x20
+#define T1F_RYEL 0x40 /* receive yellow alarm */
+#define T1F_RMYEL 0x80 /* receive multiframe yellow alarm */
+
+#define LMC_T1F_WRITE 0
+#define LMC_T1F_READ 1
+
+typedef struct lmc_st1f_control {
+ int command;
+ int address;
+ int value;
+ char __user *data;
+} lmc_t1f_control;
+
+enum lmc_xilinx_c {
+ lmc_xilinx_reset = 1,
+ lmc_xilinx_load_prom = 2,
+ lmc_xilinx_load = 3
+};
+
+struct lmc_xilinx_control {
+ enum lmc_xilinx_c command;
+ int len;
+ char __user *data;
+};
+
+/* ------------------ end T1 defs ------------------- */
+
+#define LMC_MII_LedMask 0x0780
+#define LMC_MII_LedBitPos 7
+
+#endif
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
new file mode 100644
index 00000000000..15e545f66cd
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -0,0 +1,2201 @@
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * With Help By:
+ * David Boggs
+ * Ron Crane
+ * Alan Cox
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License version 2, incorporated herein by reference.
+ *
+ * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+ *
+ * To control link specific options lmcctl is required.
+ * It can be obtained from ftp.lanmedia.com.
+ *
+ * Linux driver notes:
+ * Linux uses the device struct lmc_private to pass private information
+ * arround.
+ *
+ * The initialization portion of this driver (the lmc_reset() and the
+ * lmc_dec_reset() functions, as well as the led controls and the
+ * lmc_initcsrs() functions.
+ *
+ * The watchdog function runs every second and checks to see if
+ * we still have link, and that the timing source is what we expected
+ * it to be. If link is lost, the interface is marked down, and
+ * we no longer can transmit.
+ *
+ */
+
+/* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/bitops.h>
+
+#include <net/syncppp.h>
+
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+//#include <asm/spinlock.h>
+
+#define DRIVER_MAJOR_VERSION 1
+#define DRIVER_MINOR_VERSION 34
+#define DRIVER_SUB_VERSION 0
+
+#define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)
+
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_ioctl.h"
+#include "lmc_debug.h"
+#include "lmc_proto.h"
+
+static int lmc_first_load = 0;
+
+static int LMC_PKT_BUF_SZ = 1542;
+
+static struct pci_device_id lmc_pci_tbl[] = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
+ PCI_VENDOR_ID_LMC, PCI_ANY_ID },
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
+ PCI_ANY_ID, PCI_VENDOR_ID_LMC },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);
+MODULE_LICENSE("GPL");
+
+
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int lmc_rx (struct net_device *dev);
+static int lmc_open(struct net_device *dev);
+static int lmc_close(struct net_device *dev);
+static struct net_device_stats *lmc_get_stats(struct net_device *dev);
+static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
+static void lmc_softreset(lmc_softc_t * const);
+static void lmc_running_reset(struct net_device *dev);
+static int lmc_ifdown(struct net_device * const);
+static void lmc_watchdog(unsigned long data);
+static void lmc_reset(lmc_softc_t * const sc);
+static void lmc_dec_reset(lmc_softc_t * const sc);
+static void lmc_driver_timeout(struct net_device *dev);
+
+/*
+ * linux reserves 16 device specific IOCTLs. We call them
+ * LMCIOC* to control various bits of our world.
+ */
+int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
+{
+ lmc_softc_t *sc;
+ lmc_ctl_t ctl;
+ int ret;
+ u_int16_t regVal;
+ unsigned long flags;
+
+ struct sppp *sp;
+
+ ret = -EOPNOTSUPP;
+
+ sc = dev->priv;
+
+ lmc_trace(dev, "lmc_ioctl in");
+
+ /*
+ * Most functions mess with the structure
+ * Disable interrupts while we do the polling
+ */
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ switch (cmd) {
+ /*
+ * Return current driver state. Since we keep this up
+ * To date internally, just copy this out to the user.
+ */
+ case LMCIOCGINFO: /*fold01*/
+ if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t)))
+ return -EFAULT;
+ ret = 0;
+ break;
+
+ case LMCIOCSINFO: /*fold01*/
+ sp = &((struct ppp_device *) dev)->sppp;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ break;
+ }
+
+ if(dev->flags & IFF_UP){
+ ret = -EBUSY;
+ break;
+ }
+
+ if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)))
+ return -EFAULT;
+
+ sc->lmc_media->set_status (sc, &ctl);
+
+ if(ctl.crc_length != sc->ictl.crc_length) {
+ sc->lmc_media->set_crc_length(sc, ctl.crc_length);
+ if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16)
+ sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
+ else
+ sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE;
+ }
+
+ if (ctl.keepalive_onoff == LMC_CTL_OFF)
+ sp->pp_flags &= ~PP_KEEPALIVE; /* Turn off */
+ else
+ sp->pp_flags |= PP_KEEPALIVE; /* Turn on */
+
+ ret = 0;
+ break;
+
+ case LMCIOCIFTYPE: /*fold01*/
+ {
+ u_int16_t old_type = sc->if_type;
+ u_int16_t new_type;
+
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ break;
+ }
+
+ if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u_int16_t)))
+ return -EFAULT;
+
+
+ if (new_type == old_type)
+ {
+ ret = 0 ;
+ break; /* no change */
+ }
+
+ lmc_proto_close(sc);
+ lmc_proto_detach(sc);
+
+ sc->if_type = new_type;
+// lmc_proto_init(sc);
+ lmc_proto_attach(sc);
+ lmc_proto_open(sc);
+
+ ret = 0 ;
+ break ;
+ }
+
+ case LMCIOCGETXINFO: /*fold01*/
+ sc->lmc_xinfo.Magic0 = 0xBEEFCAFE;
+
+ sc->lmc_xinfo.PciCardType = sc->lmc_cardtype;
+ sc->lmc_xinfo.PciSlotNumber = 0;
+ sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION;
+ sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION;
+ sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION;
+ sc->lmc_xinfo.XilinxRevisionNumber =
+ lmc_mii_readreg (sc, 0, 3) & 0xf;
+ sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ;
+ sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc);
+ sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16);
+
+ sc->lmc_xinfo.Magic1 = 0xDEADBEEF;
+
+ if (copy_to_user(ifr->ifr_data, &sc->lmc_xinfo,
+ sizeof (struct lmc_xinfo)))
+ return -EFAULT;
+ ret = 0;
+
+ break;
+
+ case LMCIOCGETLMCSTATS: /*fold01*/
+ if (sc->lmc_cardtype == LMC_CARDTYPE_T1){
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB);
+ sc->stats.framingBitErrorCount +=
+ lmc_mii_readreg (sc, 0, 18) & 0xff;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_MSB);
+ sc->stats.framingBitErrorCount +=
+ (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_LSB);
+ sc->stats.lineCodeViolationCount +=
+ lmc_mii_readreg (sc, 0, 18) & 0xff;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_MSB);
+ sc->stats.lineCodeViolationCount +=
+ (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8;
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_AERR);
+ regVal = lmc_mii_readreg (sc, 0, 18) & 0xff;
+
+ sc->stats.lossOfFrameCount +=
+ (regVal & T1FRAMER_LOF_MASK) >> 4;
+ sc->stats.changeOfFrameAlignmentCount +=
+ (regVal & T1FRAMER_COFA_MASK) >> 2;
+ sc->stats.severelyErroredFrameCount +=
+ regVal & T1FRAMER_SEF_MASK;
+ }
+
+ if (copy_to_user(ifr->ifr_data, &sc->stats,
+ sizeof (struct lmc_statistics)))
+ return -EFAULT;
+
+ ret = 0;
+ break;
+
+ case LMCIOCCLEARLMCSTATS: /*fold01*/
+ if (!capable(CAP_NET_ADMIN)){
+ ret = -EPERM;
+ break;
+ }
+
+ memset (&sc->stats, 0, sizeof (struct lmc_statistics));
+ sc->stats.check = STATCHECK;
+ sc->stats.version_size = (DRIVER_VERSION << 16) +
+ sizeof (struct lmc_statistics);
+ sc->stats.lmc_cardtype = sc->lmc_cardtype;
+ ret = 0;
+ break;
+
+ case LMCIOCSETCIRCUIT: /*fold01*/
+ if (!capable(CAP_NET_ADMIN)){
+ ret = -EPERM;
+ break;
+ }
+
+ if(dev->flags & IFF_UP){
+ ret = -EBUSY;
+ break;
+ }
+
+ if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)))
+ return -EFAULT;
+ sc->lmc_media->set_circuit_type(sc, ctl.circuit_type);
+ sc->ictl.circuit_type = ctl.circuit_type;
+ ret = 0;
+
+ break;
+
+ case LMCIOCRESET: /*fold01*/
+ if (!capable(CAP_NET_ADMIN)){
+ ret = -EPERM;
+ break;
+ }
+
+ /* Reset driver and bring back to current state */
+ printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
+ lmc_running_reset (dev);
+ printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16));
+
+ LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
+
+ ret = 0;
+ break;
+
+#ifdef DEBUG
+ case LMCIOCDUMPEVENTLOG:
+ if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32)))
+ return -EFAULT;
+ if (copy_to_user(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf)))
+ return -EFAULT;
+
+ ret = 0;
+ break;
+#endif /* end ifdef _DBG_EVENTLOG */
+ case LMCIOCT1CONTROL: /*fold01*/
+ if (sc->lmc_cardtype != LMC_CARDTYPE_T1){
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+ case LMCIOCXILINX: /*fold01*/
+ {
+ struct lmc_xilinx_control xc; /*fold02*/
+
+ if (!capable(CAP_NET_ADMIN)){
+ ret = -EPERM;
+ break;
+ }
+
+ /*
+ * Stop the xwitter whlie we restart the hardware
+ */
+ netif_stop_queue(dev);
+
+ if (copy_from_user(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control)))
+ return -EFAULT;
+ switch(xc.command){
+ case lmc_xilinx_reset: /*fold02*/
+ {
+ u16 mii;
+ mii = lmc_mii_readreg (sc, 0, 16);
+
+ /*
+ * Make all of them 0 and make input
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * make the reset output
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+ /*
+ * RESET low to force configuration. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+
+ sc->lmc_gpio &= ~LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ sc->lmc_gpio |= LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /* Reset the frammer hardware */
+ sc->lmc_media->set_link_status (sc, 1);
+ sc->lmc_media->set_status (sc, NULL);
+// lmc_softreset(sc);
+
+ {
+ int i;
+ for(i = 0; i < 5; i++){
+ lmc_led_on(sc, LMC_DS3_LED0);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED0);
+ lmc_led_on(sc, LMC_DS3_LED1);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED1);
+ lmc_led_on(sc, LMC_DS3_LED3);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED3);
+ lmc_led_on(sc, LMC_DS3_LED2);
+ mdelay(100);
+ lmc_led_off(sc, LMC_DS3_LED2);
+ }
+ }
+
+
+
+ ret = 0x0;
+
+ }
+
+ break;
+ case lmc_xilinx_load_prom: /*fold02*/
+ {
+ u16 mii;
+ int timeout = 500000;
+ mii = lmc_mii_readreg (sc, 0, 16);
+
+ /*
+ * Make all of them 0 and make input
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * make the reset output
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * RESET low to force configuration. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+
+ sc->lmc_gpio &= ~(LMC_GEP_RESET | LMC_GEP_DP);
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ sc->lmc_gpio |= LMC_GEP_DP | LMC_GEP_RESET;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * busy wait for the chip to reset
+ */
+ while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
+ (timeout-- > 0))
+ ;
+
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, 0xff);
+
+ ret = 0x0;
+
+
+ break;
+
+ }
+
+ case lmc_xilinx_load: /*fold02*/
+ {
+ char *data;
+ int pos;
+ int timeout = 500000;
+
+ if(xc.data == 0x0){
+ ret = -EINVAL;
+ break;
+ }
+
+ data = kmalloc(xc.len, GFP_KERNEL);
+ if(data == 0x0){
+ printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name);
+ ret = -ENOMEM;
+ break;
+ }
+
+ if(copy_from_user(data, xc.data, xc.len))
+ {
+ kfree(data);
+ ret = -ENOMEM;
+ break;
+ }
+
+ printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
+
+ lmc_gpio_mkinput(sc, 0xff);
+
+ /*
+ * Clear the Xilinx and start prgramming from the DEC
+ */
+
+ /*
+ * Set ouput as:
+ * Reset: 0 (active)
+ * DP: 0 (active)
+ * Mode: 1
+ *
+ */
+ sc->lmc_gpio = 0x00;
+ sc->lmc_gpio &= ~LMC_GEP_DP;
+ sc->lmc_gpio &= ~LMC_GEP_RESET;
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_MODE | LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * Wait at least 10 us 20 to be safe
+ */
+ udelay(50);
+
+ /*
+ * Clear reset and activate programming lines
+ * Reset: Input
+ * DP: Input
+ * Clock: Output
+ * Data: Output
+ * Mode: Output
+ */
+ lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+
+ /*
+ * Set LOAD, DATA, Clock to 1
+ */
+ sc->lmc_gpio = 0x00;
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ sc->lmc_gpio |= LMC_GEP_DATA;
+ sc->lmc_gpio |= LMC_GEP_CLK;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE );
+
+ /*
+ * busy wait for the chip to reset
+ */
+ while( (LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0 &&
+ (timeout-- > 0))
+ ;
+
+ printk(KERN_DEBUG "%s: Waited %d for the Xilinx to clear it's memory\n", dev->name, 500000-timeout);
+
+ for(pos = 0; pos < xc.len; pos++){
+ switch(data[pos]){
+ case 0:
+ sc->lmc_gpio &= ~LMC_GEP_DATA; /* Data is 0 */
+ break;
+ case 1:
+ sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */
+ break;
+ default:
+ printk(KERN_WARNING "%s Bad data in xilinx programming data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
+ sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */
+ }
+ sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+ udelay(1);
+
+ sc->lmc_gpio |= LMC_GEP_CLK; /* Put the clack back to one */
+ sc->lmc_gpio |= LMC_GEP_MODE;
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+ udelay(1);
+ }
+ if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){
+ printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (corrupted data)\n", dev->name);
+ }
+ else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){
+ printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (done)\n", dev->name);
+ }
+ else {
+ printk(KERN_DEBUG "%s: Done reprogramming Xilinx, %d bits, good luck!\n", dev->name, pos);
+ }
+
+ lmc_gpio_mkinput(sc, 0xff);
+
+ sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ kfree(data);
+
+ ret = 0;
+
+ break;
+ }
+ default: /*fold02*/
+ ret = -EBADE;
+ break;
+ }
+
+ netif_wake_queue(dev);
+ sc->lmc_txfull = 0;
+
+ }
+ break;
+ default: /*fold01*/
+ /* If we don't know what to do, give the protocol a shot. */
+ ret = lmc_proto_ioctl (sc, ifr, cmd);
+ break;
+ }
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags); /*fold01*/
+
+ lmc_trace(dev, "lmc_ioctl out");
+
+ return ret;
+}
+
+
+/* the watchdog process that cruises around */
+static void lmc_watchdog (unsigned long data) /*fold00*/
+{
+ struct net_device *dev = (struct net_device *) data;
+ lmc_softc_t *sc;
+ int link_status;
+ u_int32_t ticks;
+ unsigned long flags;
+
+ sc = dev->priv;
+
+ lmc_trace(dev, "lmc_watchdog in");
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ if(sc->check != 0xBEAFCAFE){
+ printk("LMC: Corrupt net_device stuct, breaking out\n");
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+ return;
+ }
+
+
+ /* Make sure the tx jabber and rx watchdog are off,
+ * and the transmit and receive processes are running.
+ */
+
+ LMC_CSR_WRITE (sc, csr_15, 0x00000011);
+ sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN;
+ LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+ if (sc->lmc_ok == 0)
+ goto kick_timer;
+
+ LMC_EVENT_LOG(LMC_EVENT_WATCHDOG, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16));
+
+ /* --- begin time out check -----------------------------------
+ * check for a transmit interrupt timeout
+ * Has the packet xmt vs xmt serviced threshold been exceeded */
+ if (sc->lmc_taint_tx == sc->lastlmc_taint_tx &&
+ sc->stats.tx_packets > sc->lasttx_packets &&
+ sc->tx_TimeoutInd == 0)
+ {
+
+ /* wait for the watchdog to come around again */
+ sc->tx_TimeoutInd = 1;
+ }
+ else if (sc->lmc_taint_tx == sc->lastlmc_taint_tx &&
+ sc->stats.tx_packets > sc->lasttx_packets &&
+ sc->tx_TimeoutInd)
+ {
+
+ LMC_EVENT_LOG(LMC_EVENT_XMTINTTMO, LMC_CSR_READ (sc, csr_status), 0);
+
+ sc->tx_TimeoutDisplay = 1;
+ sc->stats.tx_TimeoutCnt++;
+
+ /* DEC chip is stuck, hit it with a RESET!!!! */
+ lmc_running_reset (dev);
+
+
+ /* look at receive & transmit process state to make sure they are running */
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+
+ /* look at: DSR - 02 for Reg 16
+ * CTS - 08
+ * DCD - 10
+ * RI - 20
+ * for Reg 17
+ */
+ LMC_EVENT_LOG(LMC_EVENT_RESET2, lmc_mii_readreg (sc, 0, 16), lmc_mii_readreg (sc, 0, 17));
+
+ /* reset the transmit timeout detection flag */
+ sc->tx_TimeoutInd = 0;
+ sc->lastlmc_taint_tx = sc->lmc_taint_tx;
+ sc->lasttx_packets = sc->stats.tx_packets;
+ }
+ else
+ {
+ sc->tx_TimeoutInd = 0;
+ sc->lastlmc_taint_tx = sc->lmc_taint_tx;
+ sc->lasttx_packets = sc->stats.tx_packets;
+ }
+
+ /* --- end time out check ----------------------------------- */
+
+
+ link_status = sc->lmc_media->get_link_status (sc);
+
+ /*
+ * hardware level link lost, but the interface is marked as up.
+ * Mark it as down.
+ */
+ if ((link_status == 0) && (sc->last_link_status != 0)) {
+ printk(KERN_WARNING "%s: hardware/physical link down\n", dev->name);
+ sc->last_link_status = 0;
+ /* lmc_reset (sc); Why reset??? The link can go down ok */
+
+ /* Inform the world that link has been lost */
+ dev->flags &= ~IFF_RUNNING;
+ }
+
+ /*
+ * hardware link is up, but the interface is marked as down.
+ * Bring it back up again.
+ */
+ if (link_status != 0 && sc->last_link_status == 0) {
+ printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name);
+ sc->last_link_status = 1;
+ /* lmc_reset (sc); Again why reset??? */
+
+ /* Inform the world that link protocol is back up. */
+ dev->flags |= IFF_RUNNING;
+
+ /* Now we have to tell the syncppp that we had an outage
+ * and that it should deal. Calling sppp_reopen here
+ * should do the trick, but we may have to call sppp_close
+ * when the link goes down, and call sppp_open here.
+ * Subject to more testing.
+ * --bbraun
+ */
+
+ lmc_proto_reopen(sc);
+
+ }
+
+ /* Call media specific watchdog functions */
+ sc->lmc_media->watchdog(sc);
+
+ /*
+ * Poke the transmitter to make sure it
+ * never stops, even if we run out of mem
+ */
+ LMC_CSR_WRITE(sc, csr_rxpoll, 0);
+
+ /*
+ * Check for code that failed
+ * and try and fix it as appropriate
+ */
+ if(sc->failed_ring == 1){
+ /*
+ * Failed to setup the recv/xmit rin
+ * Try again
+ */
+ sc->failed_ring = 0;
+ lmc_softreset(sc);
+ }
+ if(sc->failed_recv_alloc == 1){
+ /*
+ * We failed to alloc mem in the
+ * interrupt handler, go through the rings
+ * and rebuild them
+ */
+ sc->failed_recv_alloc = 0;
+ lmc_softreset(sc);
+ }
+
+
+ /*
+ * remember the timer value
+ */
+kick_timer:
+
+ ticks = LMC_CSR_READ (sc, csr_gp_timer);
+ LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL);
+ sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff);
+
+ /*
+ * restart this timer.
+ */
+ sc->timer.expires = jiffies + (HZ);
+ add_timer (&sc->timer);
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_watchdog out");
+
+}
+
+static void lmc_setup(struct net_device * const dev) /*fold00*/
+{
+ lmc_trace(dev, "lmc_setup in");
+
+ dev->type = ARPHRD_HDLC;
+ dev->hard_start_xmit = lmc_start_xmit;
+ dev->open = lmc_open;
+ dev->stop = lmc_close;
+ dev->get_stats = lmc_get_stats;
+ dev->do_ioctl = lmc_ioctl;
+ dev->tx_timeout = lmc_driver_timeout;
+ dev->watchdog_timeo = (HZ); /* 1 second */
+
+ lmc_trace(dev, "lmc_setup out");
+}
+
+
+static int __devinit lmc_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ lmc_softc_t *sc;
+ u16 subdevice;
+ u_int16_t AdapModelNum;
+ int err = -ENOMEM;
+ static int cards_found;
+#ifndef GCOM
+ /* We name by type not by vendor */
+ static const char lmcname[] = "hdlc%d";
+#else
+ /*
+ * GCOM uses LMC vendor name so that clients can know which card
+ * to attach to.
+ */
+ static const char lmcname[] = "lmc%d";
+#endif
+
+
+ /*
+ * Allocate our own device structure
+ */
+ dev = alloc_netdev(sizeof(lmc_softc_t), lmcname, lmc_setup);
+ if (!dev) {
+ printk (KERN_ERR "lmc:alloc_netdev for device failed\n");
+ goto out1;
+ }
+
+ lmc_trace(dev, "lmc_init_one in");
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "lmc: pci enable failed:%d\n", err);
+ goto out2;
+ }
+
+ if (pci_request_regions(pdev, "lmc")) {
+ printk(KERN_ERR "lmc: pci_request_region failed\n");
+ err = -EIO;
+ goto out3;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ if(lmc_first_load == 0){
+ printk(KERN_INFO "Lan Media Corporation WAN Driver Version %d.%d.%d\n",
+ DRIVER_MAJOR_VERSION, DRIVER_MINOR_VERSION,DRIVER_SUB_VERSION);
+ lmc_first_load = 1;
+ }
+
+ sc = dev->priv;
+ sc->lmc_device = dev;
+ sc->name = dev->name;
+
+ /* Initialize the sppp layer */
+ /* An ioctl can cause a subsequent detach for raw frame interface */
+ sc->if_type = LMC_PPP;
+ sc->check = 0xBEAFCAFE;
+ dev->base_addr = pci_resource_start(pdev, 0);
+ dev->irq = pdev->irq;
+
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ /*
+ * This will get the protocol layer ready and do any 1 time init's
+ * Must have a valid sc and dev structure
+ */
+ lmc_proto_init(sc);
+
+ lmc_proto_attach(sc);
+
+ /*
+ * Why were we changing this???
+ dev->tx_queue_len = 100;
+ */
+
+ /* Init the spin lock so can call it latter */
+
+ spin_lock_init(&sc->lmc_lock);
+ pci_set_master(pdev);
+
+ printk ("%s: detected at %lx, irq %d\n", dev->name,
+ dev->base_addr, dev->irq);
+
+ if (register_netdev (dev) != 0) {
+ printk (KERN_ERR "%s: register_netdev failed.\n", dev->name);
+ goto out4;
+ }
+
+ sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN;
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+
+ /*
+ *
+ * Check either the subvendor or the subdevice, some systems reverse
+ * the setting in the bois, seems to be version and arch dependent?
+ * Fix the error, exchange the two values
+ */
+ if ((subdevice = pdev->subsystem_device) == PCI_VENDOR_ID_LMC)
+ subdevice = pdev->subsystem_vendor;
+
+ switch (subdevice) {
+ case PCI_DEVICE_ID_LMC_HSSI:
+ printk ("%s: LMC HSSI\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_HSSI;
+ sc->lmc_media = &lmc_hssi_media;
+ break;
+ case PCI_DEVICE_ID_LMC_DS3:
+ printk ("%s: LMC DS3\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_DS3;
+ sc->lmc_media = &lmc_ds3_media;
+ break;
+ case PCI_DEVICE_ID_LMC_SSI:
+ printk ("%s: LMC SSI\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_SSI;
+ sc->lmc_media = &lmc_ssi_media;
+ break;
+ case PCI_DEVICE_ID_LMC_T1:
+ printk ("%s: LMC T1\n", dev->name);
+ sc->lmc_cardtype = LMC_CARDTYPE_T1;
+ sc->lmc_media = &lmc_t1_media;
+ break;
+ default:
+ printk (KERN_WARNING "%s: LMC UNKOWN CARD!\n", dev->name);
+ break;
+ }
+
+ lmc_initcsrs (sc, dev->base_addr, 8);
+
+ lmc_gpio_mkinput (sc, 0xff);
+ sc->lmc_gpio = 0; /* drive no signals yet */
+
+ sc->lmc_media->defaults (sc);
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_UP);
+
+ /* verify that the PCI Sub System ID matches the Adapter Model number
+ * from the MII register
+ */
+ AdapModelNum = (lmc_mii_readreg (sc, 0, 3) & 0x3f0) >> 4;
+
+ if ((AdapModelNum == LMC_ADAP_T1
+ && subdevice == PCI_DEVICE_ID_LMC_T1) || /* detect LMC1200 */
+ (AdapModelNum == LMC_ADAP_SSI
+ && subdevice == PCI_DEVICE_ID_LMC_SSI) || /* detect LMC1000 */
+ (AdapModelNum == LMC_ADAP_DS3
+ && subdevice == PCI_DEVICE_ID_LMC_DS3) || /* detect LMC5245 */
+ (AdapModelNum == LMC_ADAP_HSSI
+ && subdevice == PCI_DEVICE_ID_LMC_HSSI))
+ { /* detect LMC5200 */
+
+ }
+ else {
+ printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n",
+ dev->name, AdapModelNum, subdevice);
+// return (NULL);
+ }
+ /*
+ * reset clock
+ */
+ LMC_CSR_WRITE (sc, csr_gp_timer, 0xFFFFFFFFUL);
+
+ sc->board_idx = cards_found++;
+ sc->stats.check = STATCHECK;
+ sc->stats.version_size = (DRIVER_VERSION << 16) +
+ sizeof (struct lmc_statistics);
+ sc->stats.lmc_cardtype = sc->lmc_cardtype;
+
+ sc->lmc_ok = 0;
+ sc->last_link_status = 0;
+
+ lmc_trace(dev, "lmc_init_one out");
+ return 0;
+
+ out4:
+ lmc_proto_detach(sc);
+ out3:
+ if (pdev) {
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+ out2:
+ free_netdev(dev);
+ out1:
+ return err;
+}
+
+/*
+ * Called from pci when removing module.
+ */
+static void __devexit lmc_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (dev) {
+ lmc_softc_t *sc = dev->priv;
+
+ printk("%s: removing...\n", dev->name);
+ lmc_proto_detach(sc);
+ unregister_netdev(dev);
+ free_netdev(dev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+/* After this is called, packets can be sent.
+ * Does not initialize the addresses
+ */
+static int lmc_open (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc = dev->priv;
+
+ lmc_trace(dev, "lmc_open in");
+
+ lmc_led_on(sc, LMC_DS3_LED0);
+
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
+
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+
+ if (sc->lmc_ok){
+ lmc_trace(dev, "lmc_open lmc_ok out");
+ return (0);
+ }
+
+ lmc_softreset (sc);
+
+ /* Since we have to use PCI bus, this should work on x86,alpha,ppc */
+ if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){
+ printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
+ lmc_trace(dev, "lmc_open irq failed out");
+ return -EAGAIN;
+ }
+ sc->got_irq = 1;
+
+ /* Assert Terminal Active */
+ sc->lmc_miireg16 |= LMC_MII16_LED_ALL;
+ sc->lmc_media->set_link_status (sc, LMC_LINK_UP);
+
+ /*
+ * reset to last state.
+ */
+ sc->lmc_media->set_status (sc, NULL);
+
+ /* setup default bits to be used in tulip_desc_t transmit descriptor
+ * -baz */
+ sc->TxDescriptControlInit = (
+ LMC_TDES_INTERRUPT_ON_COMPLETION
+ | LMC_TDES_FIRST_SEGMENT
+ | LMC_TDES_LAST_SEGMENT
+ | LMC_TDES_SECOND_ADDR_CHAINED
+ | LMC_TDES_DISABLE_PADDING
+ );
+
+ if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) {
+ /* disable 32 bit CRC generated by ASIC */
+ sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE;
+ }
+ sc->lmc_media->set_crc_length(sc, sc->ictl.crc_length);
+ /* Acknoledge the Terminal Active and light LEDs */
+
+ /* dev->flags |= IFF_UP; */
+
+ lmc_proto_open(sc);
+
+ dev->do_ioctl = lmc_ioctl;
+
+
+ netif_start_queue(dev);
+
+ sc->stats.tx_tbusy0++ ;
+
+ /*
+ * select what interrupts we want to get
+ */
+ sc->lmc_intrmask = 0;
+ /* Should be using the default interrupt mask defined in the .h file. */
+ sc->lmc_intrmask |= (TULIP_STS_NORMALINTR
+ | TULIP_STS_RXINTR
+ | TULIP_STS_TXINTR
+ | TULIP_STS_ABNRMLINTR
+ | TULIP_STS_SYSERROR
+ | TULIP_STS_TXSTOPPED
+ | TULIP_STS_TXUNDERFLOW
+ | TULIP_STS_RXSTOPPED
+ | TULIP_STS_RXNOBUF
+ );
+ LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+
+ sc->lmc_cmdmode |= TULIP_CMD_TXRUN;
+ sc->lmc_cmdmode |= TULIP_CMD_RXRUN;
+ LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+ sc->lmc_ok = 1; /* Run watchdog */
+
+ /*
+ * Set the if up now - pfb
+ */
+
+ sc->last_link_status = 1;
+
+ /*
+ * Setup a timer for the watchdog on probe, and start it running.
+ * Since lmc_ok == 0, it will be a NOP for now.
+ */
+ init_timer (&sc->timer);
+ sc->timer.expires = jiffies + HZ;
+ sc->timer.data = (unsigned long) dev;
+ sc->timer.function = &lmc_watchdog;
+ add_timer (&sc->timer);
+
+ lmc_trace(dev, "lmc_open out");
+
+ return (0);
+}
+
+/* Total reset to compensate for the AdTran DSU doing bad things
+ * under heavy load
+ */
+
+static void lmc_running_reset (struct net_device *dev) /*fold00*/
+{
+
+ lmc_softc_t *sc = (lmc_softc_t *) dev->priv;
+
+ lmc_trace(dev, "lmc_runnig_reset in");
+
+ /* stop interrupts */
+ /* Clear the interrupt mask */
+ LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
+ lmc_softreset (sc);
+ /* sc->lmc_miireg16 |= LMC_MII16_LED_ALL; */
+ sc->lmc_media->set_link_status (sc, 1);
+ sc->lmc_media->set_status (sc, NULL);
+
+ //dev->flags |= IFF_RUNNING;
+
+ netif_wake_queue(dev);
+
+ sc->lmc_txfull = 0;
+ sc->stats.tx_tbusy0++ ;
+
+ sc->lmc_intrmask = TULIP_DEFAULT_INTR_MASK;
+ LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+
+ sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
+ LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+
+ lmc_trace(dev, "lmc_runnin_reset_out");
+}
+
+
+/* This is what is called when you ifconfig down a device.
+ * This disables the timer for the watchdog and keepalives,
+ * and disables the irq for dev.
+ */
+static int lmc_close (struct net_device *dev) /*fold00*/
+{
+ /* not calling release_region() as we should */
+ lmc_softc_t *sc;
+
+ lmc_trace(dev, "lmc_close in");
+
+ sc = dev->priv;
+ sc->lmc_ok = 0;
+ sc->lmc_media->set_link_status (sc, 0);
+ del_timer (&sc->timer);
+ lmc_proto_close(sc);
+ lmc_ifdown (dev);
+
+ lmc_trace(dev, "lmc_close out");
+
+ return 0;
+}
+
+/* Ends the transfer of packets */
+/* When the interface goes down, this is called */
+static int lmc_ifdown (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc = dev->priv;
+ u32 csr6;
+ int i;
+
+ lmc_trace(dev, "lmc_ifdown in");
+
+ /* Don't let anything else go on right now */
+ // dev->start = 0;
+ netif_stop_queue(dev);
+ sc->stats.tx_tbusy1++ ;
+
+ /* stop interrupts */
+ /* Clear the interrupt mask */
+ LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+
+ /* Stop Tx and Rx on the chip */
+ csr6 = LMC_CSR_READ (sc, csr_command);
+ csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */
+ csr6 &= ~LMC_DEC_SR; /* Turn off the Receive bit */
+ LMC_CSR_WRITE (sc, csr_command, csr6);
+
+ dev->flags &= ~IFF_RUNNING;
+
+ sc->stats.rx_missed_errors +=
+ LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+
+ /* release the interrupt */
+ if(sc->got_irq == 1){
+ free_irq (dev->irq, dev);
+ sc->got_irq = 0;
+ }
+
+ /* free skbuffs in the Rx queue */
+ for (i = 0; i < LMC_RXDESCS; i++)
+ {
+ struct sk_buff *skb = sc->lmc_rxq[i];
+ sc->lmc_rxq[i] = NULL;
+ sc->lmc_rxring[i].status = 0;
+ sc->lmc_rxring[i].length = 0;
+ sc->lmc_rxring[i].buffer1 = 0xDEADBEEF;
+ if (skb != NULL)
+ dev_kfree_skb(skb);
+ sc->lmc_rxq[i] = NULL;
+ }
+
+ for (i = 0; i < LMC_TXDESCS; i++)
+ {
+ if (sc->lmc_txq[i] != NULL)
+ dev_kfree_skb(sc->lmc_txq[i]);
+ sc->lmc_txq[i] = NULL;
+ }
+
+ lmc_led_off (sc, LMC_MII16_LED_ALL);
+
+ netif_wake_queue(dev);
+ sc->stats.tx_tbusy0++ ;
+
+ lmc_trace(dev, "lmc_ifdown out");
+
+ return 0;
+}
+
+/* Interrupt handling routine. This will take an incoming packet, or clean
+ * up after a trasmit.
+ */
+static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ lmc_softc_t *sc;
+ u32 csr;
+ int i;
+ s32 stat;
+ unsigned int badtx;
+ u32 firstcsr;
+ int max_work = LMC_RXDESCS;
+ int handled = 0;
+
+ lmc_trace(dev, "lmc_interrupt in");
+
+ sc = dev->priv;
+
+ spin_lock(&sc->lmc_lock);
+
+ /*
+ * Read the csr to find what interrupts we have (if any)
+ */
+ csr = LMC_CSR_READ (sc, csr_status);
+
+ /*
+ * Make sure this is our interrupt
+ */
+ if ( ! (csr & sc->lmc_intrmask)) {
+ goto lmc_int_fail_out;
+ }
+
+ firstcsr = csr;
+
+ /* always go through this loop at least once */
+ while (csr & sc->lmc_intrmask) {
+ handled = 1;
+
+ /*
+ * Clear interrupt bits, we handle all case below
+ */
+ LMC_CSR_WRITE (sc, csr_status, csr);
+
+ /*
+ * One of
+ * - Transmit process timed out CSR5<1>
+ * - Transmit jabber timeout CSR5<3>
+ * - Transmit underflow CSR5<5>
+ * - Transmit Receiver buffer unavailable CSR5<7>
+ * - Receive process stopped CSR5<8>
+ * - Receive watchdog timeout CSR5<9>
+ * - Early transmit interrupt CSR5<10>
+ *
+ * Is this really right? Should we do a running reset for jabber?
+ * (being a WAN card and all)
+ */
+ if (csr & TULIP_STS_ABNRMLINTR){
+ lmc_running_reset (dev);
+ break;
+ }
+
+ if (csr & TULIP_STS_RXINTR){
+ lmc_trace(dev, "rx interrupt");
+ lmc_rx (dev);
+
+ }
+ if (csr & (TULIP_STS_TXINTR | TULIP_STS_TXNOBUF | TULIP_STS_TXSTOPPED)) {
+
+ int n_compl = 0 ;
+ /* reset the transmit timeout detection flag -baz */
+ sc->stats.tx_NoCompleteCnt = 0;
+
+ badtx = sc->lmc_taint_tx;
+ i = badtx % LMC_TXDESCS;
+
+ while ((badtx < sc->lmc_next_tx)) {
+ stat = sc->lmc_txring[i].status;
+
+ LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat,
+ sc->lmc_txring[i].length);
+ /*
+ * If bit 31 is 1 the tulip owns it break out of the loop
+ */
+ if (stat & 0x80000000)
+ break;
+
+ n_compl++ ; /* i.e., have an empty slot in ring */
+ /*
+ * If we have no skbuff or have cleared it
+ * Already continue to the next buffer
+ */
+ if (sc->lmc_txq[i] == NULL)
+ continue;
+
+ /*
+ * Check the total error summary to look for any errors
+ */
+ if (stat & 0x8000) {
+ sc->stats.tx_errors++;
+ if (stat & 0x4104)
+ sc->stats.tx_aborted_errors++;
+ if (stat & 0x0C00)
+ sc->stats.tx_carrier_errors++;
+ if (stat & 0x0200)
+ sc->stats.tx_window_errors++;
+ if (stat & 0x0002)
+ sc->stats.tx_fifo_errors++;
+ }
+ else {
+
+ sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;
+
+ sc->stats.tx_packets++;
+ }
+
+ // dev_kfree_skb(sc->lmc_txq[i]);
+ dev_kfree_skb_irq(sc->lmc_txq[i]);
+ sc->lmc_txq[i] = NULL;
+
+ badtx++;
+ i = badtx % LMC_TXDESCS;
+ }
+
+ if (sc->lmc_next_tx - badtx > LMC_TXDESCS)
+ {
+ printk ("%s: out of sync pointer\n", dev->name);
+ badtx += LMC_TXDESCS;
+ }
+ LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0);
+ sc->lmc_txfull = 0;
+ netif_wake_queue(dev);
+ sc->stats.tx_tbusy0++ ;
+
+
+#ifdef DEBUG
+ sc->stats.dirtyTx = badtx;
+ sc->stats.lmc_next_tx = sc->lmc_next_tx;
+ sc->stats.lmc_txfull = sc->lmc_txfull;
+#endif
+ sc->lmc_taint_tx = badtx;
+
+ /*
+ * Why was there a break here???
+ */
+ } /* end handle transmit interrupt */
+
+ if (csr & TULIP_STS_SYSERROR) {
+ u32 error;
+ printk (KERN_WARNING "%s: system bus error csr: %#8.8x\n", dev->name, csr);
+ error = csr>>23 & 0x7;
+ switch(error){
+ case 0x000:
+ printk(KERN_WARNING "%s: Parity Fault (bad)\n", dev->name);
+ break;
+ case 0x001:
+ printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name);
+ break;
+ case 0x010:
+ printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name);
+ break;
+ default:
+ printk(KERN_WARNING "%s: This bus error code was supposed to be reserved!\n", dev->name);
+ }
+ lmc_dec_reset (sc);
+ lmc_reset (sc);
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+ }
+
+
+ if(max_work-- <= 0)
+ break;
+
+ /*
+ * Get current csr status to make sure
+ * we've cleared all interrupts
+ */
+ csr = LMC_CSR_READ (sc, csr_status);
+ } /* end interrupt loop */
+ LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr);
+
+lmc_int_fail_out:
+
+ spin_unlock(&sc->lmc_lock);
+
+ lmc_trace(dev, "lmc_interrupt out");
+ return IRQ_RETVAL(handled);
+}
+
+static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc;
+ u32 flag;
+ int entry;
+ int ret = 0;
+ unsigned long flags;
+
+ lmc_trace(dev, "lmc_start_xmit in");
+
+ sc = dev->priv;
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ /* normal path, tbusy known to be zero */
+
+ entry = sc->lmc_next_tx % LMC_TXDESCS;
+
+ sc->lmc_txq[entry] = skb;
+ sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data);
+
+ LMC_CONSOLE_LOG("xmit", skb->data, skb->len);
+
+#ifndef GCOM
+ /* If the queue is less than half full, don't interrupt */
+ if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS / 2)
+ {
+ /* Do not interrupt on completion of this packet */
+ flag = 0x60000000;
+ netif_wake_queue(dev);
+ }
+ else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2)
+ {
+ /* This generates an interrupt on completion of this packet */
+ flag = 0xe0000000;
+ netif_wake_queue(dev);
+ }
+ else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1)
+ {
+ /* Do not interrupt on completion of this packet */
+ flag = 0x60000000;
+ netif_wake_queue(dev);
+ }
+ else
+ {
+ /* This generates an interrupt on completion of this packet */
+ flag = 0xe0000000;
+ sc->lmc_txfull = 1;
+ netif_stop_queue(dev);
+ }
+#else
+ flag = LMC_TDES_INTERRUPT_ON_COMPLETION;
+
+ if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1)
+ { /* ring full, go busy */
+ sc->lmc_txfull = 1;
+ netif_stop_queue(dev);
+ sc->stats.tx_tbusy1++ ;
+ LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0);
+ }
+#endif
+
+
+ if (entry == LMC_TXDESCS - 1) /* last descriptor in ring */
+ flag |= LMC_TDES_END_OF_RING; /* flag as such for Tulip */
+
+ /* don't pad small packets either */
+ flag = sc->lmc_txring[entry].length = (skb->len) | flag |
+ sc->TxDescriptControlInit;
+
+ /* set the transmit timeout flag to be checked in
+ * the watchdog timer handler. -baz
+ */
+
+ sc->stats.tx_NoCompleteCnt++;
+ sc->lmc_next_tx++;
+
+ /* give ownership to the chip */
+ LMC_EVENT_LOG(LMC_EVENT_XMT, flag, entry);
+ sc->lmc_txring[entry].status = 0x80000000;
+
+ /* send now! */
+ LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+ dev->trans_start = jiffies;
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_start_xmit_out");
+ return ret;
+}
+
+
+static int lmc_rx (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc;
+ int i;
+ int rx_work_limit = LMC_RXDESCS;
+ unsigned int next_rx;
+ int rxIntLoopCnt; /* debug -baz */
+ int localLengthErrCnt = 0;
+ long stat;
+ struct sk_buff *skb, *nsb;
+ u16 len;
+
+ lmc_trace(dev, "lmc_rx in");
+
+ sc = dev->priv;
+
+ lmc_led_on(sc, LMC_DS3_LED3);
+
+ rxIntLoopCnt = 0; /* debug -baz */
+
+ i = sc->lmc_next_rx % LMC_RXDESCS;
+ next_rx = sc->lmc_next_rx;
+
+ while (((stat = sc->lmc_rxring[i].status) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
+ {
+ rxIntLoopCnt++; /* debug -baz */
+ len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER);
+ if ((stat & 0x0300) != 0x0300) { /* Check first segment and last segment */
+ if ((stat & 0x0000ffff) != 0x7fff) {
+ /* Oversized frame */
+ sc->stats.rx_length_errors++;
+ goto skip_packet;
+ }
+ }
+
+ if(stat & 0x00000008){ /* Catch a dribbling bit error */
+ sc->stats.rx_errors++;
+ sc->stats.rx_frame_errors++;
+ goto skip_packet;
+ }
+
+
+ if(stat & 0x00000004){ /* Catch a CRC error by the Xilinx */
+ sc->stats.rx_errors++;
+ sc->stats.rx_crc_errors++;
+ goto skip_packet;
+ }
+
+
+ if (len > LMC_PKT_BUF_SZ){
+ sc->stats.rx_length_errors++;
+ localLengthErrCnt++;
+ goto skip_packet;
+ }
+
+ if (len < sc->lmc_crcSize + 2) {
+ sc->stats.rx_length_errors++;
+ sc->stats.rx_SmallPktCnt++;
+ localLengthErrCnt++;
+ goto skip_packet;
+ }
+
+ if(stat & 0x00004000){
+ printk(KERN_WARNING "%s: Receiver descriptor error, receiver out of sync?\n", dev->name);
+ }
+
+ len -= sc->lmc_crcSize;
+
+ skb = sc->lmc_rxq[i];
+
+ /*
+ * We ran out of memory at some point
+ * just allocate an skb buff and continue.
+ */
+
+ if(skb == 0x0){
+ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if (nsb) {
+ sc->lmc_rxq[i] = nsb;
+ nsb->dev = dev;
+ sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+ }
+ sc->failed_recv_alloc = 1;
+ goto skip_packet;
+ }
+
+ dev->last_rx = jiffies;
+ sc->stats.rx_packets++;
+ sc->stats.rx_bytes += len;
+
+ LMC_CONSOLE_LOG("recv", skb->data, len);
+
+ /*
+ * I'm not sure of the sanity of this
+ * Packets could be arriving at a constant
+ * 44.210mbits/sec and we're going to copy
+ * them into a new buffer??
+ */
+
+ if(len > (LMC_MTU - (LMC_MTU>>2))){ /* len > LMC_MTU * 0.75 */
+ /*
+ * If it's a large packet don't copy it just hand it up
+ */
+ give_it_anyways:
+
+ sc->lmc_rxq[i] = NULL;
+ sc->lmc_rxring[i].buffer1 = 0x0;
+
+ skb_put (skb, len);
+ skb->protocol = lmc_proto_type(sc, skb);
+ skb->protocol = htons(ETH_P_WAN_PPP);
+ skb->mac.raw = skb->data;
+// skb->nh.raw = skb->data;
+ skb->dev = dev;
+ lmc_proto_netif(sc, skb);
+
+ /*
+ * This skb will be destroyed by the upper layers, make a new one
+ */
+ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if (nsb) {
+ sc->lmc_rxq[i] = nsb;
+ nsb->dev = dev;
+ sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+ /* Transferred to 21140 below */
+ }
+ else {
+ /*
+ * We've run out of memory, stop trying to allocate
+ * memory and exit the interrupt handler
+ *
+ * The chip may run out of receivers and stop
+ * in which care we'll try to allocate the buffer
+ * again. (once a second)
+ */
+ sc->stats.rx_BuffAllocErr++;
+ LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len);
+ sc->failed_recv_alloc = 1;
+ goto skip_out_of_mem;
+ }
+ }
+ else {
+ nsb = dev_alloc_skb(len);
+ if(!nsb) {
+ goto give_it_anyways;
+ }
+ memcpy(skb_put(nsb, len), skb->data, len);
+
+ nsb->protocol = lmc_proto_type(sc, skb);
+ nsb->mac.raw = nsb->data;
+// nsb->nh.raw = nsb->data;
+ nsb->dev = dev;
+ lmc_proto_netif(sc, nsb);
+ }
+
+ skip_packet:
+ LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, len);
+ sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4;
+
+ sc->lmc_next_rx++;
+ i = sc->lmc_next_rx % LMC_RXDESCS;
+ rx_work_limit--;
+ if (rx_work_limit < 0)
+ break;
+ }
+
+ /* detect condition for LMC1000 where DSU cable attaches and fills
+ * descriptors with bogus packets
+ *
+ if (localLengthErrCnt > LMC_RXDESCS - 3) {
+ sc->stats.rx_BadPktSurgeCnt++;
+ LMC_EVENT_LOG(LMC_EVENT_BADPKTSURGE,
+ localLengthErrCnt,
+ sc->stats.rx_BadPktSurgeCnt);
+ } */
+
+ /* save max count of receive descriptors serviced */
+ if (rxIntLoopCnt > sc->stats.rxIntLoopCnt) {
+ sc->stats.rxIntLoopCnt = rxIntLoopCnt; /* debug -baz */
+ }
+
+#ifdef DEBUG
+ if (rxIntLoopCnt == 0)
+ {
+ for (i = 0; i < LMC_RXDESCS; i++)
+ {
+ if ((sc->lmc_rxring[i].status & LMC_RDES_OWN_BIT)
+ != DESC_OWNED_BY_DC21X4)
+ {
+ rxIntLoopCnt++;
+ }
+ }
+ LMC_EVENT_LOG(LMC_EVENT_RCVEND, rxIntLoopCnt, 0);
+ }
+#endif
+
+
+ lmc_led_off(sc, LMC_DS3_LED3);
+
+skip_out_of_mem:
+
+ lmc_trace(dev, "lmc_rx out");
+
+ return 0;
+}
+
+static struct net_device_stats *lmc_get_stats (struct net_device *dev) /*fold00*/
+{
+ lmc_softc_t *sc = dev->priv;
+ unsigned long flags;
+
+ lmc_trace(dev, "lmc_get_stats in");
+
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_get_stats out");
+
+ return (struct net_device_stats *) &sc->stats;
+}
+
+static struct pci_driver lmc_driver = {
+ .name = "lmc",
+ .id_table = lmc_pci_tbl,
+ .probe = lmc_init_one,
+ .remove = __devexit_p(lmc_remove_one),
+};
+
+static int __init init_lmc(void)
+{
+ return pci_module_init(&lmc_driver);
+}
+
+static void __exit exit_lmc(void)
+{
+ pci_unregister_driver(&lmc_driver);
+}
+
+module_init(init_lmc);
+module_exit(exit_lmc);
+
+unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/
+{
+ int i;
+ int command = (0xf6 << 10) | (devaddr << 5) | regno;
+ int retval = 0;
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg in");
+
+ LMC_MII_SYNC (sc);
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg: done sync");
+
+ for (i = 15; i >= 0; i--)
+ {
+ int dataval = (command & (1 << i)) ? 0x20000 : 0;
+
+ LMC_CSR_WRITE (sc, csr_9, dataval);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ }
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg: done1");
+
+ for (i = 19; i > 0; i--)
+ {
+ LMC_CSR_WRITE (sc, csr_9, 0x40000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ retval = (retval << 1) | ((LMC_CSR_READ (sc, csr_9) & 0x80000) ? 1 : 0);
+ LMC_CSR_WRITE (sc, csr_9, 0x40000 | 0x10000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ }
+
+ lmc_trace(sc->lmc_device, "lmc_mii_readreg out");
+
+ return (retval >> 1) & 0xffff;
+}
+
+void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno, unsigned data) /*fold00*/
+{
+ int i = 32;
+ int command = (0x5002 << 16) | (devaddr << 23) | (regno << 18) | data;
+
+ lmc_trace(sc->lmc_device, "lmc_mii_writereg in");
+
+ LMC_MII_SYNC (sc);
+
+ i = 31;
+ while (i >= 0)
+ {
+ int datav;
+
+ if (command & (1 << i))
+ datav = 0x20000;
+ else
+ datav = 0x00000;
+
+ LMC_CSR_WRITE (sc, csr_9, datav);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000));
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ i--;
+ }
+
+ i = 2;
+ while (i > 0)
+ {
+ LMC_CSR_WRITE (sc, csr_9, 0x40000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ LMC_CSR_WRITE (sc, csr_9, 0x50000);
+ lmc_delay ();
+ /* __SLOW_DOWN_IO; */
+ i--;
+ }
+
+ lmc_trace(sc->lmc_device, "lmc_mii_writereg out");
+}
+
+static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/
+{
+ int i;
+
+ lmc_trace(sc->lmc_device, "lmc_softreset in");
+
+ /* Initialize the receive rings and buffers. */
+ sc->lmc_txfull = 0;
+ sc->lmc_next_rx = 0;
+ sc->lmc_next_tx = 0;
+ sc->lmc_taint_rx = 0;
+ sc->lmc_taint_tx = 0;
+
+ /*
+ * Setup each one of the receiver buffers
+ * allocate an skbuff for each one, setup the descriptor table
+ * and point each buffer at the next one
+ */
+
+ for (i = 0; i < LMC_RXDESCS; i++)
+ {
+ struct sk_buff *skb;
+
+ if (sc->lmc_rxq[i] == NULL)
+ {
+ skb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
+ if(skb == NULL){
+ printk(KERN_WARNING "%s: Failed to allocate receiver ring, will try again\n", sc->name);
+ sc->failed_ring = 1;
+ break;
+ }
+ else{
+ sc->lmc_rxq[i] = skb;
+ }
+ }
+ else
+ {
+ skb = sc->lmc_rxq[i];
+ }
+
+ skb->dev = sc->lmc_device;
+
+ /* owned by 21140 */
+ sc->lmc_rxring[i].status = 0x80000000;
+
+ /* used to be PKT_BUF_SZ now uses skb since we lose some to head room */
+ sc->lmc_rxring[i].length = skb->end - skb->data;
+
+ /* use to be tail which is dumb since you're thinking why write
+ * to the end of the packj,et but since there's nothing there tail == data
+ */
+ sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data);
+
+ /* This is fair since the structure is static and we have the next address */
+ sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i + 1]);
+
+ }
+
+ /*
+ * Sets end of ring
+ */
+ sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */
+ sc->lmc_rxring[i - 1].buffer2 = virt_to_bus (&sc->lmc_rxring[0]); /* Point back to the start */
+ LMC_CSR_WRITE (sc, csr_rxlist, virt_to_bus (sc->lmc_rxring)); /* write base address */
+
+
+ /* Initialize the transmit rings and buffers */
+ for (i = 0; i < LMC_TXDESCS; i++)
+ {
+ if (sc->lmc_txq[i] != NULL){ /* have buffer */
+ dev_kfree_skb(sc->lmc_txq[i]); /* free it */
+ sc->stats.tx_dropped++; /* We just dropped a packet */
+ }
+ sc->lmc_txq[i] = NULL;
+ sc->lmc_txring[i].status = 0x00000000;
+ sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]);
+ }
+ sc->lmc_txring[i - 1].buffer2 = virt_to_bus (&sc->lmc_txring[0]);
+ LMC_CSR_WRITE (sc, csr_txlist, virt_to_bus (sc->lmc_txring));
+
+ lmc_trace(sc->lmc_device, "lmc_softreset out");
+}
+
+void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in");
+ sc->lmc_gpio_io &= ~bits;
+ LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkinput out");
+}
+
+void lmc_gpio_mkoutput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput in");
+ sc->lmc_gpio_io |= bits;
+ LMC_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET | (sc->lmc_gpio_io));
+ lmc_trace(sc->lmc_device, "lmc_gpio_mkoutput out");
+}
+
+void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_led_on in");
+ if((~sc->lmc_miireg16) & led){ /* Already on! */
+ lmc_trace(sc->lmc_device, "lmc_led_on aon out");
+ return;
+ }
+
+ sc->lmc_miireg16 &= ~led;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+ lmc_trace(sc->lmc_device, "lmc_led_on out");
+}
+
+void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_led_off in");
+ if(sc->lmc_miireg16 & led){ /* Already set don't do anything */
+ lmc_trace(sc->lmc_device, "lmc_led_off aoff out");
+ return;
+ }
+
+ sc->lmc_miireg16 |= led;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+ lmc_trace(sc->lmc_device, "lmc_led_off out");
+}
+
+static void lmc_reset(lmc_softc_t * const sc) /*fold00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_reset in");
+ sc->lmc_miireg16 |= LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ sc->lmc_miireg16 &= ~LMC_MII16_FIFO_RESET;
+ lmc_mii_writereg(sc, 0, 16, sc->lmc_miireg16);
+
+ /*
+ * make some of the GPIO pins be outputs
+ */
+ lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
+
+ /*
+ * RESET low to force state reset. This also forces
+ * the transmitter clock to be internal, but we expect to reset
+ * that later anyway.
+ */
+ sc->lmc_gpio &= ~(LMC_GEP_RESET);
+ LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * hold for more than 10 microseconds
+ */
+ udelay(50);
+
+ /*
+ * stop driving Xilinx-related signals
+ */
+ lmc_gpio_mkinput(sc, LMC_GEP_RESET);
+
+ /*
+ * Call media specific init routine
+ */
+ sc->lmc_media->init(sc);
+
+ sc->stats.resetCount++;
+ lmc_trace(sc->lmc_device, "lmc_reset out");
+}
+
+static void lmc_dec_reset(lmc_softc_t * const sc) /*fold00*/
+{
+ u_int32_t val;
+ lmc_trace(sc->lmc_device, "lmc_dec_reset in");
+
+ /*
+ * disable all interrupts
+ */
+ sc->lmc_intrmask = 0;
+ LMC_CSR_WRITE(sc, csr_intr, sc->lmc_intrmask);
+
+ /*
+ * Reset the chip with a software reset command.
+ * Wait 10 microseconds (actually 50 PCI cycles but at
+ * 33MHz that comes to two microseconds but wait a
+ * bit longer anyways)
+ */
+ LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+ udelay(25);
+#ifdef __sparc__
+ sc->lmc_busmode = LMC_CSR_READ(sc, csr_busmode);
+ sc->lmc_busmode = 0x00100000;
+ sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET;
+ LMC_CSR_WRITE(sc, csr_busmode, sc->lmc_busmode);
+#endif
+ sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command);
+
+ /*
+ * We want:
+ * no ethernet address in frames we write
+ * disable padding (txdesc, padding disable)
+ * ignore runt frames (rdes0 bit 15)
+ * no receiver watchdog or transmitter jabber timer
+ * (csr15 bit 0,14 == 1)
+ * if using 16-bit CRC, turn off CRC (trans desc, crc disable)
+ */
+
+ sc->lmc_cmdmode |= ( TULIP_CMD_PROMISCUOUS
+ | TULIP_CMD_FULLDUPLEX
+ | TULIP_CMD_PASSBADPKT
+ | TULIP_CMD_NOHEARTBEAT
+ | TULIP_CMD_PORTSELECT
+ | TULIP_CMD_RECEIVEALL
+ | TULIP_CMD_MUSTBEONE
+ );
+ sc->lmc_cmdmode &= ~( TULIP_CMD_OPERMODE
+ | TULIP_CMD_THRESHOLDCTL
+ | TULIP_CMD_STOREFWD
+ | TULIP_CMD_TXTHRSHLDCTL
+ );
+
+ LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
+
+ /*
+ * disable receiver watchdog and transmit jabber
+ */
+ val = LMC_CSR_READ(sc, csr_sia_general);
+ val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE);
+ LMC_CSR_WRITE(sc, csr_sia_general, val);
+
+ lmc_trace(sc->lmc_device, "lmc_dec_reset out");
+}
+
+static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, /*fold00*/
+ size_t csr_size)
+{
+ lmc_trace(sc->lmc_device, "lmc_initcsrs in");
+ sc->lmc_csrs.csr_busmode = csr_base + 0 * csr_size;
+ sc->lmc_csrs.csr_txpoll = csr_base + 1 * csr_size;
+ sc->lmc_csrs.csr_rxpoll = csr_base + 2 * csr_size;
+ sc->lmc_csrs.csr_rxlist = csr_base + 3 * csr_size;
+ sc->lmc_csrs.csr_txlist = csr_base + 4 * csr_size;
+ sc->lmc_csrs.csr_status = csr_base + 5 * csr_size;
+ sc->lmc_csrs.csr_command = csr_base + 6 * csr_size;
+ sc->lmc_csrs.csr_intr = csr_base + 7 * csr_size;
+ sc->lmc_csrs.csr_missed_frames = csr_base + 8 * csr_size;
+ sc->lmc_csrs.csr_9 = csr_base + 9 * csr_size;
+ sc->lmc_csrs.csr_10 = csr_base + 10 * csr_size;
+ sc->lmc_csrs.csr_11 = csr_base + 11 * csr_size;
+ sc->lmc_csrs.csr_12 = csr_base + 12 * csr_size;
+ sc->lmc_csrs.csr_13 = csr_base + 13 * csr_size;
+ sc->lmc_csrs.csr_14 = csr_base + 14 * csr_size;
+ sc->lmc_csrs.csr_15 = csr_base + 15 * csr_size;
+ lmc_trace(sc->lmc_device, "lmc_initcsrs out");
+}
+
+static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/
+ lmc_softc_t *sc;
+ u32 csr6;
+ unsigned long flags;
+
+ lmc_trace(dev, "lmc_driver_timeout in");
+
+ sc = dev->priv;
+
+ spin_lock_irqsave(&sc->lmc_lock, flags);
+
+ printk("%s: Xmitter busy|\n", dev->name);
+
+ sc->stats.tx_tbusy_calls++ ;
+ if (jiffies - dev->trans_start < TX_TIMEOUT) {
+ goto bug_out;
+ }
+
+ /*
+ * Chip seems to have locked up
+ * Reset it
+ * This whips out all our decriptor
+ * table and starts from scartch
+ */
+
+ LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
+ LMC_CSR_READ (sc, csr_status),
+ sc->stats.tx_ProcTimeout);
+
+ lmc_running_reset (dev);
+
+ LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
+ LMC_EVENT_LOG(LMC_EVENT_RESET2,
+ lmc_mii_readreg (sc, 0, 16),
+ lmc_mii_readreg (sc, 0, 17));
+
+ /* restart the tx processes */
+ csr6 = LMC_CSR_READ (sc, csr_command);
+ LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
+ LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
+
+ /* immediate transmit */
+ LMC_CSR_WRITE (sc, csr_txpoll, 0);
+
+ sc->stats.tx_errors++;
+ sc->stats.tx_ProcTimeout++; /* -baz */
+
+ dev->trans_start = jiffies;
+
+bug_out:
+
+ spin_unlock_irqrestore(&sc->lmc_lock, flags);
+
+ lmc_trace(dev, "lmc_driver_timout out");
+
+
+}
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
new file mode 100644
index 00000000000..f55ce76b00e
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -0,0 +1,1246 @@
+/* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/bitops.h>
+
+#include <net/syncppp.h>
+
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/uaccess.h>
+
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_ioctl.h"
+#include "lmc_debug.h"
+
+#define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License version 2, incorporated herein by reference.
+ */
+
+/*
+ * For lack of a better place, put the SSI cable stuff here.
+ */
+char *lmc_t1_cables[] = {
+ "V.10/RS423", "EIA530A", "reserved", "X.21", "V.35",
+ "EIA449/EIA530/V.36", "V.28/EIA232", "none", NULL
+};
+
+/*
+ * protocol independent method.
+ */
+static void lmc_set_protocol (lmc_softc_t * const, lmc_ctl_t *);
+
+/*
+ * media independent methods to check on media status, link, light LEDs,
+ * etc.
+ */
+static void lmc_ds3_init (lmc_softc_t * const);
+static void lmc_ds3_default (lmc_softc_t * const);
+static void lmc_ds3_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_ds3_set_100ft (lmc_softc_t * const, int);
+static int lmc_ds3_get_link_status (lmc_softc_t * const);
+static void lmc_ds3_set_crc_length (lmc_softc_t * const, int);
+static void lmc_ds3_set_scram (lmc_softc_t * const, int);
+static void lmc_ds3_watchdog (lmc_softc_t * const);
+
+static void lmc_hssi_init (lmc_softc_t * const);
+static void lmc_hssi_default (lmc_softc_t * const);
+static void lmc_hssi_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_hssi_set_clock (lmc_softc_t * const, int);
+static int lmc_hssi_get_link_status (lmc_softc_t * const);
+static void lmc_hssi_set_link_status (lmc_softc_t * const, int);
+static void lmc_hssi_set_crc_length (lmc_softc_t * const, int);
+static void lmc_hssi_watchdog (lmc_softc_t * const);
+
+static void lmc_ssi_init (lmc_softc_t * const);
+static void lmc_ssi_default (lmc_softc_t * const);
+static void lmc_ssi_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static void lmc_ssi_set_clock (lmc_softc_t * const, int);
+static void lmc_ssi_set_speed (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_ssi_get_link_status (lmc_softc_t * const);
+static void lmc_ssi_set_link_status (lmc_softc_t * const, int);
+static void lmc_ssi_set_crc_length (lmc_softc_t * const, int);
+static void lmc_ssi_watchdog (lmc_softc_t * const);
+
+static void lmc_t1_init (lmc_softc_t * const);
+static void lmc_t1_default (lmc_softc_t * const);
+static void lmc_t1_set_status (lmc_softc_t * const, lmc_ctl_t *);
+static int lmc_t1_get_link_status (lmc_softc_t * const);
+static void lmc_t1_set_circuit_type (lmc_softc_t * const, int);
+static void lmc_t1_set_crc_length (lmc_softc_t * const, int);
+static void lmc_t1_set_clock (lmc_softc_t * const, int);
+static void lmc_t1_watchdog (lmc_softc_t * const);
+
+static void lmc_dummy_set_1 (lmc_softc_t * const, int);
+static void lmc_dummy_set2_1 (lmc_softc_t * const, lmc_ctl_t *);
+
+static inline void write_av9110_bit (lmc_softc_t *, int);
+static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t);
+
+lmc_media_t lmc_ds3_media = {
+ lmc_ds3_init, /* special media init stuff */
+ lmc_ds3_default, /* reset to default state */
+ lmc_ds3_set_status, /* reset status to state provided */
+ lmc_dummy_set_1, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_ds3_set_100ft, /* set cable length */
+ lmc_ds3_set_scram, /* set scrambler */
+ lmc_ds3_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_ds3_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ds3_watchdog
+};
+
+lmc_media_t lmc_hssi_media = {
+ lmc_hssi_init, /* special media init stuff */
+ lmc_hssi_default, /* reset to default state */
+ lmc_hssi_set_status, /* reset status to state provided */
+ lmc_hssi_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_hssi_get_link_status, /* get link status */
+ lmc_hssi_set_link_status, /* set link status */
+ lmc_hssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_hssi_watchdog
+};
+
+lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
+ lmc_ssi_default, /* reset to default state */
+ lmc_ssi_set_status, /* reset status to state provided */
+ lmc_ssi_set_clock, /* set clock source */
+ lmc_ssi_set_speed, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_ssi_get_link_status, /* get link status */
+ lmc_ssi_set_link_status, /* set link status */
+ lmc_ssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ssi_watchdog
+};
+
+lmc_media_t lmc_t1_media = {
+ lmc_t1_init, /* special media init stuff */
+ lmc_t1_default, /* reset to default state */
+ lmc_t1_set_status, /* reset status to state provided */
+ lmc_t1_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_t1_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_t1_set_crc_length, /* set CRC length */
+ lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
+ lmc_t1_watchdog
+};
+
+static void
+lmc_dummy_set_1 (lmc_softc_t * const sc, int a)
+{
+}
+
+static void
+lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a)
+{
+}
+
+/*
+ * HSSI methods
+ */
+
+static void
+lmc_hssi_init (lmc_softc_t * const sc)
+{
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200;
+
+ lmc_gpio_mkoutput (sc, LMC_GEP_HSSI_CLOCK);
+}
+
+static void
+lmc_hssi_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it. This will
+ * always reset the card if needed.
+ */
+static void
+lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+
+ /*
+ * check for change in clock source
+ */
+ if (ctl->clock_source && !sc->ictl.clock_source)
+ {
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT);
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT;
+ }
+ else if (!ctl->clock_source && sc->ictl.clock_source)
+ {
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ }
+
+ lmc_set_protocol (sc, ctl);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_hssi_set_clock (lmc_softc_t * const sc, int ie)
+{
+ int old;
+ old = sc->ictl.clock_source;
+ if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_gpio |= LMC_GEP_HSSI_CLOCK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_gpio &= ~(LMC_GEP_HSSI_CLOCK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ }
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_hssi_get_link_status (lmc_softc_t * const sc)
+{
+ /*
+ * We're using the same code as SSI since
+ * they're practically the same
+ */
+ return lmc_ssi_get_link_status(sc);
+}
+
+static void
+lmc_hssi_set_link_status (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_LINK_UP)
+ sc->lmc_miireg16 |= LMC_MII16_HSSI_TA;
+ else
+ sc->lmc_miireg16 &= ~LMC_MII16_HSSI_TA;
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_HSSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ }
+ else
+ {
+ /* 16 bit */
+ sc->lmc_miireg16 &= ~LMC_MII16_HSSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_hssi_watchdog (lmc_softc_t * const sc)
+{
+ /* HSSI is blank */
+}
+
+/*
+ * DS3 methods
+ */
+
+/*
+ * Set cable length
+ */
+static void
+lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie)
+{
+ if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT)
+ {
+ sc->lmc_miireg16 &= ~LMC_MII16_DS3_ZERO;
+ sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_GT_100FT;
+ }
+ else if (ie == LMC_CTL_CABLE_LENGTH_LT_100FT)
+ {
+ sc->lmc_miireg16 |= LMC_MII16_DS3_ZERO;
+ sc->ictl.cable_length = LMC_CTL_CABLE_LENGTH_LT_100FT;
+ }
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_ds3_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_cable_length (sc, LMC_CTL_CABLE_LENGTH_LT_100FT);
+ sc->lmc_media->set_scrambler (sc, LMC_CTL_OFF);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it. This will
+ * always reset the card if needed.
+ */
+static void
+lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_cable_length (sc, sc->ictl.cable_length);
+ sc->lmc_media->set_scrambler (sc, sc->ictl.scrambler_onoff);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+
+ /*
+ * check for change in cable length setting
+ */
+ if (ctl->cable_length && !sc->ictl.cable_length)
+ lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_GT_100FT);
+ else if (!ctl->cable_length && sc->ictl.cable_length)
+ lmc_ds3_set_100ft (sc, LMC_CTL_CABLE_LENGTH_LT_100FT);
+
+ /*
+ * Check for change in scrambler setting (requires reset)
+ */
+ if (ctl->scrambler_onoff && !sc->ictl.scrambler_onoff)
+ lmc_ds3_set_scram (sc, LMC_CTL_ON);
+ else if (!ctl->scrambler_onoff && sc->ictl.scrambler_onoff)
+ lmc_ds3_set_scram (sc, LMC_CTL_OFF);
+
+ lmc_set_protocol (sc, ctl);
+}
+
+static void
+lmc_ds3_init (lmc_softc_t * const sc)
+{
+ int i;
+
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5245;
+
+ /* writes zeros everywhere */
+ for (i = 0; i < 21; i++)
+ {
+ lmc_mii_writereg (sc, 0, 17, i);
+ lmc_mii_writereg (sc, 0, 18, 0);
+ }
+
+ /* set some essential bits */
+ lmc_mii_writereg (sc, 0, 17, 1);
+ lmc_mii_writereg (sc, 0, 18, 0x25); /* ser, xtx */
+
+ lmc_mii_writereg (sc, 0, 17, 5);
+ lmc_mii_writereg (sc, 0, 18, 0x80); /* emode */
+
+ lmc_mii_writereg (sc, 0, 17, 14);
+ lmc_mii_writereg (sc, 0, 18, 0x30); /* rcgen, tcgen */
+
+ /* clear counters and latched bits */
+ for (i = 0; i < 21; i++)
+ {
+ lmc_mii_writereg (sc, 0, 17, i);
+ lmc_mii_readreg (sc, 0, 18);
+ }
+}
+
+/*
+ * 1 == DS3 payload scrambled, 0 == not scrambled
+ */
+static void
+lmc_ds3_set_scram (lmc_softc_t * const sc, int ie)
+{
+ if (ie == LMC_CTL_ON)
+ {
+ sc->lmc_miireg16 |= LMC_MII16_DS3_SCRAM;
+ sc->ictl.scrambler_onoff = LMC_CTL_ON;
+ }
+ else
+ {
+ sc->lmc_miireg16 &= ~LMC_MII16_DS3_SCRAM;
+ sc->ictl.scrambler_onoff = LMC_CTL_OFF;
+ }
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_ds3_get_link_status (lmc_softc_t * const sc)
+{
+ u_int16_t link_status, link_status_11;
+ int ret = 1;
+
+ lmc_mii_writereg (sc, 0, 17, 7);
+ link_status = lmc_mii_readreg (sc, 0, 18);
+
+ /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions
+ * led0 yellow = far-end adapter is in Red alarm condition
+ * led1 blue = received an Alarm Indication signal
+ * (upstream failure)
+ * led2 Green = power to adapter, Gate Array loaded & driver
+ * attached
+ * led3 red = Loss of Signal (LOS) or out of frame (OOF)
+ * conditions detected on T3 receive signal
+ */
+
+ lmc_led_on(sc, LMC_DS3_LED2);
+
+ if ((link_status & LMC_FRAMER_REG0_DLOS) ||
+ (link_status & LMC_FRAMER_REG0_OOFS)){
+ ret = 0;
+ if(sc->last_led_err[3] != 1){
+ u16 r1;
+ lmc_mii_writereg (sc, 0, 17, 01); /* Turn on Xbit error as our cisco does */
+ r1 = lmc_mii_readreg (sc, 0, 18);
+ r1 &= 0xfe;
+ lmc_mii_writereg(sc, 0, 18, r1);
+ printk(KERN_WARNING "%s: Red Alarm - Loss of Signal or Loss of Framing\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED3); /* turn on red LED */
+ sc->last_led_err[3] = 1;
+ }
+ else {
+ lmc_led_off(sc, LMC_DS3_LED3); /* turn on red LED */
+ if(sc->last_led_err[3] == 1){
+ u16 r1;
+ lmc_mii_writereg (sc, 0, 17, 01); /* Turn off Xbit error */
+ r1 = lmc_mii_readreg (sc, 0, 18);
+ r1 |= 0x01;
+ lmc_mii_writereg(sc, 0, 18, r1);
+ }
+ sc->last_led_err[3] = 0;
+ }
+
+ lmc_mii_writereg(sc, 0, 17, 0x10);
+ link_status_11 = lmc_mii_readreg(sc, 0, 18);
+ if((link_status & LMC_FRAMER_REG0_AIS) ||
+ (link_status_11 & LMC_FRAMER_REG10_XBIT)) {
+ ret = 0;
+ if(sc->last_led_err[0] != 1){
+ printk(KERN_WARNING "%s: AIS Alarm or XBit Error\n", sc->name);
+ printk(KERN_WARNING "%s: Remote end has loss of signal or framing\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 1;
+ }
+ else {
+ lmc_led_off(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 0;
+ }
+
+ lmc_mii_writereg (sc, 0, 17, 9);
+ link_status = lmc_mii_readreg (sc, 0, 18);
+
+ if(link_status & LMC_FRAMER_REG9_RBLUE){
+ ret = 0;
+ if(sc->last_led_err[1] != 1){
+ printk(KERN_WARNING "%s: Blue Alarm - Receiving all 1's\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 1;
+ }
+ else {
+ lmc_led_off(sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_DS3_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ }
+ else
+ {
+ /* 16 bit */
+ sc->lmc_miireg16 &= ~LMC_MII16_DS3_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+static void
+lmc_ds3_watchdog (lmc_softc_t * const sc)
+{
+
+}
+
+
+/*
+ * SSI methods
+ */
+
+static void
+lmc_ssi_init (lmc_softc_t * const sc)
+{
+ u_int16_t mii17;
+ int cable;
+
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1000;
+
+ mii17 = lmc_mii_readreg (sc, 0, 17);
+
+ cable = (mii17 & LMC_MII17_SSI_CABLE_MASK) >> LMC_MII17_SSI_CABLE_SHIFT;
+ sc->ictl.cable_type = cable;
+
+ lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK);
+}
+
+static void
+lmc_ssi_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+
+ /*
+ * make TXCLOCK always be an output
+ */
+ lmc_gpio_mkoutput (sc, LMC_GEP_SSI_TXCLOCK);
+
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ sc->lmc_media->set_speed (sc, NULL);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+}
+
+/*
+ * Given a user provided state, set ourselves up to match it. This will
+ * always reset the card if needed.
+ */
+static void
+lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_clock_source (sc, sc->ictl.clock_source);
+ sc->lmc_media->set_speed (sc, &sc->ictl);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+
+ /*
+ * check for change in clock source
+ */
+ if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_INT
+ && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_INT);
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_INT;
+ }
+ else if (ctl->clock_source == LMC_CTL_CLOCK_SOURCE_EXT
+ && sc->ictl.clock_source == LMC_CTL_CLOCK_SOURCE_INT)
+ {
+ sc->lmc_media->set_clock_source (sc, LMC_CTL_CLOCK_SOURCE_EXT);
+ sc->lmc_timing = LMC_CTL_CLOCK_SOURCE_EXT;
+ }
+
+ if (ctl->clock_rate != sc->ictl.clock_rate)
+ sc->lmc_media->set_speed (sc, ctl);
+
+ lmc_set_protocol (sc, ctl);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_ssi_set_clock (lmc_softc_t * const sc, int ie)
+{
+ int old;
+ old = ie;
+ if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+ if(ie != old)
+ printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+ if(ie != old)
+ printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ }
+}
+
+static void
+lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ lmc_ctl_t *ictl = &sc->ictl;
+ lmc_av9110_t *av;
+
+ /* original settings for clock rate of:
+ * 100 Khz (8,25,0,0,2) were incorrect
+ * they should have been 80,125,1,3,3
+ * There are 17 param combinations to produce this freq.
+ * For 1.5 Mhz use 120,100,1,1,2 (226 param. combinations)
+ */
+ if (ctl == NULL)
+ {
+ av = &ictl->cardspec.ssi;
+ ictl->clock_rate = 1500000;
+ av->f = ictl->clock_rate;
+ av->n = 120;
+ av->m = 100;
+ av->v = 1;
+ av->x = 1;
+ av->r = 2;
+
+ write_av9110 (sc, av->n, av->m, av->v, av->x, av->r);
+ return;
+ }
+
+ av = &ctl->cardspec.ssi;
+
+ if (av->f == 0)
+ return;
+
+ ictl->clock_rate = av->f; /* really, this is the rate we are */
+ ictl->cardspec.ssi = *av;
+
+ write_av9110 (sc, av->n, av->m, av->v, av->x, av->r);
+}
+
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */
+static int
+lmc_ssi_get_link_status (lmc_softc_t * const sc)
+{
+ u_int16_t link_status;
+ u_int32_t ticks;
+ int ret = 1;
+ int hw_hdsk = 1;
+
+ /*
+ * missing CTS? Hmm. If we require CTS on, we may never get the
+ * link to come up, so omit it in this test.
+ *
+ * Also, it seems that with a loopback cable, DCD isn't asserted,
+ * so just check for things like this:
+ * DSR _must_ be asserted.
+ * One of DCD or CTS must be asserted.
+ */
+
+ /* LMC 1000 (SSI) LED definitions
+ * led0 Green = power to adapter, Gate Array loaded &
+ * driver attached
+ * led1 Green = DSR and DTR and RTS and CTS are set
+ * led2 Green = Cable detected
+ * led3 red = No timing is available from the
+ * cable or the on-board frequency
+ * generator.
+ */
+
+ link_status = lmc_mii_readreg (sc, 0, 16);
+
+ /* Is the transmit clock still available */
+ ticks = LMC_CSR_READ (sc, csr_gp_timer);
+ ticks = 0x0000ffff - (ticks & 0x0000ffff);
+
+ lmc_led_on (sc, LMC_MII16_LED0);
+
+ /* ====== transmit clock determination ===== */
+ if (sc->lmc_timing == LMC_CTL_CLOCK_SOURCE_INT) {
+ lmc_led_off(sc, LMC_MII16_LED3);
+ }
+ else if (ticks == 0 ) { /* no clock found ? */
+ ret = 0;
+ if(sc->last_led_err[3] != 1){
+ sc->stats.tx_lossOfClockCnt++;
+ printk(KERN_WARNING "%s: Lost Clock, Link Down\n", sc->name);
+ }
+ sc->last_led_err[3] = 1;
+ lmc_led_on (sc, LMC_MII16_LED3); /* turn ON red LED */
+ }
+ else {
+ if(sc->last_led_err[3] == 1)
+ printk(KERN_WARNING "%s: Clock Returned\n", sc->name);
+ sc->last_led_err[3] = 0;
+ lmc_led_off (sc, LMC_MII16_LED3); /* turn OFF red LED */
+ }
+
+ if ((link_status & LMC_MII16_SSI_DSR) == 0) { /* Also HSSI CA */
+ ret = 0;
+ hw_hdsk = 0;
+ }
+
+#ifdef CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE
+ if ((link_status & (LMC_MII16_SSI_CTS | LMC_MII16_SSI_DCD)) == 0){
+ ret = 0;
+ hw_hdsk = 0;
+ }
+#endif
+
+ if(hw_hdsk == 0){
+ if(sc->last_led_err[1] != 1)
+ printk(KERN_WARNING "%s: DSR not asserted\n", sc->name);
+ sc->last_led_err[1] = 1;
+ lmc_led_off(sc, LMC_MII16_LED1);
+ }
+ else {
+ if(sc->last_led_err[1] != 0)
+ printk(KERN_WARNING "%s: DSR now asserted\n", sc->name);
+ sc->last_led_err[1] = 0;
+ lmc_led_on(sc, LMC_MII16_LED1);
+ }
+
+ if(ret == 1) {
+ lmc_led_on(sc, LMC_MII16_LED2); /* Over all good status? */
+ }
+
+ return ret;
+}
+
+static void
+lmc_ssi_set_link_status (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_LINK_UP)
+ {
+ sc->lmc_miireg16 |= (LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
+ printk (LMC_PRINTF_FMT ": asserting DTR and RTS\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_miireg16 &= ~(LMC_MII16_SSI_DTR | LMC_MII16_SSI_RTS);
+ printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS);
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit
+ */
+static void
+lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_SSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
+
+ }
+ else
+ {
+ /* 16 bit */
+ sc->lmc_miireg16 &= ~LMC_MII16_SSI_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * These are bits to program the ssi frequency generator
+ */
+static inline void
+write_av9110_bit (lmc_softc_t * sc, int c)
+{
+ /*
+ * set the data bit as we need it.
+ */
+ sc->lmc_gpio &= ~(LMC_GEP_CLK);
+ if (c & 0x01)
+ sc->lmc_gpio |= LMC_GEP_DATA;
+ else
+ sc->lmc_gpio &= ~(LMC_GEP_DATA);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * set the clock to high
+ */
+ sc->lmc_gpio |= LMC_GEP_CLK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * set the clock to low again.
+ */
+ sc->lmc_gpio &= ~(LMC_GEP_CLK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+}
+
+static void
+write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v,
+ u_int32_t x, u_int32_t r)
+{
+ int i;
+
+#if 0
+ printk (LMC_PRINTF_FMT ": speed %u, %d %d %d %d %d\n",
+ LMC_PRINTF_ARGS, sc->ictl.clock_rate, n, m, v, x, r);
+#endif
+
+ sc->lmc_gpio |= LMC_GEP_SSI_GENERATOR;
+ sc->lmc_gpio &= ~(LMC_GEP_DATA | LMC_GEP_CLK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * Set the TXCLOCK, GENERATOR, SERIAL, and SERIALCLK
+ * as outputs.
+ */
+ lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK
+ | LMC_GEP_SSI_GENERATOR));
+
+ sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+
+ /*
+ * a shifting we will go...
+ */
+ for (i = 0; i < 7; i++)
+ write_av9110_bit (sc, n >> i);
+ for (i = 0; i < 7; i++)
+ write_av9110_bit (sc, m >> i);
+ for (i = 0; i < 1; i++)
+ write_av9110_bit (sc, v >> i);
+ for (i = 0; i < 2; i++)
+ write_av9110_bit (sc, x >> i);
+ for (i = 0; i < 2; i++)
+ write_av9110_bit (sc, r >> i);
+ for (i = 0; i < 5; i++)
+ write_av9110_bit (sc, 0x17 >> i);
+
+ /*
+ * stop driving serial-related signals
+ */
+ lmc_gpio_mkinput (sc,
+ (LMC_GEP_DATA | LMC_GEP_CLK
+ | LMC_GEP_SSI_GENERATOR));
+}
+
+static void
+lmc_ssi_watchdog (lmc_softc_t * const sc)
+{
+ u_int16_t mii17;
+ struct ssicsr2
+ {
+ unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1,
+ led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1;
+ };
+ struct ssicsr2 *ssicsr;
+ mii17 = lmc_mii_readreg (sc, 0, 17);
+ ssicsr = (struct ssicsr2 *) &mii17;
+ if (ssicsr->cable == 7)
+ {
+ lmc_led_off (sc, LMC_MII16_LED2);
+ }
+ else
+ {
+ lmc_led_on (sc, LMC_MII16_LED2);
+ }
+
+}
+
+/*
+ * T1 methods
+ */
+
+/*
+ * The framer regs are multiplexed through MII regs 17 & 18
+ * write the register address to MII reg 17 and the * data to MII reg 18. */
+static void
+lmc_t1_write (lmc_softc_t * const sc, int a, int d)
+{
+ lmc_mii_writereg (sc, 0, 17, a);
+ lmc_mii_writereg (sc, 0, 18, d);
+}
+
+/* Save a warning
+static int
+lmc_t1_read (lmc_softc_t * const sc, int a)
+{
+ lmc_mii_writereg (sc, 0, 17, a);
+ return lmc_mii_readreg (sc, 0, 18);
+}
+*/
+
+
+static void
+lmc_t1_init (lmc_softc_t * const sc)
+{
+ u_int16_t mii16;
+ int i;
+
+ sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200;
+ mii16 = lmc_mii_readreg (sc, 0, 16);
+
+ /* reset 8370 */
+ mii16 &= ~LMC_MII16_T1_RST;
+ lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST);
+ lmc_mii_writereg (sc, 0, 16, mii16);
+
+ /* set T1 or E1 line. Uses sc->lmcmii16 reg in function so update it */
+ sc->lmc_miireg16 = mii16;
+ lmc_t1_set_circuit_type(sc, LMC_CTL_CIRCUIT_TYPE_T1);
+ mii16 = sc->lmc_miireg16;
+
+ lmc_t1_write (sc, 0x01, 0x1B); /* CR0 - primary control */
+ lmc_t1_write (sc, 0x02, 0x42); /* JAT_CR - jitter atten config */
+ lmc_t1_write (sc, 0x14, 0x00); /* LOOP - loopback config */
+ lmc_t1_write (sc, 0x15, 0x00); /* DL3_TS - external data link timeslot */
+ lmc_t1_write (sc, 0x18, 0xFF); /* PIO - programmable I/O */
+ lmc_t1_write (sc, 0x19, 0x30); /* POE - programmable OE */
+ lmc_t1_write (sc, 0x1A, 0x0F); /* CMUX - clock input mux */
+ lmc_t1_write (sc, 0x20, 0x41); /* LIU_CR - RX LIU config */
+ lmc_t1_write (sc, 0x22, 0x76); /* RLIU_CR - RX LIU config */
+ lmc_t1_write (sc, 0x40, 0x03); /* RCR0 - RX config */
+ lmc_t1_write (sc, 0x45, 0x00); /* RALM - RX alarm config */
+ lmc_t1_write (sc, 0x46, 0x05); /* LATCH - RX alarm/err/cntr latch */
+ lmc_t1_write (sc, 0x68, 0x40); /* TLIU_CR - TX LIU config */
+ lmc_t1_write (sc, 0x70, 0x0D); /* TCR0 - TX framer config */
+ lmc_t1_write (sc, 0x71, 0x05); /* TCR1 - TX config */
+ lmc_t1_write (sc, 0x72, 0x0B); /* TFRM - TX frame format */
+ lmc_t1_write (sc, 0x73, 0x00); /* TERROR - TX error insert */
+ lmc_t1_write (sc, 0x74, 0x00); /* TMAN - TX manual Sa/FEBE config */
+ lmc_t1_write (sc, 0x75, 0x00); /* TALM - TX alarm signal config */
+ lmc_t1_write (sc, 0x76, 0x00); /* TPATT - TX test pattern config */
+ lmc_t1_write (sc, 0x77, 0x00); /* TLB - TX inband loopback config */
+ lmc_t1_write (sc, 0x90, 0x05); /* CLAD_CR - clock rate adapter config */
+ lmc_t1_write (sc, 0x91, 0x05); /* CSEL - clad freq sel */
+ lmc_t1_write (sc, 0xA6, 0x00); /* DL1_CTL - DL1 control */
+ lmc_t1_write (sc, 0xB1, 0x00); /* DL2_CTL - DL2 control */
+ lmc_t1_write (sc, 0xD0, 0x47); /* SBI_CR - sys bus iface config */
+ lmc_t1_write (sc, 0xD1, 0x70); /* RSB_CR - RX sys bus config */
+ lmc_t1_write (sc, 0xD4, 0x30); /* TSB_CR - TX sys bus config */
+ for (i = 0; i < 32; i++)
+ {
+ lmc_t1_write (sc, 0x0E0 + i, 0x00); /* SBCn - sys bus per-channel ctl */
+ lmc_t1_write (sc, 0x100 + i, 0x00); /* TPCn - TX per-channel ctl */
+ lmc_t1_write (sc, 0x180 + i, 0x00); /* RPCn - RX per-channel ctl */
+ }
+ for (i = 1; i < 25; i++)
+ {
+ lmc_t1_write (sc, 0x0E0 + i, 0x0D); /* SBCn - sys bus per-channel ctl */
+ }
+
+ mii16 |= LMC_MII16_T1_XOE;
+ lmc_mii_writereg (sc, 0, 16, mii16);
+ sc->lmc_miireg16 = mii16;
+}
+
+static void
+lmc_t1_default (lmc_softc_t * const sc)
+{
+ sc->lmc_miireg16 = LMC_MII16_LED_ALL;
+ sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
+ sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1);
+ sc->lmc_media->set_crc_length (sc, LMC_CTL_CRC_LENGTH_16);
+ /* Right now we can only clock from out internal source */
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+}
+/* * Given a user provided state, set ourselves up to match it. This will * always reset the card if needed.
+ */
+static void
+lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == NULL)
+ {
+ sc->lmc_media->set_circuit_type (sc, sc->ictl.circuit_type);
+ lmc_set_protocol (sc, NULL);
+
+ return;
+ }
+ /*
+ * check for change in circuit type */
+ if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_T1
+ && sc->ictl.circuit_type ==
+ LMC_CTL_CIRCUIT_TYPE_E1) sc->lmc_media->set_circuit_type (sc,
+ LMC_CTL_CIRCUIT_TYPE_E1);
+ else if (ctl->circuit_type == LMC_CTL_CIRCUIT_TYPE_E1
+ && sc->ictl.circuit_type == LMC_CTL_CIRCUIT_TYPE_T1)
+ sc->lmc_media->set_circuit_type (sc, LMC_CTL_CIRCUIT_TYPE_T1);
+ lmc_set_protocol (sc, ctl);
+}
+/*
+ * return hardware link status.
+ * 0 == link is down, 1 == link is up.
+ */ static int
+lmc_t1_get_link_status (lmc_softc_t * const sc)
+{
+ u_int16_t link_status;
+ int ret = 1;
+
+ /* LMC5245 (DS3) & LMC1200 (DS1) LED definitions
+ * led0 yellow = far-end adapter is in Red alarm condition
+ * led1 blue = received an Alarm Indication signal
+ * (upstream failure)
+ * led2 Green = power to adapter, Gate Array loaded & driver
+ * attached
+ * led3 red = Loss of Signal (LOS) or out of frame (OOF)
+ * conditions detected on T3 receive signal
+ */
+ lmc_trace(sc->lmc_device, "lmc_t1_get_link_status in");
+ lmc_led_on(sc, LMC_DS3_LED2);
+
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM1_STATUS);
+ link_status = lmc_mii_readreg (sc, 0, 18);
+
+
+ if (link_status & T1F_RAIS) { /* turn on blue LED */
+ ret = 0;
+ if(sc->last_led_err[1] != 1){
+ printk(KERN_WARNING "%s: Receive AIS/Blue Alarm. Far end in RED alarm\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 1;
+ }
+ else {
+ if(sc->last_led_err[1] != 0){
+ printk(KERN_WARNING "%s: End AIS/Blue Alarm\n", sc->name);
+ }
+ lmc_led_off (sc, LMC_DS3_LED1);
+ sc->last_led_err[1] = 0;
+ }
+
+ /*
+ * Yellow Alarm is nasty evil stuff, looks at data patterns
+ * inside the channel and confuses it with HDLC framing
+ * ignore all yellow alarms.
+ *
+ * Do listen to MultiFrame Yellow alarm which while implemented
+ * different ways isn't in the channel and hence somewhat
+ * more reliable
+ */
+
+ if (link_status & T1F_RMYEL) {
+ ret = 0;
+ if(sc->last_led_err[0] != 1){
+ printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 1;
+ }
+ else {
+ if(sc->last_led_err[0] != 0){
+ printk(KERN_WARNING "%s: End of Yellow AIS Alarm\n", sc->name);
+ }
+ lmc_led_off(sc, LMC_DS3_LED0);
+ sc->last_led_err[0] = 0;
+ }
+
+ /*
+ * Loss of signal and los of frame
+ * Use the green bit to identify which one lit the led
+ */
+ if(link_status & T1F_RLOF){
+ ret = 0;
+ if(sc->last_led_err[3] != 1){
+ printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED3);
+ sc->last_led_err[3] = 1;
+
+ }
+ else {
+ if(sc->last_led_err[3] != 0){
+ printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name);
+ }
+ if( ! (link_status & T1F_RLOS))
+ lmc_led_off(sc, LMC_DS3_LED3);
+ sc->last_led_err[3] = 0;
+ }
+
+ if(link_status & T1F_RLOS){
+ ret = 0;
+ if(sc->last_led_err[2] != 1){
+ printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name);
+ }
+ lmc_led_on(sc, LMC_DS3_LED3);
+ sc->last_led_err[2] = 1;
+
+ }
+ else {
+ if(sc->last_led_err[2] != 0){
+ printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name);
+ }
+ if( ! (link_status & T1F_RLOF))
+ lmc_led_off(sc, LMC_DS3_LED3);
+ sc->last_led_err[2] = 0;
+ }
+
+ sc->lmc_xinfo.t1_alarm1_status = link_status;
+
+ lmc_mii_writereg (sc, 0, 17, T1FRAMER_ALARM2_STATUS);
+ sc->lmc_xinfo.t1_alarm2_status = lmc_mii_readreg (sc, 0, 18);
+
+
+ lmc_trace(sc->lmc_device, "lmc_t1_get_link_status out");
+
+ return ret;
+}
+
+/*
+ * 1 == T1 Circuit Type , 0 == E1 Circuit Type
+ */
+static void
+lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie)
+{
+ if (ie == LMC_CTL_CIRCUIT_TYPE_T1) {
+ sc->lmc_miireg16 |= LMC_MII16_T1_Z;
+ sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_T1;
+ printk(KERN_INFO "%s: In T1 Mode\n", sc->name);
+ }
+ else {
+ sc->lmc_miireg16 &= ~LMC_MII16_T1_Z;
+ sc->ictl.circuit_type = LMC_CTL_CIRCUIT_TYPE_E1;
+ printk(KERN_INFO "%s: In E1 Mode\n", sc->name);
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+
+}
+
+/*
+ * 0 == 16bit, 1 == 32bit */
+static void
+lmc_t1_set_crc_length (lmc_softc_t * const sc, int state)
+{
+ if (state == LMC_CTL_CRC_LENGTH_32)
+ {
+ /* 32 bit */
+ sc->lmc_miireg16 |= LMC_MII16_T1_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_32;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
+
+ }
+ else
+ {
+ /* 16 bit */ sc->lmc_miireg16 &= ~LMC_MII16_T1_CRC;
+ sc->ictl.crc_length = LMC_CTL_CRC_LENGTH_16;
+ sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_2;
+
+ }
+
+ lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
+}
+
+/*
+ * 1 == internal, 0 == external
+ */
+static void
+lmc_t1_set_clock (lmc_softc_t * const sc, int ie)
+{
+ int old;
+ old = ie;
+ if (ie == LMC_CTL_CLOCK_SOURCE_EXT)
+ {
+ sc->lmc_gpio &= ~(LMC_GEP_SSI_TXCLOCK);
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_EXT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+ }
+ else
+ {
+ sc->lmc_gpio |= LMC_GEP_SSI_TXCLOCK;
+ LMC_CSR_WRITE (sc, csr_gp, sc->lmc_gpio);
+ sc->ictl.clock_source = LMC_CTL_CLOCK_SOURCE_INT;
+ if(old != ie)
+ printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+ }
+}
+
+static void
+lmc_t1_watchdog (lmc_softc_t * const sc)
+{
+}
+
+static void
+lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+{
+ if (ctl == 0)
+ {
+ sc->ictl.keepalive_onoff = LMC_CTL_ON;
+
+ return;
+ }
+}
diff --git a/drivers/net/wan/lmc/lmc_media.h b/drivers/net/wan/lmc/lmc_media.h
new file mode 100644
index 00000000000..ddcc0040356
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_media.h
@@ -0,0 +1,65 @@
+#ifndef _LMC_MEDIA_H_
+#define _LMC_MEDIA_H_
+
+lmc_media_t lmc_ds3_media = {
+ lmc_ds3_init, /* special media init stuff */
+ lmc_ds3_default, /* reset to default state */
+ lmc_ds3_set_status, /* reset status to state provided */
+ lmc_dummy_set_1, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_ds3_set_100ft, /* set cable length */
+ lmc_ds3_set_scram, /* set scrambler */
+ lmc_ds3_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_ds3_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ds3_watchdog
+};
+
+lmc_media_t lmc_hssi_media = {
+ lmc_hssi_init, /* special media init stuff */
+ lmc_hssi_default, /* reset to default state */
+ lmc_hssi_set_status, /* reset status to state provided */
+ lmc_hssi_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_hssi_get_link_status, /* get link status */
+ lmc_hssi_set_link_status, /* set link status */
+ lmc_hssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_hssi_watchdog
+};
+
+lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
+ lmc_ssi_default, /* reset to default state */
+ lmc_ssi_set_status, /* reset status to state provided */
+ lmc_ssi_set_clock, /* set clock source */
+ lmc_ssi_set_speed, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_ssi_get_link_status, /* get link status */
+ lmc_ssi_set_link_status, /* set link status */
+ lmc_ssi_set_crc_length, /* set CRC length */
+ lmc_dummy_set_1, /* set T1 or E1 circuit type */
+ lmc_ssi_watchdog
+};
+
+lmc_media_t lmc_t1_media = {
+ lmc_t1_init, /* special media init stuff */
+ lmc_t1_default, /* reset to default state */
+ lmc_t1_set_status, /* reset status to state provided */
+ lmc_t1_set_clock, /* set clock source */
+ lmc_dummy_set2_1, /* set line speed */
+ lmc_dummy_set_1, /* set cable length */
+ lmc_dummy_set_1, /* set scrambler */
+ lmc_t1_get_link_status, /* get link status */
+ lmc_dummy_set_1, /* set link status */
+ lmc_t1_set_crc_length, /* set CRC length */
+ lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
+ lmc_t1_watchdog
+};
+
+
+#endif
+
diff --git a/drivers/net/wan/lmc/lmc_prot.h b/drivers/net/wan/lmc/lmc_prot.h
new file mode 100644
index 00000000000..f3b1df9e2cd
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_prot.h
@@ -0,0 +1,15 @@
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t * const)
+void lmc_proto_attach(lmc_softc_t *sc const)
+void lmc_proto_detach(lmc_softc *sc const)
+void lmc_proto_reopen(lmc_softc_t *sc const)
+int lmc_proto_ioctl(lmc_softc_t *sc const, struct ifreq *ifr, int cmd)
+void lmc_proto_open(lmc_softc_t *sc const)
+void lmc_proto_close(lmc_softc_t *sc const)
+unsigned short lmc_proto_type(lmc_softc_t *sc const, struct skbuff *skb)
+
+
+#endif
+
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
new file mode 100644
index 00000000000..74876c0073e
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -0,0 +1,249 @@
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * With Help By:
+ * David Boggs
+ * Ron Crane
+ * Allan Cox
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License version 2, incorporated herein by reference.
+ *
+ * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/bitops.h>
+
+#include <net/syncppp.h>
+
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/smp.h>
+
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_debug.h"
+#include "lmc_ioctl.h"
+#include "lmc_proto.h"
+
+/*
+ * The compile-time variable SPPPSTUP causes the module to be
+ * compiled without referencing any of the sync ppp routines.
+ */
+#ifdef SPPPSTUB
+#define SPPP_detach(d) (void)0
+#define SPPP_open(d) 0
+#define SPPP_reopen(d) (void)0
+#define SPPP_close(d) (void)0
+#define SPPP_attach(d) (void)0
+#define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP
+#else
+#define SPPP_attach(x) sppp_attach((x)->pd)
+#define SPPP_detach(x) sppp_detach((x)->pd->dev)
+#define SPPP_open(x) sppp_open((x)->pd->dev)
+#define SPPP_reopen(x) sppp_reopen((x)->pd->dev)
+#define SPPP_close(x) sppp_close((x)->pd->dev)
+#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->pd->dev, (y), (z))
+#endif
+
+// init
+void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_init in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+ if (!sc->pd) {
+ printk("lmc_proto_init(): kmalloc failure!\n");
+ return;
+ }
+ sc->pd->dev = sc->lmc_device;
+ sc->if_ptr = sc->pd;
+ break;
+ case LMC_RAW:
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_init out");
+}
+
+// attach
+void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_attach in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ {
+ struct net_device *dev = sc->lmc_device;
+ SPPP_attach(sc);
+ dev->do_ioctl = lmc_ioctl;
+ }
+ break;
+ case LMC_NET:
+ {
+ struct net_device *dev = sc->lmc_device;
+ /*
+ * They set a few basics because they don't use sync_ppp
+ */
+ dev->flags |= IFF_POINTOPOINT;
+ dev->hard_header = NULL;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ }
+ case LMC_RAW: /* Setup the task queue, maybe we should notify someone? */
+ {
+ }
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_attach out");
+}
+
+// detach
+void lmc_proto_detach(lmc_softc_t *sc) /*FOLD00*/
+{
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_detach(sc);
+ break;
+ case LMC_RAW: /* Tell someone we're detaching? */
+ break;
+ default:
+ break;
+ }
+
+}
+
+// reopen
+void lmc_proto_reopen(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_reopen in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_reopen(sc);
+ break;
+ case LMC_RAW: /* Reset the interface after being down, prerape to receive packets again */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_reopen out");
+}
+
+
+// ioctl
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+ switch(sc->if_type){
+ case LMC_PPP:
+ return SPPP_do_ioctl (sc, ifr, cmd);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_ioctl out");
+}
+
+// open
+void lmc_proto_open(lmc_softc_t *sc) /*FOLD00*/
+{
+ int ret;
+
+ lmc_trace(sc->lmc_device, "lmc_proto_open in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ ret = SPPP_open(sc);
+ if(ret < 0)
+ printk("%s: syncPPP open failed: %d\n", sc->name, ret);
+ break;
+ case LMC_RAW: /* We're about to start getting packets! */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_open out");
+}
+
+// close
+
+void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_close in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ SPPP_close(sc);
+ break;
+ case LMC_RAW: /* Interface going down */
+ break;
+ default:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_close out");
+}
+
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_type in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ return htons(ETH_P_WAN_PPP);
+ break;
+ case LMC_NET:
+ return htons(ETH_P_802_2);
+ break;
+ case LMC_RAW: /* Packet type for skbuff kind of useless */
+ return htons(ETH_P_802_2);
+ break;
+ default:
+ printk(KERN_WARNING "%s: No protocol set for this interface, assuming 802.2 (which is wrong!!)\n", sc->name);
+ return htons(ETH_P_802_2);
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_tye out");
+
+}
+
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+{
+ lmc_trace(sc->lmc_device, "lmc_proto_netif in");
+ switch(sc->if_type){
+ case LMC_PPP:
+ case LMC_NET:
+ default:
+ skb->dev->last_rx = jiffies;
+ netif_rx(skb);
+ break;
+ case LMC_RAW:
+ break;
+ }
+ lmc_trace(sc->lmc_device, "lmc_proto_netif out");
+}
+
diff --git a/drivers/net/wan/lmc/lmc_proto.h b/drivers/net/wan/lmc/lmc_proto.h
new file mode 100644
index 00000000000..080a5577334
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_proto.h
@@ -0,0 +1,16 @@
+#ifndef _LMC_PROTO_H_
+#define _LMC_PROTO_H_
+
+void lmc_proto_init(lmc_softc_t *sc);
+void lmc_proto_attach(lmc_softc_t *sc);
+void lmc_proto_detach(lmc_softc_t *sc);
+void lmc_proto_reopen(lmc_softc_t *sc);
+int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd);
+void lmc_proto_open(lmc_softc_t *sc);
+void lmc_proto_close(lmc_softc_t *sc);
+unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb);
+void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb);
+int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused);
+
+#endif
+
diff --git a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h
new file mode 100644
index 00000000000..6d003a39bfa
--- /dev/null
+++ b/drivers/net/wan/lmc/lmc_var.h
@@ -0,0 +1,570 @@
+#ifndef _LMC_VAR_H_
+#define _LMC_VAR_H_
+
+/* $Id: lmc_var.h,v 1.17 2000/04/06 12:16:47 asj Exp $ */
+
+ /*
+ * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
+ * All rights reserved. www.lanmedia.com
+ *
+ * This code is written by:
+ * Andrew Stanley-Jones (asj@cban.com)
+ * Rob Braun (bbraun@vix.com),
+ * Michael Graff (explorer@vix.com) and
+ * Matt Thomas (matt@3am-software.com).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License version 2, incorporated herein by reference.
+ */
+
+#include <linux/timer.h>
+
+#ifndef __KERNEL__
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+#define BITS_PER_LONG 32
+
+#endif
+
+/*
+ * basic definitions used in lmc include files
+ */
+
+typedef struct lmc___softc lmc_softc_t;
+typedef struct lmc___media lmc_media_t;
+typedef struct lmc___ctl lmc_ctl_t;
+
+#define lmc_csrptr_t unsigned long
+#define u_int16_t u16
+#define u_int8_t u8
+#define tulip_uint32_t u32
+
+#define LMC_REG_RANGE 0x80
+
+#define LMC_PRINTF_FMT "%s"
+#define LMC_PRINTF_ARGS (sc->lmc_device->name)
+
+#define TX_TIMEOUT (2*HZ)
+
+#define LMC_TXDESCS 32
+#define LMC_RXDESCS 32
+
+#define LMC_LINK_UP 1
+#define LMC_LINK_DOWN 0
+
+/* These macros for generic read and write to and from the dec chip */
+#define LMC_CSR_READ(sc, csr) \
+ inl((sc)->lmc_csrs.csr)
+#define LMC_CSR_WRITE(sc, reg, val) \
+ outl((val), (sc)->lmc_csrs.reg)
+
+//#ifdef _LINUX_DELAY_H
+// #define SLOW_DOWN_IO udelay(2);
+// #undef __SLOW_DOWN_IO
+// #define __SLOW_DOWN_IO udelay(2);
+//#endif
+
+#define DELAY(n) SLOW_DOWN_IO
+
+#define lmc_delay() inl(sc->lmc_csrs.csr_9)
+
+/* This macro sync's up with the mii so that reads and writes can take place */
+#define LMC_MII_SYNC(sc) do {int n=32; while( n >= 0 ) { \
+ LMC_CSR_WRITE((sc), csr_9, 0x20000); \
+ lmc_delay(); \
+ LMC_CSR_WRITE((sc), csr_9, 0x30000); \
+ lmc_delay(); \
+ n--; }} while(0)
+
+struct lmc_regfile_t {
+ lmc_csrptr_t csr_busmode; /* CSR0 */
+ lmc_csrptr_t csr_txpoll; /* CSR1 */
+ lmc_csrptr_t csr_rxpoll; /* CSR2 */
+ lmc_csrptr_t csr_rxlist; /* CSR3 */
+ lmc_csrptr_t csr_txlist; /* CSR4 */
+ lmc_csrptr_t csr_status; /* CSR5 */
+ lmc_csrptr_t csr_command; /* CSR6 */
+ lmc_csrptr_t csr_intr; /* CSR7 */
+ lmc_csrptr_t csr_missed_frames; /* CSR8 */
+ lmc_csrptr_t csr_9; /* CSR9 */
+ lmc_csrptr_t csr_10; /* CSR10 */
+ lmc_csrptr_t csr_11; /* CSR11 */
+ lmc_csrptr_t csr_12; /* CSR12 */
+ lmc_csrptr_t csr_13; /* CSR13 */
+ lmc_csrptr_t csr_14; /* CSR14 */
+ lmc_csrptr_t csr_15; /* CSR15 */
+};
+
+#define csr_enetrom csr_9 /* 21040 */
+#define csr_reserved csr_10 /* 21040 */
+#define csr_full_duplex csr_11 /* 21040 */
+#define csr_bootrom csr_10 /* 21041/21140A/?? */
+#define csr_gp csr_12 /* 21140* */
+#define csr_watchdog csr_15 /* 21140* */
+#define csr_gp_timer csr_11 /* 21041/21140* */
+#define csr_srom_mii csr_9 /* 21041/21140* */
+#define csr_sia_status csr_12 /* 2104x */
+#define csr_sia_connectivity csr_13 /* 2104x */
+#define csr_sia_tx_rx csr_14 /* 2104x */
+#define csr_sia_general csr_15 /* 2104x */
+
+/* tulip length/control transmit descriptor definitions
+ * used to define bits in the second tulip_desc_t field (length)
+ * for the transmit descriptor -baz */
+
+#define LMC_TDES_FIRST_BUFFER_SIZE ((u_int32_t)(0x000007FF))
+#define LMC_TDES_SECOND_BUFFER_SIZE ((u_int32_t)(0x003FF800))
+#define LMC_TDES_HASH_FILTERING ((u_int32_t)(0x00400000))
+#define LMC_TDES_DISABLE_PADDING ((u_int32_t)(0x00800000))
+#define LMC_TDES_SECOND_ADDR_CHAINED ((u_int32_t)(0x01000000))
+#define LMC_TDES_END_OF_RING ((u_int32_t)(0x02000000))
+#define LMC_TDES_ADD_CRC_DISABLE ((u_int32_t)(0x04000000))
+#define LMC_TDES_SETUP_PACKET ((u_int32_t)(0x08000000))
+#define LMC_TDES_INVERSE_FILTERING ((u_int32_t)(0x10000000))
+#define LMC_TDES_FIRST_SEGMENT ((u_int32_t)(0x20000000))
+#define LMC_TDES_LAST_SEGMENT ((u_int32_t)(0x40000000))
+#define LMC_TDES_INTERRUPT_ON_COMPLETION ((u_int32_t)(0x80000000))
+
+#define TDES_SECOND_BUFFER_SIZE_BIT_NUMBER 11
+#define TDES_COLLISION_COUNT_BIT_NUMBER 3
+
+/* Constants for the RCV descriptor RDES */
+
+#define LMC_RDES_OVERFLOW ((u_int32_t)(0x00000001))
+#define LMC_RDES_CRC_ERROR ((u_int32_t)(0x00000002))
+#define LMC_RDES_DRIBBLING_BIT ((u_int32_t)(0x00000004))
+#define LMC_RDES_REPORT_ON_MII_ERR ((u_int32_t)(0x00000008))
+#define LMC_RDES_RCV_WATCHDOG_TIMEOUT ((u_int32_t)(0x00000010))
+#define LMC_RDES_FRAME_TYPE ((u_int32_t)(0x00000020))
+#define LMC_RDES_COLLISION_SEEN ((u_int32_t)(0x00000040))
+#define LMC_RDES_FRAME_TOO_LONG ((u_int32_t)(0x00000080))
+#define LMC_RDES_LAST_DESCRIPTOR ((u_int32_t)(0x00000100))
+#define LMC_RDES_FIRST_DESCRIPTOR ((u_int32_t)(0x00000200))
+#define LMC_RDES_MULTICAST_FRAME ((u_int32_t)(0x00000400))
+#define LMC_RDES_RUNT_FRAME ((u_int32_t)(0x00000800))
+#define LMC_RDES_DATA_TYPE ((u_int32_t)(0x00003000))
+#define LMC_RDES_LENGTH_ERROR ((u_int32_t)(0x00004000))
+#define LMC_RDES_ERROR_SUMMARY ((u_int32_t)(0x00008000))
+#define LMC_RDES_FRAME_LENGTH ((u_int32_t)(0x3FFF0000))
+#define LMC_RDES_OWN_BIT ((u_int32_t)(0x80000000))
+
+#define RDES_FRAME_LENGTH_BIT_NUMBER 16
+
+#define LMC_RDES_ERROR_MASK ( (u_int32_t)( \
+ LMC_RDES_OVERFLOW \
+ | LMC_RDES_DRIBBLING_BIT \
+ | LMC_RDES_REPORT_ON_MII_ERR \
+ | LMC_RDES_COLLISION_SEEN ) )
+
+
+/*
+ * Ioctl info
+ */
+
+typedef struct {
+ u_int32_t n;
+ u_int32_t m;
+ u_int32_t v;
+ u_int32_t x;
+ u_int32_t r;
+ u_int32_t f;
+ u_int32_t exact;
+} lmc_av9110_t;
+
+/*
+ * Common structure passed to the ioctl code.
+ */
+struct lmc___ctl {
+ u_int32_t cardtype;
+ u_int32_t clock_source; /* HSSI, T1 */
+ u_int32_t clock_rate; /* T1 */
+ u_int32_t crc_length;
+ u_int32_t cable_length; /* DS3 */
+ u_int32_t scrambler_onoff; /* DS3 */
+ u_int32_t cable_type; /* T1 */
+ u_int32_t keepalive_onoff; /* protocol */
+ u_int32_t ticks; /* ticks/sec */
+ union {
+ lmc_av9110_t ssi;
+ } cardspec;
+ u_int32_t circuit_type; /* T1 or E1 */
+};
+
+
+/*
+ * Carefull, look at the data sheet, there's more to this
+ * structure than meets the eye. It should probably be:
+ *
+ * struct tulip_desc_t {
+ * u8 own:1;
+ * u32 status:31;
+ * u32 control:10;
+ * u32 buffer1;
+ * u32 buffer2;
+ * };
+ * You could also expand status control to provide more bit information
+ */
+
+struct tulip_desc_t {
+ s32 status;
+ s32 length;
+ u32 buffer1;
+ u32 buffer2;
+};
+
+/*
+ * media independent methods to check on media status, link, light LEDs,
+ * etc.
+ */
+struct lmc___media {
+ void (* init)(lmc_softc_t * const);
+ void (* defaults)(lmc_softc_t * const);
+ void (* set_status)(lmc_softc_t * const, lmc_ctl_t *);
+ void (* set_clock_source)(lmc_softc_t * const, int);
+ void (* set_speed)(lmc_softc_t * const, lmc_ctl_t *);
+ void (* set_cable_length)(lmc_softc_t * const, int);
+ void (* set_scrambler)(lmc_softc_t * const, int);
+ int (* get_link_status)(lmc_softc_t * const);
+ void (* set_link_status)(lmc_softc_t * const, int);
+ void (* set_crc_length)(lmc_softc_t * const, int);
+ void (* set_circuit_type)(lmc_softc_t * const, int);
+ void (* watchdog)(lmc_softc_t * const);
+};
+
+
+#define STATCHECK 0xBEEFCAFE
+
+/* Included in this structure are first
+ * - standard net_device_stats
+ * - some other counters used for debug and driver performance
+ * evaluation -baz
+ */
+struct lmc_statistics
+{
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long multicast; /* multicast packets received */
+ unsigned long collisions;
+
+ /* detailed rx_errors: */
+ unsigned long rx_length_errors;
+ unsigned long rx_over_errors; /* receiver ring buff overflow */
+ unsigned long rx_crc_errors; /* recved pkt with crc error */
+ unsigned long rx_frame_errors; /* recv'd frame alignment error */
+ unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+ unsigned long rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ unsigned long tx_aborted_errors;
+ unsigned long tx_carrier_errors;
+ unsigned long tx_fifo_errors;
+ unsigned long tx_heartbeat_errors;
+ unsigned long tx_window_errors;
+
+ /* for cslip etc */
+ unsigned long rx_compressed;
+ unsigned long tx_compressed;
+
+ /* -------------------------------------
+ * Custom stats & counters follow -baz */
+ u_int32_t version_size;
+ u_int32_t lmc_cardtype;
+
+ u_int32_t tx_ProcTimeout;
+ u_int32_t tx_IntTimeout;
+ u_int32_t tx_NoCompleteCnt;
+ u_int32_t tx_MaxXmtsB4Int;
+ u_int32_t tx_TimeoutCnt;
+ u_int32_t tx_OutOfSyncPtr;
+ u_int32_t tx_tbusy0;
+ u_int32_t tx_tbusy1;
+ u_int32_t tx_tbusy_calls;
+ u_int32_t resetCount;
+ u_int32_t lmc_txfull;
+ u_int32_t tbusy;
+ u_int32_t dirtyTx;
+ u_int32_t lmc_next_tx;
+ u_int32_t otherTypeCnt;
+ u_int32_t lastType;
+ u_int32_t lastTypeOK;
+ u_int32_t txLoopCnt;
+ u_int32_t usedXmtDescripCnt;
+ u_int32_t txIndexCnt;
+ u_int32_t rxIntLoopCnt;
+
+ u_int32_t rx_SmallPktCnt;
+ u_int32_t rx_BadPktSurgeCnt;
+ u_int32_t rx_BuffAllocErr;
+ u_int32_t tx_lossOfClockCnt;
+
+ /* T1 error counters */
+ u_int32_t framingBitErrorCount;
+ u_int32_t lineCodeViolationCount;
+
+ u_int32_t lossOfFrameCount;
+ u_int32_t changeOfFrameAlignmentCount;
+ u_int32_t severelyErroredFrameCount;
+
+ u_int32_t check;
+};
+
+
+typedef struct lmc_xinfo {
+ u_int32_t Magic0; /* BEEFCAFE */
+
+ u_int32_t PciCardType;
+ u_int32_t PciSlotNumber; /* PCI slot number */
+
+ u_int16_t DriverMajorVersion;
+ u_int16_t DriverMinorVersion;
+ u_int16_t DriverSubVersion;
+
+ u_int16_t XilinxRevisionNumber;
+ u_int16_t MaxFrameSize;
+
+ u_int16_t t1_alarm1_status;
+ u_int16_t t1_alarm2_status;
+
+ int link_status;
+ u_int32_t mii_reg16;
+
+ u_int32_t Magic1; /* DEADBEEF */
+} LMC_XINFO;
+
+
+/*
+ * forward decl
+ */
+struct lmc___softc {
+ void *if_ptr; /* General purpose pointer (used by SPPP) */
+ char *name;
+ u8 board_idx;
+ struct lmc_statistics stats;
+ struct net_device *lmc_device;
+
+ int hang, rxdesc, bad_packet, some_counter;
+ u_int32_t txgo;
+ struct lmc_regfile_t lmc_csrs;
+ volatile u_int32_t lmc_txtick;
+ volatile u_int32_t lmc_rxtick;
+ u_int32_t lmc_flags;
+ u_int32_t lmc_intrmask; /* our copy of csr_intr */
+ u_int32_t lmc_cmdmode; /* our copy of csr_cmdmode */
+ u_int32_t lmc_busmode; /* our copy of csr_busmode */
+ u_int32_t lmc_gpio_io; /* state of in/out settings */
+ u_int32_t lmc_gpio; /* state of outputs */
+ struct sk_buff* lmc_txq[LMC_TXDESCS];
+ struct sk_buff* lmc_rxq[LMC_RXDESCS];
+ volatile
+ struct tulip_desc_t lmc_rxring[LMC_RXDESCS];
+ volatile
+ struct tulip_desc_t lmc_txring[LMC_TXDESCS];
+ unsigned int lmc_next_rx, lmc_next_tx;
+ volatile
+ unsigned int lmc_taint_tx, lmc_taint_rx;
+ int lmc_tx_start, lmc_txfull;
+ int lmc_txbusy;
+ u_int16_t lmc_miireg16;
+ int lmc_ok;
+ int last_link_status;
+ int lmc_cardtype;
+ u_int32_t last_frameerr;
+ lmc_media_t *lmc_media;
+ struct timer_list timer;
+ lmc_ctl_t ictl;
+ u_int32_t TxDescriptControlInit;
+
+ int tx_TimeoutInd; /* additional driver state */
+ int tx_TimeoutDisplay;
+ unsigned int lastlmc_taint_tx;
+ int lasttx_packets;
+ u_int32_t tx_clockState;
+ u_int32_t lmc_crcSize;
+ LMC_XINFO lmc_xinfo;
+ char lmc_yel, lmc_blue, lmc_red; /* for T1 and DS3 */
+ char lmc_timing; /* for HSSI and SSI */
+ int got_irq;
+
+ char last_led_err[4];
+
+ u32 last_int;
+ u32 num_int;
+
+ spinlock_t lmc_lock;
+ u_int16_t if_type; /* PPP or NET */
+ struct ppp_device *pd;
+
+ /* Failure cases */
+ u8 failed_ring;
+ u8 failed_recv_alloc;
+
+ /* Structure check */
+ u32 check;
+};
+
+#define LMC_PCI_TIME 1
+#define LMC_EXT_TIME 0
+
+#define PKT_BUF_SZ 1542 /* was 1536 */
+
+/* CSR5 settings */
+#define TIMER_INT 0x00000800
+#define TP_LINK_FAIL 0x00001000
+#define TP_LINK_PASS 0x00000010
+#define NORMAL_INT 0x00010000
+#define ABNORMAL_INT 0x00008000
+#define RX_JABBER_INT 0x00000200
+#define RX_DIED 0x00000100
+#define RX_NOBUFF 0x00000080
+#define RX_INT 0x00000040
+#define TX_FIFO_UNDER 0x00000020
+#define TX_JABBER 0x00000008
+#define TX_NOBUFF 0x00000004
+#define TX_DIED 0x00000002
+#define TX_INT 0x00000001
+
+/* CSR6 settings */
+#define OPERATION_MODE 0x00000200 /* Full Duplex */
+#define PROMISC_MODE 0x00000040 /* Promiscuous Mode */
+#define RECIEVE_ALL 0x40000000 /* Recieve All */
+#define PASS_BAD_FRAMES 0x00000008 /* Pass Bad Frames */
+
+/* Dec control registers CSR6 as well */
+#define LMC_DEC_ST 0x00002000
+#define LMC_DEC_SR 0x00000002
+
+/* CSR15 settings */
+#define RECV_WATCHDOG_DISABLE 0x00000010
+#define JABBER_DISABLE 0x00000001
+
+/* More settings */
+/*
+ * aSR6 -- Command (Operation Mode) Register
+ */
+#define TULIP_CMD_RECEIVEALL 0x40000000L /* (RW) Receivel all frames? */
+#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (21140) */
+#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (21140) */
+#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (21140) */
+#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (21140) */
+#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (21140) */
+#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */
+#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */
+#define TULIP_CMD_PROMISCUOUS 0x00000041L /* (RW) Promiscuous Mode */
+#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */
+#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */
+
+#define TULIP_GP_PINSET 0x00000100L
+#define TULIP_BUSMODE_SWRESET 0x00000001L
+#define TULIP_WATCHDOG_TXDISABLE 0x00000001L
+#define TULIP_WATCHDOG_RXDISABLE 0x00000010L
+
+#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */
+#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */
+#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interrupt */
+#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */
+#define TULIP_STS_GTE 0x00000800L /* (RW) General Pupose Timer Exp */
+#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interrupt */
+#define TULIP_STS_RXWT 0x00000200L /* (RW) Receiver Watchdog Timeout */
+#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receiver Process Stopped */
+#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buf Unavail */
+#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */
+#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */
+#define TULIP_STS_TXJABER 0x00000008L /* (RW) Jabber timeout */
+#define TULIP_STS_TXNOBUF 0x00000004L
+#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */
+#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */
+
+#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */
+
+#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */
+#define TULIP_STS_RXNOBUF 0x00000080L
+
+#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */
+#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */
+#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */
+#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = 21040) */
+#define TULIP_DSTS_RxMIIERR 0x00000008
+#define LMC_DSTS_ERRSUM (TULIP_DSTS_RxMIIERR)
+
+#define TULIP_DEFAULT_INTR_MASK (TULIP_STS_NORMALINTR \
+ | TULIP_STS_RXINTR \
+ | TULIP_STS_TXINTR \
+ | TULIP_STS_ABNRMLINTR \
+ | TULIP_STS_SYSERROR \
+ | TULIP_STS_TXSTOPPED \
+ | TULIP_STS_TXUNDERFLOW\
+ | TULIP_STS_RXSTOPPED )
+
+#define DESC_OWNED_BY_SYSTEM ((u_int32_t)(0x00000000))
+#define DESC_OWNED_BY_DC21X4 ((u_int32_t)(0x80000000))
+
+#ifndef TULIP_CMD_RECEIVEALL
+#define TULIP_CMD_RECEIVEALL 0x40000000L
+#endif
+
+/* Adapter module number */
+#define LMC_ADAP_HSSI 2
+#define LMC_ADAP_DS3 3
+#define LMC_ADAP_SSI 4
+#define LMC_ADAP_T1 5
+
+#define HDLC_HDR_LEN 4
+#define HDLC_ADDR_LEN 1
+#define HDLC_SLARP 0x8035
+#define LMC_MTU 1500
+#define SLARP_LINECHECK 2
+
+#define LMC_CRC_LEN_16 2 /* 16-bit CRC */
+#define LMC_CRC_LEN_32 4
+
+#ifdef LMC_HDLC
+/* definition of an hdlc header. */
+struct hdlc_hdr
+{
+ u8 address;
+ u8 control;
+ u16 type;
+};
+
+/* definition of a slarp header. */
+struct slarp
+{
+ long code;
+ union sl
+ {
+ struct
+ {
+ ulong address;
+ ulong mask;
+ ushort unused;
+ } add;
+ struct
+ {
+ ulong mysequence;
+ ulong yoursequence;
+ ushort reliability;
+ ulong time;
+ } chk;
+ } t;
+};
+#endif /* LMC_HDLC */
+
+
+#endif /* _LMC_VAR_H_ */