From 718f3a15a38a8835b3cb8b51306cb74ea59fc13f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:21:37 -0500 Subject: [PATCH] Linux 2.2.17pre5 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) --- CREDITS | 12 + Makefile | 2 +- arch/ppc/boot/Makefile | 4 +- arch/ppc/chrpboot/main.c | 25 +- arch/ppc/chrpboot/misc.S | 4 +- arch/ppc/chrpboot/start.c | 23 + arch/ppc/coffboot/Makefile | 4 +- arch/ppc/coffboot/dummy.c | 4 + arch/ppc/config.in | 1 + arch/ppc/kernel/Makefile | 3 +- arch/ppc/kernel/chrp_setup.c | 5 + arch/ppc/kernel/head.S | 1 - arch/ppc/kernel/pmac_setup.c | 6 +- arch/ppc/kernel/pmac_support.c | 40 +- arch/ppc/kernel/pmac_time.c | 65 +- arch/ppc/kernel/ppc_ksyms.c | 10 + arch/ppc/kernel/prom.c | 146 ++-- arch/ppc/kernel/time.c | 8 + arch/ppc/mm/init.c | 31 +- arch/sparc64/kernel/sys_sparc32.c | 11 +- drivers/block/cmd646.c | 4 + drivers/block/genhd.c | 29 +- drivers/block/ide-cd.c | 3 + drivers/block/ide-floppy.c | 7 + drivers/block/ide-pmac.c | 683 +++++++++++++-- drivers/block/ide-probe.c | 10 +- drivers/block/ide-proc.c | 1 + drivers/block/ide.h | 2 +- drivers/block/rd.c | 9 + drivers/block/swim3.c | 10 + drivers/macintosh/Makefile | 8 + drivers/macintosh/rtc.c | 166 ++++ drivers/net/3c59x.c | 23 +- drivers/net/dmfe.c | 2 +- drivers/net/hdlc.c | 8 +- drivers/net/lmc/Makefile | 4 +- drivers/net/lmc/lmc.h | 4 +- drivers/net/lmc/lmc_debug.c | 30 +- drivers/net/lmc/lmc_debug.h | 35 +- drivers/net/lmc/lmc_ioctl.h | 81 +- drivers/net/lmc/lmc_main.c | 1313 +++++++++++++++++++++-------- drivers/net/lmc/lmc_media.c | 855 ++++++++++++++++--- drivers/net/lmc/lmc_proto.c | 270 ++++++ drivers/net/lmc/lmc_proto.h | 15 + drivers/net/lmc/lmc_var.h | 112 ++- drivers/net/lmc/lmc_ver.h | 55 +- drivers/net/mace.c | 4 + drivers/scsi/st.c | 8 +- drivers/sound/es1370.c | 2 +- drivers/sound/es1371.c | 2 +- include/linux/hdlc.h | 2 + include/linux/openpic.h | 6 +- include/linux/sched.h | 3 +- include/net/snmp.h | 1 + include/net/sock.h | 4 + mm/vmscan.c | 12 +- net/core/sock.c | 27 + net/ipv4/proc.c | 7 +- net/ipv4/tcp.c | 34 +- scripts/Configure | 2 +- 60 files changed, 3403 insertions(+), 855 deletions(-) create mode 100644 arch/ppc/coffboot/dummy.c create mode 100644 drivers/macintosh/rtc.c create mode 100644 drivers/net/lmc/lmc_proto.c create mode 100644 drivers/net/lmc/lmc_proto.h diff --git a/CREDITS b/CREDITS index 96c56415ad39..3b58d722f446 100644 --- 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 diff --git a/Makefile b/Makefile index cb550d83350f..085821b24c04 100644 --- 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/) diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index c595afaa77b3..7152bace7c44 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -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 diff --git a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c index 80db69a7b108..fd3421f40482 100644 --- a/arch/ppc/chrpboot/main.c +++ b/arch/ppc/chrpboot/main.c @@ -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); diff --git a/arch/ppc/chrpboot/misc.S b/arch/ppc/chrpboot/misc.S index b2094b9d3df4..181450c5375c 100644 --- a/arch/ppc/chrpboot/misc.S +++ b/arch/ppc/chrpboot/misc.S @@ -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 diff --git a/arch/ppc/chrpboot/start.c b/arch/ppc/chrpboot/start.c index 161d9a980455..308f4fcd3492 100644 --- a/arch/ppc/chrpboot/start.c +++ b/arch/ppc/chrpboot/start.c @@ -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) { diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile index 7468bf7a79ed..9070cdce2cf5 100644 --- a/arch/ppc/coffboot/Makefile +++ b/arch/ppc/coffboot/Makefile @@ -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 index 000000000000..31dbf45bf99c --- /dev/null +++ b/arch/ppc/coffboot/dummy.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 1f1bcd5320db..6510dce98ef3 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -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 diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index fc0a5156eeb5..9ea51146dd1a 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -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 diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 2159e8133d39..e2c29eefd95d 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -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); +} diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 21ec8504443e..ec184b7b2a80 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -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 diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index e8fc30eb87f9..9a7882fafe11 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -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; diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index 698363261b88..a44fbe30809c 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -27,18 +27,6 @@ #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; } diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index d6e8eb095c69..a02f6f869243 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "time.h" @@ -49,11 +50,35 @@ /* 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; + } } /* diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 21302ad9bfb0..1a2bbd819df0 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -29,6 +29,7 @@ #include #include #include +#include /* 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); diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index f4676c8d99c2..3a6276d6f7b0 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -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; jname && !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"; diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 05ac55681dfc..00b8f9b62d96 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -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__ diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 9a257c82c7b8..a581e730ca94 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -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, diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 3cb037e38218..d39e27125c74 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -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; diff --git a/drivers/block/cmd646.c b/drivers/block/cmd646.c index fa97ff5fe10a..cf8b92fc3b6e 100644 --- a/drivers/block/cmd646.c +++ b/drivers/block/cmd646.c @@ -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; } diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 8a56f5a007ce..52dde9578cd9 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -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--; } diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 802d311b4248..bb2f7a7364fa 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -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; diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c index bd2c746cbdcc..891211d684a1 100644 --- a/drivers/block/ide-floppy.c +++ b/drivers/block/ide-floppy.c @@ -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) { diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index 78322f33d151..e66320309d54 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -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 @@ -35,26 +37,101 @@ #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; iio_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; } diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 0af96fedb800..489a0db1de77 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -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"); diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index a2bc04c47798..3f0ca608f6ca 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -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); diff --git a/drivers/block/ide.h b/drivers/block/ide.h index 3f9402468060..04b8b26e33cc 100644 --- a/drivers/block/ide.h +++ b/drivers/block/ide.h @@ -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 { diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 7cb0f3bfc2d3..25a6c5e056df 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -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"); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 246405aff1ed..2936c57d12c4 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -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" */ diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index e3649ca1a298..a2d446440fde 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -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 index 000000000000..a5a565672a6b --- /dev/null +++ b/drivers/macintosh/rtc.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 821b72f3e88a..8cc46e7c49d7 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -42,11 +42,15 @@ - 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) diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index 399aa68bd6ca..a6ee66c34276 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -102,7 +102,7 @@ #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) diff --git a/drivers/net/hdlc.c b/drivers/net/hdlc.c index 3472b3bf6387..0916990adc5d 100644 --- a/drivers/net/hdlc.c +++ b/drivers/net/hdlc.c @@ -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; } diff --git a/drivers/net/lmc/Makefile b/drivers/net/lmc/Makefile index cd1265a4d34e..1fe61a348437 100644 --- a/drivers/net/lmc/Makefile +++ b/drivers/net/lmc/Makefile @@ -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 diff --git a/drivers/net/lmc/lmc.h b/drivers/net/lmc/lmc.h index e1e29123ddc6..91b9e8f00ee1 100644 --- a/drivers/net/lmc/lmc.h +++ b/drivers/net/lmc/lmc.h @@ -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; diff --git a/drivers/net/lmc/lmc_debug.c b/drivers/net/lmc/lmc_debug.c index 0f36e31349cc..fa475e6c6845 100644 --- a/drivers/net/lmc/lmc_debug.c +++ b/drivers/net/lmc/lmc_debug.c @@ -1,6 +1,10 @@ #include #include +#include +#include +#include +#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 } diff --git a/drivers/net/lmc/lmc_debug.h b/drivers/net/lmc/lmc_debug.h index f39adcfa90bf..5fdcf8a065d1 100644 --- a/drivers/net/lmc/lmc_debug.h +++ b/drivers/net/lmc/lmc_debug.h @@ -11,40 +11,7 @@ #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 diff --git a/drivers/net/lmc/lmc_ioctl.h b/drivers/net/lmc/lmc_ioctl.h index 77d00b1b20e3..569fdac68686 100644 --- a/drivers/net/lmc/lmc_ioctl.h +++ b/drivers/net/lmc/lmc_ioctl.h @@ -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) @@ -16,22 +16,20 @@ * 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 */ @@ -60,6 +58,13 @@ #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. */ @@ -68,10 +73,10 @@ */ #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 @@ -80,11 +85,16 @@ #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 */ @@ -118,6 +128,7 @@ #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 */ @@ -176,7 +187,8 @@ /* * 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 */ @@ -224,6 +236,15 @@ #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 diff --git a/drivers/net/lmc/lmc_main.c b/drivers/net/lmc/lmc_main.c index 67fbb277225a..d08a5f3c4f2c 100644 --- a/drivers/net/lmc/lmc_main.c +++ b/drivers/net/lmc/lmc_main.c @@ -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. @@ -36,10 +36,11 @@ * */ -/* $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 #include +#include +#include #include #include #include @@ -50,12 +51,10 @@ #include #include #include +#include +#include #include -#include - -#if LINUX_VERSION_CODE < 0x20155 -#include -#endif +#include #include #include @@ -72,64 +71,75 @@ #if LINUX_VERSION_CODE >= 0x20200 #include -#include -#endif - -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif -#include -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT +//#include +#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 diff --git a/drivers/net/lmc/lmc_media.c b/drivers/net/lmc/lmc_media.c index bccb5dda7ac9..617663a88652 100644 --- a/drivers/net/lmc/lmc_media.c +++ b/drivers/net/lmc/lmc_media.c @@ -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 #include @@ -13,7 +13,7 @@ #include #include #include -#include +//#include #if LINUX_VERSION_CODE < 0x20155 #include @@ -34,13 +34,14 @@ #if LINUX_VERSION_CODE >= 0x20200 #include -#include +//#include #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 index 000000000000..31f6c2cba4c4 --- /dev/null +++ b/drivers/net/lmc/lmc_proto.c @@ -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 +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include +#include "../syncppp.h" +#include +#include +#include + +#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 index 000000000000..6136dfad7516 --- /dev/null +++ b/drivers/net/lmc/lmc_proto.h @@ -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 diff --git a/drivers/net/lmc/lmc_var.h b/drivers/net/lmc/lmc_var.h index 92765bb7c46e..2dd5c870c160 100644 --- a/drivers/net/lmc/lmc_var.h +++ b/drivers/net/lmc/lmc_var.h @@ -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 +#include #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 diff --git a/drivers/net/lmc/lmc_ver.h b/drivers/net/lmc/lmc_ver.h index 8325f2f08935..2c10936ba0bc 100644 --- a/drivers/net/lmc/lmc_ver.h +++ b/drivers/net/lmc/lmc_ver.h @@ -29,8 +29,25 @@ * */ +#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 + diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 3553d84101a8..44f7e1880f37 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -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) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index c428440a87f7..0fd98ebb77d4 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -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; diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 6362876717c4..810476f74810 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -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); diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 0cc83eec30b1..af30dbe37c43 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -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); diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index ae11e7011c42..aedc97e3638d 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -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 diff --git a/include/linux/openpic.h b/include/linux/openpic.h index 681020420308..66a5c6c0a2f7 100644 --- a/include/linux/openpic.h +++ b/include/linux/openpic.h @@ -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 /* diff --git a/include/linux/sched.h b/include/linux/sched.h index dff77e476c9b..a20124be73e0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -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,}, \ diff --git a/include/net/snmp.h b/include/net/snmp.h index cc8354b6c142..fcbf733ea337 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -178,6 +178,7 @@ struct linux_mib unsigned long OfoPruned; unsigned long OutOfWindowIcmps; unsigned long LockDroppedIcmps; + unsigned long SockMallocOOM; }; #endif diff --git a/include/net/sock.h b/include/net/sock.h index 28cf919e76c3..ffeaf20d772a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -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); diff --git a/mm/vmscan.c b/mm/vmscan.c index 10f3a28ff99e..993ea83f94e9 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -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; } /* diff --git a/net/core/sock.c b/net/core/sock.c index e0eb41a015a6..8eeedcdded21 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -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; } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 90d9f0ab5897..271534a29f68 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -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) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d644b365743e..415859e731d7 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -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. diff --git a/scripts/Configure b/scripts/Configure index 4916dc51d85a..eec81bbbee05 100644 --- a/scripts/Configure +++ b/scripts/Configure @@ -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 -- 2.39.5