diff -u --recursive --new-file v2.0.23/linux/CREDITS linux/CREDITS --- v2.0.23/linux/CREDITS Tue Oct 8 21:20:07 1996 +++ linux/CREDITS Tue Oct 29 15:17:25 1996 @@ -926,7 +926,7 @@ S: USA N: William (Bill) Metzenthen -E: billm@jacobi.maths.monash.edu.au +E: billm@suburbia.net D: Author of the FPU emulator. D: Minor kernel hacker for other lost causes (Hercules mono, etc). S: 22 Parker Street diff -u --recursive --new-file v2.0.23/linux/MAINTAINERS linux/MAINTAINERS --- v2.0.23/linux/MAINTAINERS Sun Sep 15 10:34:18 1996 +++ linux/MAINTAINERS Tue Oct 29 15:17:25 1996 @@ -335,6 +335,12 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +FPU EMULATOR +P: Bill Metzenthen +M: billm@suburbia.net +W: http://suburbia.net/~billm/floating-point/emulator/ +S: Maintained + CREDITS FILE P: John A. Martin M: jam@acm.org diff -u --recursive --new-file v2.0.23/linux/Makefile linux/Makefile --- v2.0.23/linux/Makefile Sat Oct 19 10:06:10 1996 +++ linux/Makefile Sat Oct 19 10:06:36 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 23 +SUBLEVEL = 24 ARCH = i386 diff -u --recursive --new-file v2.0.23/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.0.23/linux/arch/alpha/defconfig Mon Aug 5 10:13:50 1996 +++ linux/arch/alpha/defconfig Wed Oct 30 03:42:40 1996 @@ -162,6 +162,7 @@ # CONFIG_DGRS is not set # CONFIG_NET_POCKET is not set # CONFIG_TR is not set +# CONFIG_FDDI is not set # CONFIG_ARCNET is not set # diff -u --recursive --new-file v2.0.23/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.0.23/linux/arch/i386/defconfig Mon Aug 5 10:13:50 1996 +++ linux/arch/i386/defconfig Wed Oct 30 03:42:40 1996 @@ -112,6 +112,7 @@ # CONFIG_NET_EISA is not set # CONFIG_NET_POCKET is not set # CONFIG_TR is not set +# CONFIG_FDDI is not set # CONFIG_ARCNET is not set # diff -u --recursive --new-file v2.0.23/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.0.23/linux/arch/i386/kernel/process.c Tue Oct 8 21:20:08 1996 +++ linux/arch/i386/kernel/process.c Wed Oct 30 03:42:40 1996 @@ -183,44 +183,200 @@ */ static long no_idt[2] = {0, 0}; static int reboot_mode = 0; +static int reboot_thru_bios = 0; void reboot_setup(char *str, int *ints) { - int mode = 0; + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': /* "bios" reboot by jumping through the BIOS */ + reboot_thru_bios = 1; + break; + case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ + reboot_thru_bios = 0; + break; + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } +} + + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ - /* "w" for "warm" reboot (no memory testing etc) */ - if (str[0] == 'w') - mode = 0x1234; - reboot_mode = mode; +unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +struct +{ + unsigned short size __attribute__ ((packed)); + unsigned long long * base __attribute__ ((packed)); } +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }; + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSes don't assume much. */ + +unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x08, /* invd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; static inline void kb_wait(void) { int i; - for (i=0; i<0x10000; i++) if ((inb_p(0x64) & 0x02) == 0) break; } -void hard_reset_now(void) +void hard_reset_now (void) { - int i, j; - sti(); -/* rebooting needs to touch the page at absolute addr 0 */ - pg0[0] = 7; - *((unsigned short *)0x472) = reboot_mode; - for (;;) { - for (i=0; i<100; i++) { - kb_wait(); - for(j = 0; j < 100000 ; j++) - /* nothing */; - outb(0xfe,0x64); /* pulse reset low */ - udelay(10); + if(!reboot_thru_bios) { + sti(); + /* rebooting needs to touch the page at absolute addr 0 */ + pg0[0] = 7; + *((unsigned short *)0x472) = reboot_mode; + for (;;) { + int i; + for (i=0; i<100; i++) { + int j; + kb_wait(); + for(j = 0; j < 100000 ; j++) + /* nothing */; + outb(0xfe,0x64); /* pulse reset low */ + udelay(10); + } + __asm__ __volatile__("\tlidt %0": "=m" (no_idt)); } - __asm__ __volatile__("\tlidt %0": "=m" (no_idt)); } + + cli (); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. */ + + outb_p (0x8f, 0x70); + outb_p (0x00, 0x71); + + /* Remap the kernel at virtual address zero, as well as offset zero + from the kernel segment. This assumes the kernel segment starts at + virtual address 0xc0000000. */ + + memcpy (swapper_pg_dir, swapper_pg_dir + 768, + sizeof (swapper_pg_dir [0]) * 256); + + /* Make sure the first page is mapped to the start of physical memory. + It is normally not mapped, to trap kernel NULL pointer dereferences. */ + + pg0 [0] = 7; + + /* Use `swapper_pg_dir' as our page directory. Don't bother with + `SET_PAGE_DIR' because interrupts are disabled and we're rebooting. + This instruction flushes the TLB. */ + + __asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory"); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = reboot_mode; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch)), + real_mode_switch, sizeof (real_mode_switch)); + + /* Set up the IDT for real mode. */ + + __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movw $0x0010,%%ax\n" + "\tmovw %%ax,%%ds\n" + "\tmovw %%ax,%%es\n" + "\tmovw %%ax,%%fs\n" + "\tmovw %%ax,%%gs\n" + "\tmovw %%ax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch)))); } void show_regs(struct pt_regs * regs) diff -u --recursive --new-file v2.0.23/linux/arch/i386/math-emu/README linux/arch/i386/math-emu/README --- v2.0.23/linux/arch/i386/math-emu/README Thu Oct 5 15:30:43 1995 +++ linux/arch/i386/math-emu/README Tue Oct 29 15:17:25 1996 @@ -1,9 +1,9 @@ +---------------------------------------------------------------------------+ | wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | | | - | Copyright (C) 1992,1993,1994,1995 | + | Copyright (C) 1992,1993,1994,1995,1996 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | | This program is free software; you can redistribute it and/or modify | | it under the terms of the GNU General Public License version 2 as | @@ -42,11 +42,11 @@ some differences. Please report bugs, etc to me at: - billm@jacobi.maths.monash.edu.au + billm@suburbia.net --Bill Metzenthen - October 1995 + October 1996 ----------------------- Internals of wm-FPU-emu ----------------------- diff -u --recursive --new-file v2.0.23/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.0.23/linux/drivers/block/ide.c Tue Oct 8 21:20:10 1996 +++ linux/drivers/block/ide.c Tue Oct 29 00:30:43 1996 @@ -2272,11 +2272,13 @@ unsigned long capacity, check; id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL); - ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ + ide_input_data(drive, id, SECTOR_WORDS);/* read 512 bytes of id info */ sti(); +#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) /* - * EATA SCSI controllers do a hardware ATA emulation: ignore them + * EATA SCSI controllers do a hardware ATA emulation: + * Ignore them if there is a driver for them available. */ if ((id->model[0] == 'P' && id->model[1] == 'M') || (id->model[0] == 'S' && id->model[1] == 'K')) { @@ -2284,6 +2286,7 @@ drive->present = 0; return; } +#endif /* * WIN_IDENTIFY returns little-endian info, diff -u --recursive --new-file v2.0.23/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c --- v2.0.23/linux/drivers/block/umc8672.c Mon Aug 5 10:13:51 1996 +++ linux/drivers/block/umc8672.c Tue Oct 29 15:28:53 1996 @@ -28,7 +28,7 @@ * Germany * * To enable UMC8672 support there must a lilo line like - * append="hd=umc8672"... + * append="ide0=umc8672"... * To set the speed according to the abilities of the hardware there must be a * line like * #define UMC_DRIVE0 11 diff -u --recursive --new-file v2.0.23/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.0.23/linux/drivers/cdrom/cdu31a.c Sat Oct 19 10:06:10 1996 +++ linux/drivers/cdrom/cdu31a.c Mon Oct 28 22:16:53 1996 @@ -1915,7 +1915,9 @@ int num_tracks; - num_tracks = sony_toc.last_track_num - sony_toc.first_track_num + 1; + num_tracks = ( bcd_to_int(sony_toc.last_track_num) + - bcd_to_int(sony_toc.first_track_num) + + 1); for (i = 0; i < num_tracks; i++) { if (sony_toc.tracks[i].track == track) @@ -2486,8 +2488,8 @@ i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr)); if(i<0) return i; - loc_hdr.cdth_trk0 = sony_toc.first_track_num; - loc_hdr.cdth_trk1 = sony_toc.last_track_num; + loc_hdr.cdth_trk0 = bcd_to_int(sony_toc.first_track_num); + loc_hdr.cdth_trk1 = bcd_to_int(sony_toc.last_track_num); memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr)); } return 0; @@ -2567,8 +2569,8 @@ return i; memcpy_fromfs(&ti, (char *) arg, sizeof(ti)); - if ( (ti.cdti_trk0 < sony_toc.first_track_num) - || (ti.cdti_trk0 > sony_toc.last_track_num) + if ( (ti.cdti_trk0 < bcd_to_int(sony_toc.first_track_num)) + || (ti.cdti_trk0 > bcd_to_int(sony_toc.last_track_num)) || (ti.cdti_trk1 < ti.cdti_trk0)) { return -EINVAL; @@ -2587,7 +2589,7 @@ * If we want to stop after the last track, use the lead-out * MSF to do that. */ - if (ti.cdti_trk1 >= sony_toc.last_track_num) + if (ti.cdti_trk1 >= bcd_to_int(sony_toc.last_track_num)) { log_to_msf(msf_to_log(sony_toc.lead_out_start_msf)-1, &(params[4])); diff -u --recursive --new-file v2.0.23/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.0.23/linux/drivers/char/selection.c Thu Jun 6 13:42:16 1996 +++ linux/drivers/char/selection.c Wed Oct 30 03:51:32 1996 @@ -289,9 +289,9 @@ if (!bp || !c) return 0; do_unblank_screen(); - current->state = TASK_INTERRUPTIBLE; add_wait_queue(&vt->paste_wait, &wait); - while (c) { + do { + current->state = TASK_INTERRUPTIBLE; if (test_bit(TTY_THROTTLED, &tty->flags)) { schedule(); continue; @@ -300,7 +300,8 @@ tty->ldisc.receive_buf(tty, bp, 0, l); c -= l; bp += l; - } + } while (c); + remove_wait_queue(&vt->paste_wait, &wait); current->state = TASK_RUNNING; return 0; } diff -u --recursive --new-file v2.0.23/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.0.23/linux/drivers/char/tty_io.c Wed Sep 11 17:57:14 1996 +++ linux/drivers/char/tty_io.c Tue Oct 29 00:40:58 1996 @@ -1696,7 +1696,7 @@ if (((*p)->tty == tty) || ((session > 0) && ((*p)->session == session))) send_sig(SIGKILL, *p, 1); - else { + else if ((*p)->files) { for (i=0; i < NR_OPEN; i++) { filp = (*p)->files->fd[i]; if (filp && (filp->f_op == &tty_fops) && diff -u --recursive --new-file v2.0.23/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.0.23/linux/drivers/isdn/isdn_cards.c Sun Apr 21 11:56:14 1996 +++ linux/drivers/isdn/isdn_cards.c Wed Oct 30 03:42:40 1996 @@ -27,15 +27,15 @@ #include #ifdef CONFIG_ISDN_DRV_ICN -extern void icn_init(void); +extern int icn_init(void); #endif #ifdef CONFIG_ISDN_DRV_TELES -extern void teles_init(void); +extern int teles_init(void); #endif #ifdef CONFIG_ISDN_DRV_PCBIT -extern void pcbit_init(void); +extern int pcbit_init(void); #endif void isdn_cards_init(void) diff -u --recursive --new-file v2.0.23/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.0.23/linux/drivers/net/3c509.c Fri Sep 20 17:00:34 1996 +++ linux/drivers/net/3c509.c Wed Oct 30 03:42:40 1996 @@ -27,6 +27,10 @@ FIXES: Alan Cox: Removed the 'Unexpected interrupt' bug. Michael Meskes: Upgraded to Donald Becker's version 1.07. + Alan Cox: Increased the eeprom delay. Regardless of + what the docs say some people definitely + get problems with lower (but in card spec) + delays */ static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n"; @@ -312,7 +316,7 @@ { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ - udelay (300); + udelay (500); return inw(ioaddr + 12); } @@ -326,7 +330,7 @@ outb(EEPROM_READ + index, id_port); /* Pause for at least 162 us. for the read to take place. */ - udelay (300); + udelay (500); for (bit = 15; bit >= 0; bit--) word = (word << 1) + (inb(id_port) & 0x01); diff -u --recursive --new-file v2.0.23/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.0.23/linux/drivers/net/3c59x.c Thu Jul 18 10:08:45 1996 +++ linux/drivers/net/3c59x.c Tue Oct 29 16:24:57 1996 @@ -315,7 +315,7 @@ root_vortex_dev = NULL; cards_found = vortex_scan(0); - return cards_found < 0 ? cards_found : 0; + return cards_found ? 0 : -ENODEV; } #else diff -u --recursive --new-file v2.0.23/linux/drivers/net/CONFIG linux/drivers/net/CONFIG --- v2.0.23/linux/drivers/net/CONFIG Thu May 16 20:12:56 1996 +++ linux/drivers/net/CONFIG Wed Oct 30 03:42:40 1996 @@ -62,6 +62,10 @@ # DE4X5_DO_MEMCPY Forces the Intels to use memory copies into sk_buffs # rather than straight DMA. # +# DEFXX The DIGITAL series of FDDI EISA (DEFEA) and PCI (DEFPA) +# controllers +# DEFXX_DEBUG Set the desired debug level +# # TULIP Tulip (dc21040/dc21041/ds21140) driver # TULIP_PORT specify default if_port # 0: 10TP @@ -92,5 +96,6 @@ DEPCA_OPTS = EWRK3_OPTS = DE4X5_OPTS = -DDE4X5_AUTOSENSE=AUTO +DEFXX_OPTS = ELP_OPTS = TULIP_OPTS = diff -u --recursive --new-file v2.0.23/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.0.23/linux/drivers/net/Config.in Mon May 20 08:08:36 1996 +++ linux/drivers/net/Config.in Wed Oct 30 03:42:40 1996 @@ -84,7 +84,7 @@ tristate 'NE2000/NE1000 support' CONFIG_NE2000 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'NI5210 support' CONFIG_NI52 - bool 'NI6510 support' CONFIG_NI65 + tristate 'NI6510 support' CONFIG_NI65 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 @@ -115,6 +115,10 @@ bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR +fi +bool 'FDDI driver support' CONFIG_FDDI +if [ "$CONFIG_FDDI" = "y" ]; then + bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX fi tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then diff -u --recursive --new-file v2.0.23/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.0.23/linux/drivers/net/Makefile Mon May 6 12:44:31 1996 +++ linux/drivers/net/Makefile Wed Oct 30 03:42:40 1996 @@ -350,6 +350,10 @@ endif endif +ifeq ($(CONFIG_DEFXX),y) +L_OBJS += defxx.o +endif + ifeq ($(CONFIG_NI52),y) L_OBJS += ni52.o else @@ -360,6 +364,10 @@ ifeq ($(CONFIG_NI65),y) L_OBJS += ni65.o +else + ifeq ($(CONFIG_NI65),m) + M_OBJS += ni65.o + endif endif ifeq ($(CONFIG_ELPLUS),y) @@ -525,6 +533,9 @@ de4x5.o: de4x5.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $< + +defxx.o: defxx.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(DEFXX_OPTS) -c $< ewrk3.o: ewrk3.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $< diff -u --recursive --new-file v2.0.23/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.0.23/linux/drivers/net/Space.c Mon Jun 3 12:42:41 1996 +++ linux/drivers/net/Space.c Wed Oct 30 03:42:40 1996 @@ -13,7 +13,7 @@ * field of the 'device' structure to store the unit number... * -FvK * - * Version: @(#)Space.c 1.0.7 08/12/93 + * Version: @(#)Space.c 1.0.8 07/31/96 * * Authors: Ross Biro, * Fred N. van Kempen, @@ -381,6 +381,30 @@ # define NEXT_DEV (&ibmtr_dev0) #endif + +#ifdef CONFIG_DEFXX + extern int dfx_probe(struct device *dev); + static struct device fddi7_dev = + {"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, dfx_probe}; + static struct device fddi6_dev = + {"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, dfx_probe}; + static struct device fddi5_dev = + {"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, dfx_probe}; + static struct device fddi4_dev = + {"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, dfx_probe}; + static struct device fddi3_dev = + {"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, dfx_probe}; + static struct device fddi2_dev = + {"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, dfx_probe}; + static struct device fddi1_dev = + {"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, dfx_probe}; + static struct device fddi0_dev = + {"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, dfx_probe}; + +#undef NEXT_DEV +#define NEXT_DEV (&fddi0_dev) +#endif + #ifdef CONFIG_NET_IPIP #ifdef CONFIG_IP_FORWARD extern int tunnel_init(struct device *); diff -u --recursive --new-file v2.0.23/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.0.23/linux/drivers/net/arcnet.c Sat Aug 10 10:03:14 1996 +++ linux/drivers/net/arcnet.c Sat Oct 19 10:36:20 1996 @@ -17,6 +17,14 @@ ********************** + v2.56 (96/10/18) + - Turned arc0e/arc0s startup messages back on by default, as most + people will probably not notice the additional devices + otherwise, and experience more protocol confusion than + necessary. + - Fixed a tiny but noticeable bug in the packet debugging routines + (thanks Tomasz) + v2.55 (96/08/05) - A couple more messages moved to D_EXTRA. - SLOW_XMIT_COPY off by default. @@ -202,7 +210,7 @@ */ static const char *version = - "arcnet.c: v2.55 96/08/05 Avery Pennarun \n"; + "arcnet.c: v2.56 96/10/18 Avery Pennarun \n"; @@ -708,8 +716,7 @@ { if (i%16==0) printk("\n" KERN_DEBUG "[%04X] ",i); - else - printk("%02X ",((u_char *)skb->data)[i]); + printk("%02X ",((u_char *)skb->data)[i]); } printk("\n"); restore_flags(flags); @@ -731,8 +738,7 @@ { if (i%16==0) printk("\n" KERN_DEBUG "[%04X] ",i); - else - printk("%02X ",buffer[i]); + printk("%02X ",buffer[i]); } printk("\n"); restore_flags(flags); @@ -754,6 +760,8 @@ * NOTE: the list of possible ports/shmems is static, so it is retained * across calls to arcnet_probe. So, if more than one ARCnet probe is made, * values that were discarded once will not even be tried again. + * + * FIXME: grab all devices in one shot and eliminate the big static array. */ int arcnet_probe(struct device *dev) { @@ -775,9 +783,8 @@ ports[(count-0x200)/16] = count; for (count=0xA0000; count<=0xFF800; count+=2048) shmems[(count-0xA0000)/2048] = count; - } - else init_once=1; + } BUGLVL(D_NORMAL) printk(version); @@ -1370,7 +1377,7 @@ /* The RFC1201 driver is the default - just store */ lp->adev=dev; - BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n"); + BUGMSG(D_NORMAL,"ARCnet RFC1201 protocol initialized.\n"); #ifdef CONFIG_ARCNET_ETH /* Initialize the ethernet-encap protocol driver */ @@ -1388,7 +1395,7 @@ lp->edev->init=arcnetE_init; register_netdev(lp->edev); #else - BUGMSG(D_EXTRA,"Ethernet-Encap protocol not available (disabled).\n"); + BUGMSG(D_NORMAL,"Ethernet-Encap protocol not available (disabled).\n"); #endif #ifdef CONFIG_ARCNET_1051 @@ -1400,7 +1407,7 @@ lp->sdev->init=arcnetS_init; register_netdev(lp->sdev); #else - BUGMSG(D_EXTRA,"RFC1051 protocol not available (disabled).\n"); + BUGMSG(D_NORMAL,"RFC1051 protocol not available (disabled).\n"); #endif /* we're started */ @@ -2781,7 +2788,7 @@ dev->stop=arcnetE_open_close; dev->hard_start_xmit=arcnetE_send_packet; - BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n"); + BUGMSG(D_NORMAL,"ARCnet Ethernet-Encap protocol initialized.\n"); return 0; } @@ -2961,7 +2968,7 @@ dev->hard_start_xmit=arcnetS_send_packet; dev->hard_header=arcnetS_header; dev->rebuild_header=arcnetS_rebuild_header; - BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n"); + BUGMSG(D_NORMAL,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n"); return 0; } @@ -3241,10 +3248,10 @@ static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irqnum=0; /* or use the insmod io= irqnum= shmem= options */ +static int irqnum=0; /* or use the insmod io= irq= shmem= options */ static int irq=0; static int shmem=0; -static char *device = NULL; +static char *device = NULL; /* use eg. device="arc1" to change name */ int init_module(void) @@ -3304,15 +3311,3 @@ } #endif /* MODULE */ - - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c arcnet.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 8 - * End: - */ - diff -u --recursive --new-file v2.0.23/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.0.23/linux/drivers/net/defxx.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/defxx.c Wed Oct 30 03:42:40 1996 @@ -0,0 +1,3421 @@ +/* + * File Name: + * defxx.c + * + * Copyright Information: + * Copyright Digital Equipment Corporation 1996. + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + * + * Abstract: + * A Linux device driver supporting the Digital Equipment Corporation + * FDDI EISA and PCI controller families. Supported adapters include: + * + * DEC FDDIcontroller/EISA (DEFEA) + * DEC FDDIcontroller/PCI (DEFPA) + * + * Maintainers: + * LVS Lawrence V. Stefani + * + * Contact: + * The author may be reached at: + * + * Inet: stefani@lkg.dec.com + * Mail: Digital Equipment Corporation + * 550 King Street + * M/S: LKG1-3/M07 + * Littleton, MA 01460 + * + * Credits: + * I'd like to thank Patricia Cross for helping me get started with + * Linux, David Davies for a lot of help upgrading and configuring + * my development system and for answering many OS and driver + * development questions, and Alan Cox for recommendations and + * integration help on getting FDDI support into Linux. LVS + * + * Driver Architecture: + * The driver architecture is largely based on previous driver work + * for other operating systems. The upper edge interface and + * functions were largely taken from existing Linux device drivers + * such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C + * driver. + * + * Adapter Probe - + * The driver scans for supported EISA adapters by reading the + * SLOT ID register for each EISA slot and making a match + * against the expected value. The supported PCI adapters are + * discovered using successive calls to pcibios_find_device. + * The first time the probe routine is called, all supported + * devices are discovered and initialized. The adapters aren't + * brought up to an operational state until the open routine is + * called. + * + * Bus-Specific Initialization - + * This driver currently supports both EISA and PCI controller + * families. While the custom DMA chip and FDDI logic is similar + * or identical, the bus logic is very different. After + * initialization, the only bus-specific differences is in how the + * driver enables and disables interrupts. Other than that, the + * run-time critical code behaves the same on both families. + * It's important to note that both adapter families are configured + * to I/O map, rather than memory map, the adapter registers. + * + * Driver Open/Close - + * In the driver open routine, the driver ISR (interrupt service + * routine) is registered and the adapter is brought to an + * operational state. In the driver close routine, the opposite + * occurs; the driver ISR is deregistered and the adapter is + * brought to a safe, but closed state. Users may use consecutive + * commands to bring the adapter up and down as in the following + * example: + * ifconfig fddi0 up + * ifconfig fddi0 down + * ifconfig fddi0 up + * + * Driver Shutdown - + * Apparently, there is no shutdown or halt routine support under + * Linux. This routine would be called during "reboot" or + * "shutdown" to allow the driver to place the adapter in a safe + * state before a warm reboot occurs. To be really safe, the user + * should close the adapter before shutdown (eg. ifconfig fddi0 down) + * to ensure that the adapter DMA engine is taken off-line. However, + * the current driver code anticipates this problem and always issues + * a soft reset of the adapter at the beginning of driver initialization. + * A future driver enhancement in this area may occur in 2.1.X where + * Alan indicated that a shutdown handler may be implemented. + * + * Interrupt Service Routine - + * The driver supports shared interrupts, so the ISR is registered for + * each board with the appropriate flag and the pointer to that board's + * device structure. This provides the context during interrupt + * processing to support shared interrupts and multiple boards. + * + * Interrupt enabling/disabling can occur at many levels. At the host + * end, you can disable system interrupts, or disable interrupts at the + * PIC (on Intel systems). Across the bus, both EISA and PCI adapters + * have a bus-logic chip interrupt enable/disable as well as a DMA + * controller interrupt enable/disable. + * + * The driver currently enables and disables adapter interrupts at the + * bus-logic chip and assumes that Linux will take care of clearing or + * acknowledging any host-based interrupt chips. + * + * Control Functions - + * Control functions are those used to support functions such as adding + * or deleting multicast addresses, enabling or disabling packet + * reception filters, or other custom/proprietary commands. Presently, + * the driver supports the "get statistics", "set multicast list", and + * "set mac address" functions defined by Linux. A list of possible + * enhancements include: + * + * - Custom ioctl interface for executing port interface commands + * - Custom ioctl interface for adding unicast addresses to + * adapter CAM (to support bridge functions). + * - Custom ioctl interface for supporting firmware upgrades. + * + * Hardware (port interface) Support Routines - + * The driver function names that start with "dfx_hw_" represent + * low-level port interface routines that are called frequently. They + * include issuing a DMA or port control command to the adapter, + * resetting the adapter, or reading the adapter state. Since the + * driver initialization and run-time code must make calls into the + * port interface, these routines were written to be as generic and + * usable as possible. + * + * Receive Path - + * The adapter DMA engine supports a 256 entry receive descriptor block + * of which up to 255 entries can be used at any given time. The + * architecture is a standard producer, consumer, completion model in + * which the driver "produces" receive buffers to the adapter, the + * adapter "consumes" the receive buffers by DMAing incoming packet data, + * and the driver "completes" the receive buffers by servicing the + * incoming packet, then "produces" a new buffer and starts the cycle + * again. Receive buffers can be fragmented in up to 16 fragments + * (descriptor entries). For simplicity, this driver posts + * single-fragment receive buffers of 4608 bytes, then allocates a + * sk_buff, copies the data, then reposts the buffer. To reduce CPU + * utilization, a better approach would be to pass up the receive + * buffer (no extra copy) then allocate and post a replacement buffer. + * This is a performance enhancement that should be looked into at + * some point. + * + * Transmit Path - + * Like the receive path, the adapter DMA engine supports a 256 entry + * transmit descriptor block of which up to 255 entries can be used at + * any given time. Transmit buffers can be fragmented in up to 255 + * fragments (descriptor entries). This driver always posts one + * fragment per transmit packet request. + * + * The fragment contains the entire packet from FC to end of data. + * Before posting the buffer to the adapter, the driver sets a three-byte + * packet request header (PRH) which is required by the Motorola MAC chip + * used on the adapters. The PRH tells the MAC the type of token to + * receive/send, whether or not to generate and append the CRC, whether + * synchronous or asynchronous framing is used, etc. Since the PRH + * definition is not necessarily consistent across all FDDI chipsets, + * the driver, rather than the common FDDI packet handler routines, + * sets these bytes. + * + * To reduce the amount of descriptor fetches needed per transmit request, + * the driver takes advantage of the fact that there are at least three + * bytes available before the skb->data field on the outgoing transmit + * request. This is guaranteed by having fddi_setup() in net_init.c set + * dev->hard_header_len to 24 bytes. 21 bytes accounts for the largest + * header in an 802.2 SNAP frame. The other 3 bytes are the extra "pad" + * bytes which we'll use to store the PRH. + * + * There's a subtle advantage to adding these pad bytes to the + * hard_header_len, it ensures that the data portion of the packet for + * an 802.2 SNAP frame is longword aligned. Other FDDI driver + * implementations may not need the extra padding and can start copying + * or DMAing directly from the FC byte which starts at skb->data. Should + * another driver implementation need ADDITIONAL padding, the net_init.c + * module should be updated and dev->hard_header_len should be increased. + * NOTE: To maintain the alignment on the data portion of the packet, + * dev->hard_header_len should always be evenly divisible by 4 and at + * least 24 bytes in size. + * + * Modification History: + * Date Name Description + * 16-Aug-96 LVS Created. + * 20-Aug-96 LVS Updated dfx_probe so that version information + * string is only displayed if 1 or more cards are + * found. Changed dfx_rcv_queue_process to copy + * 3 NULL bytes before FC to ensure that data is + * longword aligned in receive buffer. + * 09-Sep-96 LVS Updated dfx_ctl_set_multicast_list to enable + * LLC group promiscuous mode if multicast list + * is too large. LLC individual/group promiscuous + * mode is now disabled if IFF_PROMISC flag not set. + * dfx_xmt_queue_pkt no longer checks for NULL skb + * on Alan Cox recommendation. Added node address + * override support. + * 12-Sep-96 LVS Reset current address to factory address during + * device open. Updated transmit path to post a + * single fragment which includes PRH->end of data. + */ + +/* Version information string - should be updated prior to each new release!!! */ + +static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefani@lkg.dec.com)\n"; + +/* Include files */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "defxx.h" + +/* Define global routines */ + +int dfx_probe(struct device *dev); + +/* Define module-wide (static) routines */ + +static struct device *dfx_alloc_device(struct device *dev, u16 iobase); + +static void dfx_bus_init(struct device *dev); +static void dfx_bus_config_check(DFX_board_t *bp); + +static int dfx_driver_init(struct device *dev); +static int dfx_adap_init(DFX_board_t *bp); + +static int dfx_open(struct device *dev); +static int dfx_close(struct device *dev); + +static void dfx_int_pr_halt_id(DFX_board_t *bp); +static void dfx_int_type_0_process(DFX_board_t *bp); +static void dfx_int_common(DFX_board_t *bp); +static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static struct enet_statistics *dfx_ctl_get_stats(struct device *dev); +static void dfx_ctl_set_multicast_list(struct device *dev); +static int dfx_ctl_set_mac_address(struct device *dev, void *addr); +static int dfx_ctl_update_cam(DFX_board_t *bp); +static int dfx_ctl_update_filters(DFX_board_t *bp); + +static int dfx_hw_dma_cmd_req(DFX_board_t *bp); +static int dfx_hw_port_ctrl_req(DFX_board_t *bp, PI_UINT32 command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data); +static void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type); +static int dfx_hw_adap_state_rd(DFX_board_t *bp); +static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); + +static void dfx_rcv_init(DFX_board_t *bp); +static void dfx_rcv_queue_process(DFX_board_t *bp); + +static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct device *dev); +static void dfx_xmt_done(DFX_board_t *bp); +static void dfx_xmt_flush(DFX_board_t *bp); + +/* Define module-wide (static) variables */ + +static int num_boards = 0; /* total number of adapters configured */ +static int already_probed = 0; /* have we already entered dfx_probe? */ + + +/* + * ======================= + * = dfx_port_write_byte = + * = dfx_port_read_byte = + * = dfx_port_write_long = + * = dfx_port_read_long = + * ======================= + * + * Overview: + * Routines for reading and writing values from/to adapter + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * offset - register offset from base I/O address + * data - for dfx_port_write_byte and dfx_port_write_long, this + * is a value to write. + * for dfx_port_read_byte and dfx_port_read_byte, this + * is a pointer to store the read value. + * + * Functional Description: + * These routines perform the correct operation to read or write + * the adapter register. + * + * EISA port block base addresses are based on the slot number in which the + * controller is installed. For example, if the EISA controller is installed + * in slot 4, the port block base address is 0x4000. If the controller is + * installed in slot 2, the port block base address is 0x2000, and so on. + * This port block can be used to access PDQ, ESIC, and DEFEA on-board + * registers using the register offsets defined in DEFXX.H. + * + * PCI port block base addresses are assigned by the PCI BIOS or system + * firmware. There is one 128 byte port block which can be accessed. It + * allows for I/O mapping of both PDQ and PFI registers using the register + * offsets defined in DEFXX.H. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base_addr is a valid base I/O address for this adapter. + * offset is a valid register offset for this adapter. + * + * Side Effects: + * Rather than produce macros for these functions, these routines + * are defined using "inline" to ensure that the compiler will + * generate inline code and not waste a procedure call and return. + * This provides all the benefits of macros, but with the + * advantage of strict data type checking. + */ + +static inline void dfx_port_write_byte( + DFX_board_t *bp, + int offset, + u8 data + ) + + { + u16 port = bp->base_addr + offset; + + outb(data, port); + return; + } + +static inline void dfx_port_read_byte( + DFX_board_t *bp, + int offset, + u8 *data + ) + + { + u16 port = bp->base_addr + offset; + + *data = inb(port); + return; + } + +static inline void dfx_port_write_long( + DFX_board_t *bp, + int offset, + u32 data + ) + + { + u16 port = bp->base_addr + offset; + + outl(data, port); + return; + } + +static inline void dfx_port_read_long( + DFX_board_t *bp, + int offset, + u32 *data + ) + + { + u16 port = bp->base_addr + offset; + + *data = inl(port); + return; + } + + +/* + * ============= + * = dfx_probe = + * ============= + * + * Overview: + * Probes for supported FDDI EISA and PCI controllers + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine is called by the OS for each FDDI device name (fddi0, + * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. Since + * the DEFXX.C driver currently does not support being loaded as a + * module, dfx_probe() will initialize all devices the first time + * it is called. + * + * Let's say that dfx_probe() is getting called to initialize fddi0. + * Furthermore, let's say there are three supported controllers in the + * system. Before dfx_probe() leaves, devices fddi0, fddi1, and fddi2 + * will be initialized and a global flag will be set to indicate that + * dfx_probe() has already been called. + * + * However...the OS doesn't know that we've already initialized + * devices fddi1 and fddi2 so dfx_probe() gets called again and again + * until it reaches the end of the device list for FDDI (presently, + * fddi7). It's important that the driver "pretend" to probe for + * devices fddi1 and fddi2 and return success. Devices fddi3 + * through fddi7 will return failure since they weren't initialized. + * + * This algorithm seems to work for the time being. As other FDDI + * drivers are written for Linux, a more generic approach (perhaps + * similar to the Ethernet card approach) may need to be implemented. + * + * Return Codes: + * 0 - This device (fddi0, fddi1, etc) configured successfully + * -ENODEV - No devices present, or no Digital FDDI EISA or PCI device + * present for this device name + * + * Assumptions: + * For the time being, DEFXX.C is the only FDDI driver under Linux. + * As this assumption changes, this routine will likely be impacted. + * Also, it is assumed that no more than eight (8) FDDI controllers + * will be configured in the system (fddi0 through fddi7). This + * routine will not allocate new device structures. If more than + * eight FDDI controllers need to be configured, drivers/net/Space.c + * should be updated as well as the DFX_MAX_NUM_BOARDS constant in + * DEFXX.H. + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * initialized and the board resources are read and stored in + * the device structure. + */ + +int dfx_probe( + struct device *dev + ) + + { + int i; /* used in for loops */ + int version_disp; /* was version info string already displayed? */ + int port_len; /* length of port address range (in bytes) */ + u8 pci_bus; /* PCI bus number (0-255) */ + u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ + u16 port; /* temporary I/O (port) address */ + u16 command; /* PCI Configuration space Command register val */ + u32 slot_id; /* EISA hardware (slot) ID read from adapter */ + DFX_board_t *bp; /* board pointer */ + + DBG_printk("In dfx_probe...\n"); + + /* + * Verify whether we're going through dfx_probe() again + * + * If so, see if we're going through for a subsequent fddi device that + * we've already initialized. If we are, return success (0). If not, + * return failure (-ENODEV). + */ + + version_disp = 0; /* default to version string not displayed */ + if (already_probed) + { + DBG_printk("Already entered dfx_probe\n"); + if (dev != NULL) + if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0)) + { + DBG_printk("In dfx_probe for fddi adapter (%s) we've already initialized it, so return success\n", dev->name); + return(0); + } + return(-ENODEV); + } + already_probed = 1; /* set global flag */ + + /* Scan for FDDI EISA controllers */ + + for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */ + { + port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */ + slot_id = inl(port); /* read EISA HW (slot) ID */ + if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID) + { + if (!version_disp) /* display version info if adapter is found */ + { + version_disp = 1; /* set display flag to TRUE so that */ + printk(version); /* we only display this string ONCE */ + } + + port = (i << 12); /* recalc base addr */ + + /* Verify port address range is not already being used */ + + port_len = PI_ESIC_K_CSR_IO_LEN; + if (check_region(port, port_len) == 0) + { + /* Allocate a new device structure for this adapter */ + + dev = dfx_alloc_device(dev, port); + if (dev != NULL) + { + /* Initialize board structure with bus-specific info */ + + bp = (DFX_board_t *) dev->priv; + bp->dev = dev; + bp->bus_type = DFX_BUS_TYPE_EISA; + if (dfx_driver_init(dev) == DFX_K_SUCCESS) + num_boards++; /* only increment global board count on success */ + else + dev->base_addr = 0; /* clear port address field in device structure on failure */ + } + } + else + printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); + } + } + + /* Scan for FDDI PCI controllers */ + + if (pcibios_present()) /* is PCI BIOS even present? */ + for (i=0; i < DFX_MAX_NUM_BOARDS; i++) /* scan for up to 8 PCI cards */ + if (pcibios_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, i, &pci_bus, &pci_dev_fun) == 0) + { + if (!version_disp) /* display version info if adapter is found */ + { + version_disp = 1; /* set display flag to TRUE so that */ + printk(version); /* we only display this string ONCE */ + } + + /* Verify that I/O enable bit is set (PCI slot is enabled) */ + + pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, &command); + if ((command & PCI_COMMAND_IO) == 0) + printk("I/O enable bit not set! Verify that slot is enabled\n"); + else + { + /* Turn off memory mapped space and enable mastering */ + + command |= PCI_COMMAND_MASTER; + command &= ~PCI_COMMAND_MEMORY; + pcibios_write_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, command); + + /* Read I/O base address from PCI Configuration Space */ + + pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_BASE_ADDRESS_1, &port); + port &= PCI_BASE_ADDRESS_IO_MASK; /* clear I/O bit (bit 0) */ + + /* Verify port address range is not already being used */ + + port_len = PFI_K_CSR_IO_LEN; + if (check_region(port, port_len) == 0) + { + /* Allocate a new device structure for this adapter */ + + dev = dfx_alloc_device(dev, port); + if (dev != NULL) + { + /* Initialize board structure with bus-specific info */ + + bp = (DFX_board_t *) dev->priv; + bp->dev = dev; + bp->bus_type = DFX_BUS_TYPE_PCI; + bp->pci_bus = pci_bus; + bp->pci_dev_fun = pci_dev_fun; + if (dfx_driver_init(dev) == DFX_K_SUCCESS) + num_boards++; /* only increment global board count on success */ + else + dev->base_addr = 0; /* clear port address field in device structure on failure */ + } + } + else + printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); + } + } + + /* + * If we're at this point we're going through dfx_probe() for the first + * time. Return success (0) if we've initialized 1 or more boards. + * Otherwise, return failure (-ENODEV). + */ + + if (num_boards > 0) + return(0); + else + return(-ENODEV); + } + + +/* + * ==================== + * = dfx_alloc_device = + * ==================== + * + * Overview: + * Allocate new device structure for adapter + * + * Returns: + * Pointer to device structure for this adapter or NULL if + * none are available or could not allocate memory for + * private board structure. + * + * Arguments: + * dev - pointer to device information for last device + * iobase - base I/O address of new adapter + * + * Functional Description: + * The algorithm for allocating a new device structure is + * fairly simple. Since we're presently the only FDDI driver + * under Linux, we'll find the first device structure with an + * "fddi*" device name that's free. If we run out of devices, + * we'll fail on error. This is simpler than trying to + * allocate the memory for a new device structure, determine + * the next free number (beyond 7) and link it into the chain + * of devices. A user can always modify drivers/net/Space.c + * to add new FDDI device structures if necessary. + * + * Beyond finding a free FDDI device structure, this routine + * initializes most of the fields, resource tags, and dispatch + * pointers in the device structure and calls the common + * fddi_setup() routine to perform the rest of the device + * structure initialization. + * + * Return Codes: + * None + * + * Assumptions: + * If additional FDDI drivers are integrated into Linux, + * we'll likely need to use a different approach to + * allocate a device structure. Perhaps one that is + * similar to what the Ethernet drivers use. + * + * Side Effects: + * None + */ + +struct device *dfx_alloc_device( + struct device *dev, + u16 iobase + ) + + { + struct device *tmp_dev; /* pointer to a device structure */ + + DBG_printk("In dfx_alloc_device...\n"); + + /* Find next free fddi entry */ + + for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next) + if ((strncmp(tmp_dev->name, "fddi", 4) == 0) && (tmp_dev->base_addr == 0)) + break; + if (tmp_dev == NULL) + { + printk("Could not find free FDDI device structure for this adapter!\n"); + return(NULL); + } + DBG_printk("Device entry free, device name = %s\n", tmp_dev->name); + + /* Allocate space for private board structure */ + + tmp_dev->priv = (void *) kmalloc(sizeof(DFX_board_t), GFP_KERNEL); + if (tmp_dev->priv == NULL) + { + printk("Could not allocate memory for private board structure!\n"); + return(NULL); + } + memset(tmp_dev->priv, 0, sizeof(DFX_board_t)); /* clear structure */ + + /* Initialize new device structure */ + + tmp_dev->rmem_end = 0; /* shared memory isn't used */ + tmp_dev->rmem_start = 0; /* shared memory isn't used */ + tmp_dev->mem_end = 0; /* shared memory isn't used */ + tmp_dev->mem_start = 0; /* shared memory isn't used */ + tmp_dev->base_addr = iobase; /* save port (I/O) base address */ + tmp_dev->irq = 0; /* set in dfx_bus_init() */ + tmp_dev->if_port = 0; /* not applicable to FDDI adapters */ + tmp_dev->dma = 0; /* Bus Master DMA doesn't require channel */ + + tmp_dev->get_stats = &dfx_ctl_get_stats; + tmp_dev->open = &dfx_open; + tmp_dev->stop = &dfx_close; + tmp_dev->hard_start_xmit = &dfx_xmt_queue_pkt; + tmp_dev->hard_header = NULL; /* set in fddi_setup() */ + tmp_dev->rebuild_header = NULL; /* set in fddi_setup() */ + tmp_dev->set_multicast_list = &dfx_ctl_set_multicast_list; + tmp_dev->set_mac_address = &dfx_ctl_set_mac_address; + tmp_dev->do_ioctl = NULL; /* not supported for now &&& */ + tmp_dev->set_config = NULL; /* not supported for now &&& */ + tmp_dev->header_cache_bind = NULL; /* not supported */ + tmp_dev->header_cache_update = NULL; /* not supported */ + tmp_dev->change_mtu = NULL; /* set in fddi_setup() */ + + /* Initialize remaining device structure information */ + + fddi_setup(tmp_dev); + return(tmp_dev); + } + + +/* + * ================ + * = dfx_bus_init = + * ================ + * + * Overview: + * Initializes EISA and PCI controller bus-specific logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Determine and save adapter IRQ in device table, + * then perform bus-specific logic initialization. + * + * Return Codes: + * None + * + * Assumptions: + * dev->base_addr has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are enabled at the adapter bus-specific logic. + * Note: Interrupts at the DMA engine (PDQ chip) are not + * enabled yet. + */ + +void dfx_bus_init( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + u8 val; /* used for I/O read/writes */ + + DBG_printk("In dfx_bus_init...\n"); + + /* + * Initialize base I/O address field in bp structure + * + * Note: bp->base_addr is the same as dev->base_addr. + * It's useful because often we'll need to read + * or write registers where we already have the + * bp pointer instead of the dev pointer. Having + * the base address in the bp structure will + * save a pointer dereference. + * + * IMPORTANT!! This field must be defined before + * any of the dfx_port_* inline functions are + * called. + */ + + bp->base_addr = dev->base_addr; + + /* Initialize adapter based on bus type */ + + if (bp->bus_type == DFX_BUS_TYPE_EISA) + { + /* Get the interrupt level from the ESIC chip */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); + switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ) + { + case PI_CONFIG_STAT_0_IRQ_K_9: + dev->irq = 9; + break; + + case PI_CONFIG_STAT_0_IRQ_K_10: + dev->irq = 10; + break; + + case PI_CONFIG_STAT_0_IRQ_K_11: + dev->irq = 11; + break; + + case PI_CONFIG_STAT_0_IRQ_K_15: + dev->irq = 15; + break; + } + + /* Enable access to I/O on the board by writing 0x03 to Function Control Register */ + + dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB); + + /* Set the I/O decode range of the board */ + + val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT); + dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val); + dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val); + + /* Enable access to rest of module (including PDQ and packet memory) */ + + dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB); + + /* + * Map PDQ registers into I/O space. This is done by clearing a bit + * in Burst Holdoff register. + */ + + dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val); + dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP)); + + /* Enable interrupts at EISA bus interface chip (ESIC) */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); + dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB)); + } + else + { + /* Get the interrupt level from the PCI Configuration Table */ + + pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_INTERRUPT_LINE, &val); + dev->irq = val; /* save IRQ value in device table */ + + /* Check Latency Timer and set if less than minimal */ + + pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, &val); + if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */ + { + val = PFI_K_LAT_TIMER_DEF; + pcibios_write_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, val); + } + + /* Enable interrupts at PCI bus interface chip (PFI) */ + + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); + } + return; + } + + +/* + * ======================== + * = dfx_bus_config_check = + * ======================== + * + * Overview: + * Checks the configuration (burst size, full-duplex, etc.) If any parameters + * are illegal, then this routine will set new defaults. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later + * PDQ, and all FDDI PCI controllers, all values are legal. + * + * Return Codes: + * None + * + * Assumptions: + * dfx_adap_init has NOT been called yet so burst size and other items have + * not been set. + * + * Side Effects: + * None + */ + +void dfx_bus_config_check( + DFX_board_t *bp + ) + + { + int status; /* return code from adapter port control call */ + u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */ + u32 host_data; /* LW data returned from port control call */ + + DBG_printk("In dfx_bus_config_check...\n"); + + /* Configuration check only valid for EISA adapter */ + + if (bp->bus_type == DFX_BUS_TYPE_EISA) + { + dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id); + + /* + * First check if revision 2 EISA controller. Rev. 1 cards used + * PDQ revision B, so no workaround needed in this case. Rev. 3 + * cards used PDQ revision E, so no workaround needed in this + * case, either. Only Rev. 2 cards used either Rev. D or E + * chips, so we must verify the chip revision on Rev. 2 cards. + */ + + if (slot_id == DEFEA_PROD_ID_2) + { + /* + * Revision 2 FDDI EISA controller found, so let's check PDQ + * revision of adapter. + */ + + status = dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_SUB_CMD, + PI_SUB_CMD_K_PDQ_REV_GET, + 0, + &host_data); + if ((status != DFX_K_SUCCESS) || (host_data == 2)) + { + /* + * Either we couldn't determine the PDQ revision, or + * we determined that it is at revision D. In either case, + * we need to implement the workaround. + */ + + /* Ensure that the burst size is set to 8 longwords or less */ + + switch (bp->burst_size) + { + case PI_PDATA_B_DMA_BURST_SIZE_32: + case PI_PDATA_B_DMA_BURST_SIZE_16: + bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8; + break; + + default: + break; + } + + /* Ensure that full-duplex mode is not enabled */ + + bp->full_duplex_enb = PI_SNMP_K_FALSE; + } + } + } + return; + } + + +/* + * =================== + * = dfx_driver_init = + * =================== + * + * Overview: + * Initializes remaining adapter board structure information + * and makes sure adapter is in a safe state prior to dfx_open(). + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function allocates additional resources such as the host memory + * blocks needed by the adapter (eg. descriptor and consumer blocks). + * Remaining bus initialization steps are also completed. The adapter + * is also reset so that it is in the DMA_UNAVAILABLE state. The OS + * must call dfx_open() to open the adapter and bring it on-line. + * + * Return Codes: + * DFX_K_SUCCESS - initialization succeeded + * DFX_K_FAILURE - initialization failed - could not allocate memory + * or read adapter MAC address + * + * Assumptions: + * Memory allocated from kmalloc() call is physically contiguous, locked + * memory whose physical address equals its virtual address. + * + * Side Effects: + * Adapter is reset and should be in DMA_UNAVAILABLE state before + * returning from this routine. + */ + +int dfx_driver_init( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + int alloc_size; /* total buffer size needed */ + char *top_v, *curr_v; /* virtual addrs into memory block */ + u32 top_p, curr_p; /* physical addrs into memory block */ + u32 data; /* host data register value */ + + DBG_printk("In dfx_driver_init...\n"); + + /* Initialize bus-specific hardware registers */ + + dfx_bus_init(dev); + + /* + * Initialize default values for configurable parameters + * + * Note: All of these parameters are ones that a user may + * want to customize. It'd be nice to break these + * out into Space.c or someplace else that's more + * accessible/understandable than this file. + */ + + bp->full_duplex_enb = PI_SNMP_K_FALSE; + bp->req_ttrt = 8 * 12500; /* 8ms in 80 nanosec units */ + bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_DEF; + bp->rcv_bufs_to_post = RCV_BUFS_DEF; + + /* + * Ensure that HW configuration is OK + * + * Note: Depending on the hardware revision, we may need to modify + * some of the configurable parameters to workaround hardware + * limitations. We'll perform this configuration check AFTER + * setting the parameters to their default values. + */ + + dfx_bus_config_check(bp); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); + + /* Read the factory MAC address from the adapter then save it */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_MLA, + PI_PDATA_A_MLA_K_LO, + 0, + &data) != DFX_K_SUCCESS) + { + printk("%s: Could not read adapter factory MAC address!\n", dev->name); + return(DFX_K_FAILURE); + } + memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32)); + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_MLA, + PI_PDATA_A_MLA_K_HI, + 0, + &data) != DFX_K_SUCCESS) + { + printk("%s: Could not read adapter factory MAC address!\n", dev->name); + return(DFX_K_FAILURE); + } + memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16)); + + /* + * Set current address to factory address + * + * Note: Node address override support is handled through + * dfx_ctl_set_mac_address. + */ + + memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); + if (bp->bus_type == DFX_BUS_TYPE_EISA) + printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + dev->name, + dev->base_addr, + dev->irq, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5]); + else + printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n", + dev->name, + dev->base_addr, + dev->irq, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5]); + + /* + * Get memory for descriptor block, consumer block, and other buffers + * that need to be DMA read or written to by the adapter. + */ + + alloc_size = sizeof(PI_DESCR_BLOCK) + + PI_CMD_REQ_K_SIZE_MAX + + PI_CMD_RSP_K_SIZE_MAX + + (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + + sizeof(PI_CONSUMER_BLOCK) + + (PI_ALIGN_K_DESC_BLK - 1); + top_v = (char *) kmalloc(alloc_size, GFP_KERNEL); + if (top_v == NULL) + { + printk("%s: Could not allocate memory for host buffers and structures!\n", dev->name); + return(DFX_K_FAILURE); + } + memset(top_v, 0, alloc_size); /* zero out memory before continuing */ + top_p = virt_to_bus(top_v); /* get physical address of buffer */ + + /* + * To guarantee the 8K alignment required for the descriptor block, 8K - 1 + * plus the amount of memory needed was allocated. The physical address + * is now 8K aligned. By carving up the memory in a specific order, + * we'll guarantee the alignment requirements for all other structures. + * + * Note: If the assumptions change regarding the non-paged, non-cached, + * physically contiguous nature of the memory block or the address + * alignments, then we'll need to implement a different algorithm + * for allocating the needed memory. + */ + + curr_p = (u32) (ALIGN(top_p, PI_ALIGN_K_DESC_BLK)); + curr_v = top_v + (curr_p - top_p); + + /* Reserve space for descriptor block */ + + bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v; + bp->descr_block_phys = curr_p; + curr_v += sizeof(PI_DESCR_BLOCK); + curr_p += sizeof(PI_DESCR_BLOCK); + + /* Reserve space for command request buffer */ + + bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v; + bp->cmd_req_phys = curr_p; + curr_v += PI_CMD_REQ_K_SIZE_MAX; + curr_p += PI_CMD_REQ_K_SIZE_MAX; + + /* Reserve space for command response buffer */ + + bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v; + bp->cmd_rsp_phys = curr_p; + curr_v += PI_CMD_RSP_K_SIZE_MAX; + curr_p += PI_CMD_RSP_K_SIZE_MAX; + + /* Reserve space for the LLC host receive queue buffers */ + + bp->rcv_block_virt = curr_v; + bp->rcv_block_phys = curr_p; + curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); + curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); + + /* Reserve space for the consumer block */ + + bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v; + bp->cons_block_phys = curr_p; + + /* Display virtual and physical addresses if debug driver */ + + DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n", dev->name, (long)bp->descr_block_virt, bp->descr_block_phys); + DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_req_virt, bp->cmd_req_phys); + DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys); + DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->rcv_block_virt, bp->rcv_block_phys); + DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->cons_block_virt, bp->cons_block_phys); + + return(DFX_K_SUCCESS); + } + + +/* + * ================= + * = dfx_adap_init = + * ================= + * + * Overview: + * Brings the adapter to the link avail/link unavailable state. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Issues the low-level firmware/hardware calls necessary to bring + * the adapter up, or to properly reset and restore adapter during + * run-time. + * + * Return Codes: + * DFX_K_SUCCESS - Adapter brought up successfully + * DFX_K_FAILURE - Adapter initialization failed + * + * Assumptions: + * bp->reset_type should be set to a valid reset type value before + * calling this routine. + * + * Side Effects: + * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state + * upon a successful return of this routine. + */ + +int dfx_adap_init( + DFX_board_t *bp + ) + + { + DBG_printk("In dfx_adap_init...\n"); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS) + { + printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* + * When the PDQ is reset, some false Type 0 interrupts may be pending, + * so we'll acknowledge all Type 0 interrupts now before continuing. + */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, PI_HOST_INT_K_ACK_ALL_TYPE_0); + + /* + * Clear Type 1 and Type 2 registers before going to DMA_AVAILABLE state + * + * Note: We only need to clear host copies of these registers. The PDQ reset + * takes care of the on-board register values. + */ + + bp->cmd_req_reg.lword = 0; + bp->cmd_rsp_reg.lword = 0; + bp->rcv_xmt_reg.lword = 0; + + /* Clear consumer block before going to DMA_AVAILABLE state */ + + memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + + /* Initialize the DMA Burst Size */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_SUB_CMD, + PI_SUB_CMD_K_BURST_SIZE_SET, + bp->burst_size, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set adapter burst size!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* + * Set base address of Consumer Block + * + * Assumption: 32-bit physical address of consumer block is 64 byte + * aligned. That is, bits 0-5 of the address must be zero. + */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_CONS_BLOCK, + bp->cons_block_phys, + 0, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set consumer block address!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* + * Set base address of Descriptor Block and bring adapter to DMA_AVAILABLE state + * + * Note: We also set the literal and data swapping requirements in this + * command. Since this driver presently runs on Intel platforms + * which are Little Endian, we'll tell the adapter to byte swap + * data only. This code will need to change when we support + * Big Endian systems (eg. PowerPC). + * + * Assumption: 32-bit physical address of descriptor block is 8Kbyte + * aligned. That is, bits 0-12 of the address must be zero. + */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_INIT, + (u32) (bp->descr_block_phys | PI_PDATA_A_INIT_M_BSWAP_DATA), + 0, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set descriptor block address!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Set transmit flush timeout value */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_CHARS_SET; + bp->cmd_req_virt->char_set.item[0].item_code = PI_ITEM_K_FLUSH_TIME; + bp->cmd_req_virt->char_set.item[0].value = 3; /* 3 seconds */ + bp->cmd_req_virt->char_set.item[0].item_index = 0; + bp->cmd_req_virt->char_set.item[1].item_code = PI_ITEM_K_EOL; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: DMA command request failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Set the initial values for eFDXEnable and MACTReq MIB objects */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_SNMP_SET; + bp->cmd_req_virt->snmp_set.item[0].item_code = PI_ITEM_K_FDX_ENB_DIS; + bp->cmd_req_virt->snmp_set.item[0].value = bp->full_duplex_enb; + bp->cmd_req_virt->snmp_set.item[0].item_index = 0; + bp->cmd_req_virt->snmp_set.item[1].item_code = PI_ITEM_K_MAC_T_REQ; + bp->cmd_req_virt->snmp_set.item[1].value = bp->req_ttrt; + bp->cmd_req_virt->snmp_set.item[1].item_index = 0; + bp->cmd_req_virt->snmp_set.item[2].item_code = PI_ITEM_K_EOL; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: DMA command request failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialize adapter CAM */ + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter CAM update failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialize adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter filters update failed!\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialize receive descriptor block and produce buffers */ + + dfx_rcv_init(bp); + + /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_START; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: Start command failed\n", bp->dev->name); + return(DFX_K_FAILURE); + } + + /* Initialization succeeded, reenable PDQ interrupts */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS); + return(DFX_K_SUCCESS); + } + + +/* + * ============ + * = dfx_open = + * ============ + * + * Overview: + * Opens the adapter + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function brings the adapter to an operational state. + * + * Return Codes: + * 0 - Adapter was successfully opened + * -EAGAIN - Could not register IRQ or adapter initialization failed + * + * Assumptions: + * This routine should only be called for a device that was + * initialized successfully during the dfx_probe process. + * + * Side Effects: + * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state + * if the open is successful. + */ + +int dfx_open( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + + DBG_printk("In dfx_open...\n"); + + /* Register IRQ - support shared interrupts by passing device ptr */ + + if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev)) + { + printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq); + return(-EAGAIN); + } + + /* + * Set current address to factory MAC address + * + * Note: We've already done this step in dfx_driver_init. + * However, it's possible that a user has set a node + * address override, then closed and reopened the + * adapter. Unless we reset the device address field + * now, we'll continue to use the existing modified + * address. + */ + + memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); + + /* Clear local unicast/multicast address tables and counts */ + + memset(bp->uc_table, 0, sizeof(bp->uc_table)); + memset(bp->mc_table, 0, sizeof(bp->mc_table)); + bp->uc_count = 0; + bp->mc_count = 0; + + /* Disable promiscuous filter settings */ + + bp->ind_group_prom = PI_FSTATE_K_BLOCK; + bp->group_prom = PI_FSTATE_K_BLOCK; + + /* Reset and initialize adapter */ + + bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ + if (dfx_adap_init(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter open failed!\n", dev->name); + return(-EAGAIN); + } + + /* Set device structure info */ + + dev->tbusy = 0; + dev->interrupt = DFX_UNMASK_INTERRUPTS; + dev->start = 1; + return(0); + } + + +/* + * ============= + * = dfx_close = + * ============= + * + * Overview: + * Closes the device/module. + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine closes the adapter and brings it to a safe state. + * The interrupt service routine is deregistered with the OS. + * The adapter can be opened again with another call to dfx_open(). + * + * Return Codes: + * Always return 0. + * + * Assumptions: + * No further requests for this adapter are made after this routine is + * called. dfx_open() can be called to reset and reinitialize the + * adapter. + * + * Side Effects: + * Adapter should be in DMA_UNAVAILABLE state upon completion of this + * routine. + */ + +int dfx_close( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + + DBG_printk("In dfx_close...\n"); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); + + /* + * Flush any pending transmit buffers + * + * Note: It's important that we flush the transmit buffers + * BEFORE we clear our copy of the Type 2 register. + * Otherwise, we'll have no idea how many buffers + * we need to free. + */ + + dfx_xmt_flush(bp); + + /* + * Clear Type 1 and Type 2 registers after adapter reset + * + * Note: Even though we're closing the adapter, it's + * possible that an interrupt will occur after + * dfx_close is called. Without some assurance to + * the contrary we want to make sure that we don't + * process receive and transmit LLC frames and update + * the Type 2 register with bad information. + */ + + bp->cmd_req_reg.lword = 0; + bp->cmd_rsp_reg.lword = 0; + bp->rcv_xmt_reg.lword = 0; + + /* Clear consumer block for the same reason given above */ + + memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + + /* Clear device structure flags */ + + dev->start = 0; + dev->tbusy = 1; + + /* Deregister (free) IRQ */ + + free_irq(dev->irq, dev); + return(0); + } + + +/* + * ====================== + * = dfx_int_pr_halt_id = + * ====================== + * + * Overview: + * Displays halt id's in string form. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Determine current halt id and display appropriate string. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +void dfx_int_pr_halt_id( + DFX_board_t *bp + ) + + { + PI_UINT32 port_status; /* PDQ port status register value */ + PI_UINT32 halt_id; /* PDQ port status halt ID */ + + /* Read the latest port status */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + + /* Display halt state transition information */ + + halt_id = (port_status & PI_PSTATUS_M_HALT_ID) >> PI_PSTATUS_V_HALT_ID; + switch (halt_id) + { + case PI_HALT_ID_K_SELFTEST_TIMEOUT: + printk("%s: Halt ID: Selftest Timeout\n", bp->dev->name); + break; + + case PI_HALT_ID_K_PARITY_ERROR: + printk("%s: Halt ID: Host Bus Parity Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_HOST_DIR_HALT: + printk("%s: Halt ID: Host-Directed Halt\n", bp->dev->name); + break; + + case PI_HALT_ID_K_SW_FAULT: + printk("%s: Halt ID: Adapter Software Fault\n", bp->dev->name); + break; + + case PI_HALT_ID_K_HW_FAULT: + printk("%s: Halt ID: Adapter Hardware Fault\n", bp->dev->name); + break; + + case PI_HALT_ID_K_PC_TRACE: + printk("%s: Halt ID: FDDI Network PC Trace Path Test\n", bp->dev->name); + break; + + case PI_HALT_ID_K_DMA_ERROR: + printk("%s: Halt ID: Adapter DMA Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_IMAGE_CRC_ERROR: + printk("%s: Halt ID: Firmware Image CRC Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_BUS_EXCEPTION: + printk("%s: Halt ID: 68000 Bus Exception\n", bp->dev->name); + break; + + default: + printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); + break; + } + return; + } + + +/* + * ========================== + * = dfx_int_type_0_process = + * ========================== + * + * Overview: + * Processes Type 0 interrupts. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Processes all enabled Type 0 interrupts. If the reason for the interrupt + * is a serious fault on the adapter, then an error message is displayed + * and the adapter is reset. + * + * One tricky potential timing window is the rapid succession of "link avail" + * "link unavail" state change interrupts. The acknowledgement of the Type 0 + * interrupt must be done before reading the state from the Port Status + * register. This is true because a state change could occur after reading + * the data, but before acknowledging the interrupt. If this state change + * does happen, it would be lost because the driver is using the old state, + * and it will never know about the new state because it subsequently + * acknowledges the state change interrupt. + * + * INCORRECT CORRECT + * read type 0 int reasons read type 0 int reasons + * read adapter state ack type 0 interrupts + * ack type 0 interrupts read adapter state + * ... process interrupt ... ... process interrupt ... + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * An adapter reset may occur if the adapter has any Type 0 error interrupts + * or if the port status indicates that the adapter is halted. The driver + * is responsible for reinitializing the adapter with the current CAM + * contents and adapter filter settings. + */ + +void dfx_int_type_0_process( + DFX_board_t *bp + ) + + { + PI_UINT32 type_0_status; /* Host Interrupt Type 0 register */ + PI_UINT32 state; /* current adap state (from port status) */ + + /* + * Read host interrupt Type 0 register to determine which Type 0 + * interrupts are pending. Immediately write it back out to clear + * those interrupts. + */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, &type_0_status); + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, type_0_status); + + /* Check for Type 0 error interrupts */ + + if (type_0_status & (PI_TYPE_0_STAT_M_NXM | + PI_TYPE_0_STAT_M_PM_PAR_ERR | + PI_TYPE_0_STAT_M_BUS_PAR_ERR)) + { + /* Check for Non-Existent Memory error */ + + if (type_0_status & PI_TYPE_0_STAT_M_NXM) + printk("%s: Non-Existent Memory Access Error\n", bp->dev->name); + + /* Check for Packet Memory Parity error */ + + if (type_0_status & PI_TYPE_0_STAT_M_PM_PAR_ERR) + printk("%s: Packet Memory Parity Error\n", bp->dev->name); + + /* Check for Host Bus Parity error */ + + if (type_0_status & PI_TYPE_0_STAT_M_BUS_PAR_ERR) + printk("%s: Host Bus Parity Error\n", bp->dev->name); + + /* Reset adapter and bring it back on-line */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + bp->reset_type = 0; /* rerun on-board diagnostics */ + printk("%s: Resetting adapter...\n", bp->dev->name); + if (dfx_adap_init(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + return; + } + printk("%s: Adapter reset successful!\n", bp->dev->name); + return; + } + + /* Check for transmit flush interrupt */ + + if (type_0_status & PI_TYPE_0_STAT_M_XMT_FLUSH) + { + /* Flush any pending xmt's and acknowledge the flush interrupt */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + dfx_xmt_flush(bp); /* flush any outstanding packets */ + (void) dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_XMT_DATA_FLUSH_DONE, + 0, + 0, + NULL); + } + + /* Check for adapter state change */ + + if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE) + { + /* Get latest adapter state */ + + state = dfx_hw_adap_state_rd(bp); /* get adapter state */ + if (state == PI_STATE_K_HALTED) + { + /* + * Adapter has transitioned to HALTED state, try to reset + * adapter to bring it back on-line. If reset fails, + * leave the adapter in the broken state. + */ + + printk("%s: Controller has transitioned to HALTED state!\n", bp->dev->name); + dfx_int_pr_halt_id(bp); /* display halt id as string */ + + /* Reset adapter and bring it back on-line */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + bp->reset_type = 0; /* rerun on-board diagnostics */ + printk("%s: Resetting adapter...\n", bp->dev->name); + if (dfx_adap_init(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + return; + } + printk("%s: Adapter reset successful!\n", bp->dev->name); + } + else if (state == PI_STATE_K_LINK_AVAIL) + { + bp->link_available = PI_K_TRUE; /* set link available flag */ + } + } + return; + } + + +/* + * ================== + * = dfx_int_common = + * ================== + * + * Overview: + * Interrupt service routine (ISR) + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * This is the ISR which processes incoming adapter interrupts. + * + * Return Codes: + * None + * + * Assumptions: + * This routine assumes PDQ interrupts have not been disabled. + * When interrupts are disabled at the PDQ, the Port Status register + * is automatically cleared. This routine uses the Port Status + * register value to determine whether a Type 0 interrupt occurred, + * so it's important that adapter interrupts are not normally + * enabled/disabled at the PDQ. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. dfx_xmt_queue_pkt) for the same board on a + * different thread. + * + * Side Effects: + * Pending interrupts are serviced. Depending on the type of + * interrupt, acknowledging and clearing the interrupt at the + * PDQ involves writing a register to clear the interrupt bit + * or updating completion indices. + */ + +void dfx_int_common( + DFX_board_t *bp + ) + + { + PI_UINT32 port_status; /* Port Status register */ + + /* Process xmt interrupts - frequent case, so always call this routine */ + + dfx_xmt_done(bp); /* free consumed xmt packets */ + + /* Process rcv interrupts - frequent case, so always call this routine */ + + dfx_rcv_queue_process(bp); /* service received LLC frames */ + + /* + * Transmit and receive producer and completion indices are updated on the + * adapter by writing to the Type 2 Producer register. Since the frequent + * case is that we'll be processing either LLC transmit or receive buffers, + * we'll optimize I/O writes by doing a single register write here. + */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + + /* Read PDQ Port Status register to find out which interrupts need processing */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + + /* Process Type 0 interrupts (if any) - infrequent, so only call when needed */ + + if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) + dfx_int_type_0_process(bp); /* process Type 0 interrupts */ + return; + } + + +/* + * ================= + * = dfx_interrupt = + * ================= + * + * Overview: + * Interrupt processing routine + * + * Returns: + * None + * + * Arguments: + * irq - interrupt vector + * dev_id - pointer to device information + * regs - pointer to registers structure + * + * Functional Description: + * This routine calls the interrupt processing routine for this adapter. It + * disables and reenables adapter interrupts, as appropriate. We can support + * shared interrupts since the incoming dev_id pointer provides our device + * structure context. + * + * Return Codes: + * None + * + * Assumptions: + * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC + * on Intel-based systems) is done by the operating system outside this + * routine. + * + * System interrupts are enabled through this call. + * + * Side Effects: + * Interrupts are disabled, then reenabled at the adapter. + */ + +void dfx_interrupt( + int irq, + void *dev_id, + struct pt_regs *regs + ) + + { + struct device *dev = (struct device *) dev_id; + DFX_board_t *bp; /* private board structure pointer */ + u8 tmp; /* used for disabling/enabling ints */ + + /* Get board pointer only if device structure is valid */ + + if (dev == NULL) + { + printk("dfx_interrupt(): irq %d for unknown device!\n", irq); + return; + } + bp = (DFX_board_t *) dev->priv; + + /* See if we're already servicing an interrupt */ + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler!\n", dev->name); + dev->interrupt = DFX_MASK_INTERRUPTS; /* ensure non reentrancy */ + + /* Service adapter interrupts */ + + if (bp->bus_type == DFX_BUS_TYPE_PCI) + { + /* Disable PDQ-PFI interrupts at PFI */ + + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, PFI_MODE_M_DMA_ENB); + + /* Call interrupt service routine for this adapter */ + + dfx_int_common(bp); + + /* Clear PDQ interrupt status bit and reenable interrupts */ + + dfx_port_write_long(bp, PFI_K_REG_STATUS, PFI_STATUS_M_PDQ_INT); + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, + (PFI_MODE_M_PDQ_INT_ENB + PFI_MODE_M_DMA_ENB)); + } + else + { + /* Disable interrupts at the ESIC */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp); + tmp &= ~PI_CONFIG_STAT_0_M_INT_ENB; + dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp); + + /* Call interrupt service routine for this adapter */ + + dfx_int_common(bp); + + /* Reenable interrupts at the ESIC */ + + dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp); + tmp |= PI_CONFIG_STAT_0_M_INT_ENB; + dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp); + } + + dev->interrupt = DFX_UNMASK_INTERRUPTS; + return; + } + + +/* + * ===================== + * = dfx_ctl_get_stats = + * ===================== + * + * Overview: + * Get statistics for FDDI adapter + * + * Returns: + * Pointer to FDDI statistics structure + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Gets current MIB objects from adapter, then + * returns FDDI statistics structure as defined + * in if_fddi.h. + * + * Note: Since the FDDI statistics structure is + * still new and the device structure doesn't + * have an FDDI-specific get statistics handler, + * we'll return the FDDI statistics structure as + * a pointer to an Ethernet statistics structure. + * That way, at least the first part of the statistics + * structure can be decoded properly, and it allows + * "smart" applications to perform a second cast to + * decode the FDDI-specific statistics. + * + * We'll have to pay attention to this routine as the + * device structure becomes more mature and LAN media + * independent. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +struct enet_statistics *dfx_ctl_get_stats( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + + /* Fill the bp->stats structure with driver-maintained counters */ + + bp->stats.rx_packets = bp->rcv_total_frames; + bp->stats.tx_packets = bp->xmt_total_frames; + bp->stats.rx_errors = (u32)(bp->rcv_crc_errors + bp->rcv_frame_status_errors + bp->rcv_length_errors); + bp->stats.tx_errors = bp->xmt_length_errors; + bp->stats.rx_dropped = bp->rcv_discards; + bp->stats.tx_dropped = bp->xmt_discards; + bp->stats.multicast = bp->rcv_multicast_frames; + bp->stats.transmit_collision = 0; /* always zero (0) for FDDI */ + + /* Get FDDI SMT MIB objects */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return((struct enet_statistics *) &bp->stats); + + /* Fill the bp->stats structure with the SMT MIB object values */ + + memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); + bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; + bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; + bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; + memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); + bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; + bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; + bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; + bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; + bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; + bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; + bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; + bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; + bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; + bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; + bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; + bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; + bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; + bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; + bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; + bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; + bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; + bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; + bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; + bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; + bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; + bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; + bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; + bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; + memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); + bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; + bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; + bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; + memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); + bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; + bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; + bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; + bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; + bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; + bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; + bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; + bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; + bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; + bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; + bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; + bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; + bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; + bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; + bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; + bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; + memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); + bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; + bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; + bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; + bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; + bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; + bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; + bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; + bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; + bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; + bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; + memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); + memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); + bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; + bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; + bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; + bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; + bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; + bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; + bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; + bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; + bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; + bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; + bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; + bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; + bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; + bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; + bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; + bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; + bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; + bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; + bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; + bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; + bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; + bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; + bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; + bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; + bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; + bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; + + /* Get FDDI counters */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return((struct enet_statistics *) &bp->stats); + + /* Fill the bp->stats structure with the FDDI counter values */ + + bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; + bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; + bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; + bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; + bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; + bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; + bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; + bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; + bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; + bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; + bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; + + return((struct enet_statistics *) &bp->stats); + } + + +/* + * ============================== + * = dfx_ctl_set_multicast_list = + * ============================== + * + * Overview: + * Enable/Disable LLC frame promiscuous mode reception + * on the adapter and/or update multicast address table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine follows a fairly simple algorithm for setting the + * adapter filters and CAM: + * + * if IFF_PROMISC flag is set + * enable LLC individual/group promiscuous mode + * else + * disable LLC individual/group promiscuous mode + * if number of incoming multicast addresses > + * (CAM max size - number of unicast addresses in CAM) + * enable LLC group promiscuous mode + * set driver-maintained multicast address count to zero + * else + * disable LLC group promiscuous mode + * set driver-maintained multicast address count to incoming count + * update adapter CAM + * update adapter filters + * + * Return Codes: + * None + * + * Assumptions: + * Multicast addresses are presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter CAM and filters are updated. + */ + +void dfx_ctl_set_multicast_list( + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + int i; /* used as index in for loop */ + struct dev_mc_list *dmi; /* ptr to multicast addr entry */ + + /* Enable LLC frame promiscuous mode, if necessary */ + + if (dev->flags & IFF_PROMISC) + bp->ind_group_prom = PI_FSTATE_K_PASS; /* Enable LLC ind/group prom mode */ + + /* Else, update multicast address table */ + + else + { + bp->ind_group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC ind/group prom mode */ + /* + * Check whether incoming multicast address count exceeds table size + * + * Note: The adapters utilize an on-board 64 entry CAM for + * supporting perfect filtering of multicast packets + * and bridge functions when adding unicast addresses. + * There is no hash function available. To support + * additional multicast addresses, the all multicast + * filter (LLC group promiscuous mode) must be enabled. + * + * The firmware reserves two CAM entries for SMT-related + * multicast addresses, which leaves 62 entries available. + * The following code ensures that we're not being asked + * to add more than 62 addresses to the CAM. If we are, + * the driver will enable the all multicast filter. + * Should the number of multicast addresses drop below + * the high water mark, the filter will be disabled and + * perfect filtering will be used. + */ + + if (dev->mc_count > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) + { + bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ + bp->mc_count = 0; /* Don't add mc addrs to CAM */ + } + else + { + bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ + bp->mc_count = dev->mc_count; /* Add mc addrs to CAM */ + } + + /* Copy addresses to multicast address table, then update adapter CAM */ + + dmi = dev->mc_list; /* point to first multicast addr */ + for (i=0; i < bp->mc_count; i++) + { + memcpy(&bp->mc_table[i*FDDI_K_ALEN], dmi->dmi_addr, FDDI_K_ALEN); + dmi = dmi->next; /* point to next multicast addr */ + } + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update multicast address table!\n", dev->name); + } + else + { + DBG_printk("%s: Multicast address table updated! Added %d addresses.\n", dev->name, bp->mc_count); + } + } + + /* Update adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update adapter filters!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter filters updated!\n", dev->name); + } + return; + } + + +/* + * =========================== + * = dfx_ctl_set_mac_address = + * =========================== + * + * Overview: + * Add node address override (unicast address) to adapter + * CAM and update dev_addr field in device table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * addr - pointer to sockaddr structure containing unicast address to add + * + * Functional Description: + * The adapter supports node address overrides by adding one or more + * unicast addresses to the adapter CAM. This is similar to adding + * multicast addresses. In this routine we'll update the driver and + * device structures with the new address, then update the adapter CAM + * to ensure that the adapter will copy and strip frames destined and + * sourced by that address. + * + * Return Codes: + * Always returns zero. + * + * Assumptions: + * The address pointed to by addr->sa_data is a valid unicast + * address and is presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter CAM is updated. On-board adapter filters + * may be updated. + */ + +int dfx_ctl_set_mac_address( + struct device *dev, + void *addr + ) + + { + DFX_board_t *bp = (DFX_board_t *)dev->priv; + struct sockaddr *p_sockaddr = (struct sockaddr *)addr; + + /* Copy unicast address to driver-maintained structs and update count */ + + memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); /* update device struct */ + memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN); /* update driver struct */ + bp->uc_count = 1; + + /* + * Verify we're not exceeding the CAM size by adding unicast address + * + * Note: It's possible that before entering this routine we've + * already filled the CAM with 62 multicast addresses. + * Since we need to place the node address override into + * the CAM, we have to check to see that we're not + * exceeding the CAM size. If we are, we have to enable + * the LLC group (multicast) promiscuous mode filter as + * in dfx_ctl_set_multicast_list. + */ + + if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE) + { + bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ + bp->mc_count = 0; /* Don't add mc addrs to CAM */ + + /* Update adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update adapter filters!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter filters updated!\n", dev->name); + } + } + + /* Update adapter CAM with new unicast address */ + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not set new MAC address!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name); + } + return(0); /* always return zero */ + } + + +/* + * ====================== + * = dfx_ctl_update_cam = + * ====================== + * + * Overview: + * Procedure to update adapter CAM (Content Addressable Memory) + * with desired unicast and multicast address entries. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Updates adapter CAM with current contents of board structure + * unicast and multicast address tables. Since there are only 62 + * free entries in CAM, this routine ensures that the command + * request buffer is not overrun. + * + * Return Codes: + * DFX_K_SUCCESS - Request succeeded + * DFX_K_FAILURE - Request failed + * + * Assumptions: + * All addresses being added (unicast and multicast) are in canonical + * order. + * + * Side Effects: + * On-board adapter CAM is updated. + */ + +int dfx_ctl_update_cam( + DFX_board_t *bp + ) + + { + int i; /* used as index */ + PI_LAN_ADDR *p_addr; /* pointer to CAM entry */ + + /* + * Fill in command request information + * + * Note: Even though both the unicast and multicast address + * table entries are stored as contiguous 6 byte entries, + * the firmware address filter set command expects each + * entry to be two longwords (8 bytes total). We must be + * careful to only copy the six bytes of each unicast and + * multicast table entry into each command entry. This + * is also why we must first clear the entire command + * request buffer. + */ + + memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX); /* first clear buffer */ + bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET; + p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0]; + + /* Now add unicast addresses to command request buffer, if any */ + + for (i=0; i < (int)bp->uc_count; i++) + { + if (i < PI_CMD_ADDR_FILTER_K_SIZE) + { + memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); + p_addr++; /* point to next command entry */ + } + } + + /* Now add multicast addresses to command request buffer, if any */ + + for (i=0; i < (int)bp->mc_count; i++) + { + if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE) + { + memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); + p_addr++; /* point to next command entry */ + } + } + + /* Issue command to update adapter CAM, then return */ + + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return(DFX_K_FAILURE); + return(DFX_K_SUCCESS); + } + + +/* + * ========================== + * = dfx_ctl_update_filters = + * ========================== + * + * Overview: + * Procedure to update adapter filters with desired + * filter settings. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Enables or disables filter using current filter settings. + * + * Return Codes: + * DFX_K_SUCCESS - Request succeeded. + * DFX_K_FAILURE - Request failed. + * + * Assumptions: + * We must always pass up packets destined to the broadcast + * address (FF-FF-FF-FF-FF-FF), so we'll always keep the + * broadcast filter enabled. + * + * Side Effects: + * On-board adapter filters are updated. + */ + +int dfx_ctl_update_filters( + DFX_board_t *bp + ) + + { + int i = 0; /* used as index */ + + /* Fill in command request information */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET; + + /* Initialize Broadcast filter - * ALWAYS ENABLED * */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_BROADCAST; + bp->cmd_req_virt->filter_set.item[i++].value = PI_FSTATE_K_PASS; + + /* Initialize LLC Individual/Group Promiscuous filter */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_IND_GROUP_PROM; + bp->cmd_req_virt->filter_set.item[i++].value = bp->ind_group_prom; + + /* Initialize LLC Group Promiscuous filter */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_GROUP_PROM; + bp->cmd_req_virt->filter_set.item[i++].value = bp->group_prom; + + /* Terminate the item code list */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_EOL; + + /* Issue command to update adapter filters, then return */ + + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return(DFX_K_FAILURE); + return(DFX_K_SUCCESS); + } + + +/* + * ====================== + * = dfx_hw_dma_cmd_req = + * ====================== + * + * Overview: + * Sends PDQ DMA command to adapter firmware + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * The command request and response buffers are posted to the adapter in the manner + * described in the PDQ Port Specification: + * + * 1. Command Response Buffer is posted to adapter. + * 2. Command Request Buffer is posted to adapter. + * 3. Command Request consumer index is polled until it indicates that request + * buffer has been DMA'd to adapter. + * 4. Command Response consumer index is polled until it indicates that response + * buffer has been DMA'd from adapter. + * + * This ordering ensures that a response buffer is already available for the firmware + * to use once it's done processing the request buffer. + * + * Return Codes: + * DFX_K_SUCCESS - DMA command succeeded + * DFX_K_OUTSTATE - Adapter is NOT in proper state + * DFX_K_HW_TIMEOUT - DMA command timed out + * + * Assumptions: + * Command request buffer has already been filled with desired DMA command. + * + * Side Effects: + * None + */ + +int dfx_hw_dma_cmd_req( + DFX_board_t *bp + ) + + { + int status; /* adapter status */ + int timeout_cnt; /* used in for loops */ + + /* Make sure the adapter is in a state that we can issue the DMA command in */ + + status = dfx_hw_adap_state_rd(bp); + if ((status == PI_STATE_K_RESET) || + (status == PI_STATE_K_HALTED) || + (status == PI_STATE_K_DMA_UNAVAIL) || + (status == PI_STATE_K_UPGRADE)) + return(DFX_K_OUTSTATE); + + /* Put response buffer on the command response queue */ + + bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys; + + /* Bump (and wrap) the producer index and write out to register */ + + bp->cmd_rsp_reg.index.prod += 1; + bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); + + /* Put request buffer on the command request queue */ + + bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP | + PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN)); + bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys; + + /* Bump (and wrap) the producer index and write out to register */ + + bp->cmd_req_reg.index.prod += 1; + bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); + + /* + * Here we wait for the command request consumer index to be equal + * to the producer, indicating that the adapter has DMAed the request. + */ + + for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) + { + if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + + /* Bump (and wrap) the completion index and write out to register */ + + bp->cmd_req_reg.index.comp += 1; + bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); + + /* + * Here we wait for the command response consumer index to be equal + * to the producer, indicating that the adapter has DMAed the response. + */ + + for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) + { + if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + + /* Bump (and wrap) the completion index and write out to register */ + + bp->cmd_rsp_reg.index.comp += 1; + bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); + return(DFX_K_SUCCESS); + } + + +/* + * ======================== + * = dfx_hw_port_ctrl_req = + * ======================== + * + * Overview: + * Sends PDQ port control command to adapter firmware + * + * Returns: + * Host data register value in host_data if ptr is not NULL + * + * Arguments: + * bp - pointer to board information + * command - port control command + * data_a - port data A register value + * data_b - port data B register value + * host_data - ptr to host data register value + * + * Functional Description: + * Send generic port control command to adapter by writing + * to various PDQ port registers, then polling for completion. + * + * Return Codes: + * DFX_K_SUCCESS - port control command succeeded + * DFX_K_HW_TIMEOUT - port control command timed out + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +int dfx_hw_port_ctrl_req( + DFX_board_t *bp, + PI_UINT32 command, + PI_UINT32 data_a, + PI_UINT32 data_b, + PI_UINT32 *host_data + ) + + { + PI_UINT32 port_cmd; /* Port Control command register value */ + int timeout_cnt; /* used in for loops */ + + /* Set Command Error bit in command longword */ + + port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR); + + /* Issue port command to the adapter */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a); + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b); + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd); + + /* Now wait for command to complete */ + + if (command == PI_PCTRL_M_BLAST_FLASH) + timeout_cnt = 600000; /* set command timeout count to 60 seconds */ + else + timeout_cnt = 20000; /* set command timeout count to 2 seconds */ + + for (; timeout_cnt > 0; timeout_cnt--) + { + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd); + if (!(port_cmd & PI_PCTRL_M_CMD_ERROR)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + + /* + * If the address of host_data is non-zero, assume caller has supplied a + * non NULL pointer, and return the contents of the HOST_DATA register in + * it. + */ + + if (host_data != NULL) + dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data); + return(DFX_K_SUCCESS); + } + + +/* + * ===================== + * = dfx_hw_adap_reset = + * ===================== + * + * Overview: + * Resets adapter + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * type - type of reset to perform + * + * Functional Description: + * Issue soft reset to adapter by writing to PDQ Port Reset + * register. Use incoming reset type to tell adapter what + * kind of reset operation to perform. + * + * Return Codes: + * None + * + * Assumptions: + * This routine merely issues a soft reset to the adapter. + * It is expected that after this routine returns, the caller + * will appropriately poll the Port Status register for the + * adapter to enter the proper state. + * + * Side Effects: + * Internal adapter registers are cleared. + */ + +void dfx_hw_adap_reset( + DFX_board_t *bp, + PI_UINT32 type + ) + + { + /* Set Reset type and assert reset */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type); /* tell adapter type of reset */ + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET); + + /* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */ + + udelay(20); + + /* Deassert reset */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); + return; + } + + +/* + * ======================== + * = dfx_hw_adap_state_rd = + * ======================== + * + * Overview: + * Returns current adapter state + * + * Returns: + * Adapter state per PDQ Port Specification + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Reads PDQ Port Status register and returns adapter state. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +int dfx_hw_adap_state_rd( + DFX_board_t *bp + ) + + { + PI_UINT32 port_status; /* Port Status register value */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + return((port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE); + } + + +/* + * ===================== + * = dfx_hw_dma_uninit = + * ===================== + * + * Overview: + * Brings adapter to DMA_UNAVAILABLE state + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * type - type of reset to perform + * + * Functional Description: + * Bring adapter to DMA_UNAVAILABLE state by performing the following: + * 1. Set reset type bit in Port Data A Register then reset adapter. + * 2. Check that adapter is in DMA_UNAVAILABLE state. + * + * Return Codes: + * DFX_K_SUCCESS - adapter is in DMA_UNAVAILABLE state + * DFX_K_HW_TIMEOUT - adapter did not reset properly + * + * Assumptions: + * None + * + * Side Effects: + * Internal adapter registers are cleared. + */ + +int dfx_hw_dma_uninit( + DFX_board_t *bp, + PI_UINT32 type + ) + + { + int timeout_cnt; /* used in for loops */ + + /* Set reset type bit and reset adapter */ + + dfx_hw_adap_reset(bp, type); + + /* Now wait for adapter to enter DMA_UNAVAILABLE state */ + + for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--) + { + if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return(DFX_K_HW_TIMEOUT); + return(DFX_K_SUCCESS); + } + + +/* + * ================ + * = dfx_rcv_init = + * ================ + * + * Overview: + * Produces buffers to adapter LLC Host receive descriptor block + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * This routine can be called during dfx_adap_init() or during an adapter + * reset. It initializes the descriptor block and produces all allocated + * LLC Host queue receive buffers. + * + * Return Codes: + * None + * + * Assumptions: + * The PDQ has been reset and the adapter and driver maintained Type 2 + * register indices are cleared. + * + * Side Effects: + * Receive buffers are posted to the adapter LLC queue and the adapter + * is notified. + */ + +void dfx_rcv_init( + DFX_board_t *bp + ) + + { + int i, j; /* used in for loop */ + + /* + * Since each receive buffer is a single fragment of same length, initialize + * first longword in each receive descriptor for entire LLC Host descriptor + * block. Also initialize second longword in each receive descriptor with + * physical address of receive buffer. We'll always allocate receive + * buffers in powers of 2 so that we can easily fill the 256 entry descriptor + * block and produce new receive buffers by simply updating the receive + * producer index. + * + * Assumptions: + * To support all shipping versions of PDQ, the receive buffer size + * must be mod 128 in length and the physical address must be 128 byte + * aligned. In other words, bits 0-6 of the length and address must + * be zero for the following descriptor field entries to be correct on + * all PDQ-based boards. We guaranteed both requirements during + * driver initialization when we allocated memory for the receive buffers. + */ + + for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); + bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); + } + + /* Update receive producer and Type 2 register */ + + bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + return; + } + + +/* + * ========================= + * = dfx_rcv_queue_process = + * ========================= + * + * Overview: + * Process received LLC frames. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Received LLC frames are processed until there are no more consumed frames. + * Once all frames are processed, the receive buffers are returned to the + * adapter. Note that this algorithm fixes the length of time that can be spent + * in this routine, because there are a fixed number of receive buffers to + * process and buffers are not produced until this routine exits and returns + * to the ISR. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +void dfx_rcv_queue_process( + DFX_board_t *bp + ) + + { + PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ + u32 descr, pkt_len; /* FMC descriptor field and packet length */ + struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ + + /* Service all consumed LLC receive frames */ + + p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); + while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) + { + /* Process any errors */ + + p_buff = (char *) bp->p_rcv_buff_va[bp->rcv_xmt_reg.index.rcv_comp]; + memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); + + if (descr & PI_FMC_DESCR_M_RCC_FLUSH) + { + if (descr & PI_FMC_DESCR_M_RCC_CRC) + bp->rcv_crc_errors++; + else + bp->rcv_frame_status_errors++; + } + else + { + /* The frame was received without errors - verify packet length */ + + pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); + pkt_len -= 4; /* subtract 4 byte CRC */ + if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) + bp->rcv_length_errors++; + else + { + skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ + if (skb == NULL) + { + printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + } + else + { + /* Receive buffer allocated, pass receive packet up */ + + memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3); + skb->data += 3; /* adjust data field so that it points to FC byte */ + skb->len = pkt_len; /* pass up packet length, NOT including CRC */ + skb->dev = bp->dev; /* pass up device pointer */ + skb->protocol = fddi_type_trans(skb, bp->dev); + netif_rx(skb); + + /* Update the rcv counters */ + + bp->rcv_total_frames++; + if (*(p_buff + RCV_BUFF_K_DA) & 0x01) + bp->rcv_multicast_frames++; + } + } + } + + /* + * Advance the producer (for recycling) and advance the completion + * (for servicing received frames). Note that it is okay to + * advance the producer without checking that it passes the + * completion index because they are both advanced at the same + * rate. + */ + + bp->rcv_xmt_reg.index.rcv_prod += 1; + bp->rcv_xmt_reg.index.rcv_comp += 1; + } + return; + } + + +/* + * ===================== + * = dfx_xmt_queue_pkt = + * ===================== + * + * Overview: + * Queues packets for transmission + * + * Returns: + * Condition code + * + * Arguments: + * skb - pointer to sk_buff to queue for transmission + * dev - pointer to device information + * + * Functional Description: + * Here we assume that an incoming skb transmit request + * is contained in a single physically contiguous buffer + * in which the virtual address of the start of packet + * (skb->data) can be converted to a physical address + * by using virt_to_bus(). + * + * Since the adapter architecture requires a three byte + * packet request header to prepend the start of packet, + * we'll write the three byte field immediately prior to + * the FC byte. This assumption is valid because we've + * ensured that dev->hard_header_len includes three pad + * bytes. By posting a single fragment to the adapter, + * we'll reduce the number of descriptor fetches and + * bus traffic needed to send the request. + * + * Also, we can't free the skb until after it's been DMA'd + * out by the adapter, so we'll queue it in the driver and + * return it in dfx_xmt_done. + * + * Return Codes: + * 0 - driver queued packet, link is unavailable, or skbuff was bad + * 1 - caller should requeue the sk_buff for later transmission + * + * Assumptions: + * First and foremost, we assume the incoming skb pointer + * is NOT NULL and is pointing to a valid sk_buff structure. + * + * The outgoing packet is complete, starting with the + * frame control byte including the last byte of data, + * but NOT including the 4 byte CRC. We'll let the + * adapter hardware generate and append the CRC. + * + * The entire packet is stored in one physically + * contiguous buffer which is not cached and whose + * 32-bit physical address can be determined. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. dfx_int_common) for the same board on a + * different thread. + * + * Side Effects: + * None + */ + +int dfx_xmt_queue_pkt( + struct sk_buff *skb, + struct device *dev + ) + + { + DFX_board_t *bp = (DFX_board_t *) dev->priv; + u8 prod; /* local transmit producer index */ + PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + + /* + * Verify that incoming transmit request is OK + * + * Note: The packet size check is consistent with other + * Linux device drivers, although the correct packet + * size should be verified before calling the + * transmit routine. + */ + + if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) + { + printk("%s: Invalid packet length - %lu bytes\n", dev->name, skb->len); + bp->xmt_length_errors++; /* bump error counter */ + dev_tint(dev); /* dequeue packets from xmt queue and send them */ + return(0); /* return "success" */ + } + + /* + * See if adapter link is available, if not, free buffer + * + * Note: If the link isn't available, free buffer and return 0 + * rather than tell the upper layer to requeue the packet. + * The methodology here is that by the time the link + * becomes available, the packet to be sent will be + * fairly stale. By simply dropping the packet, the + * higher layer protocols will eventually time out + * waiting for response packets which it won't receive. + */ + + if (bp->link_available == PI_K_FALSE) + { + if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL) /* is link really available? */ + bp->link_available = PI_K_TRUE; /* if so, set flag and continue */ + else + { + bp->xmt_discards++; /* bump error counter */ + dev_kfree_skb(skb, FREE_WRITE); /* free sk_buff now */ + return(0); /* return "success" */ + } + } + + /* Get the current producer and the next free xmt data descriptor */ + + prod = bp->rcv_xmt_reg.index.xmt_prod; + p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); + + /* + * Get pointer to auxiliary queue entry to contain information for this packet. + * + * Note: The current xmt producer index will become the current xmt completion + * index when we complete this packet later on. So, we'll get the + * pointer to the next auxiliary queue entry now before we bump the + * producer index. + */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ + + /* Write the three PRH bytes immediately before the FC byte */ + + *((char *)skb->data - 3) = DFX_PRH0_BYTE; /* these byte values are defined */ + *((char *)skb->data - 2) = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ + *((char *)skb->data - 1) = DFX_PRH2_BYTE; /* specification */ + + /* + * Write the descriptor with buffer info and bump producer + * + * Note: Since we need to start DMA from the packet request + * header, we'll add 3 bytes to the DMA buffer length, + * and we'll determine the physical address of the + * buffer from the PRH, not skb->data. + * + * Assumptions: + * 1. Packet starts with the frame control (FC) byte + * at skb->data. + * 2. The 4-byte CRC is not appended to the buffer or + * included in the length. + * 3. Packet length (skb->len) is from FC to end of + * data, inclusive. + * 4. The packet length does not exceed the maximum + * FDDI LLC frame length of 4491 bytes. + * 5. The entire packet is contained in a physically + * contiguous, non-cached, locked memory space + * comprised of a single buffer pointed to by + * skb->data. + * 6. The physical address of the start of packet + * can be determined from the virtual address + * by using virt_to_bus() and is only 32-bits + * wide. + */ + + p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len + 3) << PI_XMT_DESCR_V_SEG_LEN)); + p_xmt_descr->long_1 = (u32) virt_to_bus(skb->data - 3); + + /* + * Verify that descriptor is actually available + * + * Note: If descriptor isn't available, return 1 which tells + * the upper layer to requeue the packet for later + * transmission. + * + * We need to ensure that the producer never reaches the + * completion, except to indicate that the queue is empty. + */ + + if (prod == bp->rcv_xmt_reg.index.xmt_comp) + return(1); /* requeue packet for later */ + + /* + * Save info for this packet for xmt done indication routine + * + * Normally, we'd save the producer index in the p_xmt_drv_descr + * structure so that we'd have it handy when we complete this + * packet later (in dfx_xmt_done). However, since the current + * transmit architecture guarantees a single fragment for the + * entire packet, we can simply bump the completion index by + * one (1) for each completed packet. + * + * Note: If this assumption changes and we're presented with + * an inconsistent number of transmit fragments for packet + * data, we'll need to modify this code to save the current + * transmit producer index. + */ + + p_xmt_drv_descr->p_skb = skb; + + /* Update Type 2 register */ + + bp->rcv_xmt_reg.index.xmt_prod = prod; + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + return(0); /* packet queued to adapter */ + } + + +/* + * ================ + * = dfx_xmt_done = + * ================ + * + * Overview: + * Processes all frames that have been transmitted. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For all consumed transmit descriptors that have not + * yet been completed, we'll free the skb we were holding + * onto using dev_kfree_skb and bump the appropriate + * counters. + * + * Return Codes: + * None + * + * Assumptions: + * The Type 2 register is not updated in this routine. It is + * assumed that it will be updated in the ISR when dfx_xmt_done + * returns. + * + * Side Effects: + * None + */ + +void dfx_xmt_done( + DFX_board_t *bp + ) + + { + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + + /* Service all consumed transmit frames */ + + p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); + while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons) + { + /* Get pointer to the transmit driver descriptor block information */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); + + /* Return skb to operating system */ + + dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE); + + /* Increment transmit counters */ + + bp->xmt_total_frames++; + + /* + * Move to start of next packet by updating completion index + * + * Here we assume that a transmit packet request is always + * serviced by posting one fragment. We can therefore + * simplify the completion code by incrementing the + * completion index by one. This code will need to be + * modified if this assumption changes. See comments + * in dfx_xmt_queue_pkt for more details. + */ + + bp->rcv_xmt_reg.index.xmt_comp += 1; + } + return; + } + + +/* + * ================= + * = dfx_xmt_flush = + * ================= + * + * Overview: + * Processes all frames whether they've been transmitted + * or not. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For all produced transmit descriptors that have not + * yet been completed, we'll free the skb we were holding + * onto using dev_kfree_skb and bump the appropriate + * counters. Of course, it's possible that some of + * these transmit requests actually did go out, but we + * won't make that distinction here. Finally, we'll + * update the consumer index to match the producer. + * + * Return Codes: + * None + * + * Assumptions: + * This routine does NOT update the Type 2 register. It + * is assumed that this routine is being called during a + * transmit flush interrupt, or a shutdown or close routine. + * + * Side Effects: + * None + */ + +void dfx_xmt_flush( + DFX_board_t *bp + ) + + { + u32 prod_cons; /* rcv/xmt consumer block longword */ + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + + /* Flush all outstanding transmit frames */ + + while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod) + { + /* Get pointer to the transmit driver descriptor block information */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); + + /* Return skb to operating system */ + + dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE); + + /* Increment transmit error counter */ + + bp->xmt_discards++; + + /* + * Move to start of next packet by updating completion index + * + * Here we assume that a transmit packet request is always + * serviced by posting one fragment. We can therefore + * simplify the completion code by incrementing the + * completion index by one. This code will need to be + * modified if this assumption changes. See comments + * in dfx_xmt_queue_pkt for more details. + */ + + bp->rcv_xmt_reg.index.xmt_comp += 1; + } + + /* Update the transmit consumer index in the consumer block */ + + prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); + prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); + bp->cons_block_virt->xmt_rcv_data = prod_cons; + return; + } + + +/* + * Local variables: + * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c" + * End: + */ diff -u --recursive --new-file v2.0.23/linux/drivers/net/defxx.h linux/drivers/net/defxx.h --- v2.0.23/linux/drivers/net/defxx.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/defxx.h Wed Oct 30 03:42:40 1996 @@ -0,0 +1,1780 @@ +/* + * File Name: + * defxx.h + * + * Copyright Information: + * Copyright Digital Equipment Corporation 1996. + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + * + * Abstract: + * Contains all definitions specified by port specification and required + * by the defxx.c driver. + * + * Maintainers: + * LVS Lawrence V. Stefani + * + * Contact: + * The author may be reached at: + * + * Inet: stefani@lkg.dec.com + * Mail: Digital Equipment Corporation + * 550 King Street + * M/S: LKG1-3/M07 + * Littleton, MA 01460 + * + * Modification History: + * Date Name Description + * 16-Aug-96 LVS Created. + * 09-Sep-96 LVS Added group_prom field. Moved read/write I/O + * macros to DEFXX.C. + * 12-Sep-96 LVS Removed packet request header pointers. + */ + +#ifndef _DEFXX_H_ +#define _DEFXX_H_ + +/* Define basic types for unsigned chars, shorts, longs */ + +typedef u8 PI_UINT8; +typedef u16 PI_UINT16; +typedef u32 PI_UINT32; + +/* Define general structures */ + +typedef struct /* 64-bit counter */ + { + PI_UINT32 ms; + PI_UINT32 ls; + } PI_CNTR; + +typedef struct /* LAN address */ + { + PI_UINT32 lwrd_0; + PI_UINT32 lwrd_1; + } PI_LAN_ADDR; + +typedef struct /* Station ID address */ + { + PI_UINT32 octet_7_4; + PI_UINT32 octet_3_0; + } PI_STATION_ID; + + +/* Define general constants */ + +#define PI_ALIGN_K_DESC_BLK 8192 /* Descriptor block boundary */ +#define PI_ALIGN_K_CONS_BLK 64 /* Consumer block boundary */ +#define PI_ALIGN_K_CMD_REQ_BUFF 128 /* Xmt Command que buffer alignment */ +#define PI_ALIGN_K_CMD_RSP_BUFF 128 /* Rcv Command que buffer alignment */ +#define PI_ALIGN_K_UNSOL_BUFF 128 /* Unsol que buffer alignment */ +#define PI_ALIGN_K_XMT_DATA_BUFF 0 /* Xmt data que buffer alignment */ +#define PI_ALIGN_K_RCV_DATA_BUFF 128 /* Rcv que buffer alignment */ + +/* Define PHY index values */ + +#define PI_PHY_K_S 0 /* Index to S phy */ +#define PI_PHY_K_A 0 /* Index to A phy */ +#define PI_PHY_K_B 1 /* Index to B phy */ +#define PI_PHY_K_MAX 2 /* Max number of phys */ + +/* Define FMC descriptor fields */ + +#define PI_FMC_DESCR_V_SOP 31 +#define PI_FMC_DESCR_V_EOP 30 +#define PI_FMC_DESCR_V_FSC 27 +#define PI_FMC_DESCR_V_FSB_ERROR 26 +#define PI_FMC_DESCR_V_FSB_ADDR_RECOG 25 +#define PI_FMC_DESCR_V_FSB_ADDR_COPIED 24 +#define PI_FMC_DESCR_V_FSB 22 +#define PI_FMC_DESCR_V_RCC_FLUSH 21 +#define PI_FMC_DESCR_V_RCC_CRC 20 +#define PI_FMC_DESCR_V_RCC_RRR 17 +#define PI_FMC_DESCR_V_RCC_DD 15 +#define PI_FMC_DESCR_V_RCC_SS 13 +#define PI_FMC_DESCR_V_RCC 13 +#define PI_FMC_DESCR_V_LEN 0 + +#define PI_FMC_DESCR_M_SOP 0x80000000 +#define PI_FMC_DESCR_M_EOP 0x40000000 +#define PI_FMC_DESCR_M_FSC 0x38000000 +#define PI_FMC_DESCR_M_FSB_ERROR 0x04000000 +#define PI_FMC_DESCR_M_FSB_ADDR_RECOG 0x02000000 +#define PI_FMC_DESCR_M_FSB_ADDR_COPIED 0x01000000 +#define PI_FMC_DESCR_M_FSB 0x07C00000 +#define PI_FMC_DESCR_M_RCC_FLUSH 0x00200000 +#define PI_FMC_DESCR_M_RCC_CRC 0x00100000 +#define PI_FMC_DESCR_M_RCC_RRR 0x000E0000 +#define PI_FMC_DESCR_M_RCC_DD 0x00018000 +#define PI_FMC_DESCR_M_RCC_SS 0x00006000 +#define PI_FMC_DESCR_M_RCC 0x003FE000 +#define PI_FMC_DESCR_M_LEN 0x00001FFF + +#define PI_FMC_DESCR_K_RCC_FMC_INT_ERR 0x01AA + +#define PI_FMC_DESCR_K_RRR_SUCCESS 0x00 +#define PI_FMC_DESCR_K_RRR_SA_MATCH 0x01 +#define PI_FMC_DESCR_K_RRR_DA_MATCH 0x02 +#define PI_FMC_DESCR_K_RRR_FMC_ABORT 0x03 +#define PI_FMC_DESCR_K_RRR_LENGTH_BAD 0x04 +#define PI_FMC_DESCR_K_RRR_FRAGMENT 0x05 +#define PI_FMC_DESCR_K_RRR_FORMAT_ERR 0x06 +#define PI_FMC_DESCR_K_RRR_MAC_RESET 0x07 + +#define PI_FMC_DESCR_K_DD_NO_MATCH 0x0 +#define PI_FMC_DESCR_K_DD_PROMISCUOUS 0x1 +#define PI_FMC_DESCR_K_DD_CAM_MATCH 0x2 +#define PI_FMC_DESCR_K_DD_LOCAL_MATCH 0x3 + +#define PI_FMC_DESCR_K_SS_NO_MATCH 0x0 +#define PI_FMC_DESCR_K_SS_BRIDGE_MATCH 0x1 +#define PI_FMC_DESCR_K_SS_NOT_POSSIBLE 0x2 +#define PI_FMC_DESCR_K_SS_LOCAL_MATCH 0x3 + +/* Define some max buffer sizes */ + +#define PI_CMD_REQ_K_SIZE_MAX 512 +#define PI_CMD_RSP_K_SIZE_MAX 512 +#define PI_UNSOL_K_SIZE_MAX 512 +#define PI_SMT_HOST_K_SIZE_MAX 4608 /* 4 1/2 K */ +#define PI_RCV_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ +#define PI_XMT_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ + +/* Define adapter states */ + +#define PI_STATE_K_RESET 0 +#define PI_STATE_K_UPGRADE 1 +#define PI_STATE_K_DMA_UNAVAIL 2 +#define PI_STATE_K_DMA_AVAIL 3 +#define PI_STATE_K_LINK_AVAIL 4 +#define PI_STATE_K_LINK_UNAVAIL 5 +#define PI_STATE_K_HALTED 6 +#define PI_STATE_K_RING_MEMBER 7 +#define PI_STATE_K_NUMBER 8 + +/* Define codes for command type */ + +#define PI_CMD_K_START 0x00 +#define PI_CMD_K_FILTERS_SET 0x01 +#define PI_CMD_K_FILTERS_GET 0x02 +#define PI_CMD_K_CHARS_SET 0x03 +#define PI_CMD_K_STATUS_CHARS_GET 0x04 +#define PI_CMD_K_CNTRS_GET 0x05 +#define PI_CMD_K_CNTRS_SET 0x06 +#define PI_CMD_K_ADDR_FILTER_SET 0x07 +#define PI_CMD_K_ADDR_FILTER_GET 0x08 +#define PI_CMD_K_ERROR_LOG_CLEAR 0x09 +#define PI_CMD_K_ERROR_LOG_GET 0x0A +#define PI_CMD_K_FDDI_MIB_GET 0x0B +#define PI_CMD_K_DEC_EXT_MIB_GET 0x0C +#define PI_CMD_K_DEVICE_SPECIFIC_GET 0x0D +#define PI_CMD_K_SNMP_SET 0x0E +#define PI_CMD_K_UNSOL_TEST 0x0F +#define PI_CMD_K_SMT_MIB_GET 0x10 +#define PI_CMD_K_SMT_MIB_SET 0x11 +#define PI_CMD_K_MAX 0x11 /* Must match last */ + +/* Define item codes for Chars_Set and Filters_Set commands */ + +#define PI_ITEM_K_EOL 0x00 /* End-of-Item list */ +#define PI_ITEM_K_T_REQ 0x01 /* DECnet T_REQ */ +#define PI_ITEM_K_TVX 0x02 /* DECnet TVX */ +#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */ +#define PI_ITEM_K_LEM_THRESHOLD 0x04 /* DECnet LEM Threshold */ +#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */ +#define PI_ITEM_K_CNTR_INTERVAL 0x06 /* Chars_Set */ +#define PI_ITEM_K_IND_GROUP_PROM 0x07 /* Filters_Set */ +#define PI_ITEM_K_GROUP_PROM 0x08 /* Filters_Set */ +#define PI_ITEM_K_BROADCAST 0x09 /* Filters_Set */ +#define PI_ITEM_K_SMT_PROM 0x0A /* Filters_Set */ +#define PI_ITEM_K_SMT_USER 0x0B /* Filters_Set */ +#define PI_ITEM_K_RESERVED 0x0C /* Filters_Set */ +#define PI_ITEM_K_IMPLEMENTOR 0x0D /* Filters_Set */ +#define PI_ITEM_K_LOOPBACK_MODE 0x0E /* Chars_Set */ +#define PI_ITEM_K_CONFIG_POLICY 0x10 /* SMTConfigPolicy */ +#define PI_ITEM_K_CON_POLICY 0x11 /* SMTConnectionPolicy */ +#define PI_ITEM_K_T_NOTIFY 0x12 /* SMTTNotify */ +#define PI_ITEM_K_STATION_ACTION 0x13 /* SMTStationAction */ +#define PI_ITEM_K_MAC_PATHS_REQ 0x15 /* MACPathsRequested */ +#define PI_ITEM_K_MAC_ACTION 0x17 /* MACAction */ +#define PI_ITEM_K_CON_POLICIES 0x18 /* PORTConnectionPolicies */ +#define PI_ITEM_K_PORT_PATHS_REQ 0x19 /* PORTPathsRequested */ +#define PI_ITEM_K_MAC_LOOP_TIME 0x1A /* PORTMACLoopTime */ +#define PI_ITEM_K_TB_MAX 0x1B /* PORTTBMax */ +#define PI_ITEM_K_LER_CUTOFF 0x1C /* PORTLerCutoff */ +#define PI_ITEM_K_LER_ALARM 0x1D /* PORTLerAlarm */ +#define PI_ITEM_K_PORT_ACTION 0x1E /* PORTAction */ +#define PI_ITEM_K_FLUSH_TIME 0x20 /* Chars_Set */ +#define PI_ITEM_K_MAC_T_REQ 0x29 /* MACTReq */ +#define PI_ITEM_K_EMAC_RING_PURGER 0x2A /* eMACRingPurgerEnable */ +#define PI_ITEM_K_EMAC_RTOKEN_TIMEOUT 0x2B /* eMACRestrictedTokenTimeout */ +#define PI_ITEM_K_FDX_ENB_DIS 0x2C /* eFDXEnable */ +#define PI_ITEM_K_MAX 0x2C /* Must equal high item */ + +/* Values for some of the items */ + +#define PI_K_FALSE 0 /* Generic false */ +#define PI_K_TRUE 1 /* Generic true */ + +#define PI_SNMP_K_TRUE 1 /* SNMP true/false values */ +#define PI_SNMP_K_FALSE 2 + +#define PI_FSTATE_K_BLOCK 0 /* Filter State */ +#define PI_FSTATE_K_PASS 1 + +/* Define command return codes */ + +#define PI_RSP_K_SUCCESS 0x00 +#define PI_RSP_K_FAILURE 0x01 +#define PI_RSP_K_WARNING 0x02 +#define PI_RSP_K_LOOP_MODE_BAD 0x03 +#define PI_RSP_K_ITEM_CODE_BAD 0x04 +#define PI_RSP_K_TVX_BAD 0x05 +#define PI_RSP_K_TREQ_BAD 0x06 +#define PI_RSP_K_TOKEN_BAD 0x07 +#define PI_RSP_K_NO_EOL 0x0C +#define PI_RSP_K_FILTER_STATE_BAD 0x0D +#define PI_RSP_K_CMD_TYPE_BAD 0x0E +#define PI_RSP_K_ADAPTER_STATE_BAD 0x0F +#define PI_RSP_K_RING_PURGER_BAD 0x10 +#define PI_RSP_K_LEM_THRESHOLD_BAD 0x11 +#define PI_RSP_K_LOOP_NOT_SUPPORTED 0x12 +#define PI_RSP_K_FLUSH_TIME_BAD 0x13 +#define PI_RSP_K_NOT_IMPLEMENTED 0x14 +#define PI_RSP_K_CONFIG_POLICY_BAD 0x15 +#define PI_RSP_K_STATION_ACTION_BAD 0x16 +#define PI_RSP_K_MAC_ACTION_BAD 0x17 +#define PI_RSP_K_CON_POLICIES_BAD 0x18 +#define PI_RSP_K_MAC_LOOP_TIME_BAD 0x19 +#define PI_RSP_K_TB_MAX_BAD 0x1A +#define PI_RSP_K_LER_CUTOFF_BAD 0x1B +#define PI_RSP_K_LER_ALARM_BAD 0x1C +#define PI_RSP_K_MAC_PATHS_REQ_BAD 0x1D +#define PI_RSP_K_MAC_T_REQ_BAD 0x1E +#define PI_RSP_K_EMAC_RING_PURGER_BAD 0x1F +#define PI_RSP_K_EMAC_RTOKEN_TIME_BAD 0x20 +#define PI_RSP_K_NO_SUCH_ENTRY 0x21 +#define PI_RSP_K_T_NOTIFY_BAD 0x22 +#define PI_RSP_K_TR_MAX_EXP_BAD 0x23 +#define PI_RSP_K_MAC_FRM_ERR_THR_BAD 0x24 +#define PI_RSP_K_MAX_T_REQ_BAD 0x25 +#define PI_RSP_K_FDX_ENB_DIS_BAD 0x26 +#define PI_RSP_K_ITEM_INDEX_BAD 0x27 +#define PI_RSP_K_PORT_ACTION_BAD 0x28 + +/* Commonly used structures */ + +typedef struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + } PI_ITEM_LIST; + +typedef struct /* Response header */ + { + PI_UINT32 reserved; + PI_UINT32 cmd_type; + PI_UINT32 status; + } PI_RSP_HEADER; + + +/* Start Command */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_START_REQ; + +/* Start Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_START_RSP; + +/* Filters_Set Request */ + +#define PI_CMD_FILTERS_SET_K_ITEMS_MAX 63 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_ITEM_LIST item[PI_CMD_FILTERS_SET_K_ITEMS_MAX]; + } PI_CMD_FILTERS_SET_REQ; + +/* Filters_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_FILTERS_SET_RSP; + +/* Filters_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_FILTERS_GET_REQ; + +/* Filters_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_UINT32 ind_group_prom; + PI_UINT32 group_prom; + PI_UINT32 broadcast_all; + PI_UINT32 smt_all; + PI_UINT32 smt_user; + PI_UINT32 reserved_all; + PI_UINT32 implementor_all; + } PI_CMD_FILTERS_GET_RSP; + + +/* Chars_Set Request */ + +#define PI_CMD_CHARS_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_CHARS_SET_K_ITEMS_MAX]; + } PI_CMD_CHARS_SET_REQ; + +/* Chars_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_CHARS_SET_RSP; + + +/* SNMP_Set Request */ + +#define PI_CMD_SNMP_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_SNMP_SET_K_ITEMS_MAX]; + } PI_CMD_SNMP_SET_REQ; + +/* SNMP_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_SNMP_SET_RSP; + + +/* SMT_MIB_Set Request */ + +#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */ + +typedef struct + { + PI_UINT32 cmd_type; + struct + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_SMT_MIB_SET_K_ITEMS_MAX]; + } PI_CMD_SMT_MIB_SET_REQ; + +/* SMT_MIB_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_SMT_MIB_SET_RSP; + +/* SMT_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_SMT_MIB_GET_REQ; + +/* SMT_MIB_Get Response */ + +typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */ + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_STATION_ID smt_station_id; + PI_UINT32 smt_op_version_id; + PI_UINT32 smt_hi_version_id; + PI_UINT32 smt_lo_version_id; + PI_UINT32 smt_user_data[8]; + PI_UINT32 smt_mib_version_id; + PI_UINT32 smt_mac_ct; + PI_UINT32 smt_non_master_ct; + PI_UINT32 smt_master_ct; + PI_UINT32 smt_available_paths; + PI_UINT32 smt_config_capabilities; + PI_UINT32 smt_config_policy; + PI_UINT32 smt_connection_policy; + PI_UINT32 smt_t_notify; + PI_UINT32 smt_stat_rpt_policy; + PI_UINT32 smt_trace_max_expiration; + PI_UINT32 smt_bypass_present; + PI_UINT32 smt_ecm_state; + PI_UINT32 smt_cf_state; + PI_UINT32 smt_remote_disconnect_flag; + PI_UINT32 smt_station_status; + PI_UINT32 smt_peer_wrap_flag; + PI_CNTR smt_msg_time_stamp; + PI_CNTR smt_transition_time_stamp; + + /* MAC GROUP */ + + PI_UINT32 mac_frame_status_functions; + PI_UINT32 mac_t_max_capability; + PI_UINT32 mac_tvx_capability; + PI_UINT32 mac_available_paths; + PI_UINT32 mac_current_path; + PI_LAN_ADDR mac_upstream_nbr; + PI_LAN_ADDR mac_downstream_nbr; + PI_LAN_ADDR mac_old_upstream_nbr; + PI_LAN_ADDR mac_old_downstream_nbr; + PI_UINT32 mac_dup_address_test; + PI_UINT32 mac_requested_paths; + PI_UINT32 mac_downstream_port_type; + PI_LAN_ADDR mac_smt_address; + PI_UINT32 mac_t_req; + PI_UINT32 mac_t_neg; + PI_UINT32 mac_t_max; + PI_UINT32 mac_tvx_value; + PI_UINT32 mac_frame_error_threshold; + PI_UINT32 mac_frame_error_ratio; + PI_UINT32 mac_rmt_state; + PI_UINT32 mac_da_flag; + PI_UINT32 mac_unda_flag; + PI_UINT32 mac_frame_error_flag; + PI_UINT32 mac_ma_unitdata_available; + PI_UINT32 mac_hardware_present; + PI_UINT32 mac_ma_unitdata_enable; + + /* PATH GROUP */ + + PI_UINT32 path_configuration[8]; + PI_UINT32 path_tvx_lower_bound; + PI_UINT32 path_t_max_lower_bound; + PI_UINT32 path_max_t_req; + + /* PORT GROUP */ + + PI_UINT32 port_my_type[PI_PHY_K_MAX]; + PI_UINT32 port_neighbor_type[PI_PHY_K_MAX]; + PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; + PI_UINT32 port_mac_indicated[PI_PHY_K_MAX]; + PI_UINT32 port_current_path[PI_PHY_K_MAX]; + PI_UINT32 port_requested_paths[PI_PHY_K_MAX]; + PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; + PI_UINT32 port_available_paths[PI_PHY_K_MAX]; + PI_UINT32 port_pmd_class[PI_PHY_K_MAX]; + PI_UINT32 port_connection_capabilities[PI_PHY_K_MAX]; + PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; + PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; + PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; + PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; + PI_UINT32 port_connect_state[PI_PHY_K_MAX]; + PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; + PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; + PI_UINT32 port_ler_flag[PI_PHY_K_MAX]; + PI_UINT32 port_hardware_present[PI_PHY_K_MAX]; + + /* GROUP for things that were added later, so must be at the end. */ + + PI_CNTR path_ring_latency; + + } PI_CMD_SMT_MIB_GET_RSP; + + +/* + * Item and group code definitions for SMT 7.3 mandatory objects. These + * definitions are to be used as appropriate in SMT_MIB_SET commands and + * certain host-sent SMT frames such as PMF Get and Set requests. The + * codes have been taken from the MIB summary section of ANSI SMT 7.3. + */ + +#define PI_GRP_K_SMT_STATION_ID 0x100A +#define PI_ITEM_K_SMT_STATION_ID 0x100B +#define PI_ITEM_K_SMT_OP_VERS_ID 0x100D +#define PI_ITEM_K_SMT_HI_VERS_ID 0x100E +#define PI_ITEM_K_SMT_LO_VERS_ID 0x100F +#define PI_ITEM_K_SMT_USER_DATA 0x1011 +#define PI_ITEM_K_SMT_MIB_VERS_ID 0x1012 + +#define PI_GRP_K_SMT_STATION_CONFIG 0x1014 +#define PI_ITEM_K_SMT_MAC_CT 0x1015 +#define PI_ITEM_K_SMT_NON_MASTER_CT 0x1016 +#define PI_ITEM_K_SMT_MASTER_CT 0x1017 +#define PI_ITEM_K_SMT_AVAIL_PATHS 0x1018 +#define PI_ITEM_K_SMT_CONFIG_CAPS 0x1019 +#define PI_ITEM_K_SMT_CONFIG_POL 0x101A +#define PI_ITEM_K_SMT_CONN_POL 0x101B +#define PI_ITEM_K_SMT_T_NOTIFY 0x101D +#define PI_ITEM_K_SMT_STAT_POL 0x101E +#define PI_ITEM_K_SMT_TR_MAX_EXP 0x101F +#define PI_ITEM_K_SMT_PORT_INDEXES 0x1020 +#define PI_ITEM_K_SMT_MAC_INDEXES 0x1021 +#define PI_ITEM_K_SMT_BYPASS_PRESENT 0x1022 + +#define PI_GRP_K_SMT_STATUS 0x1028 +#define PI_ITEM_K_SMT_ECM_STATE 0x1029 +#define PI_ITEM_K_SMT_CF_STATE 0x102A +#define PI_ITEM_K_SMT_REM_DISC_FLAG 0x102C +#define PI_ITEM_K_SMT_STATION_STATUS 0x102D +#define PI_ITEM_K_SMT_PEER_WRAP_FLAG 0x102E + +#define PI_GRP_K_SMT_MIB_OPERATION 0x1032 +#define PI_ITEM_K_SMT_MSG_TIME_STAMP 0x1033 +#define PI_ITEM_K_SMT_TRN_TIME_STAMP 0x1034 + +#define PI_ITEM_K_SMT_STATION_ACT 0x103C + +#define PI_GRP_K_MAC_CAPABILITIES 0x200A +#define PI_ITEM_K_MAC_FRM_STAT_FUNC 0x200B +#define PI_ITEM_K_MAC_T_MAX_CAP 0x200D +#define PI_ITEM_K_MAC_TVX_CAP 0x200E + +#define PI_GRP_K_MAC_CONFIG 0x2014 +#define PI_ITEM_K_MAC_AVAIL_PATHS 0x2016 +#define PI_ITEM_K_MAC_CURRENT_PATH 0x2017 +#define PI_ITEM_K_MAC_UP_NBR 0x2018 +#define PI_ITEM_K_MAC_DOWN_NBR 0x2019 +#define PI_ITEM_K_MAC_OLD_UP_NBR 0x201A +#define PI_ITEM_K_MAC_OLD_DOWN_NBR 0x201B +#define PI_ITEM_K_MAC_DUP_ADDR_TEST 0x201D +#define PI_ITEM_K_MAC_REQ_PATHS 0x2020 +#define PI_ITEM_K_MAC_DOWN_PORT_TYPE 0x2021 +#define PI_ITEM_K_MAC_INDEX 0x2022 + +#define PI_GRP_K_MAC_ADDRESS 0x2028 +#define PI_ITEM_K_MAC_SMT_ADDRESS 0x2029 + +#define PI_GRP_K_MAC_OPERATION 0x2032 +#define PI_ITEM_K_MAC_TREQ 0x2033 +#define PI_ITEM_K_MAC_TNEG 0x2034 +#define PI_ITEM_K_MAC_TMAX 0x2035 +#define PI_ITEM_K_MAC_TVX_VALUE 0x2036 + +#define PI_GRP_K_MAC_COUNTERS 0x2046 +#define PI_ITEM_K_MAC_FRAME_CT 0x2047 +#define PI_ITEM_K_MAC_COPIED_CT 0x2048 +#define PI_ITEM_K_MAC_TRANSMIT_CT 0x2049 +#define PI_ITEM_K_MAC_ERROR_CT 0x2051 +#define PI_ITEM_K_MAC_LOST_CT 0x2052 + +#define PI_GRP_K_MAC_FRM_ERR_COND 0x205A +#define PI_ITEM_K_MAC_FRM_ERR_THR 0x205F +#define PI_ITEM_K_MAC_FRM_ERR_RAT 0x2060 + +#define PI_GRP_K_MAC_STATUS 0x206E +#define PI_ITEM_K_MAC_RMT_STATE 0x206F +#define PI_ITEM_K_MAC_DA_FLAG 0x2070 +#define PI_ITEM_K_MAC_UNDA_FLAG 0x2071 +#define PI_ITEM_K_MAC_FRM_ERR_FLAG 0x2072 +#define PI_ITEM_K_MAC_MA_UNIT_AVAIL 0x2074 +#define PI_ITEM_K_MAC_HW_PRESENT 0x2075 +#define PI_ITEM_K_MAC_MA_UNIT_ENAB 0x2076 + +#define PI_GRP_K_PATH_CONFIG 0x320A +#define PI_ITEM_K_PATH_INDEX 0x320B +#define PI_ITEM_K_PATH_CONFIGURATION 0x3212 +#define PI_ITEM_K_PATH_TVX_LB 0x3215 +#define PI_ITEM_K_PATH_T_MAX_LB 0x3216 +#define PI_ITEM_K_PATH_MAX_T_REQ 0x3217 + +#define PI_GRP_K_PORT_CONFIG 0x400A +#define PI_ITEM_K_PORT_MY_TYPE 0x400C +#define PI_ITEM_K_PORT_NBR_TYPE 0x400D +#define PI_ITEM_K_PORT_CONN_POLS 0x400E +#define PI_ITEM_K_PORT_MAC_INDICATED 0x400F +#define PI_ITEM_K_PORT_CURRENT_PATH 0x4010 +#define PI_ITEM_K_PORT_REQ_PATHS 0x4011 +#define PI_ITEM_K_PORT_MAC_PLACEMENT 0x4012 +#define PI_ITEM_K_PORT_AVAIL_PATHS 0x4013 +#define PI_ITEM_K_PORT_PMD_CLASS 0x4016 +#define PI_ITEM_K_PORT_CONN_CAPS 0x4017 +#define PI_ITEM_K_PORT_INDEX 0x401D + +#define PI_GRP_K_PORT_OPERATION 0x401E +#define PI_ITEM_K_PORT_BS_FLAG 0x4021 + +#define PI_GRP_K_PORT_ERR_CNTRS 0x4028 +#define PI_ITEM_K_PORT_LCT_FAIL_CT 0x402A + +#define PI_GRP_K_PORT_LER 0x4032 +#define PI_ITEM_K_PORT_LER_ESTIMATE 0x4033 +#define PI_ITEM_K_PORT_LEM_REJ_CT 0x4034 +#define PI_ITEM_K_PORT_LEM_CT 0x4035 +#define PI_ITEM_K_PORT_LER_CUTOFF 0x403A +#define PI_ITEM_K_PORT_LER_ALARM 0x403B + +#define PI_GRP_K_PORT_STATUS 0x403C +#define PI_ITEM_K_PORT_CONNECT_STATE 0x403D +#define PI_ITEM_K_PORT_PCM_STATE 0x403E +#define PI_ITEM_K_PORT_PC_WITHHOLD 0x403F +#define PI_ITEM_K_PORT_LER_FLAG 0x4040 +#define PI_ITEM_K_PORT_HW_PRESENT 0x4041 + +#define PI_ITEM_K_PORT_ACT 0x4046 + +/* Addr_Filter_Set Request */ + +#define PI_CMD_ADDR_FILTER_K_SIZE 62 + +typedef struct + { + PI_UINT32 cmd_type; + PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; + } PI_CMD_ADDR_FILTER_SET_REQ; + +/* Addr_Filter_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_ADDR_FILTER_SET_RSP; + +/* Addr_Filter_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_ADDR_FILTER_GET_REQ; + +/* Addr_Filter_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; + } PI_CMD_ADDR_FILTER_GET_RSP; + +/* Status_Chars_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_STATUS_CHARS_GET_REQ; + +/* Status_Chars_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_STATION_ID station_id; /* Station */ + PI_UINT32 station_type; + PI_UINT32 smt_ver_id; + PI_UINT32 smt_ver_id_max; + PI_UINT32 smt_ver_id_min; + PI_UINT32 station_state; + PI_LAN_ADDR link_addr; /* Link */ + PI_UINT32 t_req; + PI_UINT32 tvx; + PI_UINT32 token_timeout; + PI_UINT32 purger_enb; + PI_UINT32 link_state; + PI_UINT32 tneg; + PI_UINT32 dup_addr_flag; + PI_LAN_ADDR una; + PI_LAN_ADDR una_old; + PI_UINT32 un_dup_addr_flag; + PI_LAN_ADDR dna; + PI_LAN_ADDR dna_old; + PI_UINT32 purger_state; + PI_UINT32 fci_mode; + PI_UINT32 error_reason; + PI_UINT32 loopback; + PI_UINT32 ring_latency; + PI_LAN_ADDR last_dir_beacon_sa; + PI_LAN_ADDR last_dir_beacon_una; + PI_UINT32 phy_type[PI_PHY_K_MAX]; /* Phy */ + PI_UINT32 pmd_type[PI_PHY_K_MAX]; + PI_UINT32 lem_threshold[PI_PHY_K_MAX]; + PI_UINT32 phy_state[PI_PHY_K_MAX]; + PI_UINT32 nbor_phy_type[PI_PHY_K_MAX]; + PI_UINT32 link_error_est[PI_PHY_K_MAX]; + PI_UINT32 broken_reason[PI_PHY_K_MAX]; + PI_UINT32 reject_reason[PI_PHY_K_MAX]; + PI_UINT32 cntr_interval; /* Miscellaneous */ + PI_UINT32 module_rev; + PI_UINT32 firmware_rev; + PI_UINT32 mop_device_type; + PI_UINT32 phy_led[PI_PHY_K_MAX]; + PI_UINT32 flush_time; + } PI_CMD_STATUS_CHARS_GET_RSP; + +/* FDDI_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_FDDI_MIB_GET_REQ; + +/* FDDI_MIB_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_STATION_ID smt_station_id; + PI_UINT32 smt_op_version_id; + PI_UINT32 smt_hi_version_id; + PI_UINT32 smt_lo_version_id; + PI_UINT32 smt_mac_ct; + PI_UINT32 smt_non_master_ct; + PI_UINT32 smt_master_ct; + PI_UINT32 smt_paths_available; + PI_UINT32 smt_config_capabilities; + PI_UINT32 smt_config_policy; + PI_UINT32 smt_connection_policy; + PI_UINT32 smt_t_notify; + PI_UINT32 smt_status_reporting; + PI_UINT32 smt_ecm_state; + PI_UINT32 smt_cf_state; + PI_UINT32 smt_hold_state; + PI_UINT32 smt_remote_disconnect_flag; + PI_UINT32 smt_station_action; + + /* MAC GROUP */ + + PI_UINT32 mac_frame_status_capabilities; + PI_UINT32 mac_t_max_greatest_lower_bound; + PI_UINT32 mac_tvx_greatest_lower_bound; + PI_UINT32 mac_paths_available; + PI_UINT32 mac_current_path; + PI_LAN_ADDR mac_upstream_nbr; + PI_LAN_ADDR mac_old_upstream_nbr; + PI_UINT32 mac_dup_addr_test; + PI_UINT32 mac_paths_requested; + PI_UINT32 mac_downstream_port_type; + PI_LAN_ADDR mac_smt_address; + PI_UINT32 mac_t_req; + PI_UINT32 mac_t_neg; + PI_UINT32 mac_t_max; + PI_UINT32 mac_tvx_value; + PI_UINT32 mac_t_min; + PI_UINT32 mac_current_frame_status; + /* mac_frame_cts */ + /* mac_error_cts */ + /* mac_lost_cts */ + PI_UINT32 mac_frame_error_threshold; + PI_UINT32 mac_frame_error_ratio; + PI_UINT32 mac_rmt_state; + PI_UINT32 mac_da_flag; + PI_UINT32 mac_una_da_flag; + PI_UINT32 mac_frame_condition; + PI_UINT32 mac_chip_set; + PI_UINT32 mac_action; + + /* PATH GROUP => Does not need to be implemented */ + + /* PORT GROUP */ + + PI_UINT32 port_pc_type[PI_PHY_K_MAX]; + PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX]; + PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; + PI_UINT32 port_remote_mac_indicated[PI_PHY_K_MAX]; + PI_UINT32 port_ce_state[PI_PHY_K_MAX]; + PI_UINT32 port_paths_requested[PI_PHY_K_MAX]; + PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; + PI_UINT32 port_available_paths[PI_PHY_K_MAX]; + PI_UINT32 port_mac_loop_time[PI_PHY_K_MAX]; + PI_UINT32 port_tb_max[PI_PHY_K_MAX]; + PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; + /* port_lct_fail_cts[PI_PHY_K_MAX]; */ + PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; + /* port_lem_reject_cts[PI_PHY_K_MAX]; */ + /* port_lem_cts[PI_PHY_K_MAX]; */ + PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; + PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; + PI_UINT32 port_connect_state[PI_PHY_K_MAX]; + PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; + PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; + PI_UINT32 port_ler_condition[PI_PHY_K_MAX]; + PI_UINT32 port_chip_set[PI_PHY_K_MAX]; + PI_UINT32 port_action[PI_PHY_K_MAX]; + + /* ATTACHMENT GROUP */ + + PI_UINT32 attachment_class; + PI_UINT32 attachment_ob_present; + PI_UINT32 attachment_imax_expiration; + PI_UINT32 attachment_inserted_status; + PI_UINT32 attachment_insert_policy; + + /* CHIP SET GROUP => Does not need to be implemented */ + + } PI_CMD_FDDI_MIB_GET_RSP; + +/* DEC_Ext_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_DEC_EXT_MIB_GET_REQ; + +/* DEC_Ext_MIB_Get (efddi and efdx groups only) Response */ + +typedef struct + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_UINT32 esmt_station_type; + + /* MAC GROUP */ + + PI_UINT32 emac_link_state; + PI_UINT32 emac_ring_purger_state; + PI_UINT32 emac_ring_purger_enable; + PI_UINT32 emac_frame_strip_mode; + PI_UINT32 emac_ring_error_reason; + PI_UINT32 emac_up_nbr_dup_addr_flag; + PI_UINT32 emac_restricted_token_timeout; + + /* PORT GROUP */ + + PI_UINT32 eport_pmd_type[PI_PHY_K_MAX]; + PI_UINT32 eport_phy_state[PI_PHY_K_MAX]; + PI_UINT32 eport_reject_reason[PI_PHY_K_MAX]; + + /* FDX (Full-Duplex) GROUP */ + + PI_UINT32 efdx_enable; /* Valid only in SMT 7.3 */ + PI_UINT32 efdx_op; /* Valid only in SMT 7.3 */ + PI_UINT32 efdx_state; /* Valid only in SMT 7.3 */ + + } PI_CMD_DEC_EXT_MIB_GET_RSP; + +typedef struct + { + PI_CNTR traces_rcvd; /* Station */ + PI_CNTR frame_cnt; /* Link */ + PI_CNTR error_cnt; + PI_CNTR lost_cnt; + PI_CNTR octets_rcvd; + PI_CNTR octets_sent; + PI_CNTR pdus_rcvd; + PI_CNTR pdus_sent; + PI_CNTR mcast_octets_rcvd; + PI_CNTR mcast_octets_sent; + PI_CNTR mcast_pdus_rcvd; + PI_CNTR mcast_pdus_sent; + PI_CNTR xmt_underruns; + PI_CNTR xmt_failures; + PI_CNTR block_check_errors; + PI_CNTR frame_status_errors; + PI_CNTR pdu_length_errors; + PI_CNTR rcv_overruns; + PI_CNTR user_buff_unavailable; + PI_CNTR inits_initiated; + PI_CNTR inits_rcvd; + PI_CNTR beacons_initiated; + PI_CNTR dup_addrs; + PI_CNTR dup_tokens; + PI_CNTR purge_errors; + PI_CNTR fci_strip_errors; + PI_CNTR traces_initiated; + PI_CNTR directed_beacons_rcvd; + PI_CNTR emac_frame_alignment_errors; + PI_CNTR ebuff_errors[PI_PHY_K_MAX]; /* Phy */ + PI_CNTR lct_rejects[PI_PHY_K_MAX]; + PI_CNTR lem_rejects[PI_PHY_K_MAX]; + PI_CNTR link_errors[PI_PHY_K_MAX]; + PI_CNTR connections[PI_PHY_K_MAX]; + PI_CNTR copied_cnt; /* Valid only if using SMT 7.3 */ + PI_CNTR transmit_cnt; /* Valid only if using SMT 7.3 */ + PI_CNTR tokens; + } PI_CNTR_BLK; + +/* Counters_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_CNTRS_GET_REQ; + +/* Counters_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_CNTR time_since_reset; + PI_CNTR_BLK cntrs; + } PI_CMD_CNTRS_GET_RSP; + +/* Counters_Set Request */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_CNTR_BLK cntrs; + } PI_CMD_CNTRS_SET_REQ; + +/* Counters_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_CNTRS_SET_RSP; + +/* Error_Log_Clear Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_ERROR_LOG_CLEAR_REQ; + +/* Error_Log_Clear Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_ERROR_LOG_CLEAR_RSP; + +/* Error_Log_Get Request */ + +#define PI_LOG_ENTRY_K_INDEX_MIN 0 /* Minimum index for entry */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_UINT32 entry_index; + } PI_CMD_ERROR_LOG_GET_REQ; + +/* Error_Log_Get Response */ + +#define PI_K_LOG_FW_SIZE 111 /* Max number of fw longwords */ +#define PI_K_LOG_DIAG_SIZE 6 /* Max number of diag longwords */ + +typedef struct + { + struct + { + PI_UINT32 fru_imp_mask; + PI_UINT32 test_id; + PI_UINT32 reserved[PI_K_LOG_DIAG_SIZE]; + } diag; + PI_UINT32 fw[PI_K_LOG_FW_SIZE]; + } PI_LOG_ENTRY; + +typedef struct + { + PI_RSP_HEADER header; + PI_UINT32 event_status; + PI_UINT32 caller_id; + PI_UINT32 timestamp_l; + PI_UINT32 timestamp_h; + PI_UINT32 write_count; + PI_LOG_ENTRY entry_info; + } PI_CMD_ERROR_LOG_GET_RSP; + +/* Define error log related constants and types. */ +/* Not all of the caller id's can occur. The only ones currently */ +/* implemented are: none, selftest, mfg, fw, console */ + +#define PI_LOG_EVENT_STATUS_K_VALID 0 /* Valid Event Status */ +#define PI_LOG_EVENT_STATUS_K_INVALID 1 /* Invalid Event Status */ +#define PI_LOG_CALLER_ID_K_NONE 0 /* No caller */ +#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */ +#define PI_LOG_CALLER_ID_K_MFG 2 /* Mfg power-up selftest */ +#define PI_LOG_CALLER_ID_K_ONLINE 3 /* On-line diagnostics */ +#define PI_LOG_CALLER_ID_K_HW 4 /* Hardware */ +#define PI_LOG_CALLER_ID_K_FW 5 /* Firmware */ +#define PI_LOG_CALLER_ID_K_CNS_HW 6 /* CNS firmware */ +#define PI_LOG_CALLER_ID_K_CNS_FW 7 /* CNS hardware */ +#define PI_LOG_CALLER_ID_K_CONSOLE 8 /* Console Caller Id */ + +/* + * Place all DMA commands in the following request and response structures + * to simplify code. + */ + +typedef union + { + PI_UINT32 cmd_type; + PI_CMD_START_REQ start; + PI_CMD_FILTERS_SET_REQ filter_set; + PI_CMD_FILTERS_GET_REQ filter_get; + PI_CMD_CHARS_SET_REQ char_set; + PI_CMD_ADDR_FILTER_SET_REQ addr_filter_set; + PI_CMD_ADDR_FILTER_GET_REQ addr_filter_get; + PI_CMD_STATUS_CHARS_GET_REQ stat_char_get; + PI_CMD_CNTRS_GET_REQ cntrs_get; + PI_CMD_CNTRS_SET_REQ cntrs_set; + PI_CMD_ERROR_LOG_CLEAR_REQ error_log_clear; + PI_CMD_ERROR_LOG_GET_REQ error_log_read; + PI_CMD_SNMP_SET_REQ snmp_set; + PI_CMD_FDDI_MIB_GET_REQ fddi_mib_get; + PI_CMD_DEC_EXT_MIB_GET_REQ dec_mib_get; + PI_CMD_SMT_MIB_SET_REQ smt_mib_set; + PI_CMD_SMT_MIB_GET_REQ smt_mib_get; + char pad[PI_CMD_REQ_K_SIZE_MAX]; + } PI_DMA_CMD_REQ; + +typedef union + { + PI_RSP_HEADER header; + PI_CMD_START_RSP start; + PI_CMD_FILTERS_SET_RSP filter_set; + PI_CMD_FILTERS_GET_RSP filter_get; + PI_CMD_CHARS_SET_RSP char_set; + PI_CMD_ADDR_FILTER_SET_RSP addr_filter_set; + PI_CMD_ADDR_FILTER_GET_RSP addr_filter_get; + PI_CMD_STATUS_CHARS_GET_RSP stat_char_get; + PI_CMD_CNTRS_GET_RSP cntrs_get; + PI_CMD_CNTRS_SET_RSP cntrs_set; + PI_CMD_ERROR_LOG_CLEAR_RSP error_log_clear; + PI_CMD_ERROR_LOG_GET_RSP error_log_get; + PI_CMD_SNMP_SET_RSP snmp_set; + PI_CMD_FDDI_MIB_GET_RSP fddi_mib_get; + PI_CMD_DEC_EXT_MIB_GET_RSP dec_mib_get; + PI_CMD_SMT_MIB_SET_RSP smt_mib_set; + PI_CMD_SMT_MIB_GET_RSP smt_mib_get; + char pad[PI_CMD_RSP_K_SIZE_MAX]; + } PI_DMA_CMD_RSP; + +typedef union + { + PI_DMA_CMD_REQ request; + PI_DMA_CMD_RSP response; + } PI_DMA_CMD_BUFFER; + + +/* Define format of Consumer Block (resident in host memory) */ + +typedef struct + { + volatile PI_UINT32 xmt_rcv_data; + volatile PI_UINT32 reserved_1; + volatile PI_UINT32 smt_host; + volatile PI_UINT32 reserved_2; + volatile PI_UINT32 unsol; + volatile PI_UINT32 reserved_3; + volatile PI_UINT32 cmd_rsp; + volatile PI_UINT32 reserved_4; + volatile PI_UINT32 cmd_req; + volatile PI_UINT32 reserved_5; + } PI_CONSUMER_BLOCK; + +#define PI_CONS_M_RCV_INDEX 0x000000FF +#define PI_CONS_M_XMT_INDEX 0x00FF0000 +#define PI_CONS_V_RCV_INDEX 0 +#define PI_CONS_V_XMT_INDEX 16 + +/* Offsets into consumer block */ + +#define PI_CONS_BLK_K_XMT_RCV 0x00 +#define PI_CONS_BLK_K_SMT_HOST 0x08 +#define PI_CONS_BLK_K_UNSOL 0x10 +#define PI_CONS_BLK_K_CMD_RSP 0x18 +#define PI_CONS_BLK_K_CMD_REQ 0x20 + +/* Offsets into descriptor block */ + +#define PI_DESCR_BLK_K_RCV_DATA 0x0000 +#define PI_DESCR_BLK_K_XMT_DATA 0x0800 +#define PI_DESCR_BLK_K_SMT_HOST 0x1000 +#define PI_DESCR_BLK_K_UNSOL 0x1200 +#define PI_DESCR_BLK_K_CMD_RSP 0x1280 +#define PI_DESCR_BLK_K_CMD_REQ 0x1300 + +/* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host) */ +/* Note a field has been added for later versions of the PDQ to allow for */ +/* finer granularity of the rcv buffer alignment. For backwards */ +/* compatibility, the two bits (which allow the rcv buffer to be longword */ +/* aligned) have been added at the MBZ bits. To support previous drivers, */ +/* the MBZ definition is left intact. */ + +typedef struct + { + PI_UINT32 long_0; + PI_UINT32 long_1; + } PI_RCV_DESCR; + +#define PI_RCV_DESCR_M_SOP 0x80000000 +#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000 +#define PI_RCV_DESCR_M_MBZ 0x60000000 +#define PI_RCV_DESCR_M_SEG_LEN 0x1F800000 +#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000 +#define PI_RCV_DESCR_M_SEG_CNT 0x000F0000 +#define PI_RCV_DESCR_M_BUFF_HI 0x0000FFFF + +#define PI_RCV_DESCR_V_SOP 31 +#define PI_RCV_DESCR_V_SEG_LEN_LO 29 +#define PI_RCV_DESCR_V_MBZ 29 +#define PI_RCV_DESCR_V_SEG_LEN 23 +#define PI_RCV_DESCR_V_SEG_LEN_HI 20 +#define PI_RCV_DESCR_V_SEG_CNT 16 +#define PI_RCV_DESCR_V_BUFF_HI 0 + +/* Define the format of a transmit descriptor (Xmt Data, Cmd Req) */ + +typedef struct + { + PI_UINT32 long_0; + PI_UINT32 long_1; + } PI_XMT_DESCR; + +#define PI_XMT_DESCR_M_SOP 0x80000000 +#define PI_XMT_DESCR_M_EOP 0x40000000 +#define PI_XMT_DESCR_M_MBZ 0x20000000 +#define PI_XMT_DESCR_M_SEG_LEN 0x1FFF0000 +#define PI_XMT_DESCR_M_BUFF_HI 0x0000FFFF + +#define PI_XMT_DESCR_V_SOP 31 +#define PI_XMT_DESCR_V_EOP 30 +#define PI_XMT_DESCR_V_MBZ 29 +#define PI_XMT_DESCR_V_SEG_LEN 16 +#define PI_XMT_DESCR_V_BUFF_HI 0 + +/* Define format of the Descriptor Block (resident in host memory) */ + +#define PI_RCV_DATA_K_NUM_ENTRIES 256 +#define PI_XMT_DATA_K_NUM_ENTRIES 256 +#define PI_SMT_HOST_K_NUM_ENTRIES 64 +#define PI_UNSOL_K_NUM_ENTRIES 16 +#define PI_CMD_RSP_K_NUM_ENTRIES 16 +#define PI_CMD_REQ_K_NUM_ENTRIES 16 + +typedef struct + { + PI_RCV_DESCR rcv_data[PI_RCV_DATA_K_NUM_ENTRIES]; + PI_XMT_DESCR xmt_data[PI_XMT_DATA_K_NUM_ENTRIES]; + PI_RCV_DESCR smt_host[PI_SMT_HOST_K_NUM_ENTRIES]; + PI_RCV_DESCR unsol[PI_UNSOL_K_NUM_ENTRIES]; + PI_RCV_DESCR cmd_rsp[PI_CMD_RSP_K_NUM_ENTRIES]; + PI_XMT_DESCR cmd_req[PI_CMD_REQ_K_NUM_ENTRIES]; + } PI_DESCR_BLOCK; + +/* Define Port Registers - offsets from PDQ Base address */ + +#define PI_PDQ_K_REG_PORT_RESET 0x00000000 +#define PI_PDQ_K_REG_HOST_DATA 0x00000004 +#define PI_PDQ_K_REG_PORT_CTRL 0x00000008 +#define PI_PDQ_K_REG_PORT_DATA_A 0x0000000C +#define PI_PDQ_K_REG_PORT_DATA_B 0x00000010 +#define PI_PDQ_K_REG_PORT_STATUS 0x00000014 +#define PI_PDQ_K_REG_TYPE_0_STATUS 0x00000018 +#define PI_PDQ_K_REG_HOST_INT_ENB 0x0000001C +#define PI_PDQ_K_REG_TYPE_2_PROD_NOINT 0x00000020 +#define PI_PDQ_K_REG_TYPE_2_PROD 0x00000024 +#define PI_PDQ_K_REG_CMD_RSP_PROD 0x00000028 +#define PI_PDQ_K_REG_CMD_REQ_PROD 0x0000002C +#define PI_PDQ_K_REG_SMT_HOST_PROD 0x00000030 +#define PI_PDQ_K_REG_UNSOL_PROD 0x00000034 + +/* Port Control Register - Command codes for primary commands */ + +#define PI_PCTRL_M_CMD_ERROR 0x8000 +#define PI_PCTRL_M_BLAST_FLASH 0x4000 +#define PI_PCTRL_M_HALT 0x2000 +#define PI_PCTRL_M_COPY_DATA 0x1000 +#define PI_PCTRL_M_ERROR_LOG_START 0x0800 +#define PI_PCTRL_M_ERROR_LOG_READ 0x0400 +#define PI_PCTRL_M_XMT_DATA_FLUSH_DONE 0x0200 +#define PI_PCTRL_M_INIT 0x0100 +#define PI_PCTRL_M_INIT_START 0x0080 +#define PI_PCTRL_M_CONS_BLOCK 0x0040 +#define PI_PCTRL_M_UNINIT 0x0020 +#define PI_PCTRL_M_RING_MEMBER 0x0010 +#define PI_PCTRL_M_MLA 0x0008 +#define PI_PCTRL_M_FW_REV_READ 0x0004 +#define PI_PCTRL_M_DEV_SPECIFIC 0x0002 +#define PI_PCTRL_M_SUB_CMD 0x0001 + +/* Define sub-commands accessed via the PI_PCTRL_M_SUB_CMD command */ + +#define PI_SUB_CMD_K_LINK_UNINIT 0x0001 +#define PI_SUB_CMD_K_BURST_SIZE_SET 0x0002 +#define PI_SUB_CMD_K_PDQ_REV_GET 0x0004 +#define PI_SUB_CMD_K_HW_REV_GET 0x0008 + +/* Define some Port Data B values */ + +#define PI_PDATA_B_DMA_BURST_SIZE_4 0 /* valid values for command */ +#define PI_PDATA_B_DMA_BURST_SIZE_8 1 +#define PI_PDATA_B_DMA_BURST_SIZE_16 2 +#define PI_PDATA_B_DMA_BURST_SIZE_32 3 /* not supported on PCI */ +#define PI_PDATA_B_DMA_BURST_SIZE_DEF PI_PDATA_B_DMA_BURST_SIZE_16 + +/* Port Data A Reset state */ + +#define PI_PDATA_A_RESET_M_UPGRADE 0x00000001 +#define PI_PDATA_A_RESET_M_SOFT_RESET 0x00000002 +#define PI_PDATA_A_RESET_M_SKIP_ST 0x00000004 + +/* Read adapter MLA address port control command constants */ + +#define PI_PDATA_A_MLA_K_LO 0 +#define PI_PDATA_A_MLA_K_HI 1 + +/* Byte Swap values for init command */ + +#define PI_PDATA_A_INIT_M_DESC_BLK_ADDR 0x0FFFFE000 +#define PI_PDATA_A_INIT_M_RESERVED 0x000001FFC +#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002 +#define PI_PDATA_A_INIT_M_BSWAP_LITERAL 0x000000001 + +#define PI_PDATA_A_INIT_V_DESC_BLK_ADDR 13 +#define PI_PDATA_A_INIT_V_RESERVED 3 +#define PI_PDATA_A_INIT_V_BSWAP_DATA 1 +#define PI_PDATA_A_INIT_V_BSWAP_LITERAL 0 + +/* Port Reset Register */ + +#define PI_RESET_M_ASSERT_RESET 1 + +/* Port Status register */ + +#define PI_PSTATUS_V_RCV_DATA_PENDING 31 +#define PI_PSTATUS_V_XMT_DATA_PENDING 30 +#define PI_PSTATUS_V_SMT_HOST_PENDING 29 +#define PI_PSTATUS_V_UNSOL_PENDING 28 +#define PI_PSTATUS_V_CMD_RSP_PENDING 27 +#define PI_PSTATUS_V_CMD_REQ_PENDING 26 +#define PI_PSTATUS_V_TYPE_0_PENDING 25 +#define PI_PSTATUS_V_RESERVED_1 16 +#define PI_PSTATUS_V_RESERVED_2 11 +#define PI_PSTATUS_V_STATE 8 +#define PI_PSTATUS_V_HALT_ID 0 + +#define PI_PSTATUS_M_RCV_DATA_PENDING 0x80000000 +#define PI_PSTATUS_M_XMT_DATA_PENDING 0x40000000 +#define PI_PSTATUS_M_SMT_HOST_PENDING 0x20000000 +#define PI_PSTATUS_M_UNSOL_PENDING 0x10000000 +#define PI_PSTATUS_M_CMD_RSP_PENDING 0x08000000 +#define PI_PSTATUS_M_CMD_REQ_PENDING 0x04000000 +#define PI_PSTATUS_M_TYPE_0_PENDING 0x02000000 +#define PI_PSTATUS_M_RESERVED_1 0x01FF0000 +#define PI_PSTATUS_M_RESERVED_2 0x0000F800 +#define PI_PSTATUS_M_STATE 0x00000700 +#define PI_PSTATUS_M_HALT_ID 0x000000FF + +/* Define Halt Id's */ +/* Do not insert into this list, only append. */ + +#define PI_HALT_ID_K_SELFTEST_TIMEOUT 0 +#define PI_HALT_ID_K_PARITY_ERROR 1 +#define PI_HALT_ID_K_HOST_DIR_HALT 2 +#define PI_HALT_ID_K_SW_FAULT 3 +#define PI_HALT_ID_K_HW_FAULT 4 +#define PI_HALT_ID_K_PC_TRACE 5 +#define PI_HALT_ID_K_DMA_ERROR 6 /* Host Data has error reg */ +#define PI_HALT_ID_K_IMAGE_CRC_ERROR 7 /* Image is bad, update it */ +#define PI_HALT_ID_K_BUS_EXCEPTION 8 /* 68K bus exception */ + +/* Host Interrupt Enable Register as seen by host */ + +#define PI_HOST_INT_M_XMT_DATA_ENB 0x80000000 /* Type 2 Enables */ +#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000 +#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */ +#define PI_HOST_INT_M_UNSOL_ENB 0x20000000 +#define PI_HOST_INT_M_CMD_RSP_ENB 0x08000000 +#define PI_HOST_INT_M_CMD_REQ_ENB 0x04000000 +#define PI_HOST_INT_M_TYPE_1_RESERVED 0x00FF0000 +#define PI_HOST_INT_M_TYPE_0_RESERVED 0x0000FF00 /* Type 0 Enables */ +#define PI_HOST_INT_M_1MS 0x00000080 +#define PI_HOST_INT_M_20MS 0x00000040 +#define PI_HOST_INT_M_CSR_CMD_DONE 0x00000020 +#define PI_HOST_INT_M_STATE_CHANGE 0x00000010 +#define PI_HOST_INT_M_XMT_FLUSH 0x00000008 +#define PI_HOST_INT_M_NXM 0x00000004 +#define PI_HOST_INT_M_PM_PAR_ERR 0x00000002 +#define PI_HOST_INT_M_BUS_PAR_ERR 0x00000001 + +#define PI_HOST_INT_V_XMT_DATA_ENB 31 /* Type 2 Enables */ +#define PI_HOST_INT_V_RCV_DATA_ENB 30 +#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */ +#define PI_HOST_INT_V_UNSOL_ENB 28 +#define PI_HOST_INT_V_CMD_RSP_ENB 27 +#define PI_HOST_INT_V_CMD_REQ_ENB 26 +#define PI_HOST_INT_V_TYPE_1_RESERVED 16 +#define PI_HOST_INT_V_TYPE_0_RESERVED 8 /* Type 0 Enables */ +#define PI_HOST_INT_V_1MS_ENB 7 +#define PI_HOST_INT_V_20MS_ENB 6 +#define PI_HOST_INT_V_CSR_CMD_DONE_ENB 5 +#define PI_HOST_INT_V_STATE_CHANGE_ENB 4 +#define PI_HOST_INT_V_XMT_FLUSH_ENB 3 +#define PI_HOST_INT_V_NXM_ENB 2 +#define PI_HOST_INT_V_PM_PAR_ERR_ENB 1 +#define PI_HOST_INT_V_BUS_PAR_ERR_ENB 0 + +#define PI_HOST_INT_K_ACK_ALL_TYPE_0 0x000000FF +#define PI_HOST_INT_K_DISABLE_ALL_INTS 0x00000000 +#define PI_HOST_INT_K_ENABLE_ALL_INTS 0xFFFFFFFF +#define PI_HOST_INT_K_ENABLE_DEF_INTS 0xC000001F + +/* Type 0 Interrupt Status Register */ + +#define PI_TYPE_0_STAT_M_1MS 0x00000080 +#define PI_TYPE_0_STAT_M_20MS 0x00000040 +#define PI_TYPE_0_STAT_M_CSR_CMD_DONE 0x00000020 +#define PI_TYPE_0_STAT_M_STATE_CHANGE 0x00000010 +#define PI_TYPE_0_STAT_M_XMT_FLUSH 0x00000008 +#define PI_TYPE_0_STAT_M_NXM 0x00000004 +#define PI_TYPE_0_STAT_M_PM_PAR_ERR 0x00000002 +#define PI_TYPE_0_STAT_M_BUS_PAR_ERR 0x00000001 + +#define PI_TYPE_0_STAT_V_1MS 7 +#define PI_TYPE_0_STAT_V_20MS 6 +#define PI_TYPE_0_STAT_V_CSR_CMD_DONE 5 +#define PI_TYPE_0_STAT_V_STATE_CHANGE 4 +#define PI_TYPE_0_STAT_V_XMT_FLUSH 3 +#define PI_TYPE_0_STAT_V_NXM 2 +#define PI_TYPE_0_STAT_V_PM_PAR_ERR 1 +#define PI_TYPE_0_STAT_V_BUS_PAR_ERR 0 + +/* Register definition structures are defined for both big and little endian systems */ + +#ifndef BIG_ENDIAN + +/* Little endian format of Type 1 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 prod; + PI_UINT8 comp; + PI_UINT8 mbz_1; + PI_UINT8 mbz_2; + } index; + } PI_TYPE_1_PROD_REG; + +/* Little endian format of Type 2 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 rcv_prod; + PI_UINT8 xmt_prod; + PI_UINT8 rcv_comp; + PI_UINT8 xmt_comp; + } index; + } PI_TYPE_2_PROD_REG; + +/* Little endian format of Type 1 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 cons; + PI_UINT8 res0; + PI_UINT8 res1; + PI_UINT8 res2; + } index; + } PI_TYPE_1_CONSUMER; + +/* Little endian format of Type 2 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 rcv_cons; + PI_UINT8 res0; + PI_UINT8 xmt_cons; + PI_UINT8 res1; + } index; + } PI_TYPE_2_CONSUMER; + +#else + +/* Big endian format of Type 1 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 mbz_2; + PI_UINT8 mbz_1; + PI_UINT8 comp; + PI_UINT8 prod; + } index; + } PI_TYPE_1_PROD_REG; + +/* Big endian format of Type 2 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 xmt_comp; + PI_UINT8 rcv_comp; + PI_UINT8 xmt_prod; + PI_UINT8 rcv_prod; + } index; + } PI_TYPE_2_PROD_REG; + +/* Big endian format of Type 1 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 res2; + PI_UINT8 res1; + PI_UINT8 res0; + PI_UINT8 cons; + } index; + } PI_TYPE_1_CONSUMER; + +/* Big endian format of Type 2 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 res1; + PI_UINT8 xmt_cons; + PI_UINT8 res0; + PI_UINT8 rcv_cons; + } index; + } PI_TYPE_2_CONSUMER; + +#endif /* #ifndef BIG_ENDIAN */ + +/* Define EISA controller register offsets */ + +#define PI_ESIC_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_SLOT_ID 0xC80 +#define PI_ESIC_K_SLOT_CNTRL 0xC84 +#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 +#define PI_ESIC_K_MEM_ADD_CMP_1 0xC86 +#define PI_ESIC_K_MEM_ADD_CMP_2 0xC87 +#define PI_ESIC_K_MEM_ADD_HI_CMP_0 0xC88 +#define PI_ESIC_K_MEM_ADD_HI_CMP_1 0xC89 +#define PI_ESIC_K_MEM_ADD_HI_CMP_2 0xC8A +#define PI_ESIC_K_MEM_ADD_MASK_0 0xC8B +#define PI_ESIC_K_MEM_ADD_MASK_1 0xC8C +#define PI_ESIC_K_MEM_ADD_MASK_2 0xC8D +#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E +#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F +#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 +#define PI_ESIC_K_IO_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 +#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A +#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B +#define PI_ESIC_K_IO_ADD_MASK_1_1 0xC9C +#define PI_ESIC_K_IO_ADD_MASK_2_0 0xC9D +#define PI_ESIC_K_IO_ADD_MASK_2_1 0xC9E +#define PI_ESIC_K_IO_ADD_MASK_3_0 0xC9F +#define PI_ESIC_K_IO_ADD_MASK_3_1 0xCA0 +#define PI_ESIC_K_MOD_CONFIG_1 0xCA1 +#define PI_ESIC_K_MOD_CONFIG_2 0xCA2 +#define PI_ESIC_K_MOD_CONFIG_3 0xCA3 +#define PI_ESIC_K_MOD_CONFIG_4 0xCA4 +#define PI_ESIC_K_MOD_CONFIG_5 0xCA5 +#define PI_ESIC_K_MOD_CONFIG_6 0xCA6 +#define PI_ESIC_K_MOD_CONFIG_7 0xCA7 +#define PI_ESIC_K_DIP_SWITCH 0xCA8 +#define PI_ESIC_K_IO_CONFIG_STAT_0 0xCA9 +#define PI_ESIC_K_IO_CONFIG_STAT_1 0xCAA +#define PI_ESIC_K_DMA_CONFIG 0xCAB +#define PI_ESIC_K_INPUT_PORT 0xCAC +#define PI_ESIC_K_OUTPUT_PORT 0xCAD +#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE +#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */ + +/* Define the value all drivers must write to the function control register. */ + +#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03 + +/* Define the bits in the slot control register. */ + +#define PI_SLOT_CNTRL_M_RESET 0x04 /* Don't use. */ +#define PI_SLOT_CNTRL_M_ERROR 0x02 /* Not implemented. */ +#define PI_SLOT_CNTRL_M_ENB 0x01 /* Must be set. */ + +/* Define the bits in the burst holdoff register. */ + +#define PI_BURST_HOLDOFF_M_HOLDOFF 0xFC +#define PI_BURST_HOLDOFF_M_RESERVED 0x02 +#define PI_BURST_HOLDOFF_M_MEM_MAP 0x01 + +#define PI_BURST_HOLDOFF_V_HOLDOFF 2 +#define PI_BURST_HOLDOFF_V_RESERVED 1 +#define PI_BURST_HOLDOFF_V_MEM_MAP 0 + +/* + * Define the fields in the IO Compare registers. + * The driver must initialize the slot field with the slot ID shifted by the + * amount shown below. + */ + +#define PI_IO_CMP_V_SLOT 4 + +/* Define the fields in the Interrupt Channel Configuration and Status reg */ + +#define PI_CONFIG_STAT_0_M_PEND 0x80 +#define PI_CONFIG_STAT_0_M_RES_1 0x40 +#define PI_CONFIG_STAT_0_M_IREQ_OUT 0x20 +#define PI_CONFIG_STAT_0_M_IREQ_IN 0x10 +#define PI_CONFIG_STAT_0_M_INT_ENB 0x08 +#define PI_CONFIG_STAT_0_M_RES_0 0x04 +#define PI_CONFIG_STAT_0_M_IRQ 0x03 + +#define PI_CONFIG_STAT_0_V_PEND 7 +#define PI_CONFIG_STAT_0_V_RES_1 6 +#define PI_CONFIG_STAT_0_V_IREQ_OUT 5 +#define PI_CONFIG_STAT_0_V_IREQ_IN 4 +#define PI_CONFIG_STAT_0_V_INT_ENB 3 +#define PI_CONFIG_STAT_0_V_RES_0 2 +#define PI_CONFIG_STAT_0_V_IRQ 0 + +#define PI_CONFIG_STAT_0_IRQ_K_9 0 +#define PI_CONFIG_STAT_0_IRQ_K_10 1 +#define PI_CONFIG_STAT_0_IRQ_K_11 2 +#define PI_CONFIG_STAT_0_IRQ_K_15 3 + +/* Define DEC FDDIcontroller/EISA (DEFEA) EISA hardware ID's */ + +#define DEFEA_PRODUCT_ID 0x0030A310 /* DEC product 300 (no rev) */ +#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ +#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ +#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ + +/**********************************************/ +/* Digital PFI Specification v1.0 Definitions */ +/**********************************************/ + +/* PCI Configuration Space Constants */ + +#define PFI_K_LAT_TIMER_DEF 0x88 /* def max master latency timer */ +#define PFI_K_LAT_TIMER_MIN 0x20 /* min max master latency timer */ +#define PFI_K_CSR_MEM_LEN 0x80 /* 128 bytes */ +#define PFI_K_CSR_IO_LEN 0x80 /* 128 bytes */ +#define PFI_K_PKT_MEM_LEN 0x10000 /* 64K bytes */ + +/* PFI Register Offsets (starting at PDQ Register Base Address) */ + +#define PFI_K_REG_RESERVED_0 0X00000038 +#define PFI_K_REG_RESERVED_1 0X0000003C +#define PFI_K_REG_MODE_CTRL 0X00000040 +#define PFI_K_REG_STATUS 0X00000044 +#define PFI_K_REG_FIFO_WRITE 0X00000048 +#define PFI_K_REG_FIFO_READ 0X0000004C + +/* PFI Mode Control Register Constants */ + +#define PFI_MODE_M_RESERVED 0XFFFFFFF0 +#define PFI_MODE_M_TGT_ABORT_ENB 0X00000008 +#define PFI_MODE_M_PDQ_INT_ENB 0X00000004 +#define PFI_MODE_M_PFI_INT_ENB 0X00000002 +#define PFI_MODE_M_DMA_ENB 0X00000001 + +#define PFI_MODE_V_RESERVED 4 +#define PFI_MODE_V_TGT_ABORT_ENB 3 +#define PFI_MODE_V_PDQ_INT_ENB 2 +#define PFI_MODE_V_PFI_INT_ENB 1 +#define PFI_MODE_V_DMA_ENB 0 + +#define PFI_MODE_K_ALL_DISABLE 0X00000000 + +/* PFI Status Register Constants */ + +#define PFI_STATUS_M_RESERVED 0XFFFFFFC0 +#define PFI_STATUS_M_PFI_ERROR 0X00000020 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_M_PDQ_INT 0X00000010 +#define PFI_STATUS_M_PDQ_DMA_ABORT 0X00000008 +#define PFI_STATUS_M_FIFO_FULL 0X00000004 +#define PFI_STATUS_M_FIFO_EMPTY 0X00000002 +#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001 + +#define PFI_STATUS_V_RESERVED 6 +#define PFI_STATUS_V_PFI_ERROR 5 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_V_PDQ_INT 4 +#define PFI_STATUS_V_PDQ_DMA_ABORT 3 +#define PFI_STATUS_V_FIFO_FULL 2 +#define PFI_STATUS_V_FIFO_EMPTY 1 +#define PFI_STATUS_V_DMA_IN_PROGRESS 0 + +#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */ +#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */ + +#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */ +#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */ + +#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ +#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ +#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ +#define DFX_PRH2_BYTE 0x00 /* Packet Request Header byte 2 */ + +/* Driver routine status (return) codes */ + +#define DFX_K_SUCCESS 0 /* routine succeeded */ +#define DFX_K_FAILURE 1 /* routine failed */ +#define DFX_K_OUTSTATE 2 /* bad state for command */ +#define DFX_K_HW_TIMEOUT 3 /* command timed out */ + +/* Define LLC host receive buffer min/max/default values */ + +#define RCV_BUFS_MIN 2 /* minimum pre-allocated receive buffers */ +#define RCV_BUFS_MAX 32 /* maximum pre-allocated receive buffers */ +#define RCV_BUFS_DEF 8 /* default pre-allocated receive buffers */ + +/* Define offsets into FDDI LLC or SMT receive frame buffers - used when indicating frames */ + +#define RCV_BUFF_K_DESCR 0 /* four byte FMC descriptor */ +#define RCV_BUFF_K_PADDING 4 /* three null bytes */ +#define RCV_BUFF_K_FC 7 /* one byte frame control */ +#define RCV_BUFF_K_DA 8 /* six byte destination address */ +#define RCV_BUFF_K_SA 14 /* six byte source address */ +#define RCV_BUFF_K_DATA 20 /* offset to start of packet data */ + +/* Define offsets into FDDI LLC transmit frame buffers - used when sending frames */ + +#define XMT_BUFF_K_FC 0 /* one byte frame control */ +#define XMT_BUFF_K_DA 1 /* six byte destination address */ +#define XMT_BUFF_K_SA 7 /* six byte source address */ +#define XMT_BUFF_K_DATA 13 /* offset to start of packet data */ + +/* + * Macro evaluates to "value" aligned to "size" bytes. Make sure that + * "size" is greater than 0 bytes. + */ + +#define ALIGN(value,size) ((value + (size - 1)) & ~(size - 1)) + +/* Macro for checking a "value" is within a specific range */ + +#define IN_RANGE(value,low,high) ((value >= low) && (value <= high)) + +/* Only execute special print call when debug driver was built */ + +#ifdef DEFXX_DEBUG +#define DBG_printk(args...) printk(## args) +#else +#define DBG_printk(args...) +#endif + +/* Define constants for masking/unmasking interrupts */ + +#define DFX_MASK_INTERRUPTS 1 +#define DFX_UNMASK_INTERRUPTS 0 + +/* Define structure for driver transmit descriptor block */ + +typedef struct + { + struct sk_buff *p_skb; /* ptr to skb */ + } XMT_DRIVER_DESCR; + +typedef struct DFX_board_tag + { + /* Keep virtual and physical pointers to locked, physically contiguous memory */ + + PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */ + u32 descr_block_phys; /* PDQ descriptor block phys address */ + PI_DMA_CMD_REQ *cmd_req_virt; /* Command request buffer virt address */ + u32 cmd_req_phys; /* Command request buffer phys address */ + PI_DMA_CMD_RSP *cmd_rsp_virt; /* Command response buffer virt address */ + u32 cmd_rsp_phys; /* Command response buffer phys address */ + char *rcv_block_virt; /* LLC host receive queue buf blk virt */ + u32 rcv_block_phys; /* LLC host receive queue buf blk phys */ + PI_CONSUMER_BLOCK *cons_block_virt; /* PDQ consumer block virt address */ + u32 cons_block_phys; /* PDQ consumer block phys address */ + + /* Keep local copies of Type 1 and Type 2 register data */ + + PI_TYPE_1_PROD_REG cmd_req_reg; /* Command Request register */ + PI_TYPE_1_PROD_REG cmd_rsp_reg; /* Command Response register */ + PI_TYPE_2_PROD_REG rcv_xmt_reg; /* Type 2 (RCV/XMT) register */ + + /* Storage for unicast and multicast address entries in adapter CAM */ + + u8 uc_table[1*FDDI_K_ALEN]; + u32 uc_count; /* number of unicast addresses */ + u8 mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN]; + u32 mc_count; /* number of multicast addresses */ + + /* Current packet filter settings */ + + u32 ind_group_prom; /* LLC individual & group frame prom mode */ + u32 group_prom; /* LLC group (multicast) frame prom mode */ + + /* Link available flag needed to determine whether to drop outgoing packet requests */ + + u32 link_available; /* is link available? */ + + /* Resources to indicate reset type when resetting adapter */ + + u32 reset_type; /* skip or rerun diagnostics */ + + /* Store pointers to receive buffers for queue processing code */ + + char *p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES]; + + /* Store pointers to transmit buffers for transmit completion code */ + + XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES]; + + /* Store device, bus-specific, and parameter information for this adapter */ + + struct device *dev; /* pointer to device structure */ + u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ + u16 base_addr; /* base I/O address (same as dev->base_addr) */ + u8 pci_bus; /* PCI bus number */ + u8 pci_dev_fun; /* PCI device and function numbers */ + u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ + u32 req_ttrt; /* requested TTRT value (in 80ns units) */ + u32 burst_size; /* adapter burst size (enumerated) */ + u32 rcv_bufs_to_post; /* receive buffers to post for LLC host queue */ + u8 factory_mac_addr[FDDI_K_ALEN]; /* factory (on-board) MAC address */ + + /* Common FDDI statistics structure and private counters */ + + struct fddi_statistics stats; + + u32 rcv_discards; + u32 rcv_crc_errors; + u32 rcv_frame_status_errors; + u32 rcv_length_errors; + u32 rcv_total_frames; + u32 rcv_multicast_frames; + u32 xmt_discards; + u32 xmt_length_errors; + u32 xmt_total_frames; + } DFX_board_t; + +#endif /* #ifndef _DEFXX_H_ */ diff -u --recursive --new-file v2.0.23/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.0.23/linux/drivers/net/net_init.c Sat Jun 29 12:00:46 1996 +++ linux/drivers/net/net_init.c Wed Oct 30 03:42:40 1996 @@ -21,7 +21,12 @@ Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses. - 14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function. + 14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function. + + August 12, 1996 - Lawrence V. Stefani: Added fddi_change_mtu() and + fddi_setup() functions. + Sept. 10, 1996 - Lawrence V. Stefani: Increased hard_header_len to + include 3 pad bytes. */ #include @@ -34,6 +39,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_NET_ALIAS @@ -154,6 +160,18 @@ return 0; } +#ifdef CONFIG_FDDI + +static int fddi_change_mtu(struct device *dev, int new_mtu) + { + if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) + return(-EINVAL); + dev->mtu = new_mtu; + return(0); + } + +#endif + void ether_setup(struct device *dev) { int i; @@ -228,6 +246,43 @@ dev->pa_mask = 0; dev->pa_alen = 4; } + +#endif + +#ifdef CONFIG_FDDI + +void fddi_setup(struct device *dev) + { + int i; + + /* + * Fill in the fields of the device structure with FDDI-generic values. + * This should be in a common file instead of per-driver. + */ + for (i=0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + dev->change_mtu = fddi_change_mtu; + dev->hard_header = fddi_header; + dev->rebuild_header = fddi_rebuild_header; + + dev->type = ARPHRD_FDDI; + dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ + dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ + dev->addr_len = FDDI_K_ALEN; + dev->tx_queue_len = 100; /* Long queues on FDDI */ + + memset(dev->broadcast, 0xFF, FDDI_K_ALEN); + + /* New-style flags */ + dev->flags = IFF_BROADCAST | IFF_MULTICAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = 4; + return; + } #endif diff -u --recursive --new-file v2.0.23/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.0.23/linux/drivers/net/ni65.c Fri Apr 12 09:49:38 1996 +++ linux/drivers/net/ni65.c Wed Oct 30 03:42:41 1996 @@ -1,8 +1,15 @@ /* - * ni6510 (am7990 'lance' chip) driver for Linux-net-3 by MH - * Alphacode v0.51 (96/02/20) for 1.3.66 (or later) + * ni6510 (am7990 'lance' chip) driver for Linux-net-3 + * BETAcode v0.70 (96/04/07) for 1.3.66 (or later) + * copyrights (c) 1994,1995,1996 by M.Hipp + * + * This driver can handle the old ni6510 board and the newer ni6510 + * EtherBlaster. (probably it also works with every full NE2100 + * compatible card) * - * copyright (c) 1994,1995,1996 by M.Hipp + * To compile as module, type: + * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni65.c + * driver probes: io: 0x360,0x300,0x320,0x340 / dma: 3,5,6,7 * * This is an extension to the Linux operating system, and is covered by the * same Gnu Public License that covers the Linux-kernel. @@ -18,18 +25,27 @@ * known problems: * on some PCI boards (including my own) the card/board/ISA-bridge has * problems with bus master DMA. This results in lotsa overruns. - * It may help to '#define RCV_PARANOIA_CHECK' - * or just play with your BIOS options to optimize ISA-DMA access. + * It may help to '#define RCV_PARANOIA_CHECK' or try to #undef + * the XMT and RCV_VIA_SKB option .. this reduces driver performance. + * Or just play with your BIOS options to optimize ISA-DMA access. + * Maybe you also wanna play with the LOW_PERFORAMCE and MID_PERFORMANCE + * defines -> please report me your experience then * * credits: * thanx to Jason Sullivan for sending me a ni6510 card! * - * simple performance test: - * 8.1 seconds for getting a 8MB file via FTP -> near 1MB/s + * simple performance test: (486DX-33/Ni6510-EB receives from 486DX4-100/Ni6510-EB) + * average: FTP -> 8384421 bytes received in 8.5 seconds + * (no RCV_VIA_SKB,no XMT_VIA_SKB,PARANOIA_CHECK,4 XMIT BUFS, 8 RCV_BUFFS) + * peak: FTP -> 8384421 bytes received in 7.5 seconds + * (RCV_VIA_SKB,XMT_VIA_SKB,no PARANOIA_CHECK,1(!) XMIT BUF, 16 RCV BUFFS) */ /* - * 96.Feb.19: fixed a few bugs .. cleanups .. tested for 1.3.66 + * 96.April.13: enhanced error handling .. more tests (MH) + * 96.April.5/6: a lot of performance tests .. got it stable now (hopefully) (MH) + * 96.April.1: (no joke ;) .. added EtherBlaster and Module support (MH) + * 96.Feb.19: fixed a few bugs .. cleanups .. tested for 1.3.66 (MH) * hopefully no more 16MB limit * * 95.Nov.18: multicast tweaked (AC). @@ -56,75 +72,121 @@ #include #include +#include +#include + #include "ni65.h" /* - * the current setting allows max. performance + * the current setting allows an acceptable performance * for 'RCV_PARANOIA_CHECK' read the 'known problems' part in * the header of this file + * 'invert' the defines for max. performance. This may cause DMA problems + * on some boards (e.g on my ASUS SP3G) */ -#define RCV_VIA_SKB -#undef RCV_PARANOIA_CHECK #define XMT_VIA_SKB +#define RCV_VIA_SKB +#define RCV_PARANOIA_CHECK + +#define MID_PERFORMANCE + +#if defined( LOW_PERFORMANCE ) + static int isa0=7,isa1=7,csr80=0x0c10; +#elif defined( MID_PERFORMANCE ) + static int isa0=5,isa1=5,csr80=0x2810; +#else /* high performance */ + static int isa0=4,isa1=4,csr80=0x0017; +#endif /* - * a few card specific defines + * a few card/vendor specific defines */ -#define NI65_TOTAL_SIZE 16 -#define NI65_ADDR0 0x02 -#define NI65_ADDR1 0x07 -#define NI65_ADDR2 0x01 -#define NI65_ID0 0x00 -#define NI65_ID1 0x55 +#define NI65_ID0 0x00 +#define NI65_ID1 0x55 +#define NI65_EB_ID0 0x52 +#define NI65_EB_ID1 0x44 +#define NE2100_ID0 0x57 +#define NE2100_ID1 0x57 -#define PORT dev->base_addr +#define PORT p->cmdr_addr /* * buffer configuration */ +#if 1 +#define RMDNUM 16 +#define RMDNUMMASK 0x80000000 +#else #define RMDNUM 8 #define RMDNUMMASK 0x60000000 /* log2(RMDNUM)<<29 */ -#define TMDNUM 4 -#define TMDNUMMASK 0x40000000 /* log2(TMDNUM)<<29 */ +#endif -#define R_BUF_SIZE 1536 -#define T_BUF_SIZE 1536 +#if 1 +#define TMDNUM 1 +#define TMDNUMMASK 0x00000000 /* log2(TMDNUM)<<29 */ +#else +#define TMDNUM 2 +#define TMDNUMMASK 0x20000000 /* log2(TMDNUM)<<29 */ +#endif + +/* slightly oversized */ +#define R_BUF_SIZE 1544 +#define T_BUF_SIZE 1544 /* * lance register defines */ #define L_DATAREG 0x00 #define L_ADDRREG 0x02 - #define L_RESET 0x04 #define L_CONFIG 0x05 -#define L_EBASE 0x08 +#define L_BUSIF 0x06 /* - * to access the am7990-regs, you have to write + * to access the lance/am7990-regs, you have to write * reg-number into L_ADDRREG, then you can access it using L_DATAREG */ -#define CSR0 0x00 -#define CSR1 0x01 -#define CSR2 0x02 -#define CSR3 0x03 +#define CSR0 0x00 +#define CSR1 0x01 +#define CSR2 0x02 +#define CSR3 0x03 + +#define INIT_RING_BEFORE_START 0x1 +#define FULL_RESET_ON_ERROR 0x2 +#if 0 #define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);inw(PORT+L_ADDRREG); \ outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);} #define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_ADDRREG),\ inw(PORT+L_DATAREG)) +#if 0 #define writedatareg(val) {outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);} +#else +#define writedatareg(val) { writereg(val,CSR0); } +#endif +#else +#define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);outw(val,PORT+L_DATAREG);} +#define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_DATAREG)) +#define writedatareg(val) { writereg(val,CSR0); } +#endif -static int ni65_probe1(struct device **dev,int); -static void ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs); -static void ni65_recv_intr(struct device *dev,int); -static void ni65_xmit_intr(struct device *dev,int); -static int ni65_open(struct device *dev); -static int ni65_am7990_reinit(struct device *dev); -static int ni65_send_packet(struct sk_buff *skb, struct device *dev); -static int ni65_close(struct device *dev); -static struct enet_statistics *ni65_get_stats(struct device *); -static void set_multicast_list(struct device *dev); +static unsigned char ni_vendor[] = { 0x02,0x07,0x01 }; + +static struct card { + unsigned char id0,id1; + short id_offset; + short total_size; + short cmd_offset; + short addr_offset; + unsigned char *vendor_id; + char *cardname; + unsigned char config; +} cards[] = { + { NI65_ID0,NI65_ID1,0x0e,0x10,0x0,0x8,ni_vendor,"ni6510", 0x1 } , + { NI65_EB_ID0,NI65_EB_ID1,0x0e,0x18,0x10,0x0,ni_vendor,"ni6510 EtherBlaster", 0x2 } , + { NE2100_ID0,NE2100_ID1,0x0e,0x18,0x10,0x0,NULL,"generic NE2100", 0x0 } +}; +#define NUM_CARDS 3 struct priv { @@ -142,132 +204,267 @@ struct sk_buff *tmd_skb[TMDNUM]; #endif void *tmdbounce[TMDNUM]; + int tmdbouncenum; int lock,xmit_queued; struct enet_statistics stats; + void *self; + int cmdr_addr; + int cardno; + int features; }; +static int ni65_probe1(struct device *dev,int); +static void ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs); +static void ni65_recv_intr(struct device *dev,int); +static void ni65_xmit_intr(struct device *dev,int); +static int ni65_open(struct device *dev); +static int ni65_lance_reinit(struct device *dev); +static void ni65_init_lance(struct priv *p,unsigned char*,int,int); +static int ni65_send_packet(struct sk_buff *skb, struct device *dev); +static int ni65_close(struct device *dev); +static int ni65_alloc_buffer(struct device *dev); +static void ni65_free_buffer(struct priv *p); +static struct enet_statistics *ni65_get_stats(struct device *); +static void set_multicast_list(struct device *dev); + static int irqtab[] = { 9,12,15,5 }; /* irq config-translate */ -static int dmatab[] = { 0,3,5,6 }; /* dma config-translate */ -static int debuglevel = 0; +static int dmatab[] = { 0,3,5,6,7 }; /* dma config-translate and autodetect */ + +static int debuglevel = 1; /* - * open (most done by init) + * set 'performance' registers .. we must STOP lance for that + */ +static void ni65_set_performance(struct priv *p) +{ + writereg(CSR0_STOP | CSR0_CLRALL,CSR0); /* STOP */ + + if(!test_bit(1,&cards[p->cardno].config)) + return; + + outw(80,PORT+L_ADDRREG); + if(inw(PORT+L_ADDRREG) != 80) + return; + + writereg( (csr80 & 0x3fff) ,80); /* FIFO watermarks */ + outw(0,PORT+L_ADDRREG); + outw((short)isa0,PORT+L_BUSIF); /* write ISA 0: DMA_R : isa0 * 50ns */ + outw(1,PORT+L_ADDRREG); + outw((short)isa1,PORT+L_BUSIF); /* write ISA 1: DMA_W : isa1 * 50ns */ + + outw(CSR0,PORT+L_ADDRREG); /* switch back to CSR0 */ +} + +/* + * open interface (up) */ static int ni65_open(struct device *dev) { - if(ni65_am7990_reinit(dev)) + struct priv *p = (struct priv *) dev->priv; + int irqval = request_irq(dev->irq, &ni65_interrupt,0, + cards[p->cardno].cardname,NULL); + if (irqval) { + printk ("%s: unable to get IRQ %d (irqval=%d).\n", + dev->name,dev->irq, irqval); + return -EAGAIN; + } + irq2dev_map[dev->irq] = dev; + + if(ni65_lance_reinit(dev)) { dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; + MOD_INC_USE_COUNT; return 0; } else { + irq2dev_map[dev->irq] = NULL; + free_irq(dev->irq,NULL); dev->start = 0; return -EAGAIN; } } +/* + * close interface (down) + */ static int ni65_close(struct device *dev) { - outw(0,PORT+L_RESET); /* that's the hard way */ + struct priv *p = (struct priv *) dev->priv; + + outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */ + +#ifdef XMT_VIA_SKB + { + int i; + for(i=0;itmd_skb[i]) { + dev_kfree_skb(p->tmd_skb[i],FREE_WRITE); + p->tmd_skb[i] = NULL; + } + } + } +#endif + irq2dev_map[dev->irq] = NULL; + free_irq(dev->irq,NULL); dev->tbusy = 1; dev->start = 0; + MOD_DEC_USE_COUNT; return 0; } /* * Probe The Card (not the lance-chip) - * and set hardaddress */ +#ifdef MODULE +static +#endif int ni65_probe(struct device *dev) { int *port; - static int ports[] = {0x300,0x320,0x340,0x360, 0}; + static int ports[] = {0x360,0x300,0x320,0x340, 0}; - if(dev) { - int base_addr = dev->base_addr; - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ni65_probe1(&dev, base_addr); - else if (base_addr > 0) /* Don't probe at all. */ - return -ENXIO; - dev->base_addr = base_addr; - } + if (dev->base_addr > 0x1ff) /* Check a single specified location. */ + return ni65_probe1(dev, dev->base_addr); + else if (dev->base_addr > 0) /* Don't probe at all. */ + return -ENXIO; for (port = ports; *port; port++) { - int ioaddr = *port; - - if (check_region(ioaddr, NI65_TOTAL_SIZE)) - continue; - if( !(inb(ioaddr+L_EBASE+6) == NI65_ID0) || - !(inb(ioaddr+L_EBASE+7) == NI65_ID1) ) - continue; - if (ni65_probe1(&dev, ioaddr) == 0) + if (ni65_probe1(dev, *port) == 0) return 0; } return -ENODEV; } -int ni65_init(void) -{ - ni65_probe(NULL); - return 0; -} - -static int ni65_probe1(struct device **dev1,int ioaddr) +/* + * this is the real card probe .. + */ +static int ni65_probe1(struct device *dev,int ioaddr) { - int i; - unsigned char *ptr; + int i,j; struct priv *p; - struct device *dev = *dev1; - - if(inb(ioaddr+L_EBASE+0) != NI65_ADDR0 || inb(ioaddr+L_EBASE+1) != NI65_ADDR1 - || inb(ioaddr+L_EBASE+2) != NI65_ADDR2) - { - printk("%s: wrong Hardaddress \n",dev ? dev->name : "ni6510" ); - return -ENODEV; - } - if(!dev) { - dev = init_etherdev(0,0); - *dev1 = dev; + for(i=0;i= 0) { + if(inb(ioaddr+cards[i].id_offset+0) != cards[i].id0 || + inb(ioaddr+cards[i].id_offset+1) != cards[i].id1) { + continue; + } + } + if(cards[i].vendor_id) { + for(j=0;j<3;j++) + if(inb(ioaddr+cards[i].addr_offset+j) != cards[i].vendor_id[j]) + continue; + } + break; } - dev->base_addr = ioaddr; + if(i == NUM_CARDS) + return -ENODEV; - for(i=0;i<6;i++) - dev->dev_addr[i] = inb(PORT+L_EBASE+i); + for(j=0;j<6;j++) + dev->dev_addr[j] = inb(ioaddr+cards[i].addr_offset+j); - if(dev->irq == 0) - dev->irq = irqtab[(inw(PORT+L_CONFIG)>>2)&3]; - if(dev->dma == 0) - dev->dma = dmatab[inw(PORT+L_CONFIG)&3]; - - printk("%s: %s found at %#3lx, IRQ %d DMA %d.\n", dev->name, - "ni6510", dev->base_addr, dev->irq,dev->dma); - - { - int irqval = request_irq(dev->irq, &ni65_interrupt,0,"ni6510",NULL); - if (irqval) { - printk ("%s: unable to get IRQ %d (irqval=%d).\n", - dev->name,dev->irq, irqval); - return -EAGAIN; + if( (j=ni65_alloc_buffer(dev)) < 0) + return j; + p = (struct priv *) dev->priv; + p->cmdr_addr = ioaddr + cards[i].cmd_offset; + p->cardno = i; + + printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr); + + outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ + if( (j=readreg(CSR0)) != 0x4) { + printk(KERN_ERR "can't RESET card: %04x\n",j); + ni65_free_buffer(p); + return -EAGAIN; + } + + outw(88,PORT+L_ADDRREG); + if(inw(PORT+L_ADDRREG) == 88) { + unsigned long v; + v = inw(PORT+L_DATAREG); + v <<= 16; + outw(89,PORT+L_ADDRREG); + v |= inw(PORT+L_DATAREG); + printk("Version %#08lx, ",v); + p->features = INIT_RING_BEFORE_START; + } + else { + printk("ancient LANCE, "); + p->features = 0x0; + } + + if(test_bit(0,&cards[i].config)) { + dev->irq = irqtab[(inw(ioaddr+L_CONFIG)>>2)&3]; + dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3]; + printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma); + } + else { + if(dev->dma == 0) { + /* 'stuck test' from lance.c */ + int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0); + for(i=1;i<5;i++) { + int dma = dmatab[i]; + if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510")) + continue; + disable_dma(dma); + set_dma_mode(dma,DMA_MODE_CASCADE); + enable_dma(dma); + ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */ + disable_dma(dma); + free_dma(dma); + if(readreg(CSR0) & CSR0_IDON) + break; + } + if(i == 5) { + printk("Can't detect DMA channel!\n"); + ni65_free_buffer(p); + return -EAGAIN; + } + dev->dma = dmatab[i]; + printk("DMA %d (autodetected), ",dev->dma); } - if(request_dma(dev->dma, "ni6510") != 0) + else + printk("DMA %d (assigned), ",dev->dma); + + if(dev->irq < 2) { - printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma); - free_irq(dev->irq,NULL); - return -EAGAIN; + ni65_init_lance(p,dev->dev_addr,0,0); + autoirq_setup(0); + writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */ + + if(!(dev->irq = autoirq_report(2))) + { + printk("Failed to detect IRQ line!\n"); + ni65_free_buffer(p); + return -EAGAIN; + } + printk("IRQ %d (autodetected).\n",dev->irq); } + else + printk("IRQ %d (assigned).\n",dev->irq); + } + + if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0) + { + printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma); + ni65_free_buffer(p); + return -EAGAIN; } - irq2dev_map[dev->irq] = dev; /* - * Grab the region so we can find another board if autoIRQ fails. + * Grab the region so we can find another board. */ - request_region(ioaddr,NI65_TOTAL_SIZE,"ni6510"); + request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname); + + dev->base_addr = ioaddr; dev->open = ni65_open; dev->stop = ni65_close; @@ -281,75 +478,238 @@ dev->tbusy = 0; dev->start = 0; + return 0; /* everything is OK */ +} + +/* + * set lance register and trigger init + */ +static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int mode) +{ + int i; + + writereg(CSR0_CLRALL|CSR0_STOP,CSR0); + + for(i=0;i<6;i++) + p->ib.eaddr[i] = daddr[i]; + + for(i=0;i<8;i++) + p->ib.filter[i] = filter; + p->ib.mode = mode; + + p->ib.trp = (unsigned long) p->tmdhead | TMDNUMMASK; + p->ib.rrp = (unsigned long) p->rmdhead | RMDNUMMASK; + writereg(0,CSR3); /* busmaster/no word-swap */ + writereg((unsigned short) (((unsigned long) &(p->ib)) & 0xffff),CSR1); + writereg((unsigned short) (((unsigned long) &(p->ib))>>16),CSR2); + + writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */ + + for(i=0;i<32;i++) + { + udelay(4000); + if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) ) + break; /* init ok ? */ + } +} + +/* + * allocate memory area and check the 16MB border + */ +static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type) +{ + struct sk_buff *skb=NULL; + unsigned char *ptr; + void *ret; + + if(type) { + ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA); + if(!skb) { + printk("%s: unable to allocate %s memory.\n",dev->name,what); + return NULL; + } + skb->dev = dev; + skb_reserve(skb,2+16); + skb_put(skb,R_BUF_SIZE); /* grab the whole space .. (not necessary) */ + ptr = skb->data; + } + else { + ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA); + if(!ret) { + printk("%s: unable to allocate %s memory.\n",dev->name,what); + return NULL; + } + } + if( (unsigned long) (ptr+size) > 0x1000000) { + printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); + if(type) + kfree_skb(skb,FREE_WRITE); + else + kfree(ptr); + return NULL; + } + return ret; +} + +/* + * allocate all memory structures .. send/recv buffers etc ... + */ +static int ni65_alloc_buffer(struct device *dev) +{ + unsigned char *ptr; + struct priv *p; + int i; + /* * we need 8-aligned memory .. */ - ptr = kmalloc(sizeof(struct priv)+8,GFP_KERNEL|GFP_DMA); + ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0); if(!ptr) return -ENOMEM; - ptr = (unsigned char *) (((unsigned long) ptr + 7) & ~0x7); - if( (unsigned long) ptr + sizeof(struct priv) > 0x1000000) { - printk("%s: Can't alloc buffer in lower 16MB!\n",dev->name); - return -EAGAIN; - } - p = dev->priv = (struct priv *) ptr; + + p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7); memset((char *) dev->priv,0,sizeof(struct priv)); + p->self = ptr; for(i=0;iname); +#ifdef XMT_VIA_SKB + p->tmd_skb[i] = NULL; +#endif + p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0); + if(!p->tmdbounce[i]) { + ni65_free_buffer(p); + return -ENOMEM; + } + } + + for(i=0;irecv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1); + if(!p->recv_skb[i]) { + ni65_free_buffer(p); return -ENOMEM; } - if( (unsigned long) (ptr+T_BUF_SIZE) > 0x1000000) { - printk("%s: Can't alloc Xmit-Mem in lower 16MB!\n",dev->name); - return -EAGAIN; +#else + p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0); + if(!p->recvbounce[i]) { + ni65_free_buffer(p); + return -ENOMEM; } - p->tmdbounce[i] = ptr; +#endif + } + + return 0; /* everything is OK */ +} + +/* + * free buffers and private struct + */ +static void ni65_free_buffer(struct priv *p) +{ + int i; + + if(!p) + return; + + for(i=0;itmdbounce[i]) + kfree(p->tmdbounce[i]); #ifdef XMT_VIA_SKB - p->tmd_skb[i] = NULL; + if(p->tmd_skb[i]) + dev_kfree_skb(p->tmd_skb[i],FREE_WRITE); #endif } + for(i=0;iname); - return -ENOMEM; - } - skb->dev = dev; - skb_reserve(skb,2); - skb_put(skb,R_BUF_SIZE); /* grab the whole space .. (not necessary) */ - if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000 ) { - printk("%s: unable to alloc receive-memory in lower 16MB!\n",dev->name); - return -EAGAIN; - } - p->recv_skb[i] = skb; - } + if(p->recv_skb[i]) + dev_kfree_skb(p->recv_skb[i],FREE_WRITE); #else - for(i=0;irecvbounce[i] = kmalloc(R_BUF_SIZE,GFP_KERNEL | GFP_DMA )) ) { - printk("%s: unable to alloc recv-mem\n",dev->name); - return -ENOMEM; - } - if( (unsigned long) p->recvbounce[i] + R_BUF_SIZE > 0x1000000 ) { - printk("%s: unable to alloc receive-memory in lower 16MB!\n",dev->name); - return -EAGAIN; - } - } + if(p->recvbounce[i]) + kfree(p->recvbounce[i]); +#endif + } + if(p->self) + kfree(p->self); +} + + +/* + * stop and (re)start lance .. e.g after an error + */ +static void ni65_stop_start(struct device *dev,struct priv *p) +{ + int csr0 = CSR0_INEA; + + writedatareg(CSR0_STOP); + + if(debuglevel > 1) + printk("ni65_stop_start\n"); + + if(p->features & INIT_RING_BEFORE_START) { + int i; +#ifdef XMT_VIA_SKB + struct sk_buff *skb_save[TMDNUM]; +#endif + unsigned long buffer[TMDNUM]; + short blen[TMDNUM]; + + if(p->xmit_queued) { + while(1) { + if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN)) + break; + p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); + if(p->tmdlast == p->tmdnum) + break; + } + } + + for(i=0;itmdhead + i; +#ifdef XMT_VIA_SKB + skb_save[i] = p->tmd_skb[i]; #endif + buffer[i] = tmdp->u.buffer; + blen[i] = tmdp->blen; + tmdp->u.s.status = 0x0; + } - return 0; /* we've found everything */ + for(i=0;irmdhead + i; + rmdp->u.s.status = RCV_OWN; + } + p->tmdnum = p->xmit_queued = 0; + writedatareg(CSR0_STRT | csr0); + + for(i=0;itmdlast) & (TMDNUM-1); + p->tmdhead[i].u.buffer = buffer[num]; /* status is part of buffer field */ + p->tmdhead[i].blen = blen[num]; + if(p->tmdhead[i].u.s.status & XMIT_OWN) { + p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); + p->xmit_queued = 1; + writedatareg(CSR0_TDMD | CSR0_INEA | csr0); + } +#ifdef XMT_VIA_SKB + p->tmd_skb[i] = skb_save[num]; +#endif + } + p->rmdnum = p->tmdlast = 0; + if(!p->lock) + dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1; + dev->trans_start = jiffies; + } + else + writedatareg(CSR0_STRT | csr0); } /* * init lance (write init-values .. init-buffers) (open-helper) */ - -static int ni65_am7990_reinit(struct device *dev) +static int ni65_lance_reinit(struct device *dev) { int i; struct priv *p = (struct priv *) dev->priv; @@ -361,17 +721,16 @@ set_dma_mode(dev->dma,DMA_MODE_CASCADE); enable_dma(dev->dma); - outw(0,PORT+L_RESET); /* first: reset the card */ - if(inw(PORT+L_DATAREG) != 0x4) + outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ + if( (i=readreg(CSR0) ) != 0x4) { - printk(KERN_ERR "%s: can't RESET ni6510 card: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); + printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name, + cards[p->cardno].cardname,(int) i); disable_dma(dev->dma); - free_dma(dev->dma); - free_irq(dev->irq, NULL); return 0; } - p->tmdnum = 0; p->tmdlast = 0; + p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0; for(i=0;itmdhead + i; @@ -386,7 +745,6 @@ tmdp->blen = tmdp->status2 = 0; } - p->rmdnum = 0; for(i=0;irmdhead + i; @@ -400,52 +758,27 @@ rmdp->u.s.status = RCV_OWN; } - for(i=0;i<6;i++) - p->ib.eaddr[i] = dev->dev_addr[i]; - - for(i=0;i<8;i++) - p->ib.filter[i] = 0x0; - p->ib.mode = 0x0; - - if(dev->flags & IFF_PROMISC) { - p->ib.mode = M_PROM; - } - else if(dev->mc_count || dev->flags & IFF_ALLMULTI) { - for(i=0;i<8;i++) - p->ib.filter[i] = 0xff; - } - - p->ib.trp = (unsigned long) p->tmdhead | TMDNUMMASK; - p->ib.rrp = (unsigned long) p->rmdhead | RMDNUMMASK; - - writereg(0,CSR3); /* busmaster/no word-swap */ - writereg((unsigned short) (((unsigned long) &(p->ib)) & 0xffff),CSR1); - writereg((unsigned short) (((unsigned long) &(p->ib))>>16),CSR2); - - writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */ + if(dev->flags & IFF_PROMISC) + ni65_init_lance(p,dev->dev_addr,0x00,M_PROM); + else if(dev->mc_count || dev->flags & IFF_ALLMULTI) + ni65_init_lance(p,dev->dev_addr,0xff,0x0); + else + ni65_init_lance(p,dev->dev_addr,0x00,0x00); /* + * ni65_set_lance_mem() sets L_ADDRREG to CSR0 * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED */ - for(i=0;i<32;i++) - { - __delay((loops_per_sec>>8)); /* wait a while */ - if(inw(PORT+L_DATAREG) & CSR0_IDON) - break; /* init ok ? */ - } - if(i == 32) - { - printk(KERN_ERR "%s: can't init am7990/lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); - disable_dma(dev->dma); - free_dma(dev->dma); - free_irq(dev->irq, NULL); - return 0; /* false */ - } - - writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); /* start lance , enable interrupts */ - - return 1; /* OK */ + if(inw(PORT+L_DATAREG) & CSR0_IDON) { + ni65_set_performance(p); + /* init OK: start lance , enable interrupts */ + writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); + return 1; /* ->OK */ + } + printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); + disable_dma(dev->dma); + return 0; /* ->Error */ } /* @@ -455,6 +788,7 @@ { int csr0; struct device *dev = (struct device *) irq2dev_map[irq]; + struct priv *p; int bcnt = 32; if (dev == NULL) { @@ -462,62 +796,104 @@ return; } - dev->interrupt = 1; + if(set_bit(0,(int *) &dev->interrupt)) { + printk("ni65: oops .. interrupt while proceeding interrupt\n"); + return; + } + p = (struct priv *) dev->priv; while(--bcnt) { - csr0 = inw(PORT+L_DATAREG); - writedatareg(csr0 & CSR0_CLRALL); /* ack interrupts, disable int. */ + +#if 0 + writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */ +#else + writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */ +#endif if(!(csr0 & (CSR0_ERR | CSR0_RINT | CSR0_TINT))) break; + if(csr0 & CSR0_RINT) /* RECV-int? */ + ni65_recv_intr(dev,csr0); + if(csr0 & CSR0_TINT) /* XMIT-int? */ + ni65_xmit_intr(dev,csr0); + if(csr0 & CSR0_ERR) { struct priv *p = (struct priv *) dev->priv; - + if (debuglevel > 1) + printk("%s: general error: %04x.\n",dev->name,csr0); if(csr0 & CSR0_BABL) p->stats.tx_errors++; - if(csr0 & CSR0_MISS) + if(csr0 & CSR0_MISS) { + int i; + for(i=0;irmdhead[i].u.s.status); + printk("\n"); p->stats.rx_errors++; + } if(csr0 & CSR0_MERR) { - writedatareg(CSR0_STOP); - writedatareg(CSR0_STRT); + if (debuglevel > 1) + printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0); + ni65_stop_start(dev,p); } } - if(csr0 & CSR0_RINT) /* RECV-int? */ - ni65_recv_intr(dev,csr0); - if(csr0 & CSR0_TINT) /* XMIT-int? */ - ni65_xmit_intr(dev,csr0); } #ifdef RCV_PARANOIA_CHECK { + int j; + for(j=0;jpriv; - int i,f=0; - for(i=0;irmdhead + ((p->rmdnum - i - 1) & (RMDNUM-1)); - if(! (rmdp->u.s.status & RCV_OWN) ) - f = 1; - else if(f) + int i,k,num1,num2; + for(i=RMDNUM-1;i>0;i--) { + num2 = (p->rmdnum + i) & (RMDNUM-1); + if(!(p->rmdhead[num2].u.s.status & RCV_OWN)) break; } - if(i < RMDNUM) { - p->rmdnum = (p->rmdnum + 8 - i) & (RMDNUM - 1); - printk(KERN_ERR "%s: Ooops, receive ring corrupted\n",dev->name); + if(i) { + for(k=0;krmdnum + k) & (RMDNUM-1); + if(!(p->rmdhead[num1].u.s.status & RCV_OWN)) + break; + } + if(!k) + break; + + if(debuglevel > 0) + { + char buf[256],*buf1; + int k; + buf1 = buf; + for(k=0;krmdhead[k].u.s.status)); /* & RCV_OWN) ); */ + buf1 += 3; + } + *buf1 = 0; + printk(KERN_ERR "%s: Ooops, receive ring corrupted %2d %2d | %s\n",dev->name,p->rmdnum,i,buf); + } + p->rmdnum = num1; ni65_recv_intr(dev,csr0); + if((p->rmdhead[num2].u.s.status & RCV_OWN)) + break; /* ok, we are 'in sync' again */ } + else + break; + } } #endif if(csr0 & (CSR0_RXON | CSR0_TXON) != (CSR0_RXON | CSR0_TXON) ) { - writedatareg(CSR0_STOP); - writedatareg(CSR0_STRT | CSR0_INEA); + printk("%s: RX or TX was offline -> restart\n",dev->name); + ni65_stop_start(dev,p); } else writedatareg(CSR0_INEA); + dev->interrupt = 0; return; @@ -539,13 +915,6 @@ if(tmdstat & XMIT_OWN) break; -#ifdef XMT_VIA_SKB - if(p->tmd_skb[p->tmdlast]) { - dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE); - p->tmd_skb[p->tmdlast] = NULL; - } -#endif - if(tmdstat & XMIT_ERR) { #if 0 @@ -558,20 +927,34 @@ if(tmdp->status2 & XMIT_LCAR) p->stats.tx_carrier_errors++; if(tmdp->status2 & (XMIT_BUFF | XMIT_UFLO )) { + /* this stops the xmitter */ p->stats.tx_fifo_errors++; - writedatareg(CSR0_STOP); - writedatareg(CSR0_STRT); - if(debuglevel > 1) + if(debuglevel > 0) printk(KERN_ERR "%s: Xmit FIFO/BUFF error\n",dev->name); + if(p->features & INIT_RING_BEFORE_START) { + tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; /* test: resend this frame */ + ni65_stop_start(dev,p); + break; /* no more Xmit processing .. */ + } + else + ni65_stop_start(dev,p); } if(debuglevel > 2) printk(KERN_ERR "%s: xmit-error: %04x %02x-%04x\n",dev->name,csr0,(int) tmdstat,(int) tmdp->status2); - p->stats.tx_errors++; + if(!(csr0 & CSR0_BABL)) /* don't count errors twice */ + p->stats.tx_errors++; tmdp->status2 = 0; } else p->stats.tx_packets++; +#ifdef XMT_VIA_SKB + if(p->tmd_skb[p->tmdlast]) { + dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE); + p->tmd_skb[p->tmdlast] = NULL; + } +#endif + p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1); if(p->tmdlast == p->tmdnum) p->xmit_queued = 0; @@ -583,16 +966,17 @@ /* * We have received a packet */ - static void ni65_recv_intr(struct device *dev,int csr0) { struct rmd *rmdp; int rmdstat,len; + int cnt=0; struct priv *p = (struct priv *) dev->priv; rmdp = p->rmdhead + p->rmdnum; while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) { + cnt++; if( (rmdstat & (RCV_START | RCV_END | RCV_ERR)) != (RCV_START | RCV_END) ) /* error or oversized? */ { if(!(rmdstat & RCV_ERR)) { @@ -603,27 +987,27 @@ } } else { - printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n", - dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) ); + if(debuglevel > 2) + printk(KERN_ERR "%s: receive-error: %04x, lance-status: %04x/%04x\n", + dev->name,(int) rmdstat,csr0,(int) inw(PORT+L_DATAREG) ); if(rmdstat & RCV_FRAM) p->stats.rx_frame_errors++; if(rmdstat & RCV_OFLO) p->stats.rx_over_errors++; - if(rmdstat & (RCV_OFLO | RCV_BUF_ERR) ) { - writedatareg(CSR0_STOP); - writedatareg(CSR0_STRT); - if(debuglevel > 1) - printk(KERN_ERR "%s: Rcv FIFO/BUFF error.\n",dev->name); - } - if(rmdstat & RCV_CRC) p->stats.rx_crc_errors++; + if(rmdstat & RCV_CRC) + p->stats.rx_crc_errors++; + if(rmdstat & RCV_BUF_ERR) + p->stats.rx_fifo_errors++; } - rmdp->u.s.status = RCV_OWN; /* change owner */ - p->stats.rx_errors++; + if(!(csr0 & CSR0_MISS)) /* don't count errors twice */ + p->stats.rx_errors++; } else if( (len = (rmdp->mlen & 0x0fff) - 4) >= 60) { #ifdef RCV_VIA_SKB - struct sk_buff *skb = dev_alloc_skb(R_BUF_SIZE+2); + struct sk_buff *skb = alloc_skb(R_BUF_SIZE+2+16,GFP_ATOMIC); + if (skb) + skb_reserve(skb,16); #else struct sk_buff *skb = dev_alloc_skb(len+2); #endif @@ -648,23 +1032,23 @@ skb_put(skb,len); eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0); #endif - rmdp->u.s.status = RCV_OWN; p->stats.rx_packets++; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } else { - rmdp->u.s.status = RCV_OWN; printk(KERN_ERR "%s: can't alloc new sk_buff\n",dev->name); p->stats.rx_dropped++; } } else { - rmdp->u.s.status = RCV_OWN; printk(KERN_INFO "%s: received runt packet\n",dev->name); p->stats.rx_errors++; } + rmdp->blen = -(R_BUF_SIZE-8); + rmdp->mlen = 0; + rmdp->u.s.status = RCV_OWN; /* change owner */ p->rmdnum = (p->rmdnum + 1) & (RMDNUM-1); rmdp = p->rmdhead + p->rmdnum; } @@ -680,11 +1064,19 @@ if(dev->tbusy) { int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) + if (tickssofar < 50) return 1; printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); - ni65_am7990_reinit(dev); +#if 0 +{ + int i; + for(i=0;itmdhead[i].u.s.status); + printk("\n"); +} +#endif + ni65_lance_reinit(dev); dev->tbusy=0; dev->trans_start = jiffies; } @@ -708,28 +1100,37 @@ { short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - struct tmd *tmdp = p->tmdhead + p->tmdnum; + struct tmd *tmdp; long flags; #ifdef XMT_VIA_SKB if( (unsigned long) (skb->data + skb->len) > 0x1000000) { #endif - tmdp->u.buffer = (unsigned long ) p->tmdbounce[p->tmdnum]; - memcpy((char *) tmdp->u.buffer,(char *)skb->data, + + memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); dev_kfree_skb (skb, FREE_WRITE); + + save_flags(flags); + cli(); + + tmdp = p->tmdhead + p->tmdnum; + tmdp->u.buffer = (unsigned long ) p->tmdbounce[p->tmdbouncenum]; + p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1); + #ifdef XMT_VIA_SKB } else { + save_flags(flags); + cli(); + + tmdp = p->tmdhead + p->tmdnum; tmdp->u.buffer = (unsigned long) skb->data; p->tmd_skb[p->tmdnum] = skb; } #endif tmdp->blen = -len; - save_flags(flags); - cli(); - tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END; writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */ @@ -748,17 +1149,75 @@ static struct enet_statistics *ni65_get_stats(struct device *dev) { + +#if 0 + int i; + struct priv *p = (struct priv *) dev->priv; + for(i=0;irmdhead + ((p->rmdnum + i) & (RMDNUM-1)); + printk("%02x ",rmdp->u.s.status); + } + printk("\n"); +#endif + return &((struct priv *) dev->priv)->stats; } static void set_multicast_list(struct device *dev) { - if(!ni65_am7990_reinit(dev)) + if(!ni65_lance_reinit(dev)) printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name); dev->tbusy = 0; } +#ifdef MODULE +static struct device dev_ni65 = { + " ", /* "ni6510": device name inserted by net_init.c */ + 0, 0, 0, 0, + 0x360, 9, /* I/O address, IRQ */ + 0, 0, 0, NULL, ni65_probe }; + +/* set: io,irq,dma or set it when calling insmod */ +int irq=0; +int io=0; +int dma=0; + +int init_module(void) +{ +#if 0 + if(io <= 0x0 || irq < 2) { + printk("ni65: Autoprobing not allowed for modules.\n"); + printk("ni65: Set symbols 'io' 'irq' and 'dma'\n"); + return -ENODEV; + } +#endif + dev_ni65.irq = irq; + dev_ni65.dma = dma; + dev_ni65.base_addr = io; + if (register_netdev(&dev_ni65) != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + struct priv *p; + p = (struct priv *) dev_ni65.priv; + if(!p) { + printk("Ooops .. no privat struct\n"); + return; + } + disable_dma(dev_ni65.dma); + free_dma(dev_ni65.dma); + release_region(dev_ni65.base_addr,cards[p->cardno].total_size); + ni65_free_buffer(p); + dev_ni65.priv = NULL; + unregister_netdev(&dev_ni65); +} +#endif /* MODULE */ + /* * END of ni65.c */ + diff -u --recursive --new-file v2.0.23/linux/drivers/net/ni65.h linux/drivers/net/ni65.h --- v2.0.23/linux/drivers/net/ni65.h Mon Feb 26 11:58:15 1996 +++ linux/drivers/net/ni65.h Wed Oct 30 03:42:41 1996 @@ -108,7 +108,7 @@ volatile unsigned char status; } s; } u; - short blen; + volatile short blen; volatile unsigned short mlen; }; @@ -123,7 +123,7 @@ volatile unsigned char status; } s; } u; - unsigned short blen; + volatile unsigned short blen; volatile unsigned short status2; }; diff -u --recursive --new-file v2.0.23/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.0.23/linux/drivers/net/slhc.c Tue Jun 25 12:03:29 1996 +++ linux/drivers/net/slhc.c Wed Oct 30 03:42:41 1996 @@ -246,6 +246,14 @@ struct iphdr *ip; struct tcphdr *th, *oth; + + /* + * Don't play with runt packets. + */ + + if(isizeihl*4 + th->doff*4; /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or - * some other control bit is set). + * some other control bit is set). Also uncompressible if + * its a runt. */ - if(th->syn || th->fin || th->rst || + if(hlen > isize || th->syn || th->fin || th->rst || ! (th->ack)){ /* TCP connection stuff; send as regular IP */ comp->sls_o_tcp++; diff -u --recursive --new-file v2.0.23/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.0.23/linux/drivers/net/tulip.c Sat Oct 19 10:06:10 1996 +++ linux/drivers/net/tulip.c Wed Oct 30 04:02:39 1996 @@ -1133,6 +1133,25 @@ } while (++i < 15); /* Now add this frame to the Tx list. */ + { + unsigned long flags; + unsigned int entry; + + save_flags(flags); cli(); + entry = tp->cur_tx++ % TX_RING_SIZE; + tp->dirty_tx++; + restore_flags(flags); + + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + tp->tx_ring[entry].length = 192 | + (entry == TX_RING_SIZE-1 ? 0x0a000000 : 0x08000); + tp->tx_ring[entry].buffer1 = virt_to_bus((char *)tp->setup_frame); + tp->tx_ring[entry].buffer2 = 0; + tp->tx_ring[entry].status = TRING_OWN; + /* Trigger an immediate transmit demand. */ + tio_write(TPOLL_TRIGGER, CSR1); + } } } diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c --- v2.0.23/linux/drivers/scsi/AM53C974.c Fri Apr 12 09:49:40 1996 +++ linux/drivers/scsi/AM53C974.c Wed Oct 30 04:03:42 1996 @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -2241,3 +2243,10 @@ cmd->scsi_done(cmd); return SCSI_ABORT_SUCCESS; } + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = AM53C974; + +#include "scsi_module.c" +#endif diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c --- v2.0.23/linux/drivers/scsi/BusLogic.c Wed Jul 17 21:22:13 1996 +++ linux/drivers/scsi/BusLogic.c Mon Oct 28 13:39:30 1996 @@ -25,7 +25,7 @@ #define BusLogic_DriverVersion "2.0.6" -#define BusLogic_DriverDate "17 July 1996" +#define BusLogic_DriverDate "19 October 1996" #include diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h --- v2.0.23/linux/drivers/scsi/BusLogic.h Wed Jul 17 21:22:13 1996 +++ linux/drivers/scsi/BusLogic.h Mon Oct 28 13:39:30 1996 @@ -1066,11 +1066,10 @@ static inline void BusLogic_Delay(int Seconds) { - unsigned long TimeoutJiffies = jiffies + Seconds * HZ; unsigned long ProcessorFlags; save_flags(ProcessorFlags); sti(); - while (jiffies < TimeoutJiffies) barrier(); + while (--Seconds >= 0) udelay(1000000); restore_flags(ProcessorFlags); } diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.0.23/linux/drivers/scsi/Config.in Sun Jul 7 11:18:51 1996 +++ linux/drivers/scsi/Config.in Wed Oct 30 03:44:13 1996 @@ -21,12 +21,12 @@ dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI -bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 +dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI -dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI +dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.0.23/linux/drivers/scsi/Makefile Sat Jul 6 12:06:37 1996 +++ linux/drivers/scsi/Makefile Wed Oct 30 03:42:41 1996 @@ -179,6 +179,10 @@ ifeq ($(CONFIG_SCSI_AM53C974),y) L_OBJS += AM53C974.o +else + ifeq ($(CONFIG_SCSI_AM53C974),m) + M_OBJS += AM53C974.o + endif endif ifeq ($(CONFIG_SCSI_BUSLOGIC),y) diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c --- v2.0.23/linux/drivers/scsi/NCR5380.c Mon Apr 29 17:14:19 1996 +++ linux/drivers/scsi/NCR5380.c Tue Oct 29 16:21:48 1996 @@ -734,7 +734,7 @@ */ static void NCR5380_print_status (struct Scsi_Host *instance) { - char pr_bfr[256]; + static char pr_bfr[512]; char *start; int len; @@ -767,7 +767,7 @@ */ #undef SPRINTF -#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) +#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0) static char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); static diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.0.23/linux/drivers/scsi/aha152x.c Wed Sep 11 17:57:14 1996 +++ linux/drivers/scsi/aha152x.c Wed Oct 30 03:42:41 1996 @@ -404,7 +404,7 @@ /* END OF DEFINES */ -extern long loops_per_sec; +extern unsigned long loops_per_sec; #define DELAY_DEFAULT 100 diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.0.23/linux/drivers/scsi/aic7xxx.c Sat Oct 19 10:06:11 1996 +++ linux/drivers/scsi/aic7xxx.c Tue Oct 29 00:21:33 1996 @@ -1,3 +1,5 @@ +#define EXPERIMENTAL_FLAGS 0 + /*+M************************************************************************* * Adaptec AIC7xxx device driver for Linux. * @@ -4314,7 +4316,7 @@ p->flags = config->flags; p->chan_num = config->chan_num; p->scb_link = &(p->scb_usage); -#ifdef AIC7XXX_SHARE_SCBS +#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS) if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883))) { shared_3985_scbs = &(p->scb_usage); @@ -4410,7 +4412,7 @@ outb(config->scsi_id_b, SCSIID + base); scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL); outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base); -#if 1 +#if EXPERIMENTAL_FLAGS outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base); #else outb(ENSELTIMO, SIMODE1 + base); @@ -4432,7 +4434,7 @@ outb(config->scsi_id, SCSIID + base); scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL); outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base); -#if 1 +#if EXPERIMENTAL_FLAGS outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base); #else outb(ENSELTIMO, SIMODE1 + base); diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v2.0.23/linux/drivers/scsi/eata_dma.c Sat Aug 17 21:19:27 1996 +++ linux/drivers/scsi/eata_dma.c Tue Oct 29 00:30:43 1996 @@ -58,7 +58,7 @@ * Jagdis who did a lot of testing and found quite a number * * of bugs during the development. * ************************************************************ - * last change: 96/08/13 OS: Linux 2.0.12 * + * last change: 96/10/21 OS: Linux 2.0.23 * ************************************************************/ /* Look in eata_dma.h for configuration and revision information */ @@ -295,12 +295,9 @@ sp->EOC = FALSE; /* Clean out this flag */ if (ccb->status == LOCKED || ccb->status == RESET) { - ccb->status = FREE; - eata_stat = inb(base + HA_RSTATUS); - printk("eata_dma: int_handler, reseted command returned," - " freeing reseted queueslot\n"); + printk("eata_dma: int_handler, reseted command pid %ld returned" + "\n", cmd->pid); DBG(DBG_INTR && DBG_DELAY, DELAY(1)); - break; } eata_stat = inb(base + HA_RSTATUS); @@ -467,23 +464,33 @@ struct Scsi_Host *sh; struct eata_ccb *ccb; struct scatterlist *sl; + save_flags(flags); cli(); + +#if 0 + for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) { + if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) { + printk("eata_dma: scsi%d interrupt pending in eata_queue.\n" + " Calling interrupt handler.\n", sh->host_no); + eata_int_handler(sh->irq, 0, 0); + } + } +#endif queue_counter++; hd = HD(cmd); sh = cmd->host; -#if 1 if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) { DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n")); cmd->result = DID_OK << 16; done(cmd); + return(0); } -#endif /* check for free slot */ for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { @@ -678,7 +685,6 @@ " reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason)); - /* Some interrupt controllers seem to loose interrupts */ for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) { if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) { printk("eata_dma: scsi%d interrupt pending in eata_reset.\n" @@ -686,6 +692,7 @@ eata_int_handler(sh->irq, 0, 0); } } + if (HD(cmd)->state == RESET) { printk("eata_reset: exit, already in reset.\n"); restore_flags(flags); @@ -766,9 +773,9 @@ restore_flags(flags); if (success) { - DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n")); + DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n")); DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); - return (SCSI_RESET_SUCCESS); + return (SCSI_RESET_PENDING); } else { DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n")); DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); @@ -852,8 +859,9 @@ device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10; break; } - } else /* ISA forces us to limit the QS because of bounce buffers*/ - device->queue_depth = 2; /* I know this is cruel */ + } else /* ISA forces us to limit the queue depth because of the + * bounce buffer memory overhead. I know this is cruel */ + device->queue_depth = 2; /* * It showed that we need to set an upper limit of commands @@ -863,6 +871,8 @@ */ if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT) device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT; + if(device->queue_depth == 0) + device->queue_depth = 1; printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d " "set to %d\n", host->host_no, device->id, device->channel, diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v2.0.23/linux/drivers/scsi/eata_dma.h Sat Aug 17 21:19:27 1996 +++ linux/drivers/scsi/eata_dma.h Tue Oct 29 00:30:43 1996 @@ -4,7 +4,7 @@ * mike@i-Connect.Net * * neuffer@mail.uni-mainz.de * ********************************************************* -* last change: 96/08/14 * +* last change: 96/10/14 * ********************************************************/ #ifndef _EATA_DMA_H @@ -17,7 +17,7 @@ #define VER_MAJOR 2 #define VER_MINOR 5 -#define VER_SUB "9a" +#define VER_SUB "9b" /************************************************************************ diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/eata_generic.h linux/drivers/scsi/eata_generic.h --- v2.0.23/linux/drivers/scsi/eata_generic.h Sat Aug 17 21:19:27 1996 +++ linux/drivers/scsi/eata_generic.h Tue Oct 29 00:30:43 1996 @@ -68,7 +68,7 @@ #define SG_SIZE 64 #define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ -#define UPPER_DEVICE_QUEUE_LIMIT 24 /* The limit we have to set for the +#define UPPER_DEVICE_QUEUE_LIMIT 64 /* The limit we have to set for the * device queue to keep the broken * midlevel SCSI code from producing * bogus timeouts diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.0.23/linux/drivers/scsi/hosts.c Sat Aug 10 10:03:15 1996 +++ linux/drivers/scsi/hosts.c Tue Oct 29 00:30:43 1996 @@ -224,6 +224,12 @@ #ifdef CONFIG_SCSI_ADVANSYS ADVANSYS, #endif +#ifdef CONFIG_SCSI_EATA_DMA + EATA_DMA, +#endif +#ifdef CONFIG_SCSI_EATA_PIO + EATA_PIO, +#endif /* BusLogic must come before aha1542.c */ #ifdef CONFIG_SCSI_BUSLOGIC BUSLOGIC, @@ -281,12 +287,6 @@ #endif #ifdef CONFIG_SCSI_NCR53C8XX NCR53C8XX, -#endif -#ifdef CONFIG_SCSI_EATA_DMA - EATA_DMA, -#endif -#ifdef CONFIG_SCSI_EATA_PIO - EATA_PIO, #endif #ifdef CONFIG_SCSI_7000FASST WD7000, diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.0.23/linux/drivers/scsi/scsi.c Tue Oct 8 21:20:14 1996 +++ linux/drivers/scsi/scsi.c Wed Oct 30 03:12:04 1996 @@ -17,8 +17,8 @@ * add scatter-gather, multiple outstanding request, and other * enhancements. * - * Native multichannel and wide scsi support added - * by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de + * Native multichannel, wide scsi, /proc/scsi and hot plugging + * support added by Michael Neuffer * * Added request_module("scsi_hostadapter") for kerneld: * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules) @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -275,6 +276,7 @@ */ {"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN}, {"TEXEL","CD-ROM","1.06", BLIST_BORKEN}, +{"IOMEGA","Io20S *F","*", BLIST_KEY}, {"INSITE","Floptical F*8I","*", BLIST_KEY}, {"INSITE","I325VM","*", BLIST_KEY}, {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, @@ -1215,17 +1217,19 @@ */ timeout = host->last_reset + MIN_RESET_DELAY; if (jiffies < timeout) { - /* - * NOTE: This may be executed from within an interrupt - * handler! This is bad, but for now, it'll do. The irq - * level of the interrupt handler has been masked out by the - * platform dependent interrupt handling code already, so the - * sti() here will not cause another call to the SCSI host's - * interrupt handler (assuming there is one irq-level per - * host). - */ - sti(); - while (jiffies < timeout) barrier(); + int ticks_remaining = timeout - jiffies; + /* + * NOTE: This may be executed from within an interrupt + * handler! This is bad, but for now, it'll do. The irq + * level of the interrupt handler has been masked out by the + * platform dependent interrupt handling code already, so the + * sti() here will not cause another call to the SCSI host's + * interrupt handler (assuming there is one irq-level per + * host). + */ + sti(); + while (--ticks_remaining >= 0) udelay(1000000/HZ); + host->last_reset = jiffies - MIN_RESET_DELAY; } restore_flags(flags); @@ -1791,7 +1795,8 @@ if ((++SCpnt->retries) < SCpnt->allowed) { if ((SCpnt->retries >= (SCpnt->allowed >> 1)) - && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD) + && !(SCpnt->host->last_reset > 0 && + jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD) && !(SCpnt->flags & WAS_RESET)) { printk("scsi%d channel %d : resetting for second half of retries.\n", @@ -3062,7 +3067,11 @@ */ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) - if(shpnt->hostt == tpnt) scan_scsis(shpnt,0,0,0,0); + if(shpnt->hostt == tpnt) { + scan_scsis(shpnt,0,0,0,0); + if (shpnt->select_queue_depths != NULL) + (shpnt->select_queue_depths)(shpnt, scsi_devices); + } for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.0.23/linux/drivers/scsi/sd.c Fri Sep 20 17:00:34 1996 +++ linux/drivers/scsi/sd.c Tue Oct 29 00:30:44 1996 @@ -512,7 +512,7 @@ if (flag++ == 0) SCpnt = allocate_device(&CURRENT, - rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); + rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); else SCpnt = NULL; /* @@ -537,7 +537,8 @@ cli(); req = CURRENT; while(req){ - SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(req->rq_dev)].device); + SCpnt = request_queueable(req, + rscsi_disks[DEVICE_NR(req->rq_dev)].device); if(SCpnt) break; req1 = req; req = req->next; diff -u --recursive --new-file v2.0.23/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.0.23/linux/drivers/scsi/st.c Tue Oct 8 21:20:14 1996 +++ linux/drivers/scsi/st.c Tue Oct 29 17:40:50 1996 @@ -2314,6 +2314,7 @@ return (-EBUSY); STp->drv_block = (STp->mt_status)->mt_fileno = (-1); + STp->eof = ST_NOEOF; if ((STp->buffer)->last_result_fatal != 0) { result = (-EIO); if (STp->can_partitions && diff -u --recursive --new-file v2.0.23/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.0.23/linux/fs/proc/array.c Thu Aug 29 19:15:14 1996 +++ linux/fs/proc/array.c Wed Oct 30 03:42:41 1996 @@ -307,7 +307,7 @@ static int get_version(char * buffer) { - extern char *linux_banner; + extern const char *linux_banner; strcpy(buffer, linux_banner); return strlen(buffer); diff -u --recursive --new-file v2.0.23/linux/fs/super.c linux/fs/super.c --- v2.0.23/linux/fs/super.c Fri Sep 20 17:00:35 1996 +++ linux/fs/super.c Wed Oct 30 01:58:59 1996 @@ -146,6 +146,8 @@ if (vfsmnttail->mnt_dev == dev) vfsmnttail = lptr; } + if (tofree == mru_vfsmnt) + mru_vfsmnt = NULL; kfree(tofree->mnt_devname); kfree(tofree->mnt_dirname); kfree_s(tofree, sizeof(struct vfsmount)); diff -u --recursive --new-file v2.0.23/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.0.23/linux/include/asm-i386/pgtable.h Sun Sep 8 19:50:21 1996 +++ linux/include/asm-i386/pgtable.h Wed Oct 30 04:53:16 1996 @@ -88,7 +88,7 @@ __flush_tlb() -#undef CLEVER_SMP_INVALIDATE +#define CLEVER_SMP_INVALIDATE #ifdef CLEVER_SMP_INVALIDATE /* @@ -97,9 +97,6 @@ * * These mean you can really definitely utterly forget about * writing to user space from interrupts. (Its not allowed anyway). - * - * Doesn't currently work as Linus makes flush tlb calls before - * stuff like current/current->mm are setup properly */ static inline void flush_tlb_current_task(void) diff -u --recursive --new-file v2.0.23/linux/include/linux/fddidevice.h linux/include/linux/fddidevice.h --- v2.0.23/linux/include/linux/fddidevice.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/fddidevice.h Wed Oct 30 03:42:41 1996 @@ -0,0 +1,42 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the FDDI handlers. + * + * Version: @(#)fddidevice.h 1.0.0 08/12/96 + * + * Author: Lawrence V. Stefani, + * + * fddidevice.h is based on previous trdevice.h work by + * Ross Biro, + * Fred N. van Kempen, + * Alan Cox, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_FDDIDEVICE_H +#define _LINUX_FDDIDEVICE_H + +#include + +#ifdef __KERNEL__ +extern int fddi_header(struct sk_buff *skb, + struct device *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len); +extern int fddi_rebuild_header(void *buff, + struct device *dev, + unsigned long dest, + struct sk_buff *skb); +extern unsigned short fddi_type_trans(struct sk_buff *skb, + struct device *dev); +#endif + +#endif /* _LINUX_FDDIDEVICE_H */ diff -u --recursive --new-file v2.0.23/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.0.23/linux/include/linux/fs.h Fri Sep 20 17:00:36 1996 +++ linux/include/linux/fs.h Wed Oct 30 04:53:05 1996 @@ -16,8 +16,6 @@ #include #include -#include - /* * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix * that later. Anyway, now the file code is no longer dependent @@ -121,6 +119,7 @@ #ifdef __KERNEL__ +#include #include extern void buffer_init(void); diff -u --recursive --new-file v2.0.23/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.0.23/linux/include/linux/if_arp.h Thu Jul 25 20:28:49 1996 +++ linux/include/linux/if_arp.h Wed Oct 30 04:55:11 1996 @@ -5,14 +5,15 @@ * * Global definitions for the ARP (RFC 826) protocol. * - * Version: @(#)if_arp.h 1.0.1 04/16/93 + * Version: @(#)if_arp.h 1.0.2 08/12/96 * * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. * Ross Biro, * Fred N. van Kempen, * Florian La Roche, - * Jonathan Layes + * Jonathan Layes, + * Lawrence V. Stefani, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -52,6 +53,7 @@ #define ARPHRD_SKIP 771 /* SKIP vif */ #define ARPHRD_LOOPBACK 772 /* Loopback device */ #define ARPHRD_LOCALTLK 773 /* Localtalk device */ +#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */ /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request */ diff -u --recursive --new-file v2.0.23/linux/include/linux/if_fddi.h linux/include/linux/if_fddi.h --- v2.0.23/linux/include/linux/if_fddi.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/if_fddi.h Wed Oct 30 03:42:41 1996 @@ -0,0 +1,202 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the ANSI FDDI interface. + * + * Version: @(#)if_fddi.h 1.0.1 09/16/96 + * + * Author: Lawrence V. Stefani, + * + * if_fddi.h is based on previous if_ether.h and if_tr.h work by + * Fred N. van Kempen, + * Donald Becker, + * Alan Cox, + * Steve Whitehouse, + * Peter De Schrijver, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_FDDI_H +#define _LINUX_IF_FDDI_H + +/* + * Define max and min legal sizes. The frame sizes do not include + * 4 byte FCS/CRC (frame check sequence). + */ +#define FDDI_K_ALEN 6 /* Octets in one FDDI address */ +#define FDDI_K_8022_HLEN 16 /* Total octets in 802.2 header */ +#define FDDI_K_SNAP_HLEN 21 /* Total octets in 802.2 SNAP header */ +#define FDDI_K_8022_ZLEN 16 /* Min octets in 802.2 frame sans FCS */ +#define FDDI_K_SNAP_ZLEN 21 /* Min octets in 802.2 SNAP frame sans FCS */ +#define FDDI_K_8022_DLEN 4475 /* Max octets in 802.2 payload */ +#define FDDI_K_SNAP_DLEN 4470 /* Max octets in 802.2 SNAP payload */ +#define FDDI_K_LLC_ZLEN 13 /* Min octets in LLC frame sans FCS */ +#define FDDI_K_LLC_LEN 4491 /* Max octets in LLC frame sans FCS */ + +/* Define FDDI Frame Control (FC) Byte values */ +#define FDDI_FC_K_VOID 0x00 +#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80 +#define FDDI_FC_K_RESTRICTED_TOKEN 0xC0 +#define FDDI_FC_K_SMT_MIN 0x41 +#define FDDI_FC_K_SMT_MAX 0x4F +#define FDDI_FC_K_MAC_MIN 0xC1 +#define FDDI_FC_K_MAC_MAX 0xCF +#define FDDI_FC_K_ASYNC_LLC_MIN 0x50 +#define FDDI_FC_K_ASYNC_LLC_DEF 0x54 +#define FDDI_FC_K_ASYNC_LLC_MAX 0x5F +#define FDDI_FC_K_SYNC_LLC_MIN 0xD0 +#define FDDI_FC_K_SYNC_LLC_MAX 0xD7 +#define FDDI_FC_K_IMPLEMENTOR_MIN 0x60 +#define FDDI_FC_K_IMPLEMENTOR_MAX 0x6F +#define FDDI_FC_K_RESERVED_MIN 0x70 +#define FDDI_FC_K_RESERVED_MAX 0x7F + +/* Define LLC and SNAP constants */ +#define FDDI_EXTENDED_SAP 0xAA +#define FDDI_UI_CMD 0x03 + +/* Define 802.2 Type 1 header */ +struct fddi_8022_1_hdr + { + __u8 dsap; /* destination service access point */ + __u8 ssap; /* source service access point */ + __u8 ctrl; /* control byte #1 */ + } __attribute__ ((packed)); + +/* Define 802.2 Type 2 header */ +struct fddi_8022_2_hdr + { + __u8 dsap; /* destination service access point */ + __u8 ssap; /* source service access point */ + __u8 ctrl_1; /* control byte #1 */ + __u8 ctrl_2; /* control byte #2 */ + } __attribute__ ((packed)); + +/* Define 802.2 SNAP header */ +#define FDDI_K_OUI_LEN 3 +struct fddi_snap_hdr + { + __u8 dsap; /* always 0xAA */ + __u8 ssap; /* always 0xAA */ + __u8 ctrl; /* always 0x03 */ + __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */ + __u16 ethertype; /* packet type ID field */ + } __attribute__ ((packed)); + +/* Define FDDI LLC frame header */ +struct fddihdr + { + __u8 fc; /* frame control */ + __u8 daddr[FDDI_K_ALEN]; /* destination address */ + __u8 saddr[FDDI_K_ALEN]; /* source address */ + union + { + struct fddi_8022_1_hdr llc_8022_1; + struct fddi_8022_2_hdr llc_8022_2; + struct fddi_snap_hdr llc_snap; + } hdr; + } __attribute__ ((packed)); + +/* Define FDDI statistics structure */ +struct fddi_statistics + { + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 transmit_collision; /* always 0 for FDDI */ + + /* Detailed FDDI statistics. Adopted from RFC 1512 */ + + __u8 smt_station_id[8]; + __u32 smt_op_version_id; + __u32 smt_hi_version_id; + __u32 smt_lo_version_id; + __u8 smt_user_data[32]; + __u32 smt_mib_version_id; + __u32 smt_mac_cts; + __u32 smt_non_master_cts; + __u32 smt_master_cts; + __u32 smt_available_paths; + __u32 smt_config_capabilities; + __u32 smt_config_policy; + __u32 smt_connection_policy; + __u32 smt_t_notify; + __u32 smt_stat_rpt_policy; + __u32 smt_trace_max_expiration; + __u32 smt_bypass_present; + __u32 smt_ecm_state; + __u32 smt_cf_state; + __u32 smt_remote_disconnect_flag; + __u32 smt_station_status; + __u32 smt_peer_wrap_flag; + __u32 smt_time_stamp; + __u32 smt_transition_time_stamp; + __u32 mac_frame_status_functions; + __u32 mac_t_max_capability; + __u32 mac_tvx_capability; + __u32 mac_available_paths; + __u32 mac_current_path; + __u8 mac_upstream_nbr[FDDI_K_ALEN]; + __u8 mac_downstream_nbr[FDDI_K_ALEN]; + __u8 mac_old_upstream_nbr[FDDI_K_ALEN]; + __u8 mac_old_downstream_nbr[FDDI_K_ALEN]; + __u32 mac_dup_address_test; + __u32 mac_requested_paths; + __u32 mac_downstream_port_type; + __u8 mac_smt_address[FDDI_K_ALEN]; + __u32 mac_t_req; + __u32 mac_t_neg; + __u32 mac_t_max; + __u32 mac_tvx_value; + __u32 mac_frame_cts; + __u32 mac_copied_cts; + __u32 mac_transmit_cts; + __u32 mac_error_cts; + __u32 mac_lost_cts; + __u32 mac_frame_error_threshold; + __u32 mac_frame_error_ratio; + __u32 mac_rmt_state; + __u32 mac_da_flag; + __u32 mac_una_da_flag; + __u32 mac_frame_error_flag; + __u32 mac_ma_unitdata_available; + __u32 mac_hardware_present; + __u32 mac_ma_unitdata_enable; + __u32 path_tvx_lower_bound; + __u32 path_t_max_lower_bound; + __u32 path_max_t_req; + __u32 path_configuration[8]; + __u32 port_my_type[2]; + __u32 port_neighbor_type[2]; + __u32 port_connection_policies[2]; + __u32 port_mac_indicated[2]; + __u32 port_current_path[2]; + __u8 port_requested_paths[3*2]; + __u32 port_mac_placement[2]; + __u32 port_available_paths[2]; + __u32 port_pmd_class[2]; + __u32 port_connection_capabilities[2]; + __u32 port_bs_flag[2]; + __u32 port_lct_fail_cts[2]; + __u32 port_ler_estimate[2]; + __u32 port_lem_reject_cts[2]; + __u32 port_lem_cts[2]; + __u32 port_ler_cutoff[2]; + __u32 port_ler_alarm[2]; + __u32 port_connect_state[2]; + __u32 port_pcm_state[2]; + __u32 port_pc_withhold[2]; + __u32 port_ler_flag[2]; + __u32 port_hardware_present[2]; + }; + +#endif /* _LINUX_IF_FDDI_H */ diff -u --recursive --new-file v2.0.23/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.0.23/linux/include/linux/netdevice.h Mon Aug 5 10:13:54 1996 +++ linux/include/linux/netdevice.h Wed Oct 30 04:55:08 1996 @@ -5,7 +5,7 @@ * * Definitions for the Interfaces handler. * - * Version: @(#)dev.h 1.0.10 08/12/93 + * Version: @(#)dev.h 1.0.11 07/31/96 * * Authors: Ross Biro, * Fred N. van Kempen, @@ -13,6 +13,7 @@ * Donald J. Becker, * Alan Cox, * Bjorn Ekwall. + * Lawrence V. Stefani, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +21,7 @@ * 2 of the License, or (at your option) any later version. * * Moved to /usr/include/linux for NET3 + * Added extern for fddi_setup() */ #ifndef _LINUX_NETDEVICE_H #define _LINUX_NETDEVICE_H @@ -286,6 +288,7 @@ extern void ether_setup(struct device *dev); extern void tr_setup(struct device *dev); +extern void fddi_setup(struct device *dev); extern int ether_config(struct device *dev, struct ifmap *map); /* Support for loadable net-drivers */ extern int register_netdev(struct device *dev); diff -u --recursive --new-file v2.0.23/linux/include/linux/raid0.h linux/include/linux/raid0.h --- v2.0.23/linux/include/linux/raid0.h Mon Feb 26 13:51:46 1996 +++ linux/include/linux/raid0.h Tue Oct 29 15:20:35 1996 @@ -1,32 +1,3 @@ - -#ifndef _RAID0_H -#define _RAID0_H - -struct strip_zone -{ - int zone_offset; /* Zone offset in md_dev */ - int dev_offset; /* Zone offset in real dev */ - int size; /* Zone size */ - int nb_dev; /* Number of devices attached to the zone */ - struct real_dev *dev[MAX_REAL]; /* Devices attached to the zone */ -}; - -struct raid0_hash -{ - struct strip_zone *zone0, *zone1; -}; - -struct raid0_data -{ - struct raid0_hash *hash_table; /* Dynamically allocated */ - struct strip_zone *strip_zone; /* This one too */ - int nr_strip_zones; - struct strip_zone *smallest; - int nr_zones; -}; - -#endif - #ifndef _RAID0_H #define _RAID0_H diff -u --recursive --new-file v2.0.23/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.0.23/linux/include/linux/skbuff.h Thu Jul 25 20:26:55 1996 +++ linux/include/linux/skbuff.h Wed Oct 30 04:53:15 1996 @@ -102,7 +102,7 @@ #define PACKET_OTHERHOST 3 /* To someone else */ unsigned short users; /* User count - see datagram.c,tcp.c */ unsigned short protocol; /* Packet protocol from driver. */ - unsigned short truesize; /* Buffer size */ + unsigned int truesize; /* Buffer size */ atomic_t count; /* reference count */ struct sk_buff *data_skb; /* Link to the actual data skb */ diff -u --recursive --new-file v2.0.23/linux/include/net/sock.h linux/include/net/sock.h --- v2.0.23/linux/include/net/sock.h Thu Jul 25 20:28:50 1996 +++ linux/include/net/sock.h Wed Oct 30 04:55:13 1996 @@ -169,6 +169,7 @@ __u32 fin_seq; __u32 urg_seq; __u32 urg_data; + __u32 syn_seq; int users; /* user count */ /* * Not all are volatile, but some are, so we @@ -216,7 +217,7 @@ volatile unsigned long ato; /* ack timeout */ volatile unsigned long lrcvtime; /* jiffies at last data rcv */ volatile unsigned long idletime; /* jiffies at last rcv */ - unsigned short bytes_rcv; + unsigned int bytes_rcv; /* * mss is min(mtu, max_window) */ @@ -251,8 +252,8 @@ unsigned char max_ack_backlog; unsigned char priority; unsigned char debug; - unsigned short rcvbuf; - unsigned short sndbuf; + unsigned int rcvbuf; + unsigned int sndbuf; unsigned short type; unsigned char localroute; /* Route locally only */ #ifdef CONFIG_AX25 diff -u --recursive --new-file v2.0.23/linux/init/main.c linux/init/main.c --- v2.0.23/linux/init/main.c Tue Oct 8 21:20:14 1996 +++ linux/init/main.c Wed Oct 30 03:42:41 1996 @@ -50,7 +50,7 @@ #endif extern char _stext, _etext; -extern char *linux_banner; +extern const char *linux_banner; static char printbuf[1024]; @@ -65,7 +65,7 @@ extern long console_init(long, long); extern long kmalloc_init(long,long); extern void sock_init(void); -extern long pci_init(long, long); +extern unsigned long pci_init(unsigned long, unsigned long); extern void sysctl_init(void); extern void no_scroll(char *str, int *ints); diff -u --recursive --new-file v2.0.23/linux/kernel/exit.c linux/kernel/exit.c --- v2.0.23/linux/kernel/exit.c Fri Jul 5 13:48:39 1996 +++ linux/kernel/exit.c Wed Oct 30 03:42:42 1996 @@ -21,7 +21,7 @@ #include extern void sem_exit (void); -extern void acct_process (long exitcode); +extern int acct_process (long exitcode); extern void kerneld_exit(void); int getrusage(struct task_struct *, int, struct rusage *); diff -u --recursive --new-file v2.0.23/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.0.23/linux/kernel/ksyms.c Sun Sep 15 10:34:18 1996 +++ linux/kernel/ksyms.c Wed Oct 30 03:42:42 1996 @@ -65,13 +65,13 @@ #endif extern char *get_options(char *str, int *ints); -extern void set_device_ro(int dev,int flag); +extern void set_device_ro(kdev_t dev,int flag); extern struct file_operations * get_blkfops(unsigned int); extern void blkdev_release(struct inode * inode); extern void *sys_call_table; -extern int sys_tz; +extern struct timezone sys_tz; extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); diff -u --recursive --new-file v2.0.23/linux/net/802/Makefile linux/net/802/Makefile --- v2.0.23/linux/net/802/Makefile Tue Apr 9 14:36:31 1996 +++ linux/net/802/Makefile Wed Oct 30 03:42:42 1996 @@ -14,6 +14,10 @@ O_OBJS += tr.o endif +ifdef CONFIG_FDDI +O_OBJS += fddi.o +endif + ifdef CONFIG_IPX OX_OBJS += p8022.o psnap.o p8022tr.o endif diff -u --recursive --new-file v2.0.23/linux/net/802/fddi.c linux/net/802/fddi.c --- v2.0.23/linux/net/802/fddi.c Thu Jan 1 02:00:00 1970 +++ linux/net/802/fddi.c Wed Oct 30 04:36:35 1996 @@ -0,0 +1,162 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * FDDI-type device handling. + * + * Version: @(#)fddi.c 1.0.0 08/12/96 + * + * Authors: Lawrence V. Stefani, + * + * fddi.c is based on previous eth.c and tr.c work by + * Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * Florian La Roche, + * Alan Cox, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Create the FDDI MAC header for an arbitrary protocol layer + * + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp) + */ + +int fddi_header( + struct sk_buff *skb, + struct device *dev, + unsigned short type, + void *daddr, + void *saddr, + unsigned len + ) + + { + struct fddihdr *fddi = (struct fddihdr *)skb_push(skb, FDDI_K_SNAP_HLEN); + + /* Fill in frame header - assume 802.2 SNAP frames for now */ + + fddi->fc = FDDI_FC_K_ASYNC_LLC_DEF; + fddi->hdr.llc_snap.dsap = FDDI_EXTENDED_SAP; + fddi->hdr.llc_snap.ssap = FDDI_EXTENDED_SAP; + fddi->hdr.llc_snap.ctrl = FDDI_UI_CMD; + fddi->hdr.llc_snap.oui[0] = 0x00; + fddi->hdr.llc_snap.oui[1] = 0x00; + fddi->hdr.llc_snap.oui[2] = 0x00; + fddi->hdr.llc_snap.ethertype = htons(type); + + /* Set the source and destination hardware addresses */ + + if (saddr != NULL) + memcpy(fddi->saddr, saddr, dev->addr_len); + else + memcpy(fddi->saddr, dev->dev_addr, dev->addr_len); + + if (daddr != NULL) + { + memcpy(fddi->daddr, daddr, dev->addr_len); + return(FDDI_K_SNAP_HLEN); + } + return(-FDDI_K_SNAP_HLEN); + } + + +/* + * Rebuild the FDDI MAC header. This is called after an ARP + * (or in future other address resolution) has completed on + * this sk_buff. We now let ARP fill in the other fields. + */ + +int fddi_rebuild_header( + void *buff, + struct device *dev, + unsigned long dest, + struct sk_buff *skb + ) + + { + struct fddihdr *fddi = (struct fddihdr *)buff; + + /* Only ARP/IP is currently supported */ + + if (fddi->hdr.llc_snap.ethertype != htons(ETH_P_IP)) + { + printk("fddi_rebuild_header: Don't know how to resolve type %04X addresses?\n", (unsigned int)htons(fddi->hdr.llc_snap.ethertype)); + return(0); + } + + /* Try to get ARP to resolve the header and fill destination address */ + + if (arp_find(fddi->daddr, dest, dev, dev->pa_addr, skb)) + return(1); + else + return(0); + } + + +/* + * Determine the packet's protocol ID and fill in skb fields. + * This routine is called before an incoming packet is passed + * up. It's used to fill in specific skb fields and to set + * the proper pointer to the start of packet data (skb->data). + */ + +unsigned short fddi_type_trans( + struct sk_buff *skb, + struct device *dev + ) + + { + struct fddihdr *fddi = (struct fddihdr *)skb->data; + + /* + * Set mac.raw field to point to FC byte, set data field to point + * to start of packet data. Assume 802.2 SNAP frames for now. + */ + + skb->mac.raw = skb->data; /* point to frame control (FC) */ + skb_pull(skb, FDDI_K_SNAP_HLEN); /* adjust for 21 byte header */ + + /* Set packet type based on destination address and flag settings */ + + if (*fddi->daddr & 0x01) + { + if (memcmp(fddi->daddr, dev->broadcast, FDDI_K_ALEN) == 0) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } + + else if (dev->flags & IFF_PROMISC) + { + if (memcmp(fddi->daddr, dev->dev_addr, FDDI_K_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + } + + /* Assume 802.2 SNAP frames, for now */ + + return(fddi->hdr.llc_snap.ethertype); + } diff -u --recursive --new-file v2.0.23/linux/net/core/dev.c linux/net/core/dev.c --- v2.0.23/linux/net/core/dev.c Mon Aug 5 10:13:55 1996 +++ linux/net/core/dev.c Wed Oct 30 03:42:42 1996 @@ -47,6 +47,9 @@ * 1 device. * Thomas Bogendoerfer : Return ENODEV for dev_open, if there * is no device open function. + * Lawrence V. Stefani : Changed set MTU ioctl to not assume + * min MTU of 68 bytes for devices + * that have change MTU functions. * */ @@ -1196,17 +1199,17 @@ case SIOCSIFMTU: /* Set the MTU of a device */ - /* - * MTU must be positive. - */ - - if(ifr.ifr_mtu<68) - return -EINVAL; - if (dev->change_mtu) ret = (*dev->change_mtu)(dev, ifr.ifr_mtu); else { + /* + * MTU must be positive. + */ + + if(ifr.ifr_mtu<68) + return -EINVAL; + dev->mtu = ifr.ifr_mtu; ret = 0; } @@ -1367,7 +1370,7 @@ extern int ni65_init(void); extern int pi_init(void); extern void sdla_setup(void); -extern void dlci_setup(void); +extern int dlci_setup(void); int net_dev_init(void) { diff -u --recursive --new-file v2.0.23/linux/net/core/sock.c linux/net/core/sock.c --- v2.0.23/linux/net/core/sock.c Wed Aug 21 09:18:10 1996 +++ linux/net/core/sock.c Wed Oct 30 03:42:42 1996 @@ -443,7 +443,7 @@ { struct sk_buff *skb; int err; - + unsigned long mem; do { if(sk->err!=0) @@ -462,6 +462,9 @@ return NULL; } + + mem=sk->wmem_alloc; + if(!fallback) skb = sock_wmalloc(sk, size, 0, sk->allocation); else @@ -479,8 +482,6 @@ if(skb==NULL) { - unsigned long tmp; - sk->socket->flags |= SO_NOSPACE; if(noblock) { @@ -492,7 +493,6 @@ *errcode=-EPIPE; return NULL; } - tmp = sk->wmem_alloc; cli(); if(sk->shutdown&SEND_SHUTDOWN) { @@ -501,19 +501,7 @@ return NULL; } -#if 1 - if( tmp <= sk->wmem_alloc) -#else - /* ANK: Line above seems either incorrect - * or useless. sk->wmem_alloc has a tiny chance to change - * between tmp = sk->w... and cli(), - * but it might(?) change earlier. In real life - * it does not (I never seen the message). - * In any case I'd delete this check at all, or - * change it to: - */ - if (sk->wmem_alloc + size >= sk->sndbuf) -#endif + if (sk->wmem_alloc==mem) { sk->socket->flags &= ~SO_NOSPACE; interruptible_sleep_on(sk->sleep); diff -u --recursive --new-file v2.0.23/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.0.23/linux/net/ipv4/arp.c Tue Oct 8 21:20:14 1996 +++ linux/net/ipv4/arp.c Wed Oct 30 03:42:42 1996 @@ -60,6 +60,7 @@ * Mike Shaver : /proc/sys/net/ipv4/arp_* support * Stuart Cheshire : Metricom and grat arp fixes * *** FOR 2.1 clean this up *** + * Lawrence V. Stefani: (08/12/96) Added FDDI support. */ /* RFC1122 Status: @@ -86,6 +87,7 @@ #include #include #include +#include #include #include #include @@ -1289,7 +1291,8 @@ return 1; #ifdef CONFIG_IP_MULTICAST case IS_MULTICAST: - if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802) + if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802 + || dev->type==ARPHRD_FDDI) { u32 taddr; haddr[0]=0x01; @@ -1702,11 +1705,23 @@ /* * Fill the device header for the ARP frame */ - dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len); - /* Fill out the arp protocol part. */ + /* + * Fill out the arp protocol part. + * + * The arp hardware type should match the device type, except for FDDI, + * which (according to RFC 1390) should always equal 1 (Ethernet). + */ +#ifdef CONFIG_FDDI + arp->ar_hrd = (dev->type == ARPHRD_FDDI) ? htons(ARPHRD_ETHER) : htons(dev->type); +#else arp->ar_hrd = htons(dev->type); +#endif + /* + * Exceptions everywhere. AX.25 uses the AX.25 PID value not the + * DIX code for the protocol. Make these device structure fields. + */ #ifdef CONFIG_AX25 #ifdef CONFIG_NETROM arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP); @@ -1751,7 +1766,7 @@ unsigned char *arp_ptr= (unsigned char *)(arp+1); unsigned char *sha,*tha; u32 sip,tip; - + /* * The hardware length of the packet should match the hardware length * of the device. Similarly, the hardware types should match. The @@ -1759,16 +1774,44 @@ * is not from an IP number. We can't currently handle this, so toss * it. */ +#ifdef CONFIG_FDDI + if (dev->type == ARPHRD_FDDI) + { + /* + * According to RFC 1390, FDDI devices should accept ARP hardware types + * of 1 (Ethernet). However, to be more robust, we'll accept hardware + * types of either 1 (Ethernet) or 6 (IEEE 802.2). + */ + if (arp->ar_hln != dev->addr_len || + ((ntohs(arp->ar_hrd) != ARPHRD_ETHER) && (ntohs(arp->ar_hrd) != ARPHRD_IEEE802)) || + dev->flags & IFF_NOARP || + arp->ar_pln != 4) + { + kfree_skb(skb, FREE_READ); + return 0; + } + } + else + { + if (arp->ar_hln != dev->addr_len || + dev->type != ntohs(arp->ar_hrd) || + dev->flags & IFF_NOARP || + arp->ar_pln != 4) + { + kfree_skb(skb, FREE_READ); + return 0; + } + } +#else if (arp->ar_hln != dev->addr_len || - dev->type != ntohs(arp->ar_hrd) || + dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP || arp->ar_pln != 4) { kfree_skb(skb, FREE_READ); return 0; - /* Should this be an error/printk? Seems like something */ - /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */ } +#endif /* * Another test. @@ -1776,7 +1819,6 @@ * match the protocol the device speaks. If it doesn't, there is a * problem, so toss the packet. */ -/* Again, should this be an error/printk? -- MS */ switch (dev->type) { @@ -1801,14 +1843,8 @@ case ARPHRD_ETHER: case ARPHRD_ARCNET: case ARPHRD_METRICOM: - if(arp->ar_pro != htons(ETH_P_IP)) - { - kfree_skb(skb, FREE_READ); - return 0; - } - break; - case ARPHRD_IEEE802: + case ARPHRD_FDDI: if(arp->ar_pro != htons(ETH_P_IP)) { kfree_skb(skb, FREE_READ); diff -u --recursive --new-file v2.0.23/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.0.23/linux/net/ipv4/icmp.c Tue Oct 8 21:20:14 1996 +++ linux/net/ipv4/icmp.c Wed Oct 30 03:42:42 1996 @@ -282,11 +282,11 @@ { ENONET, 1 }, /* ICMP_HOST_ISOLATED */ { ENETUNREACH, 1 }, /* ICMP_NET_ANO */ { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */ - { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */ - { EOPNOTSUPP, 0 }, /* ICMP_HOST_UNR_TOS */ - { EOPNOTSUPP, 1 }, /* ICMP_PKT_FILTERED */ - { EOPNOTSUPP, 1 }, /* ICMP_PREC_VIOLATION */ - { EOPNOTSUPP, 1 } /* ICMP_PREC_CUTOFF */ + { ENETUNREACH, 0 }, /* ICMP_NET_UNR_TOS */ + { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNR_TOS */ + { EHOSTUNREACH, 1 }, /* ICMP_PKT_FILTERED */ + { EHOSTUNREACH, 1 }, /* ICMP_PREC_VIOLATION */ + { EHOSTUNREACH, 1 } /* ICMP_PREC_CUTOFF */ }; /* @@ -1030,6 +1030,14 @@ int r; #endif icmp_statistics.IcmpInMsgs++; + + if(len < sizeof(struct icmphdr)) + { + icmp_statistics.IcmpInErrors++; + printk(KERN_INFO "ICMP: runt packet\n"); + kfree_skb(skb, FREE_READ); + return 0; + } /* * Validate the packet diff -u --recursive --new-file v2.0.23/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v2.0.23/linux/net/ipv4/igmp.c Wed Aug 21 09:18:10 1996 +++ linux/net/ipv4/igmp.c Wed Oct 30 03:42:42 1996 @@ -248,7 +248,7 @@ if(skb==NULL) return; - tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL, + tmp=ip_build_header(skb, dev->pa_addr, address, &dev, IPPROTO_IGMP, NULL, 28 , 0, 1, NULL); if(tmp<0) { @@ -452,7 +452,7 @@ } ih=(struct igmphdr *)skb->h.raw; - if(skb->len ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr))) + if(len ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr))) { kfree_skb(skb, FREE_READ); return 0; diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.0.23/linux/net/ipv4/ip_forward.c Sat Oct 19 10:06:12 1996 +++ linux/net/ipv4/ip_forward.c Wed Oct 30 03:42:42 1996 @@ -230,9 +230,10 @@ /* This is for ip encap. Anand, ernet.*/ - if (is_frag&IPFWD_MULTITUNNEL) { + if (is_frag&IPFWD_MULTITUNNEL) + { encap=20; - } + } } else { diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.0.23/linux/net/ipv4/ip_fragment.c Sat Aug 10 10:03:16 1996 +++ linux/net/ipv4/ip_fragment.c Wed Oct 30 03:42:42 1996 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,8 @@ atomic_t ip_frag_mem = 0; /* Memory used for fragments */ +char *in_ntoa(unsigned long in); + /* * Memory Tracking Functions */ @@ -337,7 +340,15 @@ * Allocate a new buffer for the datagram. */ len = qp->ihlen + qp->len; - + + if(len>65535) + { + printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr)); + ip_statistics.IpReasmFails++; + ip_free(qp); + return NULL; + } + if ((skb = dev_alloc_skb(len)) == NULL) { ip_statistics.IpReasmFails++; @@ -366,7 +377,7 @@ { NETDEBUG(printk("Invalid fragment list: Fragment over size.\n")); ip_free(qp); - frag_kfree_skb(skb,FREE_WRITE); + kfree_skb(skb,FREE_WRITE); ip_statistics.IpReasmFails++; return NULL; } @@ -424,7 +435,7 @@ if (((flags & IP_MF) == 0) && (offset == 0)) { if (qp != NULL) - ip_free(qp); /* Huh? How could this exist?? */ + ip_free(qp); /* Fragmented frame replaced by full unfragmented copy */ return(skb); } @@ -461,11 +472,24 @@ if ((qp = ip_create(skb, iph, dev)) == NULL) { skb->sk = NULL; - frag_kfree_skb(skb, FREE_READ); + kfree_skb(skb, FREE_READ); ip_statistics.IpReasmFails++; return NULL; } } + + /* + * Attempt to construct an oversize packet. + */ + + if(ntohs(iph->tot_len)+(int)offset>65535) + { + skb->sk = NULL; + printk("Oversized packet received from %s\n",in_ntoa(iph->saddr)); + frag_kfree_skb(skb, FREE_READ); + ip_statistics.IpReasmFails++; + return NULL; + } /* * Determine the position of this fragment. diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.0.23/linux/net/ipv4/ip_output.c Tue Jul 9 14:28:32 1996 +++ linux/net/ipv4/ip_output.c Wed Oct 30 03:42:42 1996 @@ -123,13 +123,13 @@ skb->dev = dev; skb->arp = 1; skb->protocol = htons(ETH_P_IP); + skb_reserve(skb,(dev->hard_header_len+15)&~15); /* 16 byte aligned IP headers are always good */ if (dev->hard_header) { /* * Build a hardware header. Source address is our mac, destination unknown * (rebuild header will sort this out) */ - skb_reserve(skb,(dev->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ if (rt && dev == rt->rt_dev && rt->rt_hh) { memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len); diff -u --recursive --new-file v2.0.23/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.0.23/linux/net/ipv4/ipmr.c Fri Jul 19 08:24:05 1996 +++ linux/net/ipv4/ipmr.c Wed Oct 30 03:42:42 1996 @@ -17,6 +17,8 @@ * Malcolm Beattie : Buffer handling fixes. * Alexey Kuznetsov : Double buffer free and other fixes. * SVR Anand : Fixed several multicast bugs and problems. + * Alexey Kuznetsov : Subset of bugfixes/changes pending for + * 2.1. Doesn't include Alexey's PIM support. * * Status: * Cache manager under test. Forwarding in vague test mode @@ -60,8 +62,8 @@ static struct vif_device vif_table[MAXVIFS]; /* Devices */ static unsigned long vifc_map; /* Active device map */ int mroute_do_pim = 0; /* Set in PIM assert */ -static struct mfc_cache *mfc_cache_array[MFC_LINES]; /* Forwarding cache */ -static struct mfc_cache *cache_resolve_queue; /* Unresolved cache */ +static struct mfc_cache *mfc_cache_array[MFC_LINES+1]; /* Forwarding cache */ +#define cache_resolve_queue (mfc_cache_array[MFC_LINES])/* Unresolved cache */ int cache_resolve_queue_len = 0; /* Size of unresolved */ /* @@ -79,22 +81,6 @@ } /* - * Find a vif - */ - -static int ipmr_vifi_find(struct device *dev) -{ - struct vif_device *v=&vif_table[0]; - int ct; - for(ct=0;ctdev==dev) - return ct; - } - return -1; -} - -/* * Delete a multicast route cache entry */ @@ -388,6 +374,8 @@ */ cache->mfc_flags|=MFC_RESOLVED; + cache->mfc_parent=mfc->mfcc_parent; + memcpy(cache->mfc_ttls, mfc->mfcc_ttls,sizeof(cache->mfc_ttls)); /* @@ -733,12 +721,7 @@ struct mfc_cache *cache; struct sk_buff *skb2; int psend = -1; - int vif=ipmr_vifi_find(skb->dev); - if(vif==-1) - { - kfree_skb(skb, FREE_WRITE); - return; - } + int vif,ct=0; /* * Without the following addition, skb->h.iph points to something @@ -747,56 +730,63 @@ skb->h.iph = skb->ip_hdr; /* Anand, ernet. */ - vif_table[vif].pkt_in++; - vif_table[vif].bytes_in+=skb->len; - cache=ipmr_cache_find(skb->ip_hdr->saddr,skb->ip_hdr->daddr); - + /* * No usable cache entry */ if(cache==NULL || (cache->mfc_flags&MFC_QUEUED)) - ipmr_cache_unresolved(cache,vif,skb, is_frag); - else { - /* - * Forward the frame - */ - int ct=0; - while(ctip_hdr->ttl > cache->mfc_ttls[ct] && cache->mfc_ttls[ct]>0) - { - if(psend!=-1) - { - /* - * May get variant mac headers - * so must copy -- boo hoo. - */ - skb2=skb_copy(skb, GFP_ATOMIC); - if(skb2) - { - skb2->free=1; - ipmr_queue_xmit(skb2, &vif_table[psend], skb->dev, is_frag); - } - } - psend=ct; + ipmr_cache_unresolved(cache,ALL_VIFS,skb, is_frag); + return; + } + + vif=cache->mfc_parent; + + if(vif>=MAXVIFS || !(vifc_map&(1<dev) + { + kfree_skb(skb, FREE_READ); + return; + } + + vif_table[vif].pkt_in++; + vif_table[vif].bytes_in+=skb->len; + + /* + * Forward the frame + */ + + while(ctip_hdr->ttl > cache->mfc_ttls[ct] && cache->mfc_ttls[ct]>0) + { + if(psend!=-1) + { + /* + * May get variant mac headers + * so must copy -- boo hoo. + */ + skb2=skb_copy(skb, GFP_ATOMIC); + if(skb2) + { + skb2->free=1; + ipmr_queue_xmit(skb2, &vif_table[psend], skb->dev, is_frag); + } } - ct++; - } - if(psend==-1) - kfree_skb(skb, FREE_WRITE); - else - { - ipmr_queue_xmit(skb, &vif_table[psend], skb->dev, is_frag); + psend=ct; } - /* - * Adjust the stats - */ + ct++; + } + if(psend==-1) + kfree_skb(skb, FREE_WRITE); + else + { + ipmr_queue_xmit(skb, &vif_table[psend], skb->dev, is_frag); } } @@ -855,40 +845,38 @@ int ct; len += sprintf(buffer, - "Group Origin SrcIface \n"); + "Group Origin SrcIface VifTtls\n"); pos=len; - for (ct=0;ctmfc_parent)) + if(mfc->mfc_parent < MAXVIFS && vifc_map&(1<mfc_parent)) name=vif_table[mfc->mfc_parent].dev->name; - /* - * Interface forwarding map - */ - for(n=0;nmfc_ttls[ct]) - vifmap[n]='X'; - else - vifmap[n]='-'; - vifmap[n]=0; - /* - * Now print it out - */ - size = sprintf(buffer+len, "%08lX %08lX %-8s %s\n", + + size = sprintf(buffer+len, "%08lX %08lX %-8s", (unsigned long)mfc->mfc_mcastgrp, (unsigned long)mfc->mfc_origin, - name, - vifmap); + name); + + for(n=0;nmfc_ttls[n]); + else + size+=sprintf(buffer+len+size, + " --- "); + } + size+=sprintf(buffer+len+size,"\n"); len+=size; pos+=size; if(pos @@ -204,13 +204,40 @@ /* * If this test doesn't pass, it's not IP, or we should ignore it anyway */ - +#ifdef CONFIG_FDDI + if (dev->type == ARPHRD_FDDI) + { + /* + * Since the dev->type for FDDI is "made up", compare the rarp->ar_hrd + * field against ARPHRD_ETHER and ARPHRD_IEEE802. + * + * Ought to move to a device specifc 'arp_type_ok()' + */ + if (rarp->ar_hln != dev->addr_len + || ((ntohs(rarp->ar_hrd) != ARPHRD_ETHER) && (ntohs(rarp->ar_hrd) != ARPHRD_IEEE802)) + || dev->flags&IFF_NOARP) + { + kfree_skb(skb, FREE_READ); + return 0; + } + } + else + { + if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) + || dev->flags&IFF_NOARP) + { + kfree_skb(skb, FREE_READ); + return 0; + } + } +#else if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd) || dev->flags&IFF_NOARP) { kfree_skb(skb, FREE_READ); return 0; } +#endif /* * If it's not a RARP request, delete it. diff -u --recursive --new-file v2.0.23/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.0.23/linux/net/ipv4/tcp_input.c Mon Sep 2 15:18:26 1996 +++ linux/net/ipv4/tcp_input.c Wed Oct 30 04:13:01 1996 @@ -428,6 +428,8 @@ return; } } + + skb->when = jiffies; /* For timeout */ skb_queue_head_init(&newsk->write_queue); skb_queue_head_init(&newsk->receive_queue); newsk->send_head = NULL; @@ -470,6 +472,7 @@ newsk->delay_acks = 1; newsk->copied_seq = skb->seq+1; newsk->fin_seq = skb->seq; + newsk->syn_seq = skb->seq; newsk->state = TCP_SYN_RECV; newsk->timeout = 0; newsk->ip_xmit_timeout = 0; @@ -1587,6 +1590,9 @@ * moved inline now as tcp_urg is only called from one * place. We handle URGent data wrong. We have to - as * BSD still doesn't use the correction from RFC961. + * + * For 1003.1g we should support a new option TCP_STDURG to permit + * either form. */ static void tcp_check_urg(struct sock * sk, struct tcphdr * th) @@ -1613,6 +1619,15 @@ kill_pg(-sk->proc, SIGURG, 1); } } + /* + * We may be adding urgent data when the last byte read was + * urgent. To do this requires some care. We cannot just ignore + * sk->copied_seq since we would read the last urgent byte again + * as data, nor can we alter copied_seq until this data arrives + * or we break the sematics of SIOCATMARK (and thus sockatmark()) + */ + if (sk->urg_seq == sk->copied_seq) + sk->copied_seq++; /* Move the copied sequence on correctly */ sk->urg_data = URG_NOTYET; sk->urg_seq = ptr; } @@ -1735,7 +1750,6 @@ { struct tcphdr *th; struct sock *sk; - int syn_ok=0; __u32 seq; #ifdef CONFIG_IP_TRANSPARENT_PROXY int r; @@ -1959,7 +1973,6 @@ * Ok.. it's good. Set up sequence numbers and * move to established. */ - syn_ok=1; /* Don't reset this connection for the syn */ sk->acked_seq = skb->seq+1; sk->lastwin_seq = skb->seq+1; sk->fin_seq = skb->seq; @@ -2074,10 +2087,21 @@ return tcp_reset(sk,skb); /* - * !syn_ok is effectively the state test in RFC793. + * Check for a SYN, and ensure it matches the SYN we were + * first sent. We have to handle the rather unusual (but valid) + * sequence that KA9Q derived products may generate of + * + * SYN + * SYN|ACK Data + * ACK (lost) + * SYN|ACK Data + More Data + * .. we must ACK not RST... + * + * We keep syn_seq as the sequence space occupied by the + * original syn. */ - if(th->syn && !syn_ok) + if(th->syn && skb->seq!=sk->syn_seq) { tcp_send_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255); return tcp_reset(sk,skb); diff -u --recursive --new-file v2.0.23/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.0.23/linux/scripts/Menuconfig Fri Sep 20 17:00:36 1996 +++ linux/scripts/Menuconfig Tue Oct 29 17:38:17 1996 @@ -860,11 +860,11 @@ # # Load config options from a file. -# Converts all "# OPTION is not set" lines to "OPTION=" lines +# Converts all "# OPTION is not set" lines to "OPTION=n" lines # function load_config_file () { awk ' - /# .* is not set.*/ { printf("%s=\n", $2) } + /# .* is not set.*/ { printf("%s=n\n", $2) } ! /# .* is not set.*/ { print } ' $1 >.tmpconfig @@ -1119,12 +1119,12 @@ Please enter a hexadecimal value. \ Use the key to move from the input field to the buttons below it." -backtitle="Linux Kernel Configuration" - DIALOG="./scripts/lxdialog/lxdialog" kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}" +backtitle="Linux Kernel v$kernel_version Configuration" + trap "cleanup ; rm -f .menuconfig ; exit 1" 1 2 15 @@ -1146,7 +1146,7 @@ echo "#" echo "# Using defaults found in" $DEFAULTS echo "#" - . $DEFAULTS + load_config_file $DEFAULTS else echo "#" echo "# No defaults found"