]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.17pre5 2.2.17pre5
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:21:37 +0000 (15:21 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:21:37 +0000 (15:21 -0500)
o Fix alpha compile problems on lmc and dmfe (Alan Cox)
o Fix sparc32 lockd translation (Dave Miller)
o Fix HDLC problems with packet lengths (Ivan Passos)
o PMAC updates - should now build (Benjamin Herrenschmidt)
video update rejected as too risky
o Removed unused trashing var (Andrea Arcangeli)
o Proper fix for the TCP crash case (Andi Kleen)
o Further small vm fixups (Rik van Riel)
o Fix SCSI tape bugs (Kai Makisara)
o Lanmedia driver fixes (Andrew Stanley-Jones)
o ES1370/1371 GETOSPACE fixes (Thomas Sailer)
o FAT CD fix (Jens Axboe)
o Further small shared irq 3c59x fix (Andrew Morton)
o Fix scripts/Configure comment handler (Jun Hamano)

60 files changed:
CREDITS
Makefile
arch/ppc/boot/Makefile
arch/ppc/chrpboot/main.c
arch/ppc/chrpboot/misc.S
arch/ppc/chrpboot/start.c
arch/ppc/coffboot/Makefile
arch/ppc/coffboot/dummy.c [new file with mode: 0644]
arch/ppc/config.in
arch/ppc/kernel/Makefile
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/head.S
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/pmac_support.c
arch/ppc/kernel/pmac_time.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/time.c
arch/ppc/mm/init.c
arch/sparc64/kernel/sys_sparc32.c
drivers/block/cmd646.c
drivers/block/genhd.c
drivers/block/ide-cd.c
drivers/block/ide-floppy.c
drivers/block/ide-pmac.c
drivers/block/ide-probe.c
drivers/block/ide-proc.c
drivers/block/ide.h
drivers/block/rd.c
drivers/block/swim3.c
drivers/macintosh/Makefile
drivers/macintosh/rtc.c [new file with mode: 0644]
drivers/net/3c59x.c
drivers/net/dmfe.c
drivers/net/hdlc.c
drivers/net/lmc/Makefile
drivers/net/lmc/lmc.h
drivers/net/lmc/lmc_debug.c
drivers/net/lmc/lmc_debug.h
drivers/net/lmc/lmc_ioctl.h
drivers/net/lmc/lmc_main.c
drivers/net/lmc/lmc_media.c
drivers/net/lmc/lmc_proto.c [new file with mode: 0644]
drivers/net/lmc/lmc_proto.h [new file with mode: 0644]
drivers/net/lmc/lmc_var.h
drivers/net/lmc/lmc_ver.h
drivers/net/mace.c
drivers/scsi/st.c
drivers/sound/es1370.c
drivers/sound/es1371.c
include/linux/hdlc.h
include/linux/openpic.h
include/linux/sched.h
include/net/snmp.h
include/net/sock.h
mm/vmscan.c
net/core/sock.c
net/ipv4/proc.c
net/ipv4/tcp.c
scripts/Configure

diff --git a/CREDITS b/CREDITS
index 96c56415ad399852bf50ebe0fe0638aece057c31..3b58d722f4462dbe54510d8ad22a4bbfb585082c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -645,6 +645,10 @@ S: 1150 Ringwood Court
 S: San Jose, California 95131
 S: USA
 
+N: Kumar Gala
+E: kumar.gala@motorola.com
+D: AltiVec PowerPC support
+
 N: Nigel Gamble
 E: nigel@nrg.org
 E: nigel@sgi.com
@@ -812,6 +816,7 @@ E: bh40@calva.net
 E: benh@mipsys.com
 D: PowerMac booter (BootX)
 D: Additional PowerBook support
+D: Apple "Core99" machines support (ibook,g4,...)
 S: 22, rue des Marguettes
 S: 75012 Paris
 S: France
@@ -1632,6 +1637,13 @@ N: Ken Pizzini
 E: ken@halcyon.com
 D: CDROM driver "sonycd535" (Sony CDU-535/531)
 
+N: Matt Porter
+E: mporter@phx.mcd.mot.com
+D: Motorola PowerPC PReP support
+S: 2900 S. Diable Way
+S: Tempe, Arizona 85282
+S: USA
+
 N: Frederic Potter 
 E: Frederic.Potter@masi.ibp.fr 
 D: Some PCI kernel support
index cb550d83350f56ea876edad069346e03eb79ee1e..085821b24c045a9a56ec68750851088e13950b14 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre4
+EXTRAVERSION = pre5
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index c595afaa77b3673e0b87192b5c66ce6cfe3c5287..7152bace7c4410c9cc07d8e3a4c4a8f6fb417357 100644 (file)
@@ -69,7 +69,7 @@ all:  zImage
 zvmlinux.initrd: zvmlinux
        $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
        $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section=initrd=ramdisk.image.gz \
+               --add-section=initrd=../coffboot/ramdisk.image.gz \
                --add-section=image=../coffboot/vmlinux.gz \
                zvmlinux.initrd.tmp zvmlinux.initrd
        $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \
@@ -79,7 +79,7 @@ zvmlinux.initrd: zvmlinux
                -c -o misc.o misc.c
        $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
        $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section=initrd=ramdisk.image.gz \
+               --add-section=initrd=../coffboot/ramdisk.image.gz \
                --add-section=image=../coffboot/vmlinux.gz \
                zvmlinux.initrd.tmp $@
        rm zvmlinux.initrd.tmp
index 80db69a7b10896bc00b90c622a9fc66602a57a76..fd3421f404829deb5313168a5940e9c2ed9b25f1 100644 (file)
@@ -17,15 +17,16 @@ void gunzip(void *, int, unsigned char *, int *);
 #define get_32be(x)    (*(unsigned *)(x))
 
 #define RAM_START      0x00000000
-#define RAM_END                (8<<20)
+#define RAM_END                (64<<20)
 
-#define RAM_FREE       ((unsigned long)(_end+0x1000)&~0xFFF)
+#define BOOT_START     ((unsigned long)_start)
+#define BOOT_END       ((unsigned long)(_end + 0xFFF) & ~0xFFF)
 #define PROG_START     0x00010000
 
 char *avail_ram;
 char *end_avail;
 
-extern char _end[];
+extern char _start[], _end[];
 extern char image_data[];
 extern int image_len;
 extern char initrd_data[];
@@ -48,17 +49,23 @@ chrpboot(int a1, int a2, void *prom)
        initrd_start = (RAM_END - initrd_size) & ~0xFFF;
        a1 = initrd_start;
        a2 = initrd_size;
-       printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start,
-              initrd_data,initrd_size);
+       claim(initrd_start, RAM_END - initrd_start, 0);
+       printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+              initrd_start, initrd_data, initrd_size);
        memcpy((char *)initrd_start, initrd_data, initrd_size);
-       end_avail = (char *)initrd_start;
-    } else
-       end_avail = (char *) RAM_END;
+    }
     im = image_data;
     len = image_len;
+    /* try and claim our text/data in case of OF bugs */
+    claim(BOOT_START, BOOT_END - BOOT_START, 0);
+    /* claim 4MB starting at PROG_START */
+    claim(PROG_START, (4<<20) - PROG_START, 0);
     dst = (void *) PROG_START;
     if (im[0] == 0x1f && im[1] == 0x8b) {
-       avail_ram = (char *)RAM_FREE;
+       /* claim 512kB for scratch space */
+       avail_ram = (char *) claim(0, 512 << 10, 0x10);
+       end_avail = avail_ram + (512 << 10);
+       printf("avail_ram = %x\n", avail_ram);
        printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
        gunzip(dst, 0x400000, im, &len);
        printf("done %u bytes\n\r", len);
index b2094b9d3df4a2eac6607225ff6d7bb5184eb0a0..181450c5375c19bf50572e35649e76508d546fed 100644 (file)
@@ -9,7 +9,7 @@
        .text
 
 /*
- * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000.
+ * Use the BAT0 registers to map the 1st 8 or 64MB of RAM to 0x90000000.
  */
        .globl  setup_bats
 setup_bats:
@@ -21,7 +21,7 @@ setup_bats:
        ori     4,4,4                   /* set up BAT registers for 601 */
        li      5,0x7f
        b       5f
-4:     ori     4,4,0xff                /* set up BAT registers for 604 */
+4:     ori     4,4,0x7ff               /* set up BAT registers for 604 */
        li      5,2
        mtdbatu 3,4
        mtdbatl 3,5
index 161d9a980455b8cec80642a2f95b1cbe46fd8675..308f4fcd349299f0ecd1201ef4b10c2ebd99f9b6 100644 (file)
@@ -131,6 +131,29 @@ finddevice(const char *name)
     return args.phandle;
 }
 
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+    struct prom_args {
+       char *service;
+       int nargs;
+       int nret;
+       unsigned int virt;
+       unsigned int size;
+       unsigned int align;
+       void *ret;
+    } args;
+
+    args.service = "claim";
+    args.nargs = 3;
+    args.nret = 1;
+    args.virt = virt;
+    args.size = size;
+    args.align = align;
+    (*prom)(&args);
+    return args.ret;
+}
+
 int
 getprop(void *phandle, const char *name, void *buf, int buflen)
 {
index 7468bf7a79ed7a0d427cf7119c73e01850bd5402..9070cdce2cf517539fb4840151e9f80ec0fddac5 100644 (file)
@@ -92,11 +92,11 @@ vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote
 micoffboot: dummy.o
        $(LD) -o $@ $(COFF_LD_ARGS) dummy.o $(LIBS)
 
-miboot.image: micoffboot hack-coff
+miboot.image: micoffboot hack-coff vmlinux.gz
        $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz micoffboot $@
        ./hack-coff $@
 
-miboot.image.initrd: micoffboot hack-coff
+miboot.image.initrd: micoffboot hack-coff vmlinux.gz ramdisk.image.gz
        $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
        --add-section=initrd=ramdisk.image.gz micoffboot $@
        ./hack-coff $@
diff --git a/arch/ppc/coffboot/dummy.c b/arch/ppc/coffboot/dummy.c
new file mode 100644 (file)
index 0000000..31dbf45
--- /dev/null
@@ -0,0 +1,4 @@
+int main(void)
+{
+       return 0;
+}
index 1f1bcd5320dbc074b7926b7ea599f877d580c4b9..6510dce98ef3ecc2dc074a6ff22648c7b4bc5fc4 100644 (file)
@@ -90,6 +90,7 @@ tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
 if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
    bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
 fi
+tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
 bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
 bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
 bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
index fc0a5156eeb54f5901c26292400e5e1d4da909e2..9ea51146dd1a1d99454dc8bbfa00c59aa2f3b77a 100644 (file)
@@ -67,7 +67,8 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
                $(TOPDIR)/include/asm/ptrace.h
        $(CC) ${CFLAGS} -S mk_defs.c
        cp ppc_defs.head ppc_defs.h
-       grep '^#define' mk_defs.s >>ppc_defs.h
+       chmod 755 ppc_defs.h
+       grep '^#define' mk_defs.s >> ppc_defs.h
        rm mk_defs.s
 
 find_name : find_name.c
index 2159e8133d3977295a29f447770126ea9bb93582..e2c29eefd95dc7455c9215ca74865e6d030a5309 100644 (file)
@@ -685,3 +685,8 @@ void chrp_progress(char *s)
        while ( *s )
                call_rtas( "display-character", 1, 1, NULL, *s++ );
 }
+
+void chrp_indicator(int x)
+{
+       call_rtas("set-indicator", 3, 1, NULL, 6, 0, x);
+}
index 21ec8504443e29a820c7bfd94a3f2fdf5a12f9f5..ec184b7b2a80e365591d5b647c145225e163d9a0 100644 (file)
@@ -2832,7 +2832,6 @@ enter_rtas:
        stw     r0,20(r1)
        lis     r4,rtas_data@ha
        lwz     r4,rtas_data@l(r4)
-       addis   r4,r4,-KERNELBASE@h
        lis     r6,1f@ha        /* physical return address for rtas */
        addi    r6,r6,1f@l
        addis   r6,r6,-KERNELBASE@h
index e8fc30eb87f9a24aa0167e7ebfc92cb227fa7dbb..9a7882fafe11a52113b616dac15ee10f2760bdf0 100644 (file)
@@ -64,6 +64,7 @@
 
 #undef SHOW_GATWICK_IRQS
 
+void pmac_time_init(void);
 unsigned long pmac_get_rtc_time(void);
 int pmac_set_rtc_time(unsigned long nowtime);
 void pmac_read_rtc_time(void);
@@ -308,6 +309,8 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
        find_via_cuda();
        find_via_pmu();
 
+       pmac_nvram_init();
+
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
 #endif
@@ -402,7 +405,6 @@ __initfunc(void
 pmac_init2(void))
 {
        adb_init();
-       pmac_nvram_init();
        media_bay_init();
 }
 
@@ -642,7 +644,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.power_off      = pmac_power_off;
        ppc_md.halt           = pmac_halt;
 
-       ppc_md.time_init      = NULL;
+       ppc_md.time_init      = pmac_time_init;
        ppc_md.set_rtc_time   = pmac_set_rtc_time;
        ppc_md.get_rtc_time   = pmac_get_rtc_time;
        ppc_md.calibrate_decr = pmac_calibrate_decr;
index 698363261b884e64f397e29715501529ab31c52e..a44fbe30809c994d8d6f1742e59bf0edae30c5c6 100644 (file)
 
 #undef DEBUG
 
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static char* nvram_image;
-static int core99_bank = 0;
-
-extern int pmac_newworld;
-
 #define NVRAM_SIZE             0x2000  /* 8kB of non-volatile RAM */
 
 #define CORE99_SIGNATURE       0x5a
@@ -52,7 +40,6 @@ extern int pmac_newworld;
 #define CORE99_FLASH_CMD_RESET         0xff
 #define CORE99_FLASH_CMD_WRITE_SETUP   0x40
 
-
 /* CHRP NVRAM header */
 struct chrp_header {
   u8           signature;
@@ -69,8 +56,29 @@ struct core99_header {
   u32                  reserved[2];
 };
 
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
 static int nvram_partitions[3];
 
+/* FIXME: kmalloc fails to allocate the image now that I had to move it
+ *        before time_init(). For now, I allocate a static buffer here
+ *        but it's a waste of space on all but core99 machines
+ */
+#if 0
+static char* nvram_image;
+#else
+__pmac static char nvram_image[NVRAM_SIZE];
+#endif
+
+extern int pmac_newworld;
+
+
 static u8
 chrp_checksum(struct chrp_header* hdr)
 {
@@ -244,11 +252,13 @@ void pmac_nvram_init(void)
                        printk(KERN_ERR "nvram: no address\n");
                        return;
                }
+#if 0
                nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
                if (!nvram_image) {
                        printk(KERN_ERR "nvram: can't allocate image\n");
                        return;
                }
+#endif         
                nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
 #ifdef DEBUG
                printk("nvram: Checking bank 0...\n");
@@ -322,7 +332,7 @@ nvram_read_byte(int addr)
                return req.reply[1];
        case 1:
                if (is_core_99)
-                       return nvram_image[addr];
+                       return nvram_image ? nvram_image[addr] : 0;
                return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
        case 2:
                *nvram_addr = addr >> 5;
@@ -347,6 +357,8 @@ nvram_write_byte(unsigned char val, int addr)
                break;
        case 1:
                if (is_core_99) {
+                       if (!nvram_image)
+                               return;
                        nvram_image[addr] = val;
                        break;
                }
index d6e8eb095c6904e271f5d2f66715dea06b7781c8..a02f6f86924307f394322a33d730edd54ed36250 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/nvram.h>
 
 #include "time.h"
 
 /* Bits in IFR and IER */
 #define T1_INT         0x40            /* Timer 1 interrupt */
 
-__pmac
+extern struct timezone sys_tz;
+
+__init
+void pmac_time_init(void)
+{
+       s32 delta = 0;
+       int dst;
+       int i;
+       char tmp[1024];
+       char *p = tmp;
+       
+       delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+       delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+       delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+       if (delta & 0x00800000UL)
+               delta |= 0xFF000000UL;
+       dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+       printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+               dst ? "on" : "off");
+       sys_tz.tz_minuteswest = -delta/60;
+       /* I _suppose_ this is 0:off, 1:on */
+       sys_tz.tz_dsttime = dst;
+}
 
+__pmac
 unsigned long pmac_get_rtc_time(void)
 {
        struct adb_request req;
+       int offset = sys_tz.tz_minuteswest * 60;
 
        /* Get the time from the RTC */
        if (adb_controller == 0)
@@ -70,7 +95,7 @@ unsigned long pmac_get_rtc_time(void)
                        printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
                               req.reply_len);
                return (req.reply[3] << 24) + (req.reply[4] << 16)
-                       + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+                       + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET + offset;
        case ADB_VIAPMU:
                if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) {
                        printk("pmac_read_rtc_time: pmu_request failed\n");
@@ -82,7 +107,7 @@ unsigned long pmac_get_rtc_time(void)
                        printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
                               req.reply_len);
                return (req.reply[1] << 24) + (req.reply[2] << 16)
-                       + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
+                       + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET + offset;
        default:
                return 0;
        }
@@ -90,7 +115,39 @@ unsigned long pmac_get_rtc_time(void)
 
 int pmac_set_rtc_time(unsigned long nowtime)
 {
-       return 0;
+       struct adb_request req;
+
+       nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60;
+
+       /* Set the time in the RTC */
+       if (adb_controller == 0)
+               return 0;
+       /* adb_controller->kind, not adb_hardware, since that doesn't
+          get set until we call adb_init - paulus. */
+       switch (adb_controller->kind) {
+       case ADB_VIACUDA:
+               if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+                                nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+                       return 0;
+               while (!req.complete)
+                       cuda_poll();
+//             if (req.reply_len != 7)
+                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               return 1;
+       case ADB_VIAPMU:
+               if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+                               nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+                       return 0;
+               while (!req.complete)
+                       pmu_poll();
+               if (req.reply_len != 5)
+                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+                              req.reply_len);
+               return 1;
+       default:
+               return 0;
+       }
 }
 
 /*
index 21302ad9bfb0280677c3ca1efdc15b3e4050c2ca..1a2bbd819df03c42b05a3e9b356ae46db6eb3c12 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/spinlock.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
+#include <asm/nvram.h>
 
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
@@ -45,6 +46,9 @@ extern int sys_sigreturn(struct pt_regs *regs);
 extern atomic_t ppc_n_lost_interrupts;
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
+                            unsigned int, unsigned int, unsigned int);
+extern void to_tm(int tim, struct rtc_time * tm);
 
 long long __ashrdi3(long long, int);
 long long __ashldi3(long long, int);
@@ -222,7 +226,13 @@ EXPORT_SYMBOL(kd_mksound);
 /*#ifdef CONFIG_PMAC */
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
 /*#endif*/ /* CONFIG_PMAC */
+#ifdef CONFIG_PPC_RTC
+EXPORT_SYMBOL(mktime);
+EXPORT_SYMBOL(to_tm);
+#endif
 
 EXPORT_SYMBOL(abs);
 
index f4676c8d99c2fe2c81b7a6d8b8e5e2d71ebe63ad..3a6276d6f7b045202c4ceb2931c44747ce3ada5a 100644 (file)
@@ -96,7 +96,7 @@ extern char *klimit;
 char *bootpath = 0;
 char *bootdevice = 0;
 
-unsigned int rtas_data = 0;   /* virtual pointer */
+unsigned int rtas_data = 0;   /* physical pointer */
 unsigned int rtas_entry = 0;  /* physical pointer */
 unsigned int rtas_size = 0;
 unsigned int old_rtas = 0;
@@ -114,7 +114,7 @@ static void flushscreen(void);
 
 void drawchar(char c);
 void drawstring(const char *c);
-static void drawhex(unsigned long v);
+void drawhex(unsigned long v);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
@@ -274,6 +274,22 @@ prom_print(const char *msg)
        }
 }
 
+void
+prom_print_hex(unsigned int v)
+{
+       char buf[16];
+       int i, c;
+
+       for (i = 0; i < 8; ++i) {
+               c = (v >> ((7-i)*4)) & 0xf;
+               c += (c >= 10)? ('a' - 10): '0';
+               buf[i] = c;
+       }
+       buf[i] = ' ';
+       buf[i+1] = 0;
+       prom_print(buf);
+}
+
 unsigned long smp_ibm_chrp_hack __initdata = 0;
 
 /*
@@ -448,15 +464,6 @@ prom_init(int r3, int r4, prom_entry pp)
                RELOC(bootdevice) = PTRUNRELOC(d);
                mem = ALIGN(mem + strlen(d) + 1);
        }
-
-       mem = check_display(mem);
-
-       prom_print(RELOC("copying OF device tree..."));
-       mem = copy_device_tree(mem, mem + (1<<20));
-       prom_print(RELOC("done\n"));
-
-
-       RELOC(klimit) = (char *) (mem - offset);
        
        prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
        if (prom_rtas != (void *) -1) {
@@ -468,18 +475,14 @@ prom_init(int r3, int r4, prom_entry pp)
                        RELOC(rtas_data) = 0;
                } else {
                        /*
-                        * We do _not_ want the rtas_data inside the klimit
-                        * boundry since it'll be squashed when we do the
-                        * relocate of the kernel on chrp right after prom_init()
-                        * in head.S.  So, we just pick a spot in memory.
-                        * -- Cort
+                        * Ask OF for some space for RTAS.
                         */
-#if 0
-                       mem = (mem + 4095) & -4096;
-                       RELOC(rtas_data) = mem + KERNELBASE;
-                       mem += RELOC(rtas_size);
-#endif
-                       RELOC(rtas_data) = (6<<20) + KERNELBASE;
+                       RELOC(rtas_data) = (unsigned int)
+                               call_prom(RELOC("claim"), 3, 1, 0,
+                                         RELOC(rtas_size), 0x1000);
+                       prom_print(RELOC("rtas at "));
+                       prom_print_hex(RELOC(rtas_data));
+                       prom_print(RELOC("\n"));
                }
                prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
                {
@@ -491,7 +494,7 @@ prom_init(int r3, int r4, prom_entry pp)
                        prom_args.nret = 2;
                        prom_args.args[0] = RELOC("instantiate-rtas");
                        prom_args.args[1] = prom_rtas;
-                       prom_args.args[2] = ((void *)(RELOC(rtas_data)-KERNELBASE));
+                       prom_args.args[2] = (void *) RELOC(rtas_data);
                        RELOC(prom)(&prom_args);
                        if (prom_args.args[nargs] != 0)
                                i = 0;
@@ -505,6 +508,15 @@ prom_init(int r3, int r4, prom_entry pp)
                        prom_print(RELOC(" done\n"));
        }
 
+       mem = check_display(mem);
+
+       prom_print(RELOC("copying OF device tree..."));
+       /* N.B. do this *after* any claims */
+       mem = copy_device_tree(mem, mem + (1<<20));
+       prom_print(RELOC("done\n"));
+
+       RELOC(klimit) = (char *) (mem - offset);
+
        /* If we are already running at 0xc0000000, we assume we were loaded by
         * an OF bootloader which did set a BAT for us. This breaks OF translate
         * so we force phys to be 0
@@ -537,7 +549,7 @@ prom_init(int r3, int r4, prom_entry pp)
        }
            
 #ifdef CONFIG_BOOTX_TEXT
-       if (!chrp && RELOC(prom_disp_node) != 0)
+       if (RELOC(prom_disp_node) != 0)
                setup_disp_fake_bi(RELOC(prom_disp_node));
 #endif
 
@@ -631,10 +643,10 @@ prom_init(int r3, int r4, prom_entry pp)
                RELOC(prom_stdout) = 0;
                clearscreen();
                prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
-               prom_print(RELOC("booting...\n"));
        }
 #endif
 
+       prom_print(RELOC("booting...\n"));
        return phys;
 }
 
@@ -762,7 +774,7 @@ check_display(unsigned long mem)
 
                if (RELOC(prom_disp_node) == 0)
                        RELOC(prom_disp_node) = node;
-                       
+
                /* Setup a useable color table when the appropriate
                 * method is available. Should update this to set-colors */
                for (i = 0; i < 32; i++)
@@ -841,7 +853,10 @@ setup_disp_fake_bi(ihandle dp)
                prom_print(RELOC("Failed to get pitch\n"));
                return;
        }
+       if (pitch == 1)
+               pitch = 0x1000;
        address = len = 0;
+       len = 0xfa000000;
        call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
        address = len;
        if (address == 0) {
@@ -852,22 +867,21 @@ setup_disp_fake_bi(ihandle dp)
        /* kludge for valkyrie */
        if (strcmp(dp->name, "valkyrie") == 0) 
            address += 0x1000;
-    }
 #endif
  
-    RELOC(disp_bi) = &fake_bi;
-    bi = PTRRELOC((&fake_bi));
-    RELOC(g_loc_X) = 0;
-    RELOC(g_loc_Y) = 0;
-    RELOC(g_max_loc_X) = width / 8;
-    RELOC(g_max_loc_Y) = height / 16;
-    bi->logicalDisplayBase = (unsigned char *)address;
-    bi->dispDeviceBase = (unsigned char *)address;
-    bi->dispDeviceRowBytes = pitch;
-    bi->dispDeviceDepth = depth;
-    bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
-    bi->dispDeviceRect[2] = width;
-    bi->dispDeviceRect[3] = height;
+       RELOC(disp_bi) = &fake_bi;
+       bi = PTRRELOC((&fake_bi));
+       RELOC(g_loc_X) = 0;
+       RELOC(g_loc_Y) = 0;
+       RELOC(g_max_loc_X) = width / 8;
+       RELOC(g_max_loc_Y) = height / 16;
+       bi->logicalDisplayBase = (unsigned char *)address;
+       bi->dispDeviceBase = (unsigned char *)address;
+       bi->dispDeviceRowBytes = pitch;
+       bi->dispDeviceDepth = depth;
+       bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+       bi->dispDeviceRect[2] = width;
+       bi->dispDeviceRect[3] = height;
 }
 #endif
 
@@ -1005,31 +1019,17 @@ void
 finish_device_tree(void)
 {
        unsigned long mem = (unsigned long) klimit;
-#if 0
-       char* model;
-       
-       /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
-        * This code was only tested with Core99 machines so far, but should be easily
-        * adapted to older newworld machines (iMac, B&W G3, Lombard).
-        */
-       model = get_property(allnodes, "model", 0);
-       if ((boot_infos == 0) && model && (
-               strcmp(model, "PowerBook2,1") == 0 ||
-               strcmp(model, "PowerBook3,1") == 0 ||
-               strcmp(model, "PowerMac2,1") == 0 ||
-               strcmp(model, "PowerMac3,1") == 0))
-               use_of_interrupt_tree = 1;
-#endif         
-       /* All newworld machines now use the interrupt tree */
+
+       /* All newworld machines and CHRP now use the interrupt tree */
        struct device_node *np = allnodes;
-       while(np) {
+       while(np && (_machine == _MACH_Pmac)) {
                if (get_property(np, "interrupt-parent", 0)) {
                        pmac_newworld = 1;
                        break;
                }
                np = np->allnext;
        }
-       if (boot_infos == 0 && pmac_newworld)
+       if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld))
                use_of_interrupt_tree = 1;
 
        mem = finish_node(allnodes, mem, NULL);
@@ -1172,6 +1172,25 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start)
                    for (j=2; j<isize; j++)
                        interrupts++;
                }
+               /*
+                *  On the CHRP LongTrail, ISA interrupts are cascaded through
+                *  the OpenPIC. For compatibility reasons, ISA interrupts are
+                *  numbered 0-15 and OpenPIC interrupts start at 16.
+                *  Hence we have to fixup the interrupt numbers for sources
+                *  that are attached to the OpenPIC and thus have an
+                *  interrupt-controller named `open-pic'.
+                *
+                *  FIXME: The name of the interrupt-controller node for the
+                *         `ide' node has no name, although its parent is
+                *         correctly specified in interrupt-map, so we check
+                *         for a NULL name as well.
+                */
+               if (_machine == _MACH_chrp &&
+                   ((node->name && !strcmp(node->name, "open-pic")) ||
+                    !node->name)) {
+                   for (i = 0; i < np->n_intrs; ++i)
+                       np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
+               }
                return mem_start;
            }
            /* We lookup for an interrupt-map. This code can only handle one interrupt
@@ -2015,6 +2034,15 @@ drawchar(char c)
        }
 }
 
+void
+here(int n)
+{
+       chrp_indicator(n);
+       if (n == 1)
+               clearscreen();
+       showvalue("here ", n);
+}
+
 __pmac
 void
 drawstring(const char *c)
@@ -2024,7 +2052,7 @@ drawstring(const char *c)
 }
 
 __pmac
-static void
+void
 drawhex(unsigned long v)
 {
        static char hex_table[] = "0123456789abcdef";
index 05ac55681dfc3b6bf6b4b660d7b4ff56ff1ecb65..00b8f9b62d96f34aaedc1f33b4dffeca9ece4915 100644 (file)
@@ -106,6 +106,13 @@ void timer_interrupt(struct pt_regs * regs)
                if ( !smp_processor_id() )
                {
                        do_timer(regs);
+#if 0
+       /* -- BenH -- I'm removing this for now since it can cause various
+        *            troubles with local-time RTCs. Now that we have a
+        *            /dev/rtc that uses ppc_md.set_rtc_time() on mac, it
+        *            should be possible to program the RTC from userland
+        *            in all cases.
+        */
                        /*
                         * update the rtc when needed
                         */
@@ -119,6 +126,7 @@ void timer_interrupt(struct pt_regs * regs)
                                        /* do it again in 60 s */
                                        last_rtc_update = xtime.tv_sec;
                        }
+#endif                 
                }
        }
 #ifdef __SMP__
index 9a257c82c7b83b34a8f96bf04e74c0865ff39891..a581e730ca948b8109bcba5e85df96fa1a023c4f 100644 (file)
@@ -933,15 +933,21 @@ __initfunc(static void mapin_ram(void))
                                /* On the powerpc, no user access
                                   forces R/W kernel access */
                                f |= _PAGE_USER;
+                       map_page(v, p, f);
+                       v += PAGE_SIZE;
+                       p += PAGE_SIZE;
+               }
+       }
+
 #else  /* CONFIG_8xx */
-            for (i = 0; i < phys_mem.n_regions; ++i) {
-                    v = (ulong)__va(phys_mem.regions[i].address);
-                    p = phys_mem.regions[i].address;
-                    for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+       for (i = 0; i < phys_mem.n_regions; ++i) {
+               v = (ulong)__va(phys_mem.regions[i].address);
+               p = phys_mem.regions[i].address;
+               for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
                         /* On the MPC8xx, we want the page shared so we
                          * don't get ASID compares on kernel space.
                          */
-                            f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
+                       f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
 
                         /* I don't really need the rest of this code, but
                          * I grabbed it because I think the line:
@@ -951,14 +957,14 @@ __initfunc(static void mapin_ram(void))
                          * the MPC8xx, the PAGE_DIRTY takes care of that
                          * for us (along with the RW software state).
                          */
-                            if ((char *) v < _stext || (char *) v >= etext)
-                                    f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
-#endif /* CONFIG_8xx */
+                       if ((char *) v < _stext || (char *) v >= etext)
+                               f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
                        map_page(v, p, f);
                        v += PAGE_SIZE;
                        p += PAGE_SIZE;
                }
-       }           
+       }
+#endif /* CONFIG_8xx */
 }
 
 /* This can get called from ioremap, so don't make it an initfunc, OK? */
@@ -1057,7 +1063,6 @@ __initfunc(void MMU_init(void))
 #endif /* CONFIG_GEMINI        */
        else /* prep */
                end_of_DRAM = prep_find_end_of_memory();
-*(unsigned long *)(KERNELBASE) = 0xdeadbeef;   
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
        ioremap_base = 0xf8000000;
@@ -1257,8 +1262,8 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 #endif /* CONFIG_BLK_DEV_INITRD */
 #ifndef CONFIG_8xx               
                        if ( !rtas_data ||
-                            addr < (rtas_data & PAGE_MASK) ||
-                            addr >= (rtas_data+rtas_size))
+                            addr < (rtas_data + KERNELBASE) ||
+                            addr >= (rtas_data + KERNELBASE + rtas_size))
 #endif /* CONFIG_8xx */
                                free_page(addr);
        }
@@ -1319,6 +1324,7 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void))
        return ret;
 }
 #endif /* CONFIG_MBX */
+
 #ifndef CONFIG_8xx
 /*
  * On systems with Open Firmware, collect information about
@@ -1385,6 +1391,7 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
        if (boot_infos == 0) {
                /* record which bits the prom is using */
                get_mem_prop("available", &phys_avail);
+               remove_mem_piece(&phys_avail, __max_memory, ~0U, 0);
                prom_mem = phys_mem;
                for (i = 0; i < phys_avail.n_regions; ++i)
                        remove_mem_piece(&prom_mem,
index 3cb037e3821891a1f67e80f3d1fc5e56350e889b..d39e27125c744ae669a58dbb0970d02bf43613f6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107.2.8 2000/02/28 04:09:49 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.9 2000/06/20 17:12:25 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -2488,7 +2488,8 @@ static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_up
         * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
         */
        ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
-       while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) {
+       while(((unsigned long)ucmsg) <=
+             (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
                struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
                int clen64, clen32;
 
@@ -3689,8 +3690,10 @@ int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsct
                err = nfs_getfh32_trans(karg, arg32);
                break;
        case NFSCTL_LOCKD:
-               /* No arguments, no translations... */
-               err = 0;
+               /* We still have to copy over the version
+                * because nfsctl still checks that.
+                */
+               err = get_user(karg->ca_version, &arg32->ca32_version);
                break;
        default:
                err = -EINVAL;
index fa97ff5fe10a8b0be76d0763327534569553680e..cf8b92fc3b6e69e0b4476e279993c12a9dfbc099 100644 (file)
@@ -247,5 +247,9 @@ __initfunc(void ide_init_cmd646 (ide_hwif_t *hwif))
        (void) pci_write_config_byte(dev, 0x58, 0x3f);
        (void) pci_write_config_byte(dev, 0x5b, 0x3f);
 
+#ifdef CONFIG_PPC
+       (void) pci_write_config_byte(dev, 0x73, 0xf0);
+#endif /* CONFIG_PPC */
+
        hwif->dmaproc = &cmd646_dmaproc;
 }
index 8a56f5a007ced64769e9f6b8461dd2667cff3dd6..52dde9578cd9a8008613b7f9bb811af278f58eaa 100644 (file)
@@ -1089,6 +1089,14 @@ struct mac_driver_desc {
     /* ... more stuff */
 };
 
+static inline void mac_fix_string(char *stg, int len)
+{
+       int i;
+
+       for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
+               stg[i] = 0;
+}
+
 static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
 {
        struct buffer_head *bh;
@@ -1157,18 +1165,31 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
                 */
                if (_machine == _MACH_Pmac) {
                        int goodness = 0;
+
+                       mac_fix_string(part->processor, 16);
+                       mac_fix_string(part->name, 32);
+                       mac_fix_string(part->type, 32);                                 
                    
                        if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
                            && strcasecmp(part->processor, "powerpc") == 0)
                                goodness++;
 
-                       if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0) {
+                       if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
+                           || strcasecmp(part->type, "Linux_PPC") == 0) {
+                               int i, l;
+
                                goodness++;
-                               if ((strcmp(part->name, "/") == 0) ||
-                                   (strstr(part->name, "root") != 0)) {
+                               l = strlen(part->name);
+                               if (strcmp(part->name, "/") == 0)
                                        goodness++;
+                               for (i = 0; i <= l - 4; ++i) {
+                                       if (strnicmp(part->name + i, "root",
+                                                    4) == 0) {
+                                               goodness += 2;
+                                               break;
+                                       }
                                }
-                               if (strncmp(part->name, "swap", 4) == 0)
+                               if (strnicmp(part->name, "swap", 4) == 0)
                                        goodness--;
                        }
 
index 802d311b4248fc896c7fe1046e4c4c357718c937..bb2f7a7364fab35cc940b7382a8e2dcb41671d57 100644 (file)
@@ -1768,6 +1768,9 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        if (stat)
                toc->capacity = 0x1fffff;
 
+       HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+       drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
+
        /* Remember that we've read this stuff. */
        CDROM_STATE_FLAGS (drive)->toc_valid = 1;
 
index bd2c746cbdcc05b2c7b2e48adba9cf4b8821e2ce..891211d684a18bc6692da9ab9b94d12bfcccf338 100644 (file)
@@ -1400,6 +1400,13 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
 
        *((unsigned short *) &gcw) = id->config;
 
+#ifdef CONFIG_PPC
+       /* kludge for Apple PowerBook internal zip */
+       if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM")
+           && strstr(id->model, "ZIP"))
+               gcw.device_type = 0;                    
+#endif
+
 #if IDEFLOPPY_DEBUG_INFO
        printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
        switch (gcw.protocol) {
index 78322f33d151db879eb262e6dcb367ebb4c66629..e66320309d549fcd95bb0dfc4155d8721a561dac 100644 (file)
@@ -5,6 +5,8 @@
  *
  *  Copyright (C) 1998 Paul Mackerras.
  *
+ *  Bits from Benjamin Herrenschmidt
+ *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
  *  as published by the Free Software Foundation; either version
 #include "ide.h"
 #include "ide_modes.h"
 
-ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
-int pmac_ide_irq[MAX_HWIFS];
-int pmac_ide_count;
-struct device_node *pmac_ide_node[MAX_HWIFS];
+#undef IDE_PMAC_DEBUG
+
+#define IDE_SYSCLK_NS          30
+#define IDE_SYSCLK_ULTRA_PS    0x1d4c /* (15 * 1000 / 2)*/
+
+struct pmac_ide_hwif {
+       ide_ioreg_t                     regbase;
+       int                             irq;
+       int                             kind;
+       int                             aapl_bus_id;
+       struct device_node*             node;
+       u32                             timings[2];
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+       volatile struct dbdma_regs*     dma_regs;
+       struct dbdma_cmd*               dma_table;
+#endif
+       
+} pmac_ide[MAX_HWIFS];
+
+static int pmac_ide_count;
+
+enum {
+       controller_ohare,       /* OHare based */
+       controller_heathrow,    /* Heathrow/Paddington */
+       controller_kl_ata3,     /* KeyLargo ATA-3 */
+       controller_kl_ata4      /* KeyLargo ATA-4 */
+};
+
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+typedef struct {
+       int     accessTime;
+       int     cycleTime;
+} pmac_ide_timing;
+
+/* Multiword DMA timings */
+static pmac_ide_timing mdma_timings[] =
+{
+    { 215,    480 },   /* Mode 0 */
+    {  80,    150 },   /*      1 */
+    {  70,    120 }    /*      2 */
+};
+
+/* Ultra DMA timings (for use when I know how to calculate them */
+static pmac_ide_timing udma_timings[] =
+{
+    {   0,    114 },   /* Mode 0 */
+    {   0,     75 },   /*      1 */
+    {   0,     55 },   /*      2 */
+    {   100,   45 },   /*      3 */
+    {   100,   25 }    /*      4 */
+};
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS      256
+/* Wait 1.5s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ *       before anwering on the bus. I beleive we could add a kernel command
+ *       line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS    1500
 #define MAX_DCMDS      256     /* allow up to 256 DBDMA commands per xfer */
 
-static void pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif);
+static void pmac_ide_setup_dma(struct device_node *np, int ix);
 static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
+static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 #ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify(struct pmu_sleep_notifier *self, int when);
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
 struct pmu_sleep_notifier idepmac_sleep_notifier = {
-       idepmac_notify, SLEEP_LEVEL_BLOCK,
+       idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
+static int
+pmac_ide_find(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       ide_ioreg_t base;
+       int i;
+       
+       for (i=0; i<pmac_ide_count; i++) {
+               base = pmac_ide[i].regbase;
+               if (base && base == hwif->io_ports[0])
+                       return i;
+       }
+       return -1;
+}
+
 /*
  * N.B. this can't be an initfunc, because the media-bay task can
  * call ide_[un]register at any time.
@@ -69,7 +146,7 @@ pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
                return;
 
        for (ix = 0; ix < MAX_HWIFS; ++ix)
-               if (base == pmac_ide_regbase[ix])
+               if (base == pmac_ide[ix].regbase)
                        break;
 
        if (ix >= MAX_HWIFS) {
@@ -83,35 +160,130 @@ pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
                return;
        }
 
-       /* we check only for -EINVAL meaning that we have found a matching
-          bay but with the wrong device type */ 
-
-       i = check_media_bay_by_base(base, MB_CD);
-       if (i == -EINVAL)
-               return;
-               
        for (i = 0; i < 8; ++i)
                *p++ = base + i * 0x10;
        *p = base + 0x160;
        if (irq != NULL)
-               *irq = pmac_ide_irq[ix];
+               *irq = pmac_ide[ix].irq;
+
+       ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
+       ide_hwifs[ix].selectproc = pmac_ide_selectproc;
+       if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) {
+               ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
+#ifdef CONFIG_PMAC_IDEDMA_AUTO
+               ide_hwifs[ix].autodma = 1;
+#endif
+       }
 }
 
-void pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
+#if 0
+/* This one could be later extended to handle CMD IDE and be used by some kind
+ * of /proc interface. I want to be able to get the devicetree path of a block
+ * device for yaboot configuration
+ */
+struct device_node*
+pmac_ide_get_devnode(ide_drive_t *drive)
 {
-       ide_pio_data_t d;
+       int i = pmac_ide_find(drive);
+       if (i < 0)
+               return NULL;
+       return pmac_ide[i].node;
+}
+#endif
 
-       if (_machine != _MACH_Pmac)
+/* Setup timings for the selected drive (master/slave). I still need to verify if this
+ * is enough, I beleive selectproc will be called whenever an IDE command is started,
+ * but... */
+static void
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+       int i = pmac_ide_find(drive);
+       if (i < 0)
                return;
+                       
+       if (drive->select.all & 0x10)
+               out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]);
+       else
+               out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]);
+}
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t)                (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_UDMA(t)   (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS)
+
+/* Calculate PIO timings */
+static void
+pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
+{
+       ide_pio_data_t d;
+       int i;
+       u32 *timings;
+       int accessTicks, recTicks;
+       
+       i = pmac_ide_find(drive);
+       if (i < 0)
+               return;
+               
        pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-       switch (pio) {
-       case 4:
-               out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025);
-               break;
-       default:
-               out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526);
-               break;
+       if (drive->select.all & 0x10)
+               timings = &pmac_ide[i].timings[1];
+       else
+               timings = &pmac_ide[i].timings[0];
+
+       if (pmac_ide[i].kind == controller_kl_ata4) {
+               /* The "ata-4" IDE controller of Core99 machines */
+               accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000);
+               recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks;
+
+               *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5);
+       } else {
+               /* The old "ata-3" IDE controller */
+               accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+               if (accessTicks < 4)
+                       accessTicks = 4;
+               recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4;
+               if (recTicks < 1)
+                       recTicks = 1;
+       
+               *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
        }
+       
+#ifdef IDE_PMAC_DEBUG
+       printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+               pio,  *timings);
+#endif 
+               
+       if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
+               pmac_ide_selectproc(drive);
+}
+
+ide_ioreg_t
+pmac_ide_get_base(int index)
+{
+       return pmac_ide[index].regbase;
+}
+
+static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+
+__initfunc(kdev_t pmac_find_ide_boot(char *bootdevice, int n))
+{
+       int i;
+       
+       /*
+        * Look through the list of IDE interfaces for this one.
+        */
+       for (i = 0; i < pmac_ide_count; ++i) {
+               char *name;
+               if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+                       continue;
+               name = pmac_ide[i].node->full_name;
+               if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+                       /* XXX should cope with the 2nd drive as well... */
+                       return MKDEV(ide_majors[i], 0);
+               }
+       }
+
+       return 0;
 }
 
 __initfunc(void
@@ -122,7 +294,7 @@ pmac_ide_probe(void))
        struct device_node *atas;
        struct device_node *p, **pp, *removables, **rp;
        unsigned long base;
-       int irq;
+       int irq, big_delay;
        ide_hwif_t *hwif;
 
        if (_machine != _MACH_Pmac)
@@ -150,9 +322,11 @@ pmac_ide_probe(void))
        }
        *rp = NULL;
        *pp = removables;
+       big_delay = 0;
 
        for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
                struct device_node *tp;
+               int *bidp;
 
                /*
                 * If this node is not under a mac-io or dbdma node,
@@ -193,32 +367,79 @@ pmac_ide_probe(void))
                } else {
                        irq = np->intrs[0].line;
                }
-               pmac_ide_regbase[i] = base;
-               pmac_ide_irq[i] = irq;
-               pmac_ide_node[i] = np;
+               pmac_ide[i].regbase = base;
+               pmac_ide[i].irq = irq;
+               pmac_ide[i].node = np;
+               if (device_is_compatible(np, "keylargo-ata")) {
+                       if (strcmp(np->name, "ata-4") == 0)
+                               pmac_ide[i].kind = controller_kl_ata4;
+                       else
+                               pmac_ide[i].kind = controller_kl_ata3;
+               } else if (device_is_compatible(np, "heathrow-ata"))
+                       pmac_ide[i].kind = controller_heathrow;
+               else
+                       pmac_ide[i].kind = controller_ohare;
+
+               bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+               pmac_ide[i].aapl_bus_id =  bidp ? *bidp : 0;
 
                if (np->parent && np->parent->name
                    && strcasecmp(np->parent->name, "media-bay") == 0) {
                        media_bay_set_ide_infos(np->parent,base,irq,i);
-               } else
-                       feature_set(np, FEATURE_IDE_enable);
-
+               } else if (pmac_ide[i].kind == controller_ohare) {
+                       /* The code below is having trouble on some ohare machines
+                        * (timing related ?). Until I can put my hand on one of these
+                        * units, I keep the old way
+                        */
+                        feature_set(np, FEATURE_IDE0_enable);
+                        feature_set(np, FEATURE_IOBUS_enable);
+               } else {
+                       /* This is necessary to enable IDE when net-booting */
+                       printk("pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id);
+                       switch(pmac_ide[i].aapl_bus_id) {
+                           case 0:
+                               feature_set(np, FEATURE_IDE0_reset);
+                               feature_set(np, FEATURE_IOBUS_enable);
+                               mdelay(10);
+                               feature_set(np, FEATURE_IDE0_enable);
+                               mdelay(10);
+                               feature_clear(np, FEATURE_IDE0_reset);
+                               break;
+                           case 1:
+                               feature_set(np, FEATURE_IDE1_reset);
+                               feature_set(np, FEATURE_IOBUS_enable);
+                               mdelay(10);
+                               feature_set(np, FEATURE_IDE1_enable);
+                               mdelay(10);
+                               feature_clear(np, FEATURE_IDE1_reset);
+                               break;
+                           case 2:
+                               /* This one exists only for KL, I don't know
+                                  about any enable bit */
+                               feature_set(np, FEATURE_IDE2_reset);
+                               mdelay(10);
+                               feature_clear(np, FEATURE_IDE2_reset);
+                               break;
+                       }
+                       big_delay = 1;
+               }
                hwif = &ide_hwifs[i];
                pmac_ide_init_hwif_ports(hwif->io_ports, base, &hwif->irq);
-               hwif->chipset = ide_generic;
-               hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-               hwif->tuneproc = pmac_ide_tuneproc;
+               hwif->chipset = ide_pmac;
+               hwif->noprobe = (check_media_bay_by_base(base, MB_CD) == -EINVAL);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
                if (np->n_addrs >= 2) {
                        /* has a DBDMA controller channel */
-                       pmac_ide_setup_dma(np, hwif);
+                       pmac_ide_setup_dma(np, i);
                }
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
                ++i;
        }
        pmac_ide_count = i;
+       if (big_delay)
+               mdelay(IDE_WAKEUP_DELAY_MS);
 
 #ifdef CONFIG_PMAC_PBOOK
        pmu_register_sleep_notifier(&idepmac_sleep_notifier);
@@ -228,26 +449,27 @@ pmac_ide_probe(void))
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
 __initfunc(static void
-pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif))
+pmac_ide_setup_dma(struct device_node *np, int ix))
 {
-       hwif->dma_base = (unsigned long) ioremap(np->addrs[1].address, 0x200);
+       pmac_ide[ix].dma_regs =
+               (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
 
        /*
         * Allocate space for the DBDMA commands.
         * The +2 is +1 for the stop command and +1 to allow for
         * aligning the start address to a multiple of 16 bytes.
         */
-       hwif->dmatable = (unsigned long *)
-              kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
-       if (hwif->dmatable == 0) {
+       pmac_ide[ix].dma_table = (struct dbdma_cmd*)
+               kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
+       if (pmac_ide[ix].dma_table == 0) {
                printk(KERN_ERR "%s: unable to allocate DMA command list\n",
-                      hwif->name);
+                      ide_hwifs[ix].name);
                return;
        }
 
-       hwif->dmaproc = &pmac_ide_dmaproc;
+       ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_PMAC_IDEDMA_AUTO
-       hwif->autodma = 1;
+       ide_hwifs[ix].autodma = 1;
 #endif
 }
 
@@ -256,19 +478,20 @@ pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif))
  * for a transfer and sets the DBDMA channel to point to it.
  */
 static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int wr)
+pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
 {
-       ide_hwif_t *hwif = HWIF(drive);
        struct dbdma_cmd *table, *tstart;
        int count = 0;
        struct request *rq = HWGROUP(drive)->rq;
        struct buffer_head *bh = rq->bh;
        unsigned int size, addr;
-       volatile struct dbdma_regs *dma
-               = (volatile struct dbdma_regs *) hwif->dma_base;
+       volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
 
-       table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(hwif->dmatable);
+       table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table);
        out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
+       /* Should this be dma->control like in macserial.c ? */
+       while (in_le32(&dma->status) & RUN)
+               udelay(1);
 
        do {
                /*
@@ -331,30 +554,274 @@ pmac_ide_build_dmatable(ide_drive_t *drive, int wr)
        return 1;
 }
 
+
+/* This is fun.  -DaveM */
+#define IDE_SETXFER            0x03
+#define IDE_SETFEATURE         0xef
+#define IDE_DMA2_ENABLE                0x22
+#define IDE_DMA1_ENABLE                0x21
+#define IDE_DMA0_ENABLE                0x20
+#define IDE_UDMA4_ENABLE       0x44
+#define IDE_UDMA3_ENABLE       0x43
+#define IDE_UDMA2_ENABLE       0x42
+#define IDE_UDMA1_ENABLE       0x41
+#define IDE_UDMA0_ENABLE       0x40
+
+static __inline__ unsigned char
+dma_bits_to_command(unsigned char bits)
+{
+       if(bits & 0x04)
+               return IDE_DMA2_ENABLE;
+       if(bits & 0x02)
+               return IDE_DMA1_ENABLE;
+       return IDE_DMA0_ENABLE;
+}
+
+static __inline__ unsigned char
+udma_bits_to_command(unsigned char bits)
+{
+       if(bits & 0x10)
+               return IDE_UDMA4_ENABLE;
+       if(bits & 0x08)
+               return IDE_UDMA3_ENABLE;
+       if(bits & 0x04)
+               return IDE_UDMA2_ENABLE;
+       if(bits & 0x02)
+               return IDE_UDMA1_ENABLE;
+       if(bits & 0x01)
+               return IDE_UDMA0_ENABLE;
+       return 0;
+}
+
+static __inline__ int
+wait_for_ready(ide_drive_t *drive)
+{
+       /* Timeout bumped for some powerbooks */
+       int timeout = 2000;
+       byte stat;
+
+       while(--timeout) {
+               stat = GET_STAT();
+               if(!(stat & BUSY_STAT)) {
+                       if (drive->ready_stat == 0)
+                               break;
+                       else if((stat & drive->ready_stat) || (stat & ERR_STAT))
+                               break;
+               }
+               mdelay(1);
+       }
+       if((stat & ERR_STAT) || timeout <= 0) {
+               if (stat & ERR_STAT) {
+                       printk("ide_pmace: wait_for_ready, error status: %x\n", stat);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+static int
+pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
+{
+       unsigned long flags;
+       byte old_select;
+       int result = 1;
+
+       save_flags(flags);
+       cli();
+       old_select = IN_BYTE(IDE_SELECT_REG);
+       OUT_BYTE(drive->select.all, IDE_SELECT_REG);
+       udelay(10);
+       OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
+       OUT_BYTE(command, IDE_NSECTOR_REG);
+       if(wait_for_ready(drive)) {
+               printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
+               goto out;
+       }
+       OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);
+       result = wait_for_ready(drive);
+       if (result)
+               printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
+out:
+       OUT_BYTE(old_select, IDE_SELECT_REG);
+       restore_flags(flags);
+       
+       return result;
+}
+
+/* Calculate MultiWord DMA timings */
+static int
+pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
+{
+       byte bits = drive->id->dma_mword & 0x07;
+       byte feature = dma_bits_to_command(bits);
+       u32 *timings;
+       int cycleTime, accessTime;
+       int accessTicks, recTicks;
+       struct hd_driveid *id = drive->id;
+       
+       /* Set feature on drive */
+       printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+       if (pmac_ide_do_setfeature(drive, feature)) {
+               printk("%s: Failed !\n", drive->name);
+               return 0;
+       }
+       
+       /* which drive is it ? */
+       if (drive->select.all & 0x10)
+               timings = &pmac_ide[idx].timings[1];
+       else
+               timings = &pmac_ide[idx].timings[0];
+
+       /* Calculate accesstime and cycle time */
+       cycleTime = mdma_timings[feature & 0xf].cycleTime;
+       accessTime = mdma_timings[feature & 0xf].accessTime;
+       if ((id->field_valid & 2) && (id->eide_dma_time))
+               cycleTime = id->eide_dma_time;
+       if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150))
+               cycleTime = 150;
+
+       /* For ata-4 controller, we don't know the calculation */
+       if (pmac_ide[idx].kind == controller_kl_ata4) {
+               accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+               recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
+               *timings = ((*timings) & 0xffe003ff) |
+                       (accessTicks | (recTicks << 5)) << 10;
+       } else {
+               int halfTick = 0;
+               int origAccessTime = accessTime;
+               int origCycleTime = cycleTime;
+               
+               accessTicks = SYSCLK_TICKS(accessTime);
+               if (accessTicks < 1)
+                       accessTicks = 1;
+               accessTime = accessTicks * IDE_SYSCLK_NS;
+               recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;
+               if (recTicks < 1)
+                       recTicks = 1;
+               cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
+
+               /* KeyLargo ata-3 don't support the half-tick stuff */
+               if ((pmac_ide[idx].kind != controller_kl_ata3) &&
+                       (accessTicks > 1) &&
+                       ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+                       ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
+                               halfTick    = 1;
+                               accessTicks--;
+               }
+               *timings = ((*timings) & 0x7FF) |
+                       (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
+       }
+#ifdef IDE_PMAC_DEBUG
+       printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+               feature & 0xf, *timings);
+#endif 
+       return 1;
+}
+
+/* Calculate Ultra DMA timings */
+static int
+pmac_ide_udma_enable(ide_drive_t *drive, int idx)
+{
+       byte bits = drive->id->dma_ultra & 0x1f;
+       byte feature = udma_bits_to_command(bits);
+       int cycleTime, accessTime;
+       int rdyToPauseTicks, cycleTicks;
+       u32 *timings;
+       
+       /* Set feature on drive */
+       printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+       if (pmac_ide_do_setfeature(drive, feature)) {
+               printk("%s: Failed !\n", drive->name);
+               return 0;
+       }
+
+       /* which drive is it ? */
+       if (drive->select.all & 0x10)
+               timings = &pmac_ide[idx].timings[1];
+       else
+               timings = &pmac_ide[idx].timings[0];
+       
+
+       cycleTime = udma_timings[feature & 0xf].cycleTime;
+       accessTime = udma_timings[feature & 0xf].accessTime;
+
+       rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+       cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
+       
+       *timings = ((*timings) & 0xe00fffff) |
+                       ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+       return 1;
+}
+
+static int
+pmac_ide_dma_onoff(ide_drive_t *drive, int enable)
+{
+       int ata4, udma, idx;
+       struct hd_driveid *id = drive->id;
+
+       drive->using_dma = 0;
+       
+       idx = pmac_ide_find(drive);
+       if (idx < 0)
+               return 0;
+               
+       if (drive->media == ide_floppy)
+               enable = 0;
+       if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
+               enable = 0;
+       if (check_drive_lists(drive, BAD_DMA_DRIVE))
+               enable = 0;
+
+       udma = 0;
+       ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
+                       
+       if(enable) {
+               if (ata4 && (drive->media == ide_disk) &&
+                   (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
+                       /* UltraDMA modes. */
+                       drive->using_dma = pmac_ide_udma_enable(drive, idx);
+               }
+               if (!drive->using_dma && (id->dma_mword & 0x0007)) {
+                       /* Normal MultiWord DMA modes. */
+                       drive->using_dma = pmac_ide_mdma_enable(drive, idx);
+               }
+               /* Without this, strange things will happen on Keylargo-based
+                * machines
+                */
+               OUT_BYTE(0, IDE_CONTROL_REG);
+               if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
+                       pmac_ide_selectproc(drive);
+       }
+       return 0;
+}
+
 int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       volatile struct dbdma_regs *dma
-               = (volatile struct dbdma_regs *) hwif->dma_base;
-       int dstat;
+       int ix, dstat;
+       volatile struct dbdma_regs *dma;
+
+       /* Can we stuff a pointer to our intf structure in config_data
+        * or select_data in hwif ?
+        */
+       ix = pmac_ide_find(drive);
+       if (ix < 0)
+               return 0;               
+       dma = pmac_ide[ix].dma_regs;
 
        switch (func) {
        case ide_dma_on:
-               /* ide-floppy DMA doesn't work yet... */
-               drive->using_dma = drive->media != ide_floppy;
-               break;
        case ide_dma_off:
-               printk(KERN_INFO "%s: DMA disabled\n", drive->name);
        case ide_dma_off_quietly:
-               drive->using_dma = 0;
+               pmac_ide_dma_onoff(drive, (func == ide_dma_on));
                break;
        case ide_dma_check:
-               /* ide-floppy DMA doesn't work yet... */
-               drive->using_dma = hwif->autodma && drive->media != ide_floppy;
+               if (hwif->autodma)
+                       pmac_ide_dma_onoff(drive, 1);
                break;
        case ide_dma_read:
        case ide_dma_write:
-               if (!pmac_ide_build_dmatable(drive, func==ide_dma_write))
+               if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
                        return 1;
                drive->waiting_for_dma = 1;
                if (drive->media != ide_disk)
@@ -383,11 +850,9 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 #ifdef CONFIG_PMAC_PBOOK
 static void idepmac_sleep_disk(int i, unsigned long base)
 {
+       struct device_node* np = pmac_ide[i].node;
        int j;
 
-       /* Reset to PIO 0 */
-       out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
-
        /* FIXME: We only handle the master IDE */
        if (ide_hwifs[i].drives[0].media == ide_disk) {
                /* Spin down the drive */
@@ -406,22 +871,61 @@ static void idepmac_sleep_disk(int i, unsigned long base)
                                break;
                }
        }
+       feature_set(np, FEATURE_IDE0_reset);
+       feature_clear(np, FEATURE_IDE0_enable);
+       switch(pmac_ide[i].aapl_bus_id) {
+           case 0:
+               feature_set(np, FEATURE_IDE0_reset);
+               feature_clear(np, FEATURE_IDE0_enable);
+               break;
+           case 1:
+               feature_set(np, FEATURE_IDE1_reset);
+               feature_clear(np, FEATURE_IDE1_enable);
+               break;
+           case 2:
+               feature_set(np, FEATURE_IDE2_reset);
+               break;
+       }
+       pmac_ide[i].timings[0] = 0;
+       pmac_ide[i].timings[1] = 0;
 }
 
 static void idepmac_wake_disk(int i, unsigned long base)
 {
+       struct device_node* np = pmac_ide[i].node;
        int j;
 
        /* Revive IDE disk and controller */
-       feature_set(pmac_ide_node[i], FEATURE_IDE_enable);
-       mdelay(1);
-       feature_set(pmac_ide_node[i], FEATURE_IDE_DiskPower);
-       mdelay(100);
-       feature_set(pmac_ide_node[i], FEATURE_IDE_Reset);
-       mdelay(1);
-       /* Make sure we are still PIO0 */
-       out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
-       mdelay(100);
+       switch(pmac_ide[i].aapl_bus_id) {
+           case 0:
+               feature_set(np, FEATURE_IDE0_reset);
+               feature_set(np, FEATURE_IOBUS_enable);
+               mdelay(10);
+               feature_set(np, FEATURE_IDE0_enable);
+               mdelay(10);
+               feature_clear(np, FEATURE_IDE0_reset);
+               break;
+           case 1:
+               feature_set(np, FEATURE_IDE1_reset);
+               feature_set(np, FEATURE_IOBUS_enable);
+               mdelay(10);
+               feature_set(np, FEATURE_IDE1_enable);
+               mdelay(10);
+               feature_clear(np, FEATURE_IDE1_reset);
+               break;
+           case 2:
+               /* This one exists only for KL, I don't know
+                  about any enable bit */
+               feature_set(np, FEATURE_IDE2_reset);
+               mdelay(10);
+               feature_clear(np, FEATURE_IDE2_reset);
+               break;
+       }
+       mdelay(IDE_WAKEUP_DELAY_MS);
+
+       /* Reset timings */
+       pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
+       mdelay(10);
 
        /* Wait up to 10 seconds (enough for recent drives) */
        for (j = 0; j < 100; j++) {
@@ -439,14 +943,22 @@ idepmac_wake_bay(int i, unsigned long base)
 {
        int timeout;
 
-       timeout = 5000;
+       /* Reset timings */
+       pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
+       mdelay(10);
+
+       timeout = 10000;
        while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
                mdelay(1);
                --timeout;
        }
 }
 
-static int idepmac_notify(struct pmu_sleep_notifier *self, int when)
+/* Note: We support only master drives for now. This will have to be
+ * improved if we want to handle sleep on the iMacDV where the CD-ROM
+ * is a slave
+ */
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
        int i, ret;
        unsigned long base;
@@ -458,27 +970,34 @@ static int idepmac_notify(struct pmu_sleep_notifier *self, int when)
                break;
        case PBOOK_SLEEP_NOW:
                for (i = 0; i < pmac_ide_count; ++i) {
-                       if ((base = pmac_ide_regbase[i]) == 0)
+                       if ((base = pmac_ide[i].regbase) == 0)
                                continue;
                        /* Disable irq during sleep */
-                       disable_irq(pmac_ide_irq[i]);
+                       disable_irq(pmac_ide[i].irq);
                        ret = check_media_bay_by_base(base, MB_CD);
-                       if (ret == -ENODEV)
+                       if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
                                /* not media bay - put the disk to sleep */
                                idepmac_sleep_disk(i, base);
                }
                break;
        case PBOOK_WAKE:
                for (i = 0; i < pmac_ide_count; ++i) {
-                       if ((base = pmac_ide_regbase[i]) == 0)
+                       ide_hwif_t *hwif;
+                       if ((base = pmac_ide[i].regbase) == 0)
                                continue;
+                       hwif = &ide_hwifs[i];
                        /* We don't handle media bay devices this way */
                        ret = check_media_bay_by_base(base, MB_CD);
-                       if (ret == -ENODEV)
+                       if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
                                idepmac_wake_disk(i, base);
                        else if (ret == 0)
                                idepmac_wake_bay(i, base);
-                       enable_irq(pmac_ide_irq[i]);
+                       enable_irq(pmac_ide[i].irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+                       if (hwif->drives[0].present && hwif->drives[0].using_dma)
+                               pmac_ide_dma_onoff(&hwif->drives[0], 1);
+#endif                         
                }
                break;
        }
index 0af96fedb80078d947b31b0c044e9dde7bb8bca4..489a0db1de77592f091eb3d5735304f2aa125a10 100644 (file)
@@ -109,8 +109,16 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                                }
                                type = ide_cdrom;       /* Early cdrom models used zero */
                        case ide_cdrom:
-                               printk ("CDROM");
                                drive->removable = 1;
+#ifdef CONFIG_PPC
+                               /* kludge for Apple PowerBook internal zip */
+                               if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+                                       printk ("FLOPPY");
+                                       type = ide_floppy;
+                                       break;
+                               }
+#endif
+                               printk ("CDROM");
                                break;
                        case ide_tape:
                                printk ("TAPE");
index a2bc04c477989b6aefbdde668ede4616615c60b1..3f0ca608f6cae1fb9204f2db67b0457d365e498a 100644 (file)
@@ -333,6 +333,7 @@ static int proc_ide_read_imodel
                case ide_rz1000:        name = "rz1000";        break;
                case ide_trm290:        name = "trm290";        break;
                case ide_4drives:       name = "4drives";       break;
+               case ide_pmac:          name = "mac-io";        break;
                default:                name = "(unknown)";     break;
        }
        len = sprintf(page, "%s\n", name);
index 3f940246806059e415ffdddd37f8d3c5d6670f94..04b8b26e33ccbc440d8664ae9aadd9861e1786e7 100644 (file)
@@ -306,7 +306,7 @@ typedef enum {      ide_unknown,    ide_generic,    ide_pci,
                ide_cmd640,     ide_dtc2278,    ide_ali14xx,
                ide_qd6580,     ide_umc8672,    ide_ht6560b,
                ide_pdc4030,    ide_rz1000,     ide_trm290,
-               ide_cmd646,     ide_4drives
+               ide_cmd646,     ide_4drives,    ide_pmac
        } hwif_chipset_t;
 
 typedef struct ide_pci_devid_s {
index 7cb0f3bfc2d3e5568f2ad4efee92aa49eee6214c..25a6c5e056df5990962429d0f0c0409f395f5a84 100644 (file)
@@ -587,6 +587,9 @@ done:
        set_fs(fs);
 }
 
+#ifdef CONFIG_MAC_FLOPPY
+int swim3_fd_eject(int devnum);
+#endif
 
 __initfunc(static void rd_load_disk(int n))
 {
@@ -607,6 +610,12 @@ __initfunc(static void rd_load_disk(int n))
        if (rd_prompt) {
 #ifdef CONFIG_BLK_DEV_FD
                floppy_eject();
+#endif
+#ifdef CONFIG_MAC_FLOPPY
+               if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR)
+                       swim3_fd_eject(MINOR(ROOT_DEV));
+               else if(MAJOR(real_root_dev) == FLOPPY_MAJOR)
+                       swim3_fd_eject(MINOR(real_root_dev));
 #endif
                printk(KERN_NOTICE
                       "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n");
index 246405aff1ed917f3135915009bfb127d2a4b6d1..2936c57d12c40b42a679e482482df2d04e4e1be4 100644 (file)
@@ -808,6 +808,16 @@ static int fd_eject(struct floppy_state *fs)
        return err;
 }
 
+int swim3_fd_eject(int devnum)
+{
+       if (devnum >= floppy_count)
+               return -ENODEV;
+       /* Do not check this - this function should ONLY be called early
+        * in the boot process! */
+       /* if (floppy_states[devnum].ref_count != 1) return -EBUSY; */
+       return fd_eject(&floppy_states[devnum]);
+}
+
 static struct floppy_struct floppy_type =
        { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };    /*  7 1.44MB 3.5"   */
 
index e3649ca1a2985e67405e586c3123c65f52d05b38..a2d446440fdecb69b3aa60d4e4d368179c5bc9b3 100644 (file)
@@ -36,6 +36,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_PPC_RTC),y)
+  L_OBJS += rtc.o
+else
+  ifeq ($(CONFIG_PPC_RTC),m)
+    M_OBJS += rtc.o
+  endif
+endif
+
 ifdef CONFIG_MAC_KEYBOARD
 L_OBJS += mac_keyb.o
 endif
diff --git a/drivers/macintosh/rtc.c b/drivers/macintosh/rtc.c
new file mode 100644 (file)
index 0000000..a5a5656
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Linux/PowerPC Real Time Clock Driver
+ *
+ * heavily based on:
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * This is a little driver that lets a user-level program access
+ * the PPC clocks chip. It is no use unless you
+ * use the modified clock utility.
+ *
+ * Get the modified clock utility from:
+ *   ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+/* in kernel/time.c, these prototypes shouldn't be here */
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
+                            unsigned int, unsigned int, unsigned int);
+extern void to_tm(int tim, struct rtc_time * tm);
+
+static int rtc_busy = 0;
+
+/* Retrieve the current date and time from the real time clock. */
+void get_rtc_time(struct rtc_time *t)
+{
+       unsigned long nowtime;
+    
+       nowtime = (ppc_md.get_rtc_time)();
+
+       to_tm(nowtime, t);
+
+       t->tm_year -= 1900;
+       t->tm_mon -= 1;
+       t->tm_wday -= 1;
+}
+
+/* Set the current date and time inthe real time clock. */
+void set_rtc_time(struct rtc_time *t)
+{
+       unsigned long nowtime;
+
+       printk(KERN_INFO "rtc.c:set_rtc_time: %04d-%02d-%02d %02d:%02d:%02d.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+
+       nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+
+       printk(KERN_INFO "rtc.c:set_rtc_time: set rtc time to %d seconds.\n", nowtime);
+
+       (ppc_md.set_rtc_time)(nowtime);
+}
+
+static long long rtc_lseek(struct file *file, long long offset, int origin)
+{
+       return -ESPIPE;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+       unsigned long arg)
+{
+       struct rtc_time rtc_tm;
+
+       switch (cmd)
+       {
+       case RTC_RD_TIME:
+               if (ppc_md.get_rtc_time)
+               {
+                       get_rtc_time(&rtc_tm);
+
+                       copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT);
+
+                       return 0;
+               }
+               else
+                       return -EINVAL;
+
+       case RTC_SET_TIME:
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+
+               if (ppc_md.set_rtc_time)
+               {
+                       copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT);
+
+                       set_rtc_time(&rtc_tm);
+
+                       return 0;
+               }
+               else
+                       return -EINVAL;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+       if (rtc_busy)
+               return -EBUSY;
+
+       rtc_busy = 1;
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+       MOD_DEC_USE_COUNT;
+       rtc_busy = 0;
+       return 0;
+}
+
+static struct file_operations rtc_fops = {
+       rtc_lseek,
+       NULL,           /* rtc_read */
+       NULL,           /* rtc_write */
+       NULL,           /* rtc_readdir */
+       NULL,           /* rtc_poll */
+       rtc_ioctl,
+       NULL,           /* rtc_mmap */
+       rtc_open,
+       NULL,           /* flush */
+       rtc_release
+};
+
+static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int rtc_init(void))
+#endif
+{
+       int error;
+
+       error = misc_register(&rtc_dev);
+       if (error) {
+               printk(KERN_ERR "rtc: unable to get misc minor\n");
+               return error;
+       }
+
+       return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       misc_deregister(&rtc_dev);
+}
+#endif
index 821b72f3e88aa0492b6d159d5314ab7908a541d0..8cc46e7c49d7f8e90238f39a4b7fee35b84910fe 100644 (file)
     - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex): clear
       tbusy and force a BH rerun to better recover from errors.
 
+    12Jun00 <2.2.16> andrewm
+    - Better handling of shared interrupts
+    - Reset the transmitter in vortex_error() on both maxcollisions and Tx reclaim error
+
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details.
 */
 
 static char *version =
-"3c59x.c:v0.99H 27May00 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99H 12Jun00 Donald Becker and others http://www.scyld.com/network/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -1443,8 +1447,8 @@ vortex_error(struct device *dev, int status)
                if (tx_status & 0x14)  vp->stats.tx_fifo_errors++;
                if (tx_status & 0x38)  vp->stats.tx_aborted_errors++;
                outb(0, ioaddr + TxStatus);
-               if (tx_status & 0x30)
-                       do_tx_reset = 1;
+               if (tx_status & 0x3a)   /* TxReset after 16 collisions, despite what the manual says */
+                       do_tx_reset = 1;        /* Also reset on reclaim errors */
                else                                    /* Merely re-enable the transmitter. */
                        outw(TxEnable, ioaddr + EL3_CMD);
        }
@@ -1650,14 +1654,14 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        struct device *dev = dev_id;
        struct vortex_private *vp = (struct vortex_private *)dev->priv;
        long ioaddr;
-       int latency, status;
+       int status;
        int work_done = max_interrupt_work;
 
-       spin_lock(&vp->lock);
-
        ioaddr = dev->base_addr;
-       latency = inb(ioaddr + Timer);
+       spin_lock(&vp->lock);
        status = inw(ioaddr + EL3_STATUS);
+       if ((status & IntLatch) == 0)
+               goto no_int;    /* Happens during shared interrupts */
 
        if (status & IntReq) {
                status |= vp->deferred;
@@ -1666,7 +1670,8 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        if (vortex_debug > 4)
                printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
-                          dev->name, status, latency);
+                          dev->name, status, inb(ioaddr + Timer));
+
        do {
                if (vortex_debug > 5)
                                printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
@@ -1761,8 +1766,8 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
                           dev->name, status);
 
+no_int:
        spin_unlock(&vp->lock);
-       return;
 }
 
 static int vortex_rx(struct device *dev)
index 399aa68bd6caa41b20272dbe33aa4c93a076af35..a6ee66c3427676e01ad37ee6b14481ddfbb568a2 100644 (file)
 #define DMFE_AUTO       8
 
 #define DMFE_TIMER_WUT  jiffies+(HZ*2)/2       /* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT HZ*1.5 /* tx packet time-out time 1.5 s" */
+#define DMFE_TX_TIMEOUT ((HZ*3)/2)     /* tx packet time-out time 1.5 s" */
 
 #define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule)
 
index 3472b3bf63877643ff77107d75f84ae234ee42e7..0916990adc5dbb5554a20eed1645a5d01ce70016 100644 (file)
@@ -41,7 +41,7 @@
 #ifndef MODULE
 static int version_printed=0;
 #endif
-static const char* version = "HDLC support routines revision: 1.0-pre9";
+static const char* version = "HDLC support routines revision: 1.0-pre10";
 
 
 #define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
@@ -139,9 +139,11 @@ static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
 #endif
 
        case CISCO_KEEPALIVE:
-               if (skb->len != sizeof(cisco_packet)) {
+               if (skb->len != CISCO_PACKET_LEN && 
+                   skb->len != CISCO_BIG_PACKET_LEN) {
                        printk(KERN_INFO "%s: Invalid length of Cisco "
-                              "control packet\n", hdlc->name);
+                              "control packet (%d bytes)\n", hdlc->name, 
+                              skb->len);
                        goto rx_error;
                }
 
index cd1265a4d34ebdeb659bf406d70e32d7b27e59f5..1fe61a348437423c98d49f6573bb1a0f7a0a65d6 100644 (file)
@@ -6,13 +6,13 @@
 
 ifeq ($(CONFIG_LANMEDIA),y)
     O_TARGET := lmc.o
-    O_OBJS = lmc_debug.o lmc_media.o lmc_main.o
+    O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
 else
   ifeq ($(CONFIG_LANMEDIA),m)
     MOD_LIST_NAME := NET_MODULES
     M_OBJS := lmc.o
     O_TARGET := lmc.o
-    O_OBJS = lmc_debug.o lmc_media.o lmc_main.o
+    O_OBJS = lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
   endif
 endif
 
index e1e29123ddc6ad33fc6f80aab9e314f5abe9f775..91b9e8f00ee1d09a96bb6e03460dd16399d49f60 100644 (file)
@@ -6,7 +6,7 @@
 /*
  * prototypes for everyone
  */
-int lmc_probe(struct device * dev);
+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,
@@ -18,6 +18,8 @@ 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;
index 0f36e31349cc7bebf5274174a26ffc19dc06450e..fa475e6c68459d5fa6558c7341ded0a30dd8eeac 100644 (file)
@@ -1,6 +1,10 @@
 
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include "lmc_ver.h"
 #include "lmc_debug.h"
 
 /*
@@ -45,20 +49,20 @@ void lmcConsoleLog(char *type, unsigned char *ucData, int iLen)
 #endif
 }
 
-#ifdef DEBUG
-u_int32_t lmcEventLogIndex = 0;
-u_int32_t lmcEventLogBuf[LMC_EVENTLOGSIZE * LMC_EVENTLOGARGS];
-#endif
+inline void lmc_trace(struct net_device *dev, char *msg){
+#ifdef LMC_TRACE
+    unsigned long j = jiffies + 3; /* Wait for 50 ms */
 
-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;
+    if(in_interrupt()){
+        printk("%s: * %s\n", dev->name, msg);
+//        while(jiffies < j+10)
+//            ;
+    }
+    else {
+        printk("%s: %s\n", dev->name, msg);
+        while(jiffies < j)
+            schedule();
+    }
 #endif
 }
 
index f39adcfa90bfefa7d27473c74b6bb99b0c5a834a..5fdcf8a065d12d5f7e4575f2a0968a3f64e93e5c 100644 (file)
 #define LMC_CONSOLE_LOG(x,y,z)
 #endif
 
-
-
-/* Debug --- Event log definitions --- */
-/* EVENTLOGSIZE*EVENTLOGARGS needs to be a power of 2 */
-#define LMC_EVENTLOGSIZE 512   /* 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
-
-
-#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);
+inline void lmc_trace(struct net_device *dev, char *msg);
 
 #endif
index 77d00b1b20e34cd31832475328a788925c5d7381..569fdac6868630231357331df63973fa42048b9d 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef _LMC_IOCTL_H_
 #define _LMC_IOCTL_H_
-/*     $Id: lmc_ioctl.h,v 1.9 2000/01/21 13:29:47 asj Exp $    */
+/*     $Id: lmc_ioctl.h,v 1.18 2000/06/06 08:32:12 asj Exp $   */
 
  /*
   * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
   * of the GNU 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 LMCIOCSKEEPALIVE    SIOCDEVPRIVATE+5 /* Turn keepalives on/off */
-#ifdef  LMC_DEBUG_FILE
-#define LMCIOCLEARSTATS LMCIOCSINFO + 1 /* Clear debug stats */
-#endif
-#define LMCIOCGETLMCSTATS       LMCIOCSINFO + 3
-#define LMCIOCCLEARLMCSTATS     LMCIOCSINFO + 4
-#define LMCIOCDUMPEVENTLOG      LMCIOCSINFO + 5
-#define LMCIOCGETXINFO          LMCIOCSINFO + 6
-#define LMCIOCSETCIRCUIT        LMCIOCSINFO + 7
-#define LMCIOCUNUSEDATM         LMCIOCSINFO + 8
-#define LMCIOCRESET             LMCIOCSINFO + 9
-#define LMCIOCT1CONTROL         LMCIOCSINFO + 10
-
-#define LMC_CARDTYPE_UNKNOWN    -1
+#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 LMCIOCMEDIA             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_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.
  */
  */
 #define LMC_GEP_INIT           0x01 /* 0: */
 #define LMC_GEP_RESET          0x02 /* 1: */
-#define LMC_GEP_LOAD           0x10 /* 4: */
+#define LMC_GEP_MODE           0x10 /* 4: */
 #define LMC_GEP_DP             0x20 /* 5: */
-#define LMC_GEP_SERIAL         0x40 /* 6: serial out */
-#define LMC_GEP_SERIALCLK      0x80 /* 7: serial clock */
+#define LMC_GEP_DATA           0x40 /* 6: serial out */
+#define LMC_GEP_CLK            0x80 /* 7: serial clock */
 
 /*
  * HSSI GPIO assignments
 #define LMC_GEP_HSSI_CLOCK     0x08 /* 3: clock source */
 
 /*
- * T1 GPIO assignments
+ * SSI 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 */
 
+/*
+ * T1 GPIO assigments
+ */
+#define LMC_GEP_T1_INT         0x08 /* 3: Interupt enable */
+
 /*
  * Common MII16 bits
  */
 #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 */
 /*
  * And T1, LMC1200
  */
-#define LMC_MII16_T1_UNUSED1    0x0003
+#define LMC_MII16_T1_UNUSED1            0x0001
+#define LMC_MII16_T1_INVERT             0x0002
 #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_T1F_WRITE       0
 #define LMC_T1F_READ        1
 
+enum lmc_st1f_cmd {
+    lmc_st1f_write = 1,
+    lmc_st1f_read = 2,
+    lmc_st1f_inv = 3,
+    lmc_st1f_amisf = 4,
+    lmc_st1f_frac = 5,
+    lmc_st1f_loopt = 6,
+};
+
 typedef struct lmc_st1f_control {
   int command;
   int address;
@@ -231,9 +252,23 @@ typedef struct lmc_st1f_control {
   char *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 *data;
+};
+
 /* ------------------ end T1 defs ------------------- */
 
 #define LMC_MII_LedMask                 0x0780
 #define LMC_MII_LedBitPos               7
 
-#endif
\ No newline at end of file
+#endif
index 67fbb277225abeb778b01c650566214578aaad33..d08a5f3c4f2ca9f51c6f782e00df5183f8c8512c 100644 (file)
@@ -11,7 +11,7 @@
   * With Help By:
   * David Boggs
   * Ron Crane
-  * Allan Cox
+  * Alan Cox
   *
   * This software may be used and distributed according to the terms
   * of the GNU Public License version 2, incorporated herein by reference.
   *
   */
 
-/* $Id: lmc_main.c,v 1.24 2000/01/21 13:29:48 asj Exp $ */
+/* $Id: lmc_main.c,v 1.44 2000/06/19 16:53:59 asj Exp $ */
 
-#include <linux/version.h>
 #include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/delay.h>
 #include <asm/segment.h>
-#include <asm/smp.h>
-
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h>
-#endif
+#include <linux/init.h>
 
 #include <linux/in.h>
 #include <linux/if_arp.h>
 
 #if LINUX_VERSION_CODE >= 0x20200
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
-#endif
-
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
+//#include <asm/spinlock.h>
+#else                          /* 2.0 kernel */
+#define ARPHRD_HDLC 513
 #endif
 
 #define DRIVER_MAJOR_VERSION     1
-#define DRIVER_MINOR_VERSION    33
-#define DRIVER_SUB_VERSION       1
+#define DRIVER_MINOR_VERSION    34
+#define DRIVER_SUB_VERSION       7
 
 #define DRIVER_VERSION  ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)
 
-#include "lmc.h"
 #include "lmc_ver.h"
+#include "lmc.h"
 #include "lmc_var.h"
 #include "lmc_ioctl.h"
 #include "lmc_debug.h"
+#include "lmc_proto.h"
+
 
 static int Lmc_Count = 0;
-static struct device *Lmc_root_dev = NULL;
+static struct net_device *Lmc_root_dev = NULL;
 static u8 cards_found = 0;
 
 static int lmc_first_load = 0;
 
-int lmc_probe_fake(struct device *dev);
-static struct device *lmc_probe1(struct device *dev, int ioaddr, int irq,
-                                int chip_id, int subdevice, int board_idx);
-static int lmc_start_xmit(struct sk_buff *skb, struct device *dev);
-static int lmc_rx(struct device *dev);
-static int lmc_open(struct device *dev);
-static int lmc_close(struct device *dev);
-static struct enet_statistics *lmc_get_stats(struct device *dev);
+int LMC_PKT_BUF_SZ = 1542;
+
+#if LINUX_VERSION_CODE >= 0x20363
+#ifdef MODULE
+static struct pci_device_id lmc_pci_tbl[] __devinitdata = {
+    { 0x1011, 0x009, 0x1376, PCI_ANY_ID, 0, 0, 0},
+    { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);
+#endif
+#endif
+
+
+int lmc_probe_fake(struct net_device *dev);
+static struct net_device *lmc_probe1(struct net_device *dev, unsigned long ioaddr, unsigned int irq,
+                                int chip_id, int subdevice, int board_idx, void *pci_dev);
+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 enet_statistics *lmc_get_stats(struct net_device *dev);
 static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int lmc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int lmc_set_config(struct device *dev, struct ifmap *map);
-static void lmc_initcsrs(lmc_softc_t * const, u32, size_t);
+static int lmc_set_config(struct net_device *dev, struct ifmap *map);
+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 device *dev);
-static int lmc_ifdown(struct device * 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 int lmc_init(struct device * const);
+static int lmc_init(struct net_device * const);
 static void lmc_reset(lmc_softc_t * const sc);
 static void lmc_dec_reset(lmc_softc_t * const sc);
-static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base,size_t csr_size);
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev);
+int lmc_setup(void);
+#endif
+
 
 /*
  * linux reserves 16 device specific IOCTLs.  We call them
  * LMCIOC* to control various bits of our world.
  */
-static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
+int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 {
     lmc_softc_t *sc;
     lmc_ctl_t ctl;
@@ -143,23 +153,25 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 
     sc = dev->priv;
 
+    lmc_trace(dev, "lmc_ioctl in");
+
     /*
      * Most functions mess with the structure
      * Disable interupts while we do the polling
      */
-    spin_lock_irqsave(&sc->lmc_lock, flags);
+    LMC_SPIN_LOCK_IRQSAVE(sc);
 
     switch (cmd) {
         /*
          * Return current driver state.  Since we keep this up
          * To date internally, just copy this out to the user.
          */
-    case LMCIOCGINFO:
+    case LMCIOCGINFO: /*fold01*/
         LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t));
         ret = 0;
         break;
 
-    case LMCIOCSINFO:
+    case LMCIOCSINFO: /*fold01*/
         sp = &((struct ppp_device *) dev)->sppp;
         if (!suser ()) {
             ret = -EPERM;
@@ -177,6 +189,10 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 
         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)
@@ -186,7 +202,39 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 
         ret = 0;
         break;
-    case LMCIOCGETXINFO:
+
+    case LMCIOCIFTYPE: /*fold01*/
+        {
+            u_int16_t  old_type = sc->if_type;
+            u_int16_t  new_type;
+
+           if (!suser ()) {
+               ret = -EPERM;
+               break;
+           }
+
+           LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t));
+
+            
+           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;
@@ -196,7 +244,7 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
         sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION;
         sc->lmc_xinfo.XilinxRevisionNumber =
             lmc_mii_readreg (sc, 0, 3) & 0xf;
-        sc->lmc_xinfo.MaxFrameSize = PKT_BUF_SZ;
+        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);
 
@@ -208,7 +256,7 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 
         break;
 
-    case LMCIOCGETLMCSTATS:
+    case LMCIOCGETLMCSTATS: /*fold01*/
         if (sc->lmc_cardtype == LMC_CARDTYPE_T1){
             lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB);
             sc->stats.framingBitErrorCount +=
@@ -239,7 +287,7 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
         ret = 0;
         break;
 
-    case LMCIOCCLEARLMCSTATS:
+    case LMCIOCCLEARLMCSTATS: /*fold01*/
         if (!suser ()){
             ret = -EPERM;
             break;
@@ -253,7 +301,7 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
         ret = 0;
         break;
 
-    case LMCIOCSETCIRCUIT:
+    case LMCIOCSETCIRCUIT: /*fold01*/
         if (!suser ()){
             ret = -EPERM;
             break;
@@ -271,7 +319,7 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 
         break;
 
-    case LMCIOCRESET:
+    case LMCIOCRESET: /*fold01*/
         if (!suser ()){
             ret = -EPERM;
             break;
@@ -282,31 +330,289 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
         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;
+    case LMCIOCMEDIA: /*fold01*/
+        ret = sc->lmc_media->ioctl(sc, ifr->ifr_data);
+        break;
+    case LMCIOCXILINX: /*fold01*/
+        {
+            struct lmc_xilinx_control xc; /*fold02*/
 
-#ifdef DEBUG
-    case LMCIOCDUMPEVENTLOG:
-        LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32));
-        LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf));
+            if (!suser ()){
+                ret = -EPERM;
+                break;
+            }
+
+            /*
+             * Stop the xwitter whlie we restart the hardware
+             */
+            LMC_XMITTER_BUSY(dev);
+
+            LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control));
+            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, cpu_to_le32(sc->lmc_gpio));
+
+
+                    /*
+                     * hold for more than 10 microseconds
+                     */
+                    udelay(50);
+
+                    sc->lmc_gpio |= LMC_GEP_RESET;
+                    LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(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, cpu_to_le32(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, cpu_to_le32(sc->lmc_gpio));
+
+                    /*
+                     * busy wait for the chip to reset
+                     */
+                    while( (le32_to_cpu(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;
+                    }
+                    
+                    LMC_COPY_FROM_USER(data, xc.data, xc.len);
+
+                    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, cpu_to_le32(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 programing 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, cpu_to_le32(sc->lmc_gpio));
+                    
+                    lmc_gpio_mkoutput(sc, LMC_GEP_DATA | LMC_GEP_CLK | LMC_GEP_MODE );
+
+                    /*
+                     * busy wait for the chip to reset
+                     */
+                    while( (le32_to_cpu(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 programing 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, cpu_to_le32(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, cpu_to_le32(sc->lmc_gpio));
+                        udelay(1);
+                    }
+                    if((le32_to_cpu(LMC_CSR_READ(sc, csr_gp)) & LMC_GEP_INIT) == 0){
+                        printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name);
+                    }
+                    else if((le32_to_cpu(LMC_CSR_READ(sc, csr_gp)) & LMC_GEP_DP) == 0){
+                        printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name);
+                    }
+                    else {
+                        printk(KERN_DEBUG "%s: Done reprograming 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;
+            }
+
+            LMC_XMITTER_FREE(dev);
+            sc->lmc_txfull = 0;
 
-        ret = 0;
-        break;
-#endif /* end ifdef _DBG_EVENTLOG */
-    case LMCIOCT1CONTROL:
-        if (sc->lmc_cardtype != LMC_CARDTYPE_T1){
-            ret = -EOPNOTSUPP;
-            break;
         }
         break;
-    default:
-        /* If we don't know what to do, give syncppp a shot. */
-        ret = sppp_do_ioctl (dev, ifr, cmd);
+    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);
+    LMC_SPIN_UNLOCK_IRQRESTORE(sc); /*fold01*/
+
+    lmc_trace(dev, "lmc_ioctl out");
 
     return ret;
 }
@@ -315,29 +621,35 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/
 /* the watchdog process that cruises around */
 static void lmc_watchdog (unsigned long data) /*fold00*/
 {
-    struct device *dev = (struct device *) data;
+    struct net_device *dev = (struct net_device *) data;
     lmc_softc_t *sc;
     int link_status;
     u_int32_t ticks;
-    LMC_SPIN_FLAGS
+    LMC_SPIN_FLAGS;
 
     sc = dev->priv;
 
-    spin_lock_irqsave(&sc->lmc_lock, flags);
+    lmc_trace(dev, "lmc_watchdog in");
+
+    LMC_SPIN_LOCK_IRQSAVE(sc);
+
+    if(sc->check != 0xBEAFCAFE){
+        printk("LMC: Corrupt net_device stuct, breaking out\n");
+        return;
+    }
+
 
     /* Make sure the tx jabber and rx watchdog are off,
      * and the transmit and recieve processes are running.
      */
 
-    LMC_CSR_WRITE (sc, csr_15, 0x00000011);
+    LMC_CSR_WRITE (sc, csr_15, cpu_to_le32(0x00000011));
     sc->lmc_cmdmode |= TULIP_CMD_TXRUN | TULIP_CMD_RXRUN;
-    LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+    LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(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 */
@@ -354,26 +666,12 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
              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;
@@ -396,7 +694,7 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
      * Mark it as down.
      */
     if ((link_status == 0) && (sc->last_link_status != 0)) {
-        printk(KERN_WARNING "%s: link down\n", dev->name);
+        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 */
 
@@ -409,7 +707,7 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
      * Bring it back up again.
      */
      if (link_status != 0 && sc->last_link_status == 0) {
-         printk(KERN_WARNING "%s: link up\n", dev->name);
+         printk(KERN_WARNING "%s: hardware/physical link up\n", dev->name);
          sc->last_link_status = 1;
          /* lmc_reset (sc); Again why reset??? */
 
@@ -424,7 +722,7 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
           * --bbraun
           */
 
-         sppp_reopen (dev);
+         lmc_proto_reopen(sc);
 
      }
 
@@ -435,7 +733,29 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
      * Poke the transmitter to make sure it
      * never stops, even if we run out of mem
      */
-    LMC_CSR_WRITE(sc, csr_rxpoll, 0);
+    LMC_CSR_WRITE(sc, csr_rxpoll, cpu_to_le32(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
+         * interupt halder, go through the rings
+         * and rebuild them
+         */
+        sc->failed_recv_alloc = 0;
+        lmc_softreset(sc);
+    }
 
 
     /*
@@ -443,8 +763,8 @@ static void lmc_watchdog (unsigned long data) /*fold00*/
      */
 kick_timer:
 
-    ticks = LMC_CSR_READ (sc, csr_gp_timer);
-    LMC_CSR_WRITE (sc, csr_gp_timer, 0xffffffffUL);
+    ticks = le32_to_cpu(LMC_CSR_READ (sc, csr_gp_timer));
+    LMC_CSR_WRITE (sc, csr_gp_timer, cpu_to_le32(0xffffffffUL));
     sc->ictl.ticks = 0x0000ffff - (ticks & 0x0000ffff);
 
     /*
@@ -453,58 +773,87 @@ kick_timer:
     sc->timer.expires = jiffies + (HZ);
     add_timer (&sc->timer);
 
-    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+    LMC_SPIN_UNLOCK_IRQRESTORE(sc);
+
+    lmc_trace(dev, "lmc_watchdog out");
 
 }
 
-static int lmc_init(struct device * const dev) /*fold00*/
+static int lmc_init(struct net_device * const dev) /*fold00*/
 {
+    lmc_trace(dev, "lmc_init in");
+    lmc_trace(dev, "lmc_init out");
+       
     return 0;
 }
 
 /* This initializes each card from lmc_probe() */
-static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fold00*/
-                                  int chip_id, int subdevice, int board_idx)
+static struct net_device *lmc_probe1 (struct net_device *dev, unsigned long ioaddr, unsigned int irq, /*FOLD00*/
+                                  int chip_id, int subdevice, int board_idx, void *pci_dev)
 {
     lmc_softc_t *sc = NULL;
     u_int16_t AdapModelNum;
-
+#if LINUX_VERSION_CODE >= 0x20363
+    struct pci_dev *pdev = pci_dev;
+    dma_addr_t dma_handle;
+#endif
     /*
      * Allocate our own device structure
      */
-
+    
+#if LINUX_VERSION_CODE < 0x20210 /* Changed in 2.2.16 */
     dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL);
+#else
+    dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL);
+#endif
     if (dev == NULL){
         printk (KERN_ERR "lmc: kmalloc for device failed\n");
         return NULL;
     }
-    memset (dev, 0, sizeof (struct ppp_device));
+    memset (dev, 0, sizeof (struct net_device));
 
-       /*
-        *      Switch to common hdlc%d naming. We name by type not by vendor
-        */
-    dev->name = (char *) (((u32) (dev)) + sizeof (struct ppp_device));
+#ifndef GCOM
+    /*
+     * Switch to common hdlc%d naming. We name by type not by vendor
+     */
+#if LINUX_VERSION_CODE < 0x20210
+    dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+#elif LINUX_VERSION_CODE < 0x20363
+    dev->name = ((char *) (dev)) + sizeof (struct net_device);
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20200
     dev_alloc_name(dev, "hdlc%d");
+#else
+    sprintf(dev->name, "hdlc%d", Lmc_Count);
+#endif
+    
+#else
+    /*
+     * GCOM uses LMC vendor name so that clients can know which card
+     * to attach to.
+     */
+    dev->name = ((char *) (dev)) + sizeof (struct ppp_device);
+    dev_alloc_name(dev, "lmc%d");
+#endif
 
+    lmc_trace(dev, "lmc_probe1 in");
+    
     Lmc_Count++;
 
     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);
-#ifndef MODULE
-        sync_ppp_init();
-#endif
         lmc_first_load = 1;
     }
-
-
-    /* Initialize the sppp layer */
-    sppp_attach ((struct ppp_device *) dev);
-
+    
     /*
      * Allocate space for the private data structure
      */
-
+#if LINUX_VERSION_CODE >= 0x20363
+    sc = pci_alloc_consistent(pdev, sizeof (lmc_softc_t), &dma_handle);
+#else
     sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL);
+#endif
     if (sc == NULL) {
         printk (KERN_WARNING "%s: Cannot allocate memory for device state\n",
                 dev->name);
@@ -514,16 +863,37 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol
     dev->priv = sc;
     sc->lmc_device = dev;
     sc->name = dev->name;
-
+    sc->if_type = LMC_PPP;
+    sc->check = 0xBEAFCAFE;
+#if LINUX_VERSION_CODE >= 0x20363
+    sc->pdev = pdev;
+    sc->sc_dma_handle = dma_handle;
+    sc->sc_dma = (lmc_softc_t *) dma_handle;
+#endif
+    
+    dev->base_addr = ioaddr;
+    dev->irq = irq;
+    /*
+     * 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);
     /* Just fill in the entries for the device */
 
     dev->init = lmc_init;
+    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->set_config = lmc_set_config;
+#if LINUX_VERSION_CODE >= 0x20363
+    dev->tx_timeout = lmc_driver_timeout;
+    dev->watchdog_timeo = (HZ); /* 1 second */
+#endif
+
     /*
      * Why were we changing this???
      dev->tx_queue_len = 100;
@@ -531,18 +901,15 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol
 
     /* Init the spin lock so can call it latter */
 
-    spin_lock_init(&sc->lmc_lock);
+    LMC_SPIN_LOCK_INIT(sc);
 
     LMC_SETUP_20_DEV;
-
-    printk ("%s: detected at %#3x, irq %d\n", dev->name, ioaddr, irq);
-
-    dev->base_addr = ioaddr;
-    dev->irq = irq;
+    
+    printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq);
 
     if (register_netdev (dev) != 0) {
         printk (KERN_ERR "%s: register_netdev failed.\n", dev->name);
-        sppp_detach (dev);
+        lmc_proto_detach(sc);
         kfree (dev->priv);
         kfree (dev);
         return NULL;
@@ -610,14 +977,14 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol
 
     }
     else {
-        printk ("%s: Model number (%d) miscompare for PCI Subsystem ID = 0x%04x\n",
+        /* Print a warning but not a major failure case */
+        printk (KERN_WARNING "%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);
+    LMC_CSR_WRITE (sc, csr_gp_timer, cpu_to_le32(0xFFFFFFFFUL));
 
     sc->board_idx = board_idx;
 
@@ -631,6 +998,8 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol
     sc->lmc_ok = 0;
     sc->last_link_status = 0;
 
+    lmc_trace(dev, "lmc_probe1 out");
+
     return dev;
 }
 
@@ -638,19 +1007,29 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol
 /* This is the entry point.  This is what is called immediatly. */
 /* This goes out and finds the card */
 
-int lmc_probe_fake(struct device *dev)
+int lmc_probe_fake(struct net_device *dev) /*fold00*/
 {
     lmc_probe(NULL);
     /* Return 1 to unloaded bogus device */
     return 1;
 }
 
-int lmc_probe (struct device *dev) /*fold00*/
+int lmc_probe (struct net_device *dev) /*fold00*/
 {
     int pci_index = 0;
+#if LINUX_VERSION_CODE >= 0x20155
+    unsigned long pci_ioaddr;
+    unsigned int pci_irq_line;
+    struct pci_dev *pdev;
+#if LINUX_VERSION_CODE < 0x20363
+    unsigned short pci_command;
+#endif
+#else
     unsigned char pci_irq_line;
+    u32 pci_ioaddr;
+#endif
     u16 vendor, subvendor, device, subdevice;
-    u32 pci_ioaddr, foundaddr = 0;
+    u32 foundaddr = 0;
     unsigned char pci_bus, pci_device_fn;
     u8 intcf = 0;
 
@@ -674,16 +1053,31 @@ int lmc_probe (struct device *dev) /*fold00*/
         /* Read the info we need to determine if this is
          * our card or not
          */
-#if LINUX_VERSION_CODE >= 0x20155
-        vendor = pci_find_slot (pci_bus, pci_device_fn)->vendor;
-        device = pci_find_slot (pci_bus, pci_device_fn)->device;
-        pci_irq_line = pci_find_slot (pci_bus, pci_device_fn)->irq;
-        pci_ioaddr = pci_find_slot (pci_bus, pci_device_fn)->base_address[0];
-        pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
-                              PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
-        pci_read_config_word (pci_find_slot (pci_bus, pci_device_fn),
-                              PCI_SUBSYSTEM_ID, &subdevice);
-#else
+#if LINUX_VERSION_CODE >= 0x20155 /* 2.2, 2.4 */
+        pdev = pci_find_slot (pci_bus, pci_device_fn);
+        
+        if (!pdev)
+            break;
+
+#if LINUX_VERSION_CODE >= 0x20363
+        if(pci_enable_device(pdev)){
+            break;
+        }
+#endif
+        
+        vendor = pdev->vendor;
+        device = pdev->device;
+        pci_irq_line = pdev->irq;
+#if LINUX_VERSION_CODE < 0x20363 /* 2.2 */
+        pci_ioaddr = pdev->base_address[0];
+        pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
+        pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subdevice);
+#else /* 2.4 */
+        pci_ioaddr = pci_resource_start (pdev, 0);
+        subvendor = pdev->subsystem_vendor;
+        subdevice = pdev->subsystem_device;
+#endif
+#else /* 2.0 */
         pcibios_read_config_word (pci_bus, pci_device_fn,
                                   PCI_VENDOR_ID, &vendor);
         pcibios_read_config_word (pci_bus, pci_device_fn,
@@ -717,7 +1111,7 @@ int lmc_probe (struct device *dev) /*fold00*/
             (vendor == CORRECT_VENDOR_ID) &&
             (device == CORRECT_DEV_ID) &&
             ((subvendor == PCI_VENDOR_LMC)  || (subdevice == PCI_VENDOR_LMC))){
-            struct device *cur, *prev = NULL;
+            struct net_device *cur, *prev = NULL;
 
             /* Fix the error, exchange the two values */
             if(subdevice == PCI_VENDOR_LMC){
@@ -725,9 +1119,27 @@ int lmc_probe (struct device *dev) /*fold00*/
                 subvendor = PCI_VENDOR_LMC ;
             }
 
+            /* Set the bus master bit */
+#if LINUX_VERSION_CODE < 0x20363
+#if LINUX_VERSION_CODE > 0x20155
+            pci_read_config_word(pdev, PCI_COMMAND,
+                                 &pci_command);
+            pci_command |= PCI_COMMAND_MASTER;
+            pci_write_config_word(pdev, PCI_COMMAND,
+                                  pci_command);
+#endif
+            /* Make the call to actually setup this card */
+            dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line,
+                              device, subdevice, cards_found, 0x0);
+
+#else
+            pci_set_master (pdev);
             /* Make the call to actually setup this card */
             dev = lmc_probe1 (dev, pci_ioaddr, pci_irq_line,
-                              device, subdevice, cards_found);
+                              device, subdevice, cards_found, pdev);
+
+#endif
+
             if (dev == NULL) {
                 printk ("lmc_probe: lmc_probe1 failed\n");
                 goto lmc_probe_next_card;
@@ -769,28 +1181,28 @@ int lmc_probe (struct device *dev) /*fold00*/
 /* After this is called, packets can be sent.
  * Does not initialize the addresses
  */
-static int lmc_open (struct device *dev) /*fold00*/
+static int lmc_open (struct net_device *dev) /*fold00*/
 {
     lmc_softc_t *sc = dev->priv;
-    int err;
 
-    lmc_dec_reset (sc);
-    lmc_reset (sc);
+    lmc_trace(dev, "lmc_open in");
 
-    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));
+    lmc_led_on(sc, LMC_DS3_LED0);
 
+    lmc_dec_reset (sc);
+    lmc_reset (sc);
 
-    if (sc->lmc_ok)
+    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;
@@ -818,17 +1230,23 @@ static int lmc_open (struct device *dev) /*fold00*/
         /* 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; */
 
-    err = sppp_open (dev);
-    if (err){
-        return err;
-    }
+    lmc_proto_open(sc);
+
     dev->do_ioctl = lmc_ioctl;
-    dev->tbusy = 0;
+
+
+    LMC_XMITTER_INIT(dev);
+    
+#if LINUX_VERSION_CODE < 0x20363
     dev->start = 1;
+#endif
+    
+    sc->stats.tx_tbusy0++ ;
 
     MOD_INC_USE_COUNT;
 
@@ -845,12 +1263,13 @@ static int lmc_open (struct device *dev) /*fold00*/
                          | TULIP_STS_TXSTOPPED
                          | TULIP_STS_TXUNDERFLOW
                          | TULIP_STS_RXSTOPPED
+                        | TULIP_STS_RXNOBUF
                         );
-    LMC_CSR_WRITE (sc, csr_intr, sc->lmc_intrmask);
+    LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(sc->lmc_intrmask));
 
     sc->lmc_cmdmode |= TULIP_CMD_TXRUN;
     sc->lmc_cmdmode |= TULIP_CMD_RXRUN;
-    LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+    LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
 
     sc->lmc_ok = 1; /* Run watchdog */
 
@@ -870,6 +1289,8 @@ static int lmc_open (struct device *dev) /*fold00*/
     sc->timer.function = &lmc_watchdog;
     add_timer (&sc->timer);
 
+    lmc_trace(dev, "lmc_open out");
+
     return (0);
 }
 
@@ -877,14 +1298,16 @@ static int lmc_open (struct device *dev) /*fold00*/
  *  under heavy load
  */
 
-static void lmc_running_reset (struct device *dev) /*fold00*/
+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_CSR_WRITE (sc, csr_intr, cpu_to_le32(0x00000000));
 
     lmc_dec_reset (sc);
     lmc_reset (sc);
@@ -893,15 +1316,20 @@ static void lmc_running_reset (struct device *dev) /*fold00*/
     sc->lmc_media->set_link_status (sc, 1);
     sc->lmc_media->set_status (sc, NULL);
 
-    dev->flags |= IFF_RUNNING;
-    dev->tbusy = 0;
+    //dev->flags |= IFF_RUNNING;
+    
+    LMC_XMITTER_FREE(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);
+    LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(sc->lmc_intrmask));
 
     sc->lmc_cmdmode |= (TULIP_CMD_TXRUN | TULIP_CMD_RXRUN);
-    LMC_CSR_WRITE (sc, csr_command, sc->lmc_cmdmode);
+    LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
+
+    lmc_trace(dev, "lmc_runnin_reset_out");
 }
 
 
@@ -909,47 +1337,68 @@ static void lmc_running_reset (struct device *dev) /*fold00*/
  * This disables the timer for the watchdog and keepalives,
  * and disables the irq for dev.
  */
-static int lmc_close (struct device *dev) /*fold00*/
+static int lmc_close (struct net_device *dev) /*fold00*/
 {
     /* not calling release_region() as we should */
-    lmc_softc_t *sc;
+    lmc_softc_t *sc = dev->priv;
 
+    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);
-    sppp_close (dev);
+    lmc_proto_close(sc);
     lmc_ifdown (dev);
 
+#if LINUX_VERSION_CODE < 0x20363
+    dev->start = 0;
+#endif
+
+    
+    /*
+     * Let's make sure all the leds are off
+     * when not configured
+     */
+    lmc_led_off(sc, LMC_DS3_LED0);
+    lmc_led_off(sc, LMC_DS3_LED1);
+    lmc_led_off(sc, LMC_DS3_LED2);
+    lmc_led_off(sc, LMC_DS3_LED3);
+
+    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 device *dev) /*fold00*/
+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;
-    dev->tbusy = 1;
+    //    dev->start = 0;
+    LMC_XMITTER_BUSY(dev);
+    sc->stats.tx_tbusy1++ ;
 
     /* stop interrupts */
     /* Clear the interrupt mask */
-    LMC_CSR_WRITE (sc, csr_intr, 0x00000000);
+    LMC_CSR_WRITE (sc, csr_intr, cpu_to_le32(0x00000000));
 
     /* Stop Tx and Rx on the chip */
-    csr6 = LMC_CSR_READ (sc, csr_command);
+    csr6 = le32_to_cpu(LMC_CSR_READ (sc, csr_command));
     csr6 &= ~LMC_DEC_ST;               /* Turn off the Transmission bit */
     csr6 &= ~LMC_DEC_SR;               /* Turn off the Recieve bit */
-    LMC_CSR_WRITE (sc, csr_command, csr6);
+    LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6));
 
     dev->flags &= ~IFF_RUNNING;
 
     sc->stats.rx_missed_errors +=
-        LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+        le32_to_cpu(LMC_CSR_READ (sc, csr_missed_frames)) & 0xffff;
 
     /* release the interrupt */
     if(sc->got_irq == 1){
@@ -982,7 +1431,10 @@ static int lmc_ifdown (struct device *dev) /*fold00*/
 
     lmc_led_off (sc, LMC_MII16_LED_ALL);
 
-    dev->tbusy = 0;
+    LMC_XMITTER_FREE(dev);
+    sc->stats.tx_tbusy0++ ;
+
+    lmc_trace(dev, "lmc_ifdown out");
 
     MOD_DEC_USE_COUNT;
     return 0;
@@ -993,31 +1445,34 @@ static int lmc_ifdown (struct device *dev) /*fold00*/
  */
 static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
 {
-    struct device *dev = (struct device *) dev_instance;
-    lmc_softc_t *sc;
+    struct net_device *dev = (struct net_device *) dev_instance;
+    lmc_softc_t *sc = dev->priv;
     u32 csr;
     int i;
     s32 stat;
     unsigned int badtx;
     u32 firstcsr;
+    int max_work = LMC_RXDESCS;
+    unsigned long flags;
 
-    sc = dev->priv;
+    lmc_trace(dev, "lmc_interrupt in");
 
-    spin_lock(&sc->lmc_lock);
 
-    if (test_and_set_bit (0, (void *) &dev->interrupt)) {
-        goto lmc_int_fail_out;
-    }
+    LMC_SPIN_LOCK_IRQSAVE(sc);
 
     /*
      * Read the csr to find what interupts we have (if any)
      */
-    csr = LMC_CSR_READ (sc, csr_status);
+    csr = le32_to_cpu(LMC_CSR_READ (sc, csr_status));
 
     /*
      * Make sure this is our interrupt
      */
     if ( ! (csr & sc->lmc_intrmask)) {
+        /*
+         * If it's not make sure it's not a media interupt first
+         */
+        sc->lmc_media->got_interupt(sc);
         goto lmc_int_fail_out;
     }
 
@@ -1025,11 +1480,10 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
 
     /* always go through this loop at least once */
     while (csr & sc->lmc_intrmask) {
-
         /*
          * Clear interupt bits, we handle all case below
          */
-        LMC_CSR_WRITE (sc, csr_status, csr);
+        LMC_CSR_WRITE (sc, csr_status, cpu_to_le32(csr));
 
         /*
          * One of
@@ -1048,14 +1502,15 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
             lmc_running_reset (dev);
             break;
         }
-
         
-        if (csr & (TULIP_STS_RXINTR | TULIP_STS_RXNOBUF)) {
-         lmc_rx (dev);
+        if (csr & TULIP_STS_RXINTR){
+            lmc_trace(dev, "rx interupt");
+            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;
 
@@ -1063,15 +1518,15 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
             i = badtx % LMC_TXDESCS;
 
             while ((badtx < sc->lmc_next_tx)) {
-                stat = sc->lmc_txring[i].status;
+                stat = le32_to_cpu(sc->lmc_txring[i].status);
 
-                LMC_EVENT_LOG (LMC_EVENT_XMTINT, stat, 0);
                 /*
                  * If bit 31 is 1 the tulip owns it break out of the loop
                  */
-                if (stat 0)
+                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
@@ -1096,13 +1551,16 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
                 else {
                     
 #if LINUX_VERSION_CODE >= 0x20200
-                    sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;
+                    sc->stats.tx_bytes += le32_to_cpu(sc->lmc_txring[i].length) & 0x7ff;
 #endif
                     
                     sc->stats.tx_packets++;
                 }
-                
-                LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+                pci_unmap_single(sc->pdev, sc->lmc_txring[i].buffer1, sc->lmc_txq[i]->len, PCI_DMA_TODEVICE);
+#endif
+                dev_kfree_skb_irq(sc->lmc_txq[i]);
                 sc->lmc_txq[i] = 0;
 
                 badtx++;
@@ -1115,20 +1573,13 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
                 badtx += LMC_TXDESCS;
             }
             sc->lmc_txfull = 0;
-            dev->tbusy = 0;
-            mark_bh (NET_BH);  /* Tell Linux to give me more packets */
-
-#ifdef DEBUG
-            sc->stats.dirtyTx = badtx;
-            sc->stats.lmc_next_tx = sc->lmc_next_tx;
-            sc->stats.lmc_txfull = sc->lmc_txfull;
-            sc->stats.tbusy = dev->tbusy;
+            LMC_XMITTER_FREE(dev);
+            sc->stats.tx_tbusy0++ ;
+#if LINUX_VERSION_CODE < 0x20363
+            mark_bh (NET_BH);  /* Tell Linux to give me more packets */
 #endif
             sc->lmc_taint_tx = badtx;
 
-            /*
-             * Why was there a break here???
-             */
         }                      /* end handle transmit interrupt */
 
         if (csr & TULIP_STS_SYSERROR) {
@@ -1150,29 +1601,30 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
             }
             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 interupts
          */
-        csr = LMC_CSR_READ (sc, csr_status);
+        csr = le32_to_cpu(LMC_CSR_READ (sc, csr_status));
     }                          /* end interrupt loop */
-    LMC_EVENT_LOG(LMC_EVENT_INT, firstcsr, csr);
-
-    dev->interrupt = 0;
 
 lmc_int_fail_out:
 
-    spin_unlock(&sc->lmc_lock);
+    LMC_SPIN_UNLOCK_IRQRESTORE(sc);
+
+    lmc_trace(dev, "lmc_interrupt out");
+
     return;
 }
 
-static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
+static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
 {
     lmc_softc_t *sc;
     u32 flag;
@@ -1180,13 +1632,11 @@ static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
     int ret = 0;
     LMC_SPIN_FLAGS;
 
-    sc = dev->priv;
+    lmc_trace(dev, "lmc_start_xmit in");
 
-    /* the interface better be up */
-    if ( ! (dev->flags & IFF_UP))
-        return 1;
+    sc = dev->priv;
 
-    spin_lock_irqsave(&sc->lmc_lock, flags);
+    LMC_SPIN_LOCK_IRQSAVE(sc);
 
     /*
      * If the transmitter is busy
@@ -1195,9 +1645,13 @@ static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
      * Poke the chip and try to get it running
      *
      */
-    if (dev->tbusy) {
+#if LINUX_VERSION_CODE < 0x20363
+    if(dev->tbusy != 0){
         u32 csr6;
 
+        printk("%s: Xmitter busy|\n", dev->name);
+
+       sc->stats.tx_tbusy_calls++ ;
         if (jiffies - dev->trans_start < TX_TIMEOUT) {
             ret = 1;
             goto lmc_start_xmit_bug_out;
@@ -1210,24 +1664,15 @@ static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
          * 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);
+        csr6 = le32_to_cpu(LMC_CSR_READ (sc, csr_command));
+        LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x0002));
+        LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x2002));
 
         /* immediate transmit */
-        LMC_CSR_WRITE (sc, csr_txpoll, 0);
+        LMC_CSR_WRITE (sc, csr_txpoll, cpu_to_le32(0));
 
         sc->stats.tx_errors++;
         sc->stats.tx_ProcTimeout++;    /* -baz */
@@ -1237,57 +1682,66 @@ static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
         ret = 1;
         goto lmc_start_xmit_bug_out;
     }
-    /* normal path */
+#endif
+    /* normal path, tbusy known to be zero */
 
     entry = sc->lmc_next_tx % LMC_TXDESCS;
 
     sc->lmc_txq[entry] = skb;
+#if LINUX_VERSION_CODE >= 0x20363
+    sc->lmc_txring[entry].buffer1 = pci_map_single (sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+#else
     sc->lmc_txring[entry].buffer1 = virt_to_bus (skb->data);
+#endif
 
     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;
-        dev->tbusy = 0;
+        LMC_XMITTER_FREE(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;
-        dev->tbusy = 0;
+        LMC_XMITTER_FREE(dev);
     }
     else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1)
     {
         /* Do not interrupt on completion of this packet */
         flag = 0x60000000;
-        dev->tbusy = 0;
+        LMC_XMITTER_FREE(dev);
     }
     else
     {
         /* This generates an interrupt on completion of this packet */
         flag = 0xe0000000;
         sc->lmc_txfull = 1;
-        dev->tbusy = 1;
+        LMC_XMITTER_BUSY(dev);
     }
+#else
+    flag = LMC_TDES_INTERRUPT_ON_COMPLETION;
 
-    if ((entry == LMC_TXDESCS - 1))
-    {
-        flag |= 0xe2000000;
-        dev->tbusy = 1;
+    if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1)
+    {                          /* ring full, go busy */
+        sc->lmc_txfull = 1;
+        LMC_XMITTER_BUSY(dev);
+        sc->stats.tx_tbusy1++ ;
+        LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0);
     }
-    /* don't pad small packets either */
-    sc->lmc_txring[entry].length = (skb->len) | flag | sc->TxDescriptControlInit;
+#endif
 
-    /* Done above through TxDescControlInit */
-    /*
-     sc->lmc_txring[entry].length = (skb->len) | flag | 0x00800000;
-     if(sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16){
-     sc->lmc_txring[entry].length |= 0x04000000;
-     }
-     */
+
+    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 = cpu_to_le32((skb->len) | flag |
+                                               sc->TxDescriptControlInit);
 
     /* set the transmit timeout flag to be checked in
      * the watchdog timer handler. -baz
@@ -1296,22 +1750,25 @@ static int lmc_start_xmit (struct sk_buff *skb, struct device *dev) /*fold00*/
     sc->stats.tx_NoCompleteCnt++;
     sc->lmc_next_tx++;
 
-    /* give ownership to the chip */
-    sc->lmc_txring[entry].status = 0x80000000;
+    sc->lmc_txring[entry].status = cpu_to_le32(0x80000000);
 
     /* send now! */
-    LMC_CSR_WRITE (sc, csr_txpoll, 0);
+    LMC_CSR_WRITE (sc, csr_txpoll, cpu_to_le32(0));
 
     dev->trans_start = jiffies;
 
+#if LINUX_VERSION_CODE < 0x20363
 lmc_start_xmit_bug_out:
+#endif
+
+    LMC_SPIN_UNLOCK_IRQRESTORE(sc);
 
-    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+    lmc_trace(dev, "lmc_start_xmit_out");
     return ret;
 }
 
 
-static int lmc_rx (struct device *dev) /*fold00*/
+static int lmc_rx (struct net_device *dev) /*fold00*/
 {
     lmc_softc_t *sc;
     int i;
@@ -1323,45 +1780,44 @@ static int lmc_rx (struct device *dev) /*fold00*/
     struct sk_buff *skb, *nsb;
     u16 len;
 
-    sc = dev->priv;
+    lmc_trace(dev, "lmc_rx in");
 
-    if ( ! (dev->flags & IFF_UP))
-        return 1;
+    sc = dev->priv;
 
-    rxIntLoopCnt = 0;          /* debug -baz */
+    rxIntLoopCnt = 0;
 
     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)
+    while (((stat = le32_to_cpu(sc->lmc_rxring[i].status)) & LMC_RDES_OWN_BIT) != DESC_OWNED_BY_DC21X4)
     {
         rxIntLoopCnt++;                /* debug -baz */
-        LMC_EVENT_LOG(LMC_EVENT_RCVINT, stat, 0);
-
+        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++;
+                sc->stats.rx_errors++;
                 goto skip_packet;
             }
         }
 
-        if(stat & 0x00000008){ /* Catch a dribbling bit error */
+        if(stat & 0x00000004){ /* 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 */
+        if(stat & 0x00000008){ /* Catch a CRC error by the Xilinx */
             sc->stats.rx_errors++;
             sc->stats.rx_crc_errors++;
             goto skip_packet;
         }
 
 
-        len = ((stat & LMC_RDES_FRAME_LENGTH) >> RDES_FRAME_LENGTH_BIT_NUMBER);
-        if (len > PKT_BUF_SZ){
+        if (len > LMC_PKT_BUF_SZ){
+            sc->stats.rx_errors++;
             sc->stats.rx_length_errors++;
             localLengthErrCnt++;
             goto skip_packet;
@@ -1370,6 +1826,7 @@ static int lmc_rx (struct device *dev) /*fold00*/
         if (len < sc->lmc_crcSize + 2) {
             sc->stats.rx_length_errors++;
             sc->stats.rx_SmallPktCnt++;
+            sc->stats.rx_errors++;
             localLengthErrCnt++;
             goto skip_packet;
         }
@@ -1388,19 +1845,29 @@ static int lmc_rx (struct device *dev) /*fold00*/
          */
         
         if(skb == 0x0){
-            nsb = dev_alloc_skb (PKT_BUF_SZ + 2);
+            nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
             if (nsb) {
                 LMC_SKB_FREE(nsb, 1);
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x20363
+                sc->lmc_rxring[i].buffer1 = pci_map_single(sc->pdev, nsb->tail, LMC_PKT_BUF_SZ+2, PCI_DMA_FROMDEVICE);
+#else
                 sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+#endif
             }
+            sc->failed_recv_alloc = 1;
             goto skip_packet;
         }
         
         dev->last_rx = jiffies;
         sc->stats.rx_packets++;
 
+#if LINUX_VERSION_CODE >= 0x20363
+#ifdef LMC_PACKET_LOG
+        pci_dma_sync_single(sc->pdev, sc->lmc_rxring[i].buffer1, len, PCI_DMA_FROMDEVICE);
+#endif
+#endif
         LMC_CONSOLE_LOG("recv", skb->data, len);
 
         /*
@@ -1410,31 +1877,39 @@ static int lmc_rx (struct device *dev) /*fold00*/
          * them into a new buffer??
          */
         
-        if(len > (3*LMC_MTU)/4){
+        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] = 0x0;
-            sc->lmc_rxring[i].buffer1 = 0x0;
+            sc->lmc_rxring[i].buffer1 = cpu_to_le32(0x0);
 
             skb_put (skb, len);
-            skb->protocol=htons(ETH_P_WAN_PPP);
+            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->nh.raw = skb->data;
             skb->dev = dev;
-            netif_rx(skb);
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+            pci_unmap_single(sc->pdev, sc->lmc_rxring[i].buffer1, len, PCI_DMA_FROMDEVICE);
+#endif
+            lmc_proto_netif(sc, skb);
 
             /*
              * This skb will be destroyed by the upper layers, make a new one
              */
-            nsb = dev_alloc_skb (PKT_BUF_SZ + 2);
+            nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
             if (nsb) {
                 LMC_SKB_FREE(nsb, 1);
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x20363
+                sc->lmc_rxring[i].buffer1 = pci_map_single(sc->pdev, nsb->tail, LMC_PKT_BUF_SZ+2, PCI_DMA_FROMDEVICE);
+#else
                 sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+#endif
                 /* Transfered to 21140 below */
             }
             else {
@@ -1447,10 +1922,9 @@ static int lmc_rx (struct device *dev) /*fold00*/
                  * again.  (once a second)
                  */
                 sc->stats.rx_BuffAllocErr++;
+                sc->failed_recv_alloc = 1;
                 goto skip_out_of_mem;
-
             }
-
         }
         else {
             nsb = dev_alloc_skb(len);
@@ -1458,15 +1932,19 @@ static int lmc_rx (struct device *dev) /*fold00*/
                 goto give_it_anyways;
             }
             memcpy(skb_put(nsb, len), skb->data, len);
-            nsb->protocol=htons(ETH_P_WAN_PPP);
+            
+            nsb->protocol = lmc_proto_type(sc, skb);
             nsb->mac.raw = nsb->data;
-            nsb->nh.raw = nsb->data;
+            //            nsb->nh.raw = nsb->data;
             nsb->dev = dev;
-            netif_rx(nsb);
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+            pci_unmap_single(sc->pdev, sc->lmc_rxring[i].buffer1, len, PCI_DMA_FROMDEVICE);
+#endif
+            lmc_proto_netif(sc, nsb);
         }
 
     skip_packet:
-        sc->lmc_rxring[i].status = DESC_OWNED_BY_DC21X4;
+        sc->lmc_rxring[i].status = cpu_to_le32(DESC_OWNED_BY_DC21X4);
 
         sc->lmc_next_rx++;
         i = sc->lmc_next_rx % LMC_RXDESCS;
@@ -1475,54 +1953,34 @@ static int lmc_rx (struct device *dev) /*fold00*/
             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
-
 skip_out_of_mem:
 
+    lmc_trace(dev, "lmc_rx out");
+
     return 0;
 }
 
-static struct enet_statistics *lmc_get_stats (struct device *dev) /*fold00*/
+static struct enet_statistics *lmc_get_stats (struct net_device *dev) /*fold00*/
 {
     lmc_softc_t *sc;
     LMC_SPIN_FLAGS;
 
+    lmc_trace(dev, "lmc_get_stats in");
+
     sc = dev->priv;
 
-    spin_lock_irqsave(&sc->lmc_lock, flags);
+    LMC_SPIN_LOCK_IRQSAVE(sc);
+
+    sc->stats.rx_missed_errors += le32_to_cpu(LMC_CSR_READ (sc, csr_missed_frames)) & 0xffff;
 
-    if (dev->start)
-        sc->stats.rx_missed_errors += LMC_CSR_READ (sc, csr_missed_frames) & 0xffff;
+    LMC_SPIN_UNLOCK_IRQRESTORE(sc);
 
-    spin_unlock_irqrestore(&sc->lmc_lock, flags);
+    lmc_trace(dev, "lmc_get_stats out");
 
     return (struct enet_statistics *) &sc->stats;
 }
@@ -1542,7 +2000,8 @@ int init_module (void) /*fold00*/
 
 void cleanup_module (void) /*fold00*/
 {
-    struct device *dev, *next;
+    struct net_device *dev, *next;
+    lmc_softc_t *sc;
 
     /* we have no pointer to our devices, since they are all dynamically
      * allocated.  So, here we loop through all the network devices
@@ -1559,19 +2018,27 @@ void cleanup_module (void) /*fold00*/
 
         /* close the syncppp stuff, and release irq. Close is run on unreg net */
         lmc_close (dev);
-        sppp_detach (dev);
+        
+        sc = dev->priv;
+
+        printk ("%s: detaching from protocol...\n", dev->name);
+        if (sc != NULL)
+            lmc_proto_detach(sc);
 
-        /* Remove the device from the linked list */
         unregister_netdev (dev);
 
         /* Let go of the io region */;
         release_region (dev->base_addr, LMC_REG_RANGE);
 
         /* free our allocated structures. */
+#if LINUX_VERSION_CODE >= 0x20363
+        pci_free_consistent(sc->pdev, sizeof(lmc_softc_t), sc, sc->sc_dma_handle);
+#else
         kfree (dev->priv);
+#endif
         dev->priv = NULL;
 
-        kfree ((struct ppp_device *) dev);
+        kfree (dev);
         dev = NULL;
     }
 
@@ -1587,40 +2054,49 @@ unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned reg
     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_CSR_WRITE (sc, csr_9, cpu_to_le32(dataval));
         lmc_delay ();
         /* __SLOW_DOWN_IO; */
-        LMC_CSR_WRITE (sc, csr_9, dataval | 0x10000);
+        LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(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_CSR_WRITE (sc, csr_9, cpu_to_le32(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);
+        retval = (retval << 1) | (le32_to_cpu((LMC_CSR_READ(sc, csr_9)) & 0x80000) ? 1 : 0);
+        LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(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, /*fold00*/
-                       unsigned regno, unsigned data)
+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;
@@ -1633,10 +2109,10 @@ void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, /*fold00*/
         else
             datav = 0x00000;
 
-        LMC_CSR_WRITE (sc, csr_9, datav);
+        LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(datav));
         lmc_delay ();
         /* __SLOW_DOWN_IO; */
-        LMC_CSR_WRITE (sc, csr_9, (datav | 0x10000));
+        LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(datav | 0x10000));
         lmc_delay ();
         /* __SLOW_DOWN_IO; */
         i--;
@@ -1645,20 +2121,24 @@ void lmc_mii_writereg (lmc_softc_t * const sc, unsigned devaddr, /*fold00*/
     i = 2;
     while (i > 0)
     {
-        LMC_CSR_WRITE (sc, csr_9, 0x40000);
+        LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(0x40000));
         lmc_delay ();
         /* __SLOW_DOWN_IO; */
-        LMC_CSR_WRITE (sc, csr_9, 0x50000);
+        LMC_CSR_WRITE (sc, csr_9, cpu_to_le32(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 recieve rings and buffers. */
     sc->lmc_txfull = 0;
     sc->lmc_next_rx = 0;
@@ -1678,8 +2158,15 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/
 
         if (sc->lmc_rxq[i] == NULL)
         {
-            skb = dev_alloc_skb (PKT_BUF_SZ + 2);
-            sc->lmc_rxq[i] = skb;
+            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
         {
@@ -1690,77 +2177,120 @@ static void lmc_softreset (lmc_softc_t * const sc) /*fold00*/
         LMC_SKB_FREE(skb, 1);
 
         /* owned by 21140 */
-        sc->lmc_rxring[i].status = 0x80000000;
+        sc->lmc_rxring[i].status = cpu_to_le32(0x80000000);
 
         /* used to be PKT_BUF_SZ now uses skb since we loose some to head room */
-        sc->lmc_rxring[i].length = skb->end - skb->data;
+        sc->lmc_rxring[i].length = cpu_to_le32(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
          */
+#if LINUX_VERSION_CODE >= 0x20363
+        sc->lmc_rxring[i].buffer1 = pci_map_single(sc->pdev, skb->data, sc->lmc_rxring[i].length, PCI_DMA_FROMDEVICE);
+        sc->lmc_rxring[i].buffer2 = (u32) &(sc->sc_dma->lmc_rxring[i + 1]);
+#else
         sc->lmc_rxring[i].buffer1 = virt_to_bus (skb->data);
+        sc->lmc_rxring[i].buffer2 = virt_to_bus (&sc->lmc_rxring[i+1]);
 
-        /* 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]);
+#endif
 
     }
 
     /*
      * Sets end of ring
      */
-    sc->lmc_rxring[i - 1].length |= 0x02000000; /* Set end of buffers flag */
+    sc->lmc_rxring[i - 1].length |= cpu_to_le32(0x02000000); /* Set end of buffers flag */
+#if LINUX_VERSION_CODE >= 0x20363
+    sc->lmc_rxring[i - 1].buffer2 = (u32) &sc->sc_dma->lmc_rxring[0]; /* Point back to the start */
+    LMC_CSR_WRITE (sc, csr_rxlist, (u32) &sc->sc_dma->lmc_rxring); /* write base address */
+#else
     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 */
+#endif
 
 
     /* Initialize the transmit rings and buffers */
     for (i = 0; i < LMC_TXDESCS; i++)
     {
+        if (sc->lmc_txq[i] != NULL){           /* have buffer */
+#if LINUX_VERSION_CODE >= 0x20363 /* 2.4 */
+            pci_unmap_single(sc->pdev, sc->lmc_txring[i].buffer1, sc->lmc_txq[i]->len, PCI_DMA_TODEVICE);
+#endif
+            LMC_DEV_KFREE_SKB(sc->lmc_txq[i]); /* free it */
+            sc->stats.tx_dropped++;      /* We just dropped a packet */
+        }
         sc->lmc_txq[i] = 0;
-        sc->lmc_txring[i].status = 0x00000000;
+        sc->lmc_txring[i].status = cpu_to_le32(0x00000000);
+#if LINUX_VERSION_CODE >= 0x20363
+        sc->lmc_txring[i].buffer2 = (u32) &(sc->sc_dma->lmc_txring[i + 1]);
+#else
         sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]);
+#endif
     }
+    
+#if LINUX_VERSION_CODE >= 0x20363
+    sc->lmc_txring[i - 1].buffer2 = (u32) &sc->sc_dma->lmc_txring[0]; /* Point back to the start */
+    LMC_CSR_WRITE (sc, csr_txlist, (u32) &sc->sc_dma->lmc_txring); /* write base address */
+#else
     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));
+#endif
+    
+    lmc_trace(sc->lmc_device, "lmc_softreset out");
 }
 
-static int lmc_set_config(struct device *dev, struct ifmap *map) /*fold00*/
+static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/
 {
+    lmc_trace(dev, "lmc_set_config in");
+    lmc_trace(dev, "lmc_set_config out");
     return -EOPNOTSUPP;
 }
 
-void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits)
+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_CSR_WRITE(sc, csr_gp, cpu_to_le32(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)
+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_CSR_WRITE(sc, csr_gp, cpu_to_le32(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)
+void lmc_led_on(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
 {
-    if((~sc->lmc_miireg16) & led) /* Already on! */
+    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)
+void lmc_led_off(lmc_softc_t * const sc, u_int32_t led) /*fold00*/
 {
-    if(sc->lmc_miireg16 & led) /* Already set don't do anything */
+    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)
+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);
 
@@ -1770,15 +2300,15 @@ static void lmc_reset(lmc_softc_t * const sc)
     /*
      * make some of the GPIO pins be outputs
      */
-    lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET);
+    lmc_gpio_mkoutput(sc, LMC_GEP_RESET);
 
     /*
-     * drive DP and RESET low to force configuration.  This also forces
+     * 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_DP | LMC_GEP_RESET);
-    LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+    sc->lmc_gpio &= ~(LMC_GEP_RESET);
+    LMC_CSR_WRITE(sc, csr_gp, cpu_to_le32(sc->lmc_gpio));
 
     /*
      * hold for more than 10 microseconds
@@ -1788,13 +2318,7 @@ static void lmc_reset(lmc_softc_t * const sc)
     /*
      * stop driving Xilinx-related signals
      */
-    lmc_gpio_mkinput(sc, LMC_GEP_DP | LMC_GEP_RESET);
-
-    /*
-     * busy wait for the chip to reset
-     */
-    while ((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0)
-        ;
+    lmc_gpio_mkinput(sc, LMC_GEP_RESET);
 
     /*
      * Call media specific init routine
@@ -1802,17 +2326,19 @@ static void lmc_reset(lmc_softc_t * const sc)
     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)
+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);
+    LMC_CSR_WRITE(sc, csr_intr, cpu_to_le32(sc->lmc_intrmask));
 
     /*
      * Reset the chip with a software reset command.
@@ -1820,9 +2346,16 @@ static void lmc_dec_reset(lmc_softc_t * const sc)
      * 33MHz that comes to two microseconds but wait a
      * bit longer anyways)
      */
-    LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
+    LMC_CSR_WRITE(sc, csr_busmode, cpu_to_le32(TULIP_BUSMODE_SWRESET));
     udelay(25);
-    sc->lmc_cmdmode = LMC_CSR_READ(sc, csr_command);
+#ifdef __sparc__
+    sc->lmc_busmode = LMC_CSR_READ(sc, cpu_to_le32(csr_busmode));
+    sc->lmc_busmode = 0x00000000;
+    //sc->lmc_busmode = 0x00100000;
+    sc->lmc_busmode &= ~TULIP_BUSMODE_SWRESET;
+    LMC_CSR_WRITE(sc, csr_busmode, cpu_to_le32(sc->lmc_busmode));
+#endif
+    sc->lmc_cmdmode = le32_to_cpu(LMC_CSR_READ(sc, csr_command));
 
     /*
      * We want:
@@ -1848,20 +2381,22 @@ static void lmc_dec_reset(lmc_softc_t * const sc)
                           | TULIP_CMD_TXTHRSHLDCTL
                         );
 
-    LMC_CSR_WRITE(sc, csr_command, sc->lmc_cmdmode);
+    LMC_CSR_WRITE(sc, csr_command, cpu_to_le32(sc->lmc_cmdmode));
 
     /*
      * disable receiver watchdog and transmit jabber
      */
-    val = LMC_CSR_READ(sc, csr_sia_general);
+    val = le32_to_cpu(LMC_CSR_READ(sc, csr_sia_general));
     val |= (TULIP_WATCHDOG_TXDISABLE | TULIP_WATCHDOG_RXDISABLE);
-    LMC_CSR_WRITE(sc, csr_sia_general, val);
+    LMC_CSR_WRITE(sc, csr_sia_general, cpu_to_le32(val));
 
+    lmc_trace(sc->lmc_device, "lmc_dec_reset out");
 }
 
-static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base,
+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;
@@ -1878,5 +2413,61 @@ static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base,
     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");
+}
+
+#if LINUX_VERSION_CODE >= 0x20363
+static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/
+    lmc_softc_t *sc;
+    u32 csr6;
+    LMC_SPIN_FLAGS;
+
+    lmc_trace(dev, "lmc_driver_timeout in");
+
+    sc = dev->priv;
+
+    LMC_SPIN_LOCK_IRQSAVE(sc);
+
+    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_running_reset (dev);
+
+    /* restart the tx processes */
+    csr6 = le32_to_cpu(LMC_CSR_READ (sc, csr_command));
+    LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x0002));
+    LMC_CSR_WRITE (sc, csr_command, cpu_to_le32(csr6 | 0x2002));
+
+    /* immediate transmit */
+    LMC_CSR_WRITE (sc, csr_txpoll, cpu_to_le32(0));
+
+    sc->stats.tx_errors++;
+    sc->stats.tx_ProcTimeout++;        /* -baz */
+
+    dev->trans_start = jiffies;
+
+bug_out:
+
+    LMC_SPIN_UNLOCK_IRQRESTORE(sc);
+
+    lmc_trace(dev, "lmc_driver_timout out");
+
+
 }
 
+int lmc_setup(void) { /*fold00*/
+   return lmc_probe(NULL);
+}
+
+#endif
index bccb5dda7ac99a2999173c8355849bdf837a1ec4..617663a88652cf505e17161a5c5c30dd8086188b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: lmc_media.c,v 1.9 2000/01/21 13:29:49 asj Exp $ */
+/* $Id: lmc_media.c,v 1.16 2000/06/06 08:32:14 asj Exp $ */
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -13,7 +13,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <asm/segment.h>
-#include <asm/smp.h>
+//#include <asm/smp.h>
 
 #if LINUX_VERSION_CODE < 0x20155
 #include <linux/bios32.h>
 
 #if LINUX_VERSION_CODE >= 0x20200
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
+//#include <asm/spinlock.h>
 #endif
 
-#include "lmc.h"
 #include "lmc_ver.h"
+#include "lmc.h"
 #include "lmc_var.h"
 #include "lmc_ioctl.h"
+#include "lmc_debug.h"
 
 #define CONFIG_LMC_IGNORE_HARDWARE_HANDSHAKE 1
 
@@ -59,7 +60,7 @@
   */
 
 /*
- * For lack of a better place, put the T1 cable stuff here.
+ * 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",
@@ -111,12 +112,16 @@ 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 int  lmc_t1_ioctl (lmc_softc_t * const, void *);
+static int  lmc_t1_got_interupt (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 int  lmc_dummy_ioctl (lmc_softc_t * const, void *);
+static int  lmc_dummy_got_interupt (lmc_softc_t * const);
 
 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,
+static void write_av9110 (lmc_softc_t *, u_int32_t, u_int32_t, u_int32_t, /*fold00*/
                          u_int32_t, u_int32_t);
 
 lmc_media_t lmc_ds3_media = {
@@ -131,7 +136,9 @@ lmc_media_t lmc_ds3_media = {
   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_ds3_watchdog,
+  lmc_dummy_ioctl,
+  lmc_dummy_got_interupt,
 };
 
 lmc_media_t lmc_hssi_media = {
@@ -146,7 +153,10 @@ lmc_media_t lmc_hssi_media = {
   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_hssi_watchdog,
+  lmc_dummy_ioctl,
+  lmc_dummy_got_interupt,
+
 };
 
 lmc_media_t lmc_ssi_media = { lmc_ssi_init,    /* special media init stuff */
@@ -160,7 +170,10 @@ lmc_media_t lmc_ssi_media = { lmc_ssi_init,        /* special media init stuff */
   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_ssi_watchdog,
+  lmc_dummy_ioctl,
+  lmc_dummy_got_interupt,
+
 };
 
 lmc_media_t lmc_t1_media = {
@@ -175,25 +188,38 @@ lmc_media_t lmc_t1_media = {
   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
+  lmc_t1_watchdog,
+  lmc_t1_ioctl,
+  lmc_t1_got_interupt,
+
 };
 
-static void
-lmc_dummy_set_1 (lmc_softc_t * const sc, int a)
+static void lmc_dummy_set_1 (lmc_softc_t * const sc, int a) /*fold00*/
 {
 }
 
-static void
-lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a)
+static void lmc_dummy_set2_1 (lmc_softc_t * const sc, lmc_ctl_t * a) /*fold00*/
 {
 }
 
+static int lmc_dummy_ioctl (lmc_softc_t * const sc, void *d) /*fold00*/
+{
+    return -ENOSYS;
+}
+
+static int lmc_dummy_got_interupt (lmc_softc_t * const sc) /*fold00*/
+{
+    return -ENOSYS;
+}
+
+
+
 /*
  *  HSSI methods
  */
 
 static void
-lmc_hssi_init (lmc_softc_t * const sc)
+lmc_hssi_init (lmc_softc_t * const sc) /*fold00*/
 {
   sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC5200;
 
@@ -201,7 +227,7 @@ lmc_hssi_init (lmc_softc_t * const sc)
 }
 
 static void
-lmc_hssi_default (lmc_softc_t * const sc)
+lmc_hssi_default (lmc_softc_t * const sc) /*fold00*/
 {
   sc->lmc_miireg16 = LMC_MII16_LED_ALL;
 
@@ -215,7 +241,7 @@ lmc_hssi_default (lmc_softc_t * const sc)
  * always reset the card if needed.
  */
 static void
-lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
 {
   if (ctl == NULL)
     {
@@ -246,21 +272,25 @@ lmc_hssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
  * 1 == internal, 0 == external
  */
 static void
-lmc_hssi_set_clock (lmc_softc_t * const sc, int ie)
+lmc_hssi_set_clock (lmc_softc_t * const sc, int ie) /*fold00*/
 {
+  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;
-      printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+      if(old != ie)
+        printk (KERN_INFO "%s: clock external\n", sc->name);
     }
   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;
-      printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+      if(old != ie)
+        printk (KERN_INFO "%s: clock internal\n", sc->name);
     }
 }
 
@@ -269,7 +299,7 @@ lmc_hssi_set_clock (lmc_softc_t * const sc, int ie)
  * 0 == link is down, 1 == link is up.
  */
 static int
-lmc_hssi_get_link_status (lmc_softc_t * const sc)
+lmc_hssi_get_link_status (lmc_softc_t * const sc) /*fold00*/
 {
     /*
      * We're using the same code as SSI since
@@ -279,7 +309,7 @@ lmc_hssi_get_link_status (lmc_softc_t * const sc)
 }
 
 static void
-lmc_hssi_set_link_status (lmc_softc_t * const sc, int state)
+lmc_hssi_set_link_status (lmc_softc_t * const sc, int state) /*fold00*/
 {
   if (state == LMC_LINK_UP)
     sc->lmc_miireg16 |= LMC_MII16_HSSI_TA;
@@ -293,26 +323,28 @@ lmc_hssi_set_link_status (lmc_softc_t * const sc, int state)
  * 0 == 16bit, 1 == 32bit
  */
 static void
-lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_hssi_set_crc_length (lmc_softc_t * const sc, int state) /*FOLD00*/
 {
   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;
+      sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
     }
   else
     {
       /* 16 bit */
       sc->lmc_miireg16 &= ~LMC_MII16_HSSI_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);
 }
 
 static void
-lmc_hssi_watchdog (lmc_softc_t * const sc)
+lmc_hssi_watchdog (lmc_softc_t * const sc) /*fold00*/
 {
   /* HSSI is blank */
 }
@@ -325,7 +357,7 @@ lmc_hssi_watchdog (lmc_softc_t * const sc)
  * Set cable length
  */
 static void
-lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie)
+lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie) /*fold00*/
 {
   if (ie == LMC_CTL_CABLE_LENGTH_GT_100FT)
     {
@@ -341,7 +373,7 @@ lmc_ds3_set_100ft (lmc_softc_t * const sc, int ie)
 }
 
 static void
-lmc_ds3_default (lmc_softc_t * const sc)
+lmc_ds3_default (lmc_softc_t * const sc) /*fold00*/
 {
   sc->lmc_miireg16 = LMC_MII16_LED_ALL;
 
@@ -356,7 +388,7 @@ lmc_ds3_default (lmc_softc_t * const sc)
  * always reset the card if needed.
  */
 static void
-lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
 {
   if (ctl == NULL)
     {
@@ -387,7 +419,7 @@ lmc_ds3_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
 }
 
 static void
-lmc_ds3_init (lmc_softc_t * const sc)
+lmc_ds3_init (lmc_softc_t * const sc) /*fold00*/
 {
   int i;
 
@@ -422,7 +454,7 @@ lmc_ds3_init (lmc_softc_t * const sc)
  * 1 == DS3 payload scrambled, 0 == not scrambled
  */
 static void
-lmc_ds3_set_scram (lmc_softc_t * const sc, int ie)
+lmc_ds3_set_scram (lmc_softc_t * const sc, int ie) /*fold00*/
 {
   if (ie == LMC_CTL_ON)
     {
@@ -442,7 +474,7 @@ lmc_ds3_set_scram (lmc_softc_t * const sc, int ie)
  * 0 == link is down, 1 == link is up.
  */
 static int
-lmc_ds3_get_link_status (lmc_softc_t * const sc)
+lmc_ds3_get_link_status (lmc_softc_t * const sc) /*fold00*/
 {
     u_int16_t link_status, link_status_11;
     int ret = 1;
@@ -528,34 +560,30 @@ lmc_ds3_get_link_status (lmc_softc_t * const sc)
  * 0 == 16bit, 1 == 32bit
  */
 static void
-lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_ds3_set_crc_length (lmc_softc_t * const sc, int state) /*FOLD00*/
 {
   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;
+      sc->lmc_crcSize = LMC_CTL_CRC_BYTESIZE_4;
     }
   else
     {
       /* 16 bit */
       sc->lmc_miireg16 &= ~LMC_MII16_DS3_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);
 }
 
 static void
-lmc_ds3_watchdog (lmc_softc_t * const sc)
+lmc_ds3_watchdog (lmc_softc_t * const sc) /*fold00*/
 {
-  sc->lmc_miireg16 = lmc_mii_readreg (sc, 0, 16);
-  if (sc->lmc_miireg16 & 0x0018) {
-      printk ("%s: AIS Recieved\n", sc->name);
-      lmc_led_on (sc, LMC_DS3_LED1 | LMC_DS3_LED2);
-  }
-  else{
-  }
+    
 }
 
 
@@ -564,7 +592,7 @@ lmc_ds3_watchdog (lmc_softc_t * const sc)
  */
 
 static void
-lmc_ssi_init (lmc_softc_t * const sc)
+lmc_ssi_init (lmc_softc_t * const sc) /*fold00*/
 {
   u_int16_t mii17;
   int cable;
@@ -580,7 +608,7 @@ lmc_ssi_init (lmc_softc_t * const sc)
 }
 
 static void
-lmc_ssi_default (lmc_softc_t * const sc)
+lmc_ssi_default (lmc_softc_t * const sc) /*fold00*/
 {
   sc->lmc_miireg16 = LMC_MII16_LED_ALL;
 
@@ -600,7 +628,7 @@ lmc_ssi_default (lmc_softc_t * const sc)
  * always reset the card if needed.
  */
 static void
-lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
 {
   if (ctl == NULL)
     {
@@ -637,26 +665,30 @@ lmc_ssi_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl)
  * 1 == internal, 0 == external
  */
 static void
-lmc_ssi_set_clock (lmc_softc_t * const sc, int ie)
+lmc_ssi_set_clock (lmc_softc_t * const sc, int ie) /*fold00*/
 {
+  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;
-      printk (LMC_PRINTF_FMT ": clock external\n", LMC_PRINTF_ARGS);
+      if(ie != old)
+        printk (KERN_INFO "%s: clock external\n", sc->name);
     }
   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;
-      printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
+      if(ie != old)
+        printk (KERN_INFO "%s: clock internal\n", sc->name);
     }
 }
 
 static void
-lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
 {
   lmc_ctl_t *ictl = &sc->ictl;
   lmc_av9110_t *av;
@@ -698,7 +730,7 @@ lmc_ssi_set_speed (lmc_softc_t * const sc, lmc_ctl_t * ctl)
  * 0 == link is down, 1 == link is up.
  */
 static int
-lmc_ssi_get_link_status (lmc_softc_t * const sc)
+lmc_ssi_get_link_status (lmc_softc_t * const sc) /*fold00*/
 {
   u_int16_t link_status;
   u_int32_t ticks;
@@ -741,7 +773,7 @@ lmc_ssi_get_link_status (lmc_softc_t * const sc)
       ret = 0;
       if(sc->last_led_err[3] != 1){
           sc->stats.tx_lossOfClockCnt++;
-          printk(KERN_WARNING "%s: Lost Clock Card Down\n", sc->name);
+          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 */
@@ -767,7 +799,7 @@ lmc_ssi_get_link_status (lmc_softc_t * const sc)
 
   if(hw_hdsk == 0){
       if(sc->last_led_err[1] != 1)
-          printk(KERN_WARNING "%s: DSR no asserted\n", sc->name);
+          printk(KERN_WARNING "%s: DSR not asserted\n", sc->name);
       sc->last_led_err[1] = 1;
       lmc_led_off(sc, LMC_MII16_LED1);
   }
@@ -786,17 +818,17 @@ lmc_ssi_get_link_status (lmc_softc_t * const sc)
 }
 
 static void
-lmc_ssi_set_link_status (lmc_softc_t * const sc, int state)
+lmc_ssi_set_link_status (lmc_softc_t * const sc, int state) /*fold00*/
 {
   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);
+//      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);
+//      printk (LMC_PRINTF_FMT ": deasserting DTR and RTS\n", LMC_PRINTF_ARGS);
     }
 
   lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
@@ -807,7 +839,7 @@ lmc_ssi_set_link_status (lmc_softc_t * const sc, int state)
  * 0 == 16bit, 1 == 32bit
  */
 static void
-lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state) /*FOLD00*/
 {
   if (state == LMC_CTL_CRC_LENGTH_32)
     {
@@ -832,51 +864,46 @@ lmc_ssi_set_crc_length (lmc_softc_t * const sc, int state)
  * These are bits to program the ssi frequency generator
  */
 static inline void
-write_av9110_bit (lmc_softc_t * sc, int c)
+write_av9110_bit (lmc_softc_t * sc, int c) /*fold00*/
 {
   /*
    * set the data bit as we need it.
    */
-  sc->lmc_gpio &= ~(LMC_GEP_SERIALCLK);
+  sc->lmc_gpio &= ~(LMC_GEP_CLK);
   if (c & 0x01)
-    sc->lmc_gpio |= LMC_GEP_SERIAL;
+    sc->lmc_gpio |= LMC_GEP_DATA;
   else
-    sc->lmc_gpio &= ~(LMC_GEP_SERIAL);
+    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_SERIALCLK;
+  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_SERIALCLK);
+  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,
+write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v, /*fold00*/
              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_SERIAL | LMC_GEP_SERIALCLK);
+  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_SERIAL | LMC_GEP_SERIALCLK
+  lmc_gpio_mkoutput (sc, (LMC_GEP_DATA | LMC_GEP_CLK
                          | LMC_GEP_SSI_GENERATOR));
 
   sc->lmc_gpio &= ~(LMC_GEP_SSI_GENERATOR);
@@ -902,12 +929,12 @@ write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v,
    * stop driving serial-related signals
    */
   lmc_gpio_mkinput (sc,
-                   (LMC_GEP_SERIAL | LMC_GEP_SERIALCLK
+                   (LMC_GEP_DATA | LMC_GEP_CLK
                     | LMC_GEP_SSI_GENERATOR));
 }
 
 static void
-lmc_ssi_watchdog (lmc_softc_t * const sc)
+lmc_ssi_watchdog (lmc_softc_t * const sc) /*fold00*/
 {
   u_int16_t mii17;
   struct ssicsr2
@@ -937,24 +964,24 @@ lmc_ssi_watchdog (lmc_softc_t * const sc)
  * 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_t1_write (lmc_softc_t * const sc, int a, int d) /*fold00*/
 {
   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_t1_read (lmc_softc_t * const sc, int a) /*fold00*/
 {
   lmc_mii_writereg (sc, 0, 17, a);
   return lmc_mii_readreg (sc, 0, 18);
 }
-*/
+
 
 
 static void
-lmc_t1_init (lmc_softc_t * const sc)
+lmc_t1_init (lmc_softc_t * const sc) /*fold00*/
 {
   u_int16_t mii16;
   int i;
@@ -962,6 +989,10 @@ lmc_t1_init (lmc_softc_t * const sc)
   sc->ictl.cardtype = LMC_CTL_CARDTYPE_LMC1200;
   mii16 = lmc_mii_readreg (sc, 0, 16);
 
+  mii16 &= ~LMC_MII16_T1_XOE;
+  lmc_mii_writereg (sc, 0, 16, mii16);
+  sc->lmc_miireg16 = mii16;
+
   /* reset 8370 */
   mii16 &= ~LMC_MII16_T1_RST;
   lmc_mii_writereg (sc, 0, 16, mii16 | LMC_MII16_T1_RST);
@@ -972,52 +1003,430 @@ lmc_t1_init (lmc_softc_t * const sc)
   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 */
+  /* Clear "foreced alarm" bis */
+  sc->yellow_alarm = 0;
+  sc->red_alarm = 0;
+  sc->blue_alarm = 0;
+
+  /*
+   * CR0
+   * - Set framing too ESF + Force CRC
+   * - Set T1
+   */
+  
+  lmc_t1_write (sc, 0x01, 0x1b);
+  /*
+   * JAT_CR
+   * - set Free Running JCLK and CLAD0
+   * - Reset Elastic store to center
+   * - 64 bit elastic store
+   */
+  lmc_t1_write (sc, 0x02, 0x4b);
+  
+  /*
+   * JAT_CR
+   * - Release Elastic store reset
+   */
+  lmc_t1_write (sc, 0x02, 0x43);
+  
+  /*
+   * Disable all interupts
+   * Except: BOP receive
+   */
+
+  lmc_t1_write (sc, 0x0C, 0x00);
+  lmc_t1_write (sc, 0x0D, 0x00);
+  lmc_t1_write (sc, 0x0E, 0x00);
+  lmc_t1_write (sc, 0x0F, 0x00);
+  lmc_t1_write (sc, 0x10, 0x00);
+  lmc_t1_write (sc, 0x11, 0x00);
+  lmc_t1_write (sc, 0x12, 0x80);
+  lmc_t1_write (sc, 0x13, 0x00);
+  
+  /*
+   * LOOP
+   * - No loopbacks set
+   */
+  lmc_t1_write (sc, 0x14, 0x00);
+  
+  /*
+   * DL3_TS
+   * - Disabled
+   */
+  lmc_t1_write (sc, 0x15, 0x00);
+  
+  /*
+   * PIO
+   * - ONESEC_IO, RDL_IO, TDL_IO, INDY_IO, RFSYNC_IO, RMSYNC_IO
+   *   TFSNYC_IO, TMSYNC_IO: Set for output
+   */
   lmc_t1_write (sc, 0x18, 0xFF);       /* PIO     - programmable I/O            */
+  
+  /*
+   * POE
+   * TDL_OE, RDL_OE: tri state output capable enable
+   * Rest: 2 level output
+   */
   lmc_t1_write (sc, 0x19, 0x30);       /* POE     - programmable OE             */
+  
+  /*
+   * CMUX - Clock Input Mux
+   * RSBCKLI: Normal RSB timebase
+   * TSBCKI: Normal TSB timebase
+   * CLADI: CLAD slaved to transmit
+   * TCKI: Internal CLAD
+   */
   lmc_t1_write (sc, 0x1A, 0x0F);       /* CMUX    - clock input mux             */
+  
+  /*
+   * LIU_CR
+   * RST_LIU: Reset LIU
+   * SQUELCH: Enable squelch
+   * Must be 1: Set to 1
+   */
+  lmc_t1_write (sc, 0x20, 0xC1);       /* LIU_CR  - RX LIU config               */
   lmc_t1_write (sc, 0x20, 0x41);       /* LIU_CR  - RX LIU config               */
-  lmc_t1_write (sc, 0x22, 0x76);       /* RLIU_CR - RX LIU config               */
+  /*
+   * RLIU_CR
+   * WHAT IS GOING ON HERE? USED TO BE 0x76
+   * FRZ_SHORT: don't update on strong signals
+   * AGC: 0x11 normal op
+   * LONG_EYE: normal
+   */
+  lmc_t1_write (sc, 0x22, 0xB1);       /* RLIU_CR - RX LIU config               */
+
+  /*
+   * VGA_MAX
+   * Setting of -20db sesitivity
+   */
+  lmc_t1_write (sc, 0x24, 0x21);
+
+  /*
+   * PRE_EQ
+   * Force off the pre-equilizer
+   * Load 0x26 in VTHRESH
+   */
+  lmc_t1_write (sc, 0x2A, 0xA6);
+
+  /*
+   * GAIN
+   * Equilizer Gain threshholds
+   * Number taken straight from David test code
+   */
+  lmc_t1_write (sc, 0x38, 0x24);  /* RX_TH0  - RX gain threshold 0         */
+  lmc_t1_write (sc, 0x39, 0x28);  /* RX_TH1  - RX gain threshold 0         */
+  lmc_t1_write (sc, 0x3A, 0x2C);  /* RX_TH2  - RX gain threshold 0         */
+  lmc_t1_write (sc, 0x3B, 0x30);  /* RX_TH3  - RX gain threshold 0         */
+  lmc_t1_write (sc, 0x3C, 0x34);  /* RX_TH4  - RX gain threshold 0         */
+
+  /*
+   *  LIU_CR
+   *  Reset the LIU so it'll load the new constants
+   */
+  lmc_t1_write (sc, 0x20, 0x81);  /* LIU_CR  - RX LIU config (reset RLIU)  */
+  lmc_t1_write (sc, 0x20, 0x01);  /* LIU_CR  - RX LIU config (clear reset) */
+  
+  /*
+   * RCR0
+   * Receive B8ZS and 2 out of 4 F-bit errors for reframe
+   */
   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   */
+
+  /*
+   * RPATT
+   * Zero the test pattern generator
+   */
+  lmc_t1_write (sc, 0x41, 0x00);
+
+  /*
+   * RLB
+   * Loop back code detector
+   * DN_LEN: Down length is 8 bits
+   * UP_LEN: 5 bits
+   */
+  lmc_t1_write (sc, 0x42, 0x09);
+
+  /*
+   * LBA: Loopback activate
+   * LBA[6]: 1
+   * Loopback activate code
+   */
+  lmc_t1_write (sc, 0x43, 0x08);
+
+  /*
+   * LBD: Loopback deactivate
+   *
+   * Loopback deactivate code
+   */
+  lmc_t1_write (sc, 0x44, 0x24);
+
+  /*
+   * RALM: Receive Alarm Signal Configuration
+   *
+   * Set 0 which seems to be narmal alarms
+   */
+  lmc_t1_write (sc, 0x45, 0x00);
+
+  /*
+   * LATCH: Alarm/Error/Cournetr Latch register
+   *
+   * STOP_CNT: Stop error counters durring RLOF/RLOS/RAIS
+   */
+  lmc_t1_write (sc, 0x46, 0x08);
+
+  /*
+   * TLIU_CR: Transmit LIU Control Register
+   *
+   * TERM: External Transmit termination
+   * LBO: No line buildout
+   * Pulse shape from N8370DSE: 3-66
+   * // PULSE: 000 = 0 - 133ft 100 ohm twisted pair T1 DSX
+   * PULSE: 111 = Long Haul FCC Part 68 100 ohm twisted T1 CSU/NCTE
+   */
+  
+  lmc_t1_write (sc, 0x68, 0x4E);
+
+  /*
+   * TCR0: Transmit Framer Configuration
+   *
+   * TFRAME: 1101 == ESF + Froce CRC
+   */
+  lmc_t1_write (sc, 0x70, 0x0D);
+
+  /*
+   * TCR1: Transmit Configuration Registers
+   *
+   * TLOFA: 2 out of 4 bit errors = LOF
+   * TZCS: 000VB0VB Table 3-20 page 3-72
+   */
+  lmc_t1_write (sc, 0x71, 0x05);
+
+  /*
+   * TFRM: Transmit Frame Format
+   *
+   * INS_MF: Insert Multiframe aligement
+   * INS_CRC: Insert CRC
+   * INS_FBIT: Insert Framing
+   */
+  lmc_t1_write (sc, 0x72, 0x0B);
+
+  /*
+   * TERROR
+   *
+   * Don't xmit any errors
+   */
+  lmc_t1_write (sc, 0x73, 0x00);
+
+  /*
+   * TMAN: Tranimit Mahual Sa-byte/FEBE configuration
+   */
+  lmc_t1_write (sc, 0x74, 0x00);
+
+
+  /*
+   * TALM: Transmit Alarm Signal Configuration
+   *
+   * Don't use any of these auto alarms
+   */
+  lmc_t1_write (sc, 0x75, 0x00);
+
+
+  /*
+   * TPATT: Transmit Pattern Canfiguration
+   *
+   * No special test patterns
+   */
+  lmc_t1_write (sc, 0x76, 0x00);
+
+  /*
+   * TLB: Transmit Inband Loopback Codhe Configuration
+   *
+   * Not enabled
+   */
+  lmc_t1_write (sc, 0x77, 0x00);
+
+  /*
+   * CLAD_CR: Clack Rate Adapter Configuration
+   *
+   * LFGAIN: Loop filter gain 1/2^6
+   */
+  lmc_t1_write (sc, 0x90, 0x06);       /* CLAD_CR - clock rate adapter config   */
+
+  /*
+   * CSEL: CLAD Frequency Select
+   *
+   * CLADV: 0000 - 1024 kHz
+   * CLADO: 0101 - 1544 kHz
+   */
   lmc_t1_write (sc, 0x91, 0x05);       /* CSEL    - clad freq sel               */
-  lmc_t1_write (sc, 0xA6, 0x00);       /* DL1_CTL - DL1 control                 */
+
+  /*
+   * CPHASE: CLAD Phase detector
+   */
+  lmc_t1_write (sc, 0x92, 0x00);
+
+  /*
+   * CTEST: Clad Test
+   *
+   * No tests
+   */
+  lmc_t1_write (sc, 0x93, 0x00);
+
+  /*
+   * BOP: Bop receiver
+   *
+   * Enable, 25 messages receive, 25 send, BOP has priority over FDL
+   */
+  lmc_t1_write (sc, 0xA0, 0xea);        /* BOP     - Bit oriented protocol xcvr  */
+
+  /*
+   * Setup required to activae BOP.
+   * See table: 3-22 page 3-87
+   * See at the end
+   */
+  lmc_t1_write (sc, 0xA4, 0x40);        /* DL1_TS  - DL1 time slot enable        */
+  lmc_t1_write (sc, 0xA5, 0x00);        /* DL1_BIT - DL1 bit enable              */
+  lmc_t1_write (sc, 0xA6, 0x03);        /* DL1_CTL - DL1 control                 */
+  lmc_t1_write (sc, 0xA7, 0x00);        /* RDL1_FFC - DL1 FIFO Size */
+  lmc_t1_write (sc, 0xAB, 0x00);        /* TDL1_FFC - DL1 Empty Control*/
+
+  /*
+   * PRM: FDL PRM Messages
+   *
+   * Disable all automatic FDL messages
+   */
+  
+  lmc_t1_write (sc, 0xAA, 0x00);        /* PRM     - performance report message  */
+
+  /*
+   * DLC2 Control
+   *
+   * TDL2_EN: Disable transmit
+   * RDL2_EN: Disable receive
+   */
   lmc_t1_write (sc, 0xB1, 0x00);       /* DL2_CTL - DL2 control                 */
+  /*
+   * SBI_CR: System Bus Interface Configuration
+   *
+   * SBI_OE: Enable system bus
+   * SBI: T1 at 1544 with 24+fbit Page 3-113
+   */
   lmc_t1_write (sc, 0xD0, 0x47);       /* SBI_CR  - sys bus iface config        */
-  lmc_t1_write (sc, 0xD1, 0x70);       /* RSB_CR  - RX sys bus config           */
+  /*
+   * RSB_CR: Receive System Bus Coniguration
+   *
+   * SIG_OFF: RPCMO signalling off
+   * RPCM_NEG: Output on falling edge
+   * RSYN_NEG: Output sync an negative edge of clock
+   *
+   */
+  lmc_t1_write (sc, 0xD1, 0x70);
+
+  /*
+   * TSB_CR: Transmit System Bus  Configuration
+   *
+   * TPCM_NEG: Tranimettr multiframe follows TSB
+   * TSYN_NEG: TFSYNC or TMSYNC on falling edge output
+   */
   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, 0x01);       /* SBCn - sys bus per-channel ctl    */
   for (i = 1; i < 25; i++)
     {
       lmc_t1_write (sc, 0x0E0 + i, 0x0D);      /* SBCn - sys bus per-channel ctl    */
     }
 
+  /*
+   * Seems to get lost sometimes
+   */
+  lmc_t1_write (sc, 0xA4, 0x40);        /* DL1_TS  - DL1 time slot enable        */
+  lmc_t1_write (sc, 0xA5, 0x00);        /* DL1_BIT - DL1 bit enable              */
+  lmc_t1_write (sc, 0xA6, 0x03);        /* DL1_CTL - DL1 control                 */
+  lmc_t1_write (sc, 0xA7, 0x00);        /* RDL1_FFC - DL1 FIFO Size */
+  lmc_t1_write (sc, 0xAB, 0x00);        /* TDL1_FFC - DL1 Empty Control*/
+
+  /*
+   * Basic setup is done, now setup modes like SF AMI, and
+   * Fractional T1.
+   */
+
+  if(sc->t1_amisf != 0){
+      /*
+       * Set ami line codeing
+       */
+      lmc_t1_write (sc, 0x40, 0x83);
+      lmc_t1_write (sc, 0x71, 0x07); // 0x03 is ami
+
+      /*
+       * Set SF framing
+       */
+      lmc_t1_write (sc, 0x70, 0x04);
+      lmc_t1_write (sc, 0x72, 0x09);
+      lmc_t1_write (sc, 0x01, 0x09);
+
+      lmc_t1_write (sc, 0x46,0x00);
+      lmc_t1_write (sc, 0xa6,0x00);
+      lmc_t1_write (sc, 0xa0,0x00);
+
+      /* Setup Loopback */
+      lmc_t1_write (sc, 0x0d, 0xc0);
+      lmc_t1_write (sc, 0x42, 0x09);
+      lmc_t1_write (sc, 0x43, 0x08);
+      lmc_t1_write (sc, 0x44, 0x24);
+
+
+      if(sc->t1_amisf == 2 && sc->t1_frac_mask == 0){
+          sc->t1_frac_mask = 0xfffffffe;
+      }
+  }
+
+  if(sc->t1_frac_mask){
+      u32 mask = sc->t1_frac_mask;
+      int i;
+      int onoff;
+      for(i = 24; i >= 1; i--){
+          onoff = mask & 0x1;
+          mask >>= 1;
+          if(onoff == 0){
+              lmc_t1_write(sc, 0x0e0+i,0x01);
+              lmc_t1_write(sc, 0x100+i,0x20);
+              lmc_t1_write(sc, 0x140+i,0x7f);
+          }
+          else{
+              lmc_t1_write(sc, 0x0e0+i,0x0D);
+              lmc_t1_write(sc, 0x100+i,0x00);
+              lmc_t1_write(sc, 0x140+i,0x00);
+          }
+      }
+      mii16 |= LMC_MII16_T1_INVERT;
+      lmc_mii_writereg (sc, 0, 16, mii16);
+  }
+  else {
+      mii16 &= ~LMC_MII16_T1_INVERT; /* Unless we're on AMI SF don't invert */
+  }
+
+  if(sc->t1_loop_time){
+         lmc_t1_write(sc, 0x02, 0xa3);
+  }
+
+  lmc_gpio_mkoutput(sc, LMC_GEP_T1_INT);
+  sc->lmc_gpio |= LMC_GEP_T1_INT;
+  LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio);
+
   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)
+lmc_t1_default (lmc_softc_t * const sc) /*fold00*/
 {
   sc->lmc_miireg16 = LMC_MII16_LED_ALL;
   sc->lmc_media->set_link_status (sc, LMC_LINK_DOWN);
@@ -1029,7 +1438,7 @@ lmc_t1_default (lmc_softc_t * const sc)
 /* * 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)
+lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
 {
   if (ctl == NULL)
     {
@@ -1053,7 +1462,7 @@ lmc_t1_set_status (lmc_softc_t * const sc, lmc_ctl_t * 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)
+lmc_t1_get_link_status (lmc_softc_t * const sc) /*fold00*/
 {
     u_int16_t link_status;
     int ret = 1;
@@ -1067,19 +1476,23 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
    * 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 */
+    if ((link_status & T1F_RAIS) || sc->blue_alarm) {                  /* 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);
         }
+        if(sc->blue_alarm != 0){
+            sc->blue_alarm--;
+        }
         lmc_led_on(sc, LMC_DS3_LED1);
+        
         sc->last_led_err[1] = 1;
     }
     else {
@@ -1091,20 +1504,26 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
     }
 
     /*
-     * Yellow Alarm is nasty evil stuff, looks at data patterns
+     * AMI: Yellow Alarm is nasty evil stuff, looks at data patterns
      * inside the channel and confuses it with HDLC framing
      * ignore all yellow alarms.
      *
+     * B8ZS: RAI/Yellow alarm is implemented via a continous BOP
+     * message.
+     *
      * 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) {
+    if ((link_status & T1F_RMYEL) || sc->yellow_alarm) {
         ret = 0;
         if(sc->last_led_err[0] != 1){
             printk(KERN_WARNING "%s: Receive Yellow AIS Alarm\n", sc->name);
         }
+        if(sc->yellow_alarm > 0){
+            sc->yellow_alarm--;
+        }
         lmc_led_on(sc, LMC_DS3_LED0);
         sc->last_led_err[0] = 1;
     }
@@ -1120,10 +1539,21 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
      * Loss of signal and los of frame
      * Use the green bit to identify which one lit the led
      */
-    if(link_status & T1F_RLOF){
+    if((link_status & T1F_RLOF) || sc->red_alarm){
         ret = 0;
         if(sc->last_led_err[3] != 1){
-            printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing\n", sc->name);
+            printk(KERN_WARNING "%s: Local Red Alarm: Loss of Framing (LOF)\n", sc->name);
+            /*
+             * Send AIS/Yellow
+             * So send continuous AIS/Yellom BOP messages
+             */
+            if(!sc->t1_amisf){
+                lmc_t1_write (sc, 0xA0, 0xee); /* Cont BOP */
+                lmc_t1_write (sc, 0xA1, 0x00); /* 0x00 is AIS/yellow BOP */
+            }
+        }
+        if(sc->red_alarm != 0){
+            sc->red_alarm--;
         }
         lmc_led_on(sc, LMC_DS3_LED3);
         sc->last_led_err[3] = 1;
@@ -1132,16 +1562,34 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
     else {
         if(sc->last_led_err[3] != 0){
             printk(KERN_WARNING "%s: End Red Alarm (LOF)\n", sc->name);
+            /*
+             * Stop sending continuous BOP
+             * hence end yellow alarm
+             */
+            if(!sc->t1_amisf){
+                lmc_t1_write (sc, 0xA0, 0xea); /* Normal 25 BOP */
+            }
         }
         if( ! (link_status & T1F_RLOS))
             lmc_led_off(sc, LMC_DS3_LED3);
         sc->last_led_err[3] = 0;
     }
     
-    if(link_status & T1F_RLOS){
+    if((link_status & T1F_RLOS) || sc->red_alarm){
         ret = 0;
         if(sc->last_led_err[2] != 1){
-            printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal\n", sc->name);
+            printk(KERN_WARNING "%s: Local Red Alarm: Loss of Signal (LOS)\n", sc->name);
+            /*
+             * Send AIS/Yellow
+             * So send continuous AIS/Yellom BOP messages
+             */
+            if(!sc->t1_amisf){
+                lmc_t1_write (sc, 0xA0, 0xee); /* Cont BOP */
+                lmc_t1_write (sc, 0xA1, 0x00); /* 0x00 is AIS/yellow BOP */
+            }
+        }
+        if(sc->red_alarm != 0){
+            sc->red_alarm--;
         }
         lmc_led_on(sc, LMC_DS3_LED3);
         sc->last_led_err[2] = 1;
@@ -1150,6 +1598,14 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
     else {
         if(sc->last_led_err[2] != 0){
             printk(KERN_WARNING "%s: End Red Alarm (LOS)\n", sc->name);
+            /*
+             * Stop sending continuous BOP
+             * hence end yellow alarm
+             */
+            if(!sc->t1_amisf){
+                lmc_t1_write (sc, 0xA0, 0xea); /* Normal 25 BOP */
+            }
+
         }
         if( ! (link_status & T1F_RLOF))
             lmc_led_off(sc, LMC_DS3_LED3);
@@ -1161,6 +1617,9 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
     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;
 }
 
@@ -1168,17 +1627,19 @@ lmc_t1_get_link_status (lmc_softc_t * const sc)
  * 1 == T1 Circuit Type , 0 == E1 Circuit Type
  */
 static void
-lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie)
+lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie) /*fold00*/
 {
+  int old;
+  old = sc->ictl.circuit_type;
   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);
+      if(old != sc->ictl.circuit_type)
+          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);
+      if(old != sc->ictl.circuit_type)
+          printk(KERN_INFO "%s: In E1 Mode (non functional)\n", sc->name);
   }
 
   lmc_mii_writereg (sc, 0, 16, sc->lmc_miireg16);
@@ -1188,7 +1649,7 @@ lmc_t1_set_circuit_type (lmc_softc_t * const sc, int ie)
 /*
  * 0 == 16bit, 1 == 32bit */
 static void
-lmc_t1_set_crc_length (lmc_softc_t * const sc, int state)
+lmc_t1_set_crc_length (lmc_softc_t * const sc, int state) /*fold00*/
 {
   if (state == LMC_CTL_CRC_LENGTH_32)
     {
@@ -1213,31 +1674,167 @@ lmc_t1_set_crc_length (lmc_softc_t * const sc, int state)
  * 1 == internal, 0 == external
  */
 static void
-lmc_t1_set_clock (lmc_softc_t * const sc, int ie)
+lmc_t1_set_clock (lmc_softc_t * const sc, int ie) /*fold00*/
 {
-  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;
-      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;
-      printk (LMC_PRINTF_FMT ": clock internal\n", LMC_PRINTF_ARGS);
-    }
+    /*
+     * Not set this way, done through T1 specific IOCTL
+     */
 }
 
-static void
-lmc_t1_watchdog (lmc_softc_t * const sc)
+static void lmc_t1_watchdog (lmc_softc_t * const sc) /*fold00*/
 {
+        if(sc->loop_timer != 0){
+                sc->loop_timer--;
+                if(sc->loop_timer == 0){
+                        if(lmc_t1_read(sc, 0x014) != 0x00){
+                                printk(KERN_DEBUG "%s: Timeout: Loop down\n", sc->name);
+                                lmc_t1_write(sc, 0x014, 0x00);
+                                /*
+                                 * If we're not loop timed
+                                 * go back to intelnal clack
+                                 */
+                                if(! sc->t1_loop_time){
+                                    lmc_t1_write(sc, 0x02, 0x4b);
+                                }
+                        }
+                }
+        }
+        /*
+         * Check for BOP messages on A2 rev boards
+         */
+        lmc_t1_got_interupt (sc);
 }
 
-static void
-lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl)
+static int lmc_t1_ioctl (lmc_softc_t * const sc, void *d) /*fold00*/
+{
+        struct lmc_st1f_control ctl;
+        int ret;
+
+        LMC_COPY_FROM_USER(&ctl, d, sizeof (struct lmc_st1f_control));
+
+        switch(ctl.command){
+        case lmc_st1f_write:
+                lmc_t1_write(sc, ctl.address, ctl.value);
+                ret = 0;
+                break;
+        case lmc_st1f_read:
+                ctl.value = lmc_t1_read(sc, ctl.address) & 0xff;
+                LMC_COPY_TO_USER(d, &ctl, sizeof (struct lmc_st1f_control));
+                ret = 0;
+                break;
+        case lmc_st1f_inv:
+                if(ctl.value == 1){
+                  sc->lmc_miireg16 |= LMC_MII16_T1_INVERT;
+                  lmc_mii_writereg (sc, 0, 16,   sc->lmc_miireg16);
+                  printk("%s: Request to invert data\n", sc->name);
+                }
+                else {
+                  sc->lmc_miireg16 &= ~LMC_MII16_T1_INVERT;
+                  lmc_mii_writereg (sc, 0, 16,   sc->lmc_miireg16);
+                  printk("%s: Request to non-invert data\n", sc->name);
+                }
+                ret = 0;
+                break;
+        case lmc_st1f_amisf:
+                sc->t1_amisf = ctl.value;
+                if(sc->lmc_ok){
+                 lmc_t1_init(sc);
+                }
+                ret = 0;
+                break;
+        case lmc_st1f_frac:
+                LMC_COPY_FROM_USER(&sc->t1_frac_mask, ctl.data, sizeof (u32));
+                if(sc->lmc_ok){
+                 lmc_t1_init(sc);
+                }
+                ret = 0;
+                break;
+        case lmc_st1f_loopt:
+               sc->t1_loop_time = ctl.value;
+               if(sc->lmc_ok){
+                       lmc_t1_init(sc);
+               }
+               ret = 0;
+               break;
+        default:
+        ret = -ENOSYS;
+        }
+
+        return ret;
+}
+
+static int lmc_t1_got_interupt (lmc_softc_t * const sc) /*fold00*/
+{
+        u8 reg;
+
+        /* And it with the mask in case we're polling
+         * and we have want the int disabsled
+         */
+        reg = lmc_t1_read(sc, 0x00a) & lmc_t1_read(sc, 0x12);
+
+        if(reg & 0x80){
+//                printk(KERN_DEBUG "%s: Got Inbound BOP message 0x%02x\n", sc->name, lmc_t1_read(sc, 0x0a2) & 0x3f);
+                switch(lmc_t1_read(sc, 0x0a2) & 0x3f) {
+                case 0x00: /* Yellow Alarm */
+                        sc->yellow_alarm = 5; /* Start Yellow Alarm for 3 seconds */
+                        break;
+
+                case 0x07: /* Loop up */
+                        printk(KERN_DEBUG "%s: BOP: Loop up\n", sc->name);
+                        sc->loop_timer = 305;
+                        lmc_t1_write(sc, 0x002, 0xa3); /* Enter loop timeing */
+                        lmc_t1_write(sc, 0x014, 0x04); /* Loop towards net */
+                        break;
+                        
+                case 0x0b: /* Pay load loop back */
+                        printk(KERN_DEBUG "%s: BOP: Payload Loop up\n", sc->name);
+                        sc->loop_timer = 305;
+                        lmc_t1_write(sc, 0x014, 0x08);
+                        break;
+                        
+                case 0x1a:
+                case 0x1c: /* Loop down T1.409, etc */
+                case 0x1d: /* Loop down T1.403 */
+                        printk(KERN_DEBUG "%s: BOP: Loop down\n", sc->name);
+                        lmc_t1_write(sc, 0x014, 0x00); /* Loop down */
+                        /*
+                         * If we're not loop timed
+                         * go back to intelnal clack
+                         */
+                        if(! sc->t1_loop_time){
+                            lmc_t1_write(sc, 0x02, 0x4b);
+                        }
+
+                        break;
+
+                }
+        }
+
+        reg = lmc_t1_read(sc, 0x005) & lmc_t1_read(sc, 0x0d);
+        
+        if(reg & 0x04){
+            printk(KERN_DEBUG "%s: Inband: Loop up\n", sc->name);
+            sc->loop_timer = 305;
+            lmc_t1_write(sc, 0x002, 0xa3); /* Enter loop timeing */
+            lmc_t1_write(sc, 0x014, 0x04); /* Loop up */
+        }
+        if(reg & 0x08){
+            printk(KERN_DEBUG "%s: Inband: Loop down\n", sc->name);
+            lmc_t1_write(sc, 0x014, 0x00);
+            /*
+             * If we're not loop timed
+             * go back to intelnal clack
+             */
+            if(! sc->t1_loop_time){
+                lmc_t1_write(sc, 0x02, 0x4b);
+            }
+        }
+        
+        return 0;
+}
+
+
+static void lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl) /*fold00*/
 {
   if (ctl == 0)
     {
diff --git a/drivers/net/lmc/lmc_proto.c b/drivers/net/lmc/lmc_proto.c
new file mode 100644 (file)
index 0000000..31f6c2c
--- /dev/null
@@ -0,0 +1,270 @@
+ /*
+  * 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)
+  *
+  * With Help By:
+  * David Boggs
+  * Ron Crane
+  * Allan Cox
+  *
+  * This software may be used and distributed according to the terms
+  * of the GNU Public License version 2, incorporated herein by reference.
+  *
+  * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
+  */
+
+#include <linux/version.h>
+//#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <asm/processor.h>             /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "../syncppp.h"
+#include <linux/inet.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+
+#include "lmc_ver.h"
+#include "lmc.h"
+#include "lmc_var.h"
+#include "lmc_debug.h"
+#include "lmc_ioctl.h"
+#include "lmc_proto.h"
+//#include "lmc_proto_raw.h"
+
+/*
+ * The compile-time variable SPPPSTUP causes the module to be
+ * compiled without referencing any of the sync ppp routines.
+ */
+#ifdef SPPPSTUB
+#define SYNC_PPP_init() (void)0
+#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
+#if LINUX_VERSION_CODE < 0x20211
+#define SYNC_PPP_init  sync_ppp_init
+#define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device)
+#define SPPP_detach(x) sppp_detach((x)->lmc_device)
+#define SPPP_open(x)   sppp_open((x)->lmc_device)
+#define SPPP_reopen(x) sppp_reopen((x)->lmc_device)
+#define SPPP_close(x)  sppp_close((x)->lmc_device)
+#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z))
+#else
+#define SYNC_PPP_init  sync_ppp_init
+#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
+#endif
+
+static int lmc_first_ppp_load = 0;
+
+// 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:
+        if(lmc_first_ppp_load == 0) {
+            lmc_first_ppp_load = 1;
+#ifndef MODULE
+            SYNC_PPP_init();
+#endif
+        }
+        
+#if LINUX_VERSION_CODE >= 0x20210
+        sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+        sc->pd->dev = sc->lmc_device;
+#endif
+        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 = 0;
+            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:
+        netif_rx(skb);
+        break;
+    case LMC_RAW:
+        break;
+    }
+    lmc_trace(sc->lmc_device, "lmc_proto_netif out");
+}
+
diff --git a/drivers/net/lmc/lmc_proto.h b/drivers/net/lmc/lmc_proto.h
new file mode 100644 (file)
index 0000000..6136dfa
--- /dev/null
@@ -0,0 +1,15 @@
+#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
\ No newline at end of file
index 92765bb7c46e7b7d7a7ab796f0ddcf9dd8a42bfc..2dd5c870c1606e35ba4a76f89e555c958545c27d 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _LMC_VAR_H_
 #define _LMC_VAR_H_
 
-/* $Id: lmc_var.h,v 1.14 2000/01/21 13:29:50 asj Exp $ */
+/* $Id: lmc_var.h,v 1.24 2000/06/16 23:37:16 asj Exp $ */
 
  /*
   * Copyright (c) 1997-2000 LAN Media Corporation (LMC)
@@ -18,6 +18,7 @@
   */
 
 #include <linux/timer.h>
+#include <linux/version.h>
 
 #ifndef __KERNEL__
 typedef signed char s8;
@@ -32,6 +33,14 @@ typedef unsigned int u32;
 typedef signed long long s64;
 typedef unsigned long long u64;
 
+#if LINUX_VERSION_CODE >= 0x20363
+struct timer_list {
+};
+#endif
+
+typedef u32 spinlock_t;
+typedef u32 dma_addr_t;
+
 #define BITS_PER_LONG 32 
 
 #endif
@@ -44,7 +53,7 @@ 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   u32
+#define lmc_csrptr_t    unsigned long
 #define u_int16_t      u16
 #define u_int8_t       u8
 #define tulip_uint32_t u32
@@ -69,13 +78,13 @@ typedef struct lmc___ctl lmc_ctl_t;
 #define LMC_CSR_READ(sc, csr) \
        inl((sc)->lmc_csrs.csr)
 #define LMC_CSR_WRITE(sc, reg, val) \
-       outl(val, (sc)->lmc_csrs.reg)
+       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
+//#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
 
@@ -83,10 +92,10 @@ typedef struct lmc___ctl lmc_ctl_t;
 
 /* 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_CSR_WRITE((sc), csr_9, 0x20000); \
                lmc_delay(); \
                LMC_CSR_WRITE((sc), csr_9, 0x30000); \
-               lmc_delay(); \
+                lmc_delay(); \
                n--; }} while(0);
 
 struct lmc_regfile_t {
@@ -242,6 +251,8 @@ struct lmc___media {
        void    (* set_crc_length)(lmc_softc_t * const, int);
         void    (* set_circuit_type)(lmc_softc_t * const, int);
         void   (* watchdog)(lmc_softc_t * const);
+        int     (* ioctl)(lmc_softc_t * const, void *);
+        int     (* got_interupt)(lmc_softc_t * const);
 };
 
 
@@ -254,32 +265,32 @@ struct lmc___media {
  */
 struct lmc_statistics
 {
-        int     rx_packets;             /* total packets received       */
-        int     tx_packets;             /* total packets transmitted    */
-       int     rx_bytes;
-        int     tx_bytes;
+        unsigned long     rx_packets;             /* total packets received       */
+        unsigned long     tx_packets;             /* total packets transmitted    */
+       unsigned long     rx_bytes;
+        unsigned long     tx_bytes;
         
-        int     rx_errors;              /* bad packets received         */
-        int     tx_errors;              /* packet transmit problems     */
-        int     rx_dropped;             /* no space in linux buffers    */
-        int     tx_dropped;             /* no space available in linux  */
-        int     multicast;              /* multicast packets received   */
-        int     collisions;
+        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: */
-        int     rx_length_errors;
-        int     rx_over_errors;         /* receiver ring buff overflow  */
-        int     rx_crc_errors;          /* recved pkt with crc error    */
-        int     rx_frame_errors;        /* recv'd frame alignment error */
-        int     rx_fifo_errors;         /* recv'r fifo overrun          */
-        int     rx_missed_errors;       /* receiver missed packet       */
+        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 */
-        int     tx_aborted_errors;
-        int     tx_carrier_errors;
-        int     tx_fifo_errors;
-        int     tx_heartbeat_errors;
-        int     tx_window_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;
@@ -296,6 +307,9 @@ struct lmc_statistics
         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;
@@ -353,10 +367,11 @@ typedef struct lmc_xinfo {
  * forward decl
  */
 struct lmc___softc {
+        void                   *if_ptr;   /* General purpose pointer (used by SPPP >= 2.4) */
        char                   *name;
        u8                      board_idx;
        struct lmc_statistics   stats;
-       struct device          *lmc_device;
+       struct net_device          *lmc_device;
 
        int                     hang, rxdesc, bad_packet, some_counter;
        u_int32_t               txgo;
@@ -371,9 +386,12 @@ struct lmc___softc {
        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;
@@ -382,27 +400,49 @@ struct lmc___softc {
        int                     last_link_status;
        int                     lmc_cardtype;
        u_int32_t               last_frameerr;
-       lmc_media_t            *lmc_media;
+        lmc_media_t           *lmc_media;
        struct timer_list       timer;
        lmc_ctl_t               ictl;
        u_int32_t               TxDescriptControlInit;  
-       struct device           *next_module;   /* Link to the next module  */
+       struct net_device      *next_module;   /* Link to the next module  */
        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 */
+       LMC_XINFO               lmc_xinfo;
         char                    lmc_timing; /* for HSSI and SSI */
         int                     got_irq;
 
         char                    last_led_err[4];
+        char                    yellow_alarm; /* Time in seconds to run yellow alarm for */
+        char                    red_alarm;    /* Time in seconds to run red alarm for */
+        char                    blue_alarm;   /* Time in seconds to run blue alarm for */
 
 #if LINUX_VERSION_CODE >= 0x20200
        spinlock_t              lmc_lock;
 #endif
+#if LINUX_VERSION_CODE >= 0x20363
+        struct pci_dev          *pdev;
+        dma_addr_t              sc_dma_handle;
+        struct lmc___softc      *sc_dma;
+#endif
+        u_int16_t               if_type;       /* PPP or NET */
+        struct ppp_device       *pd;
+
+        /* Failure cases */
+        u8                       failed_ring;
+        u8                       failed_recv_alloc;
+
+        /* T1 Specicfic Variable */
+        u16                      loop_timer; /* Time out loop up requests */
+        u8                       t1_amisf;
+        u32                      t1_frac_mask;
+        u8                       t1_loop_time;
+
+        /* Structure check */
+        u32                     check;
 };
 
 #define LMC_PCI_TIME 1
index 8325f2f08935c3f84ef3fcc58dfbed1a132e2ccd..2c10936ba0bc6eeae968df3bd005d81b81205828 100644 (file)
   *
   */
 
+#if LINUX_VERSION_CODE < 0x20363
+#define net_device device
+#define dev_kfree_skb_irq LMC_DEV_KFREE_SKB
+#endif
+
+#if LINUX_VERSION_CODE < 0x20363
+#define LMC_XMITTER_BUSY(x) (x)->tbusy = 1
+#define LMC_XMITTER_FREE(x) (x)->tbusy = 0
+#define LMC_XMITTER_INIT(x) (x)->tbusy = 0
+#else
+#define LMC_XMITTER_BUSY(x) netif_stop_queue(x)
+#define LMC_XMITTER_FREE(x) netif_wake_queue(x)
+#define LMC_XMITTER_INIT(x) netif_start_queue(x)
+
+#endif
+
+
 #if LINUX_VERSION_CODE < 0x20100
-typedef unsigned int u_int32_t;
+//typedef unsigned int u_int32_t;
 
 #define  LMC_SETUP_20_DEV {\
                              int indx; \
@@ -41,7 +58,11 @@ typedef unsigned int u_int32_t;
                           dev->pa_addr = 0; \
                           dev->pa_brdaddr = 0; \
                           dev->pa_mask = 0xFCFFFFFF; \
-                          dev->pa_alen = 4;            /* IP addr.  sizeof(u32) */
+    dev->pa_alen = 4;          /* IP addr.  sizeof(u32) */
+
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
 
 #else
 
@@ -73,20 +94,20 @@ typedef unsigned int u_int32_t;
 #define LMC_SKB_FREE(skb, val)
 #endif
 
-#define LMC_SPIN_FLAGS                unsigned long flags;
 
-#if (LINUX_VERSION_CODE >= 0x20200)
+#if LINUX_VERSION_CODE >= 0x20200
 
+#define LMC_SPIN_FLAGS                unsigned long flags;
 #define LMC_SPIN_LOCK_INIT(x)         spin_lock_init(&(x)->lmc_lock);
 #define LMC_SPIN_UNLOCK(x)            ((x)->lmc_lock = SPIN_LOCK_UNLOCKED)
 #define LMC_SPIN_LOCK_IRQSAVE(x)      spin_lock_irqsave (&(x)->lmc_lock, flags);
 #define LMC_SPIN_UNLOCK_IRQRESTORE(x) spin_unlock_irqrestore (&(x)->lmc_lock, flags);
 #else
-#define LMC_SPIN_FLAGS
-#define LMC_SPIN_LOCK_INIT(x)
-#define LMC_SPIN_UNLOCK(x)
-#define LMC_SPIN_LOCK_IRQSAVE(x)
-#define LMC_SPIN_UNLOCK_IRQRESTORE(x)
+#define LMC_SPIN_FLAGS                unsigned long flags;
+#define LMC_SPIN_LOCK_INIT(x)         
+#define LMC_SPIN_UNLOCK(x)            
+#define LMC_SPIN_LOCK_IRQSAVE(x)      save_flags(flags); cli();
+#define LMC_SPIN_UNLOCK_IRQRESTORE(x) restore_flags(flags); 
 #endif
 
 
@@ -105,3 +126,19 @@ typedef unsigned int u_int32_t;
 
 
 #endif
+
+#if LINUX_VERSION_CODE >= 0x20200
+#else
+#define mdelay(x) { int j; for(j = 0; j < x; j++){ udelay(1000); } }
+
+#endif
+
+/*
+ * See DMA-mapping.txt for info
+ */
+
+#if LINUX_VERSION_CODE < 0x20363
+#else
+#define LMC_PCI_ALLOC_CONSISTENT(x, y, z) pci_alloc_consistent(x, y, z)
+#endif
+
index 3553d84101a8f384f8057803bb02ecf6823a93e6..44f7e1880f37b424def62fb3562d9d2a9e3e8a46 100644 (file)
@@ -266,7 +266,11 @@ static void mace_reset(struct device *dev)
     /* done changing address */
     out_8(&mb->iac, 0);
 
+#ifndef CONFIG_MACE_AAUI_PORT
     out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
+#else
+    out_8(&mb->plscc, PORTSEL_AUI + ENPLSIO);
+#endif /* CONFIG_MACE_AAUI_PORT */
 }
 
 static void __mace_set_address(struct device *dev, void *addr)
index c428440a87f74da26dbbc10a6b3d3d70743fc22c..0fd98ebb77d426ab6de539507a0496601c336439 100644 (file)
@@ -11,7 +11,7 @@
   Copyright 1992 - 2000 Kai Makisara
                 email Kai.Makisara@metla.fi
 
-  Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
+  Last modified: Sat Jun 17 17:29:35 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
@@ -896,7 +896,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
 scsi_tape_flush(struct file * filp)
 {
     int result = 0, result2;
-    static unsigned char cmd[10];
+    unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
     Scsi_Tape * STp;
     ST_mode * STm;
@@ -1060,7 +1060,7 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
     ssize_t i, do_count, blks, retval, transfer;
     int write_threshold;
     int doing_write = 0;
-    static unsigned char cmd[10];
+    unsigned char cmd[10];
     const char *b_point;
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Tape * STp;
@@ -1380,7 +1380,7 @@ static long
 read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt)
 {
     int transfer, blks, bytes;
-    static unsigned char cmd[10];
+    unsigned char cmd[10];
     Scsi_Cmnd *SCpnt;
     Scsi_Tape *STp;
     ST_mode * STm;
index 6362876717c4af90ab0baa8d89520d234157a8bf..810476f74810f387c8da1bc4c527c97efb9a91d9 100644 (file)
@@ -1993,7 +1993,7 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int
                return 0;
 
        case SNDCTL_DSP_GETOSPACE:
-               if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+               if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
                        return val;
                spin_lock_irqsave(&s->lock, flags);
                es1370_update_ptr(s);
index 0cc83eec30b113bc85b09b17e1133779839bb6e0..af30dbe37c43411bdb25e8f88fbd7f0444d321dc 100644 (file)
@@ -2564,7 +2564,7 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int
                return 0;
 
        case SNDCTL_DSP_GETOSPACE:
-               if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+               if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
                        return val;
                spin_lock_irqsave(&s->lock, flags);
                es1371_update_ptr(s);
index ae11e7011c42a7566cc7e735d30e8623f2a3628d..aedc97e3638deb327d888511862b68974d8947e7 100644 (file)
@@ -128,6 +128,8 @@ typedef struct {
        u16 rel;                /* reliability */
        u32 time;
 }__attribute__ ((packed)) cisco_packet;
+#define        CISCO_PACKET_LEN        18
+#define        CISCO_BIG_PACKET_LEN    20
 
 
 
index 681020420308f314bdca695ee64f4edf371f57b5..66a5c6c0a2f78f54b05223631dcb51f56b2a1123 100644 (file)
@@ -262,8 +262,12 @@ extern u_char *OpenPIC_InitSenses;
      *  Interrupt Source Registers
      */
 
-#define OPENPIC_SENSE_POLARITY                 0x00800000      /* Undoc'd */
+#define OPENPIC_POLARITY_POSITIVE              0x00800000
+#define OPENPIC_POLARITY_NEGATIVE              0x00000000
+#define OPENPIC_POLARITY_MASK                  0x00800000
 #define OPENPIC_SENSE_LEVEL                    0x00400000
+#define OPENPIC_SENSE_EDGE                     0x00000000
+#define OPENPIC_SENSE_MASK                     0x00400000
 
 
     /*
index dff77e476c9b2e36c381ef170a2a9d8426a4e550..a20124be73e08666f50c41bc35588868ba78cbd9 100644 (file)
@@ -291,7 +291,6 @@ struct task_struct {
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
        unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
        int swappable:1;
-       int trashing_mem:1;
 /* process credentials */
        uid_t uid,euid,suid,fsuid;
        gid_t gid,egid,sgid,fsgid;
@@ -382,7 +381,7 @@ struct task_struct {
 /* utime */    {0,0,0,0},0, \
 /* per CPU times */ {0, }, {0, }, \
 /* flt */      0,0,0,0,0,0, \
-/* swp */      0,0, \
+/* swp */      0, \
 /* process credentials */                                      \
 /* uid etc */  0,0,0,0,0,0,0,0,                                \
 /* suppl grps*/ 0, {0,},                                       \
index cc8354b6c1428fcc20e35a0d4f05c52ac6dc0858..fcbf733ea337c0764fe458cbb793ad33ebbe5cec 100644 (file)
@@ -178,6 +178,7 @@ struct linux_mib
        unsigned long   OfoPruned;
        unsigned long   OutOfWindowIcmps; 
        unsigned long   LockDroppedIcmps; 
+       unsigned long   SockMallocOOM; 
 };
        
 #endif
index 28cf919e76c35e8cc582fde0016689390ddac981..ffeaf20d772ad1942f570e73e53da5723327d757 100644 (file)
@@ -717,6 +717,10 @@ extern void                        destroy_sock(struct sock *sk);
 extern struct sk_buff          *sock_wmalloc(struct sock *sk,
                                              unsigned long size, int force,
                                              int priority);
+
+extern struct sk_buff          *sock_wmalloc_err(struct sock *sk,
+                                             unsigned long size, int force,
+                                             int priority, int *err);
 extern struct sk_buff          *sock_rmalloc(struct sock *sk,
                                              unsigned long size, int force,
                                              int priority);
index 10f3a28ff99e4a9efa6ac1acd6d537e72bbce84e..993ea83f94e9eb93ccfe8ff901ad5f07ffced006 100644 (file)
@@ -380,6 +380,8 @@ out:
 static int do_try_to_free_pages(unsigned int gfp_mask)
 {
        int priority;
+       int ret = 0;
+       int swapcount;
        int count = SWAP_CLUSTER_MAX;
 
        lock_kernel();
@@ -390,6 +392,7 @@ static int do_try_to_free_pages(unsigned int gfp_mask)
        priority = 6;
        do {
                while (shrink_mmap(priority, gfp_mask)) {
+                       ret = 1;
                        if (!--count)
                                goto done;
                }
@@ -397,15 +400,18 @@ static int do_try_to_free_pages(unsigned int gfp_mask)
                /* Try to get rid of some shared memory pages.. */
                if (gfp_mask & __GFP_IO) {
                        while (shm_swap(priority, gfp_mask)) {
+                               ret = 1;
                                if (!--count)
                                        goto done;
                        }
                }
 
                /* Then, try to page stuff out.. */
+               swapcount = count;
                while (swap_out(priority, gfp_mask)) {
-                       if (!--count)
-                               goto done;
+                       ret = 1;
+                       if (!--swapcount)
+                               break;
                }
 
                shrink_dcache_memory(priority, gfp_mask);
@@ -417,7 +423,7 @@ done:
                printk("VM: do_try_to_free_pages failed for %s...\n",
                                current->comm);
        /* Return success if we freed a page. */
-       return priority >= 0;
+       return ret;
 }
 
 /*
index e0eb41a015a6f70cfc276929d55a217c57d15c38..8eeedcdded21b8b7530d6a8a1ad3c056c41abc04 100644 (file)
@@ -566,6 +566,31 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int
                        skb->sk = sk;
                        return skb;
                }
+               net_statistics.SockMallocOOM++; 
+       }
+       return NULL;
+}
+
+/*
+ * Allocate memory from the sockets send buffer, telling caller about real OOM. 
+ * err is only set for oom, not for socket buffer overflow.
+ */ 
+struct sk_buff *sock_wmalloc_err(struct sock *sk, unsigned long size, int force, int priority, int *err)
+{
+       *err = 0; 
+       /* Note: overcommitment possible */ 
+       if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
+               struct sk_buff * skb;
+               *err = -ENOMEM; 
+               skb = alloc_skb(size, priority);
+               if (skb) {
+                       *err = 0;
+                       atomic_add(skb->truesize, &sk->wmem_alloc);
+                       skb->destructor = sock_wfree;
+                       skb->sk = sk;
+                       return skb;
+               }
+               net_statistics.SockMallocOOM++; 
        }
        return NULL;
 }
@@ -583,6 +608,7 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
                        skb->sk = sk;
                        return skb;
                }
+               net_statistics.SockMallocOOM++; 
        }
        return NULL;
 }
@@ -602,6 +628,7 @@ void *sock_kmalloc(struct sock *sk, int size, int priority)
                if (mem)
                        return mem;
                atomic_sub(size, &sk->omem_alloc);
+               net_statistics.SockMallocOOM++; 
        }
        return NULL;
 }
index 90d9f0ab589796617198d57c3dfc69e709003f6c..271534a29f68405b25aec8d8193ab02a63c66fcc 100644 (file)
@@ -359,8 +359,8 @@ int netstat_get_info(char *buffer, char **start, off_t offset, int length, int d
        len = sprintf(buffer,
                      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
                      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
-                     " OutOfWindowIcmps LockDroppedIcmps\n"    
-                     "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+                     " OutOfWindowIcmps LockDroppedIcmps SockMallocOOM\n"      
+                     "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
                      net_statistics.SyncookiesSent,
                      net_statistics.SyncookiesRecv,
                      net_statistics.SyncookiesFailed,
@@ -369,7 +369,8 @@ int netstat_get_info(char *buffer, char **start, off_t offset, int length, int d
                      net_statistics.RcvPruned,
                      net_statistics.OfoPruned,
                      net_statistics.OutOfWindowIcmps,
-                     net_statistics.LockDroppedIcmps);
+                     net_statistics.LockDroppedIcmps,
+                     net_statistics.SockMallocOOM);
 
        if (offset >= len)
        {
index d644b365743efdc372ba5402adfc67c41e58e143..415859e731d7b41787a745904e53a15c20ba363b 100644 (file)
@@ -697,40 +697,38 @@ static inline int tcp_memory_free(struct sock *sk)
 }
 
 /*
- *     Wait for more memory for a socket
- *
- *     If we got here an allocation has failed on us. We cannot
- *     spin here or we may block the very code freeing memory
- *     for us.
+ *     Wait for more memory for a socket.
+ *     Special case is err == -ENOMEM, in this case just sleep a bit waiting
+ *     for the system to free up some memory. 
  */
-static void wait_for_tcp_memory(struct sock * sk)
+static void wait_for_tcp_memory(struct sock * sk, int err)
 {
        release_sock(sk);
        if (!tcp_memory_free(sk)) {
                struct wait_queue wait = { current, NULL };
+
                sk->socket->flags &= ~SO_NOSPACE;
                add_wait_queue(sk->sleep, &wait);
                for (;;) {
                        if (signal_pending(current))
                                break;
                        current->state = TASK_INTERRUPTIBLE;
-                       if (tcp_memory_free(sk))
+                       if (tcp_memory_free(sk) && !err)
                                break;
                        if (sk->shutdown & SEND_SHUTDOWN)
                                break;
                        if (sk->err)
                                break;
-                       schedule();
+                       if (!err) 
+                               schedule();
+                       else {
+                               schedule_timeout(1); 
+                               break;
+                       }       
                }
                current->state = TASK_RUNNING;
                remove_wait_queue(sk->sleep, &wait);
        }
-       else
-       {
-               /* Yield time to the memory freeing paths */
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
-       }
        lock_sock(sk);
 }
 
@@ -924,7 +922,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg)
                                tmp += copy;
                                queue_it = 0;
                        }
-                       skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
+                       skb = sock_wmalloc_err(sk, tmp, 0, GFP_KERNEL, &err);
 
                        /* If we didn't get any memory, we need to sleep. */
                        if (skb == NULL) {
@@ -937,8 +935,10 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg)
                                        err = -ERESTARTSYS;
                                        goto do_interrupted;
                                }
-                               tcp_push_pending_frames(sk, tp);
-                               wait_for_tcp_memory(sk);
+                               /* In OOM that would fail anyways so do not bother. */ 
+                               if (!err) 
+                                       tcp_push_pending_frames(sk, tp);
+                               wait_for_tcp_memory(sk, err);
 
                                /* If SACK's were formed or PMTU events happened,
                                 * we must find out about it.
index 4916dc51d85a0c2fa574ac3504c5ef79e336402f..eec81bbbee05a13452f5a78134e5345040c9a9d7 100644 (file)
@@ -542,7 +542,7 @@ if [ -f $DEFAULTS ]; then
   echo "# Using defaults found in" $DEFAULTS
   echo "#"
   . $DEFAULTS
-  sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .config-is-not.$$
+  sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
   . .config-is-not.$$
   rm .config-is-not.$$
 else