From 53d0479d6e6b542da8c20d32aa220149402483b5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:14:57 -0500 Subject: [PATCH] Import 2.1.90 --- CREDITS | 9 + Documentation/Changes | 39 +- Documentation/cdrom/ide-cd | 17 +- MAINTAINERS | 4 +- arch/alpha/kernel/alpha_ksyms.c | 5 + arch/alpha/kernel/process.c | 7 +- arch/arm/kernel/armksyms.c | 5 + arch/i386/kernel/i386_ksyms.c | 4 + arch/i386/kernel/init_task.c | 2 +- arch/i386/kernel/process.c | 1 - arch/i386/lib/checksum.c | 13 +- arch/m68k/amiga/amiga_ksyms.c | 5 + arch/m68k/atari/atari_ksyms.c | 6 + arch/m68k/kernel/m68k_ksyms.c | 5 + arch/m68k/kernel/process.c | 2 +- arch/m68k/mac/ksyms.c | 5 + arch/mips/kernel/mips_ksyms.c | 5 + arch/ppc/kernel/ppc_ksyms.c | 5 + arch/ppc/kernel/process.c | 2 +- arch/sparc/kernel/sparc_ksyms.c | 5 + drivers/block/ide-cd.c | 114 +- drivers/block/ide-cd.h | 4 +- drivers/char/rtc.c | 1 - drivers/net/de4x5.c | 301 +- drivers/net/eepro100.c | 2 +- drivers/net/hp100.c | 4642 +++++++++++++++++-------------- drivers/net/hp100.h | 2 +- drivers/net/seeq8005.c | 1 + drivers/net/tulip.c | 4 +- drivers/scsi/ncr53c8xx.c | 2 +- fs/coda/Makefile | 2 +- fs/coda/cache.c | 196 +- fs/coda/cnode.c | 59 +- fs/coda/coda_linux.c | 23 +- fs/coda/dir.c | 104 +- fs/coda/file.c | 49 +- fs/coda/{super.c => inode.c} | 35 +- fs/coda/psdev.c | 4 +- fs/coda/upcall.c | 55 +- fs/ncpfs/Config.in | 2 +- fs/ncpfs/Makefile | 3 +- fs/ncpfs/inode.c | 1 + fs/ncpfs/ioctl.c | 33 +- fs/ncpfs/ncpsign_kernel.c | 114 + fs/ncpfs/ncpsign_kernel.h | 16 + fs/umsdos/README-WIP.txt | 75 +- fs/umsdos/dir.c | 12 +- fs/umsdos/emd.c | 155 +- fs/umsdos/inode.c | 33 +- fs/umsdos/namei.c | 54 +- fs/umsdos/symlink.c | 3 +- include/asm-alpha/fpu.h | 22 +- include/linux/coda.h | 6 +- include/linux/coda_cache.h | 15 +- include/linux/coda_fs_i.h | 7 +- include/linux/coda_linux.h | 18 + include/linux/hfs_fs.h | 1 + include/linux/ncp_fs.h | 11 +- include/linux/ncp_fs_sb.h | 6 +- include/linux/sysctl.h | 1 + include/linux/umsdos_fs.p | 13 +- include/net/dst.h | 2 +- include/net/tcp.h | 15 +- ipc/msg.c | 33 - kernel/sched.c | 98 +- mm/page_alloc.c | 6 +- net/802/tr.c | 1 - net/core/dst.c | 2 +- net/core/neighbour.c | 7 +- net/ipv4/ip_fw.c | 35 +- net/ipv4/ip_nat_dumb.c | 34 +- net/ipv4/sysctl_net_ipv4.c | 7 +- net/ipv4/tcp.c | 30 +- net/ipv4/tcp_input.c | 50 +- net/ipv4/tcp_ipv4.c | 40 +- net/ipv4/tcp_output.c | 40 +- net/ipv6/route.c | 11 +- net/ipv6/tcp_ipv6.c | 81 +- 78 files changed, 4006 insertions(+), 2833 deletions(-) rename fs/coda/{super.c => inode.c} (92%) create mode 100644 fs/ncpfs/ncpsign_kernel.c create mode 100644 fs/ncpfs/ncpsign_kernel.h diff --git a/CREDITS b/CREDITS index 8ed3dc55278e..5bed63d68fbd 100644 --- a/CREDITS +++ b/CREDITS @@ -1420,6 +1420,15 @@ S: 6, rue Augustin Thierry S: 75019 Paris S: France +N: Rik van Riel +E: H.H.vanRiel@fys.ruu.nl +W: http://www.fys.ruu.nl/~riel/ +D: Maintainer of the mm-patches page (see www.linuxhq.com) +D: Documentation/sysctl/*, kswapd fixes, random kernel hacker +S: Vorenkampsweg 1 +S: NL-9488 TG Zeijerveld +S: The Netherlands + N: William E. Roadcap E: roadcapw@cfw.com W: http://www.cfw.com/~roadcapw diff --git a/Documentation/Changes b/Documentation/Changes index 29dc474a224c..9b5846d92fb1 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -32,7 +32,7 @@ http://cyberbuzz.gatech.edu/kaboom/linux/ as well. Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: February 16. 1998 +Last updated: March 16. 1998 Current Author: Chris Ricker (kaboom@gatech.edu). Current Minimal Requirements @@ -45,11 +45,11 @@ running, the suggested command should tell you. - Kernel modules modutils-2.1.85 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.8.1.0.1 ; ld -v -- Linux C Library 5.4.38 ; ls -l /lib/libc.so.* +- Linux C Library 5.4.44 ; ls -l /lib/libc.so.* - Dynamic Linker (ld.so) 1.9.5 ; ldd -v - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* - Procps 1.2.5 ; ps --version -- Procinfo 0.11 ; procinfo -v +- Procinfo 0.13 ; procinfo -v - Mount 2.7l ; mount --version - Net-tools 1.41 ; hostname -V - Loadlin 1.6a @@ -58,7 +58,7 @@ running, the suggested command should tell you. - NFS 0.4.21 ; showmount --version - Bash 1.14.7 ; bash -version - Ncpfs 2.1.1 ; ncpmount -v -- Pcmcia-cs 2.9.12 +- Pcmcia-cs 3.0.0 - PPP 2.3.3 ; pppd -v Upgrade notes @@ -73,6 +73,10 @@ know it works on your hardware, add a "reboot=warm" command line option in Lilo. A small number of machines need "reboot=bios" to reboot via the BIOS. + Also, please remember that cua* devices are now obsolete. Switch to +the corresponding ttyS* device instead (e.g., cua0 -> ttyS0, cua1 -> +ttyS1, etc.). + Libc ==== @@ -109,6 +113,12 @@ Modules You need to upgrade to modutils-2.1.85 for kernels 2.1.85 and later. This version will also work with 2.0.x kernels. + As of 2.1.90-pre1, kerneld has been replaced by a kernel thread, +kmod. See Documentation/kmod.txt for more information. The main +user-level change this requires is modification to your init scripts to +check for the absence of /proc/sys/kernel/modprobe before starting +kerneld. + Binutils ======== @@ -266,12 +276,12 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.3 Linux C Library =============== -The 5.4.38 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.38.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.38.bin.tar.gz +The 5.4.44 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.44.bin.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.44.bin.tar.gz Installation notes for 5.4.38: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.38 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.38 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.44 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.44 Linux C++ Library ================= @@ -308,7 +318,7 @@ Procinfo utilities ================== The 0.11 release: -ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.11.tar.gz +ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.13.tar.gz RPM utilities ============= @@ -391,8 +401,8 @@ ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/ncpfs/ncpfs-2.1.1.tgz Pcmcia-cs ========= -The 1.9.12 release: -ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-2.9.12.tar.gz +The 3.0.0 release: +ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-3.0.0.tar.gz PPP === @@ -415,11 +425,12 @@ distribution), most of these are available in RPM format. Check around your favorite Red Hat mirror site before installing the non-RPM version. Remember, you might need to use the -force option to get the upgrade to install. ftp://ftp.redhat.com/pub/contrib/ will have almost -everything you need. +everything you need, as does RedHat 5.0. Those of you running Debian (or a different distribution that supports .deb packages) can look in the "unstable" and -"project/experimental" directories of your favorite Debian mirror. +"project/experimental" directories of your favorite Debian mirror. The +Debian 2.0 release should have most packages you need as well. For others, David Bourgin has put together a package of everything necessary to quickly and easily upgrade to 2.1.x. See diff --git a/Documentation/cdrom/ide-cd b/Documentation/cdrom/ide-cd index d6ceef8a5e1d..ecd498158106 100644 --- a/Documentation/cdrom/ide-cd +++ b/Documentation/cdrom/ide-cd @@ -224,10 +224,8 @@ a. Drive is not detected during booting. - If the autoprobing is not finding your drive, you can tell the driver to assume that one exists by using a lilo option of the form `hdX=cdrom', where X is the drive letter corresponding to - where your drive is installed (see section 2). This is required - for CDROM drives such as the Pioneer DR-A24X, which do not properly - identify themselves as ATAPI CDROM drives. Note that if you - do this and you see a boot message like + where your drive is installed. Note that if you do this and you + see a boot message like hdX: ATAPI cdrom (?) @@ -281,7 +279,16 @@ b. Timeout/IRQ errors. there are hardware problems with the interrupt setup; they apparently don't use interrupts. - + - If you own a Pioneer DR-A24X, you _will_ get nasty error messages + on boot such as "irq timeout: status=0x50 { DriveReady SeekComplete }" + The Pioneer DR-A24X cdrom drives are fairly popular these days. + Unfortunatly, these drives seem to become very confused when we perform + the standard Linux ATA disk drive probe. If you own one of these drives, + you can bypass the ATA probing which confuses these cdrom drives, by + adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing + lilo (again where X is the drive letter corresponding to where your drive + is installed.) + c. System hangups. - If the system locks up when you try to access the cdrom, the most diff --git a/MAINTAINERS b/MAINTAINERS index 90f0299866ca..b8198cbf3dba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -275,8 +275,8 @@ M: oe1kib@oe1xtu.ampr.org L: linux-hams@vger.rutgers.edu S: Maintained -HP100: Driver for HP 10/100 Mbit/s Network Adapter Series -P: Jarsolav Kysela +HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series +P: Jaroslav Kysela M: perex@jcu.cz S: Maintained diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 53741095c22f..132175541e6d 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -146,3 +147,7 @@ EXPORT_SYMBOL_NOVERS(__remq); EXPORT_SYMBOL_NOVERS(__remqu); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 5970d443aed9..f8146c54f7f1 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -39,6 +39,7 @@ #include #include #include +#include /* * Initial task structure. Make this a per-architecture thing, @@ -50,7 +51,7 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -199,6 +200,10 @@ void exit_thread(void) void flush_thread(void) { + /* Arrange for each exec'ed process to start off with a + clean slate wrt the fpu. */ + current->tss.flags &= ~IEEE_SW_MASK; + wrfpcr(FPCR_DYN_NORMAL); } void release_thread(struct task_struct *dead_task) diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 19666ac1e948..20c62e2e6d5b 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -176,3 +177,7 @@ EXPORT_SYMBOL(change_bit); EXPORT_SYMBOL(test_and_change_bit); EXPORT_SYMBOL(find_first_zero_bit); EXPORT_SYMBOL(find_next_zero_bit); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index e5812400ee93..d2837d648e3c 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -97,3 +98,6 @@ EXPORT_SYMBOL(mca_isenabled); EXPORT_SYMBOL(mca_isadapter); #endif +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c index 90ae6952f7eb..c0571c769e08 100644 --- a/arch/i386/kernel/init_task.c +++ b/arch/i386/kernel/init_task.c @@ -6,7 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index e7aa2f46add8..6f22457902c6 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -480,7 +480,6 @@ void release_thread(struct task_struct *dead_task) int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, struct task_struct * p, struct pt_regs * regs) { - int i; struct pt_regs * childregs; p->tss.tr = _TSS(nr); diff --git a/arch/i386/lib/checksum.c b/arch/i386/lib/checksum.c index 1c108a2e8bca..88f250d62dee 100644 --- a/arch/i386/lib/checksum.c +++ b/arch/i386/lib/checksum.c @@ -123,8 +123,6 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) unsigned int csum_partial_copy_generic (const char *src, char *dst, int len, int sum, int *src_err_ptr, int *dst_err_ptr) { - __u32 tmp_var; - __asm__ __volatile__ ( " testl $2, %%edi # Check alignment. jz 2f # Jump if alignment is ok. @@ -139,7 +137,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, addw %%bx, %%ax adcl $0, %%eax 2: - movl %%ecx, %8 + pushl %%ecx shrl $5, %%ecx jz 2f testl %%esi, %%esi @@ -176,7 +174,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, dec %%ecx jne 1b adcl $0, %%eax - 2: movl %8, %%edx + 2: popl %%edx movl %%edx, %%ecx andl $0x1c, %%edx je 4f @@ -233,10 +231,9 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, ################################################ " - : "=a" (sum) - : "m" (src_err_ptr), "m" (dst_err_ptr), - "0" (sum), "c" (len), "S" (src), "D" (dst), - "i" (-EFAULT), "m"(tmp_var) + : "=a" (sum), "=m" (src_err_ptr), "=m" (dst_err_ptr) + : "0" (sum), "c" (len), "S" (src), "D" (dst), + "i" (-EFAULT) : "bx", "cx", "dx", "si", "di" ); return(sum); diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c index bc962f7d3826..0eae9cfdb59c 100644 --- a/arch/m68k/amiga/amiga_ksyms.c +++ b/arch/m68k/amiga/amiga_ksyms.c @@ -2,6 +2,7 @@ #include #include #include +#include extern volatile u_short amiga_audio_min_period; extern u_short amiga_audio_period; @@ -24,3 +25,7 @@ EXPORT_SYMBOL(zorro_get_board); EXPORT_SYMBOL(zorro_config_board); EXPORT_SYMBOL(zorro_unconfig_board); EXPORT_SYMBOL(zorro_unused_z2ram); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c index 0eb19e4a0caa..86e34fb7f8d0 100644 --- a/arch/m68k/atari/atari_ksyms.c +++ b/arch/m68k/atari/atari_ksyms.c @@ -1,4 +1,6 @@ #include +#include + #include #include #include @@ -40,3 +42,7 @@ EXPORT_SYMBOL(ikbd_mouse_rel_pos); EXPORT_SYMBOL(ikbd_mouse_disable); EXPORT_SYMBOL(atari_microwire_cmd); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index a5c83712bda2..3e6721d697c2 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -58,3 +59,7 @@ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 1f82ba8251bc..a6fbd5718ca4 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -40,7 +40,7 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff --git a/arch/m68k/mac/ksyms.c b/arch/m68k/mac/ksyms.c index 05373b04e092..573e6f78e9a1 100644 --- a/arch/m68k/mac/ksyms.c +++ b/arch/m68k/mac/ksyms.c @@ -1,7 +1,12 @@ #include +#include #include #include /* Hook for mouse driver */ extern void (*mac_mouse_interrupt_hook) (char *); EXPORT_SYMBOL(mac_mouse_interrupt_hook); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 3e8fc275da06..e6668eb8bce9 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -97,3 +98,7 @@ EXPORT_SYMBOL(__compute_return_epc); EXPORT_SYMBOL(register_fpe); EXPORT_SYMBOL(unregister_fpe); #endif + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 8f3225d599ab..6ec6258ab401 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -147,3 +148,7 @@ EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(note_scsi_host); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index f42e6162ed65..7ffaf58c07f7 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -64,7 +64,7 @@ task_top(struct task_struct *tsk) static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index df3eac3008b1..92be6f74dfaf 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -271,3 +272,7 @@ EXPORT_SYMBOL_DOT(mul); EXPORT_SYMBOL_DOT(umul); EXPORT_SYMBOL_DOT(div); EXPORT_SYMBOL_DOT(udiv); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 24f00c950824..27b7d4c702cf 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -26,7 +26,6 @@ * (If you are using a cd changer, you may get errors in the kernel * logs that are completly expected. Don't complain to me about this, * unless you have a patch to fix it. I am working on it...) - * -Implement ide_cdrom_select_speed using the generic cdrom interface * -Fix ide_cdrom_reset so that it works (it does nothing right now) * -Query the drive to find what features are available before trying to * use them (like trying to close the tray in drives that can't). @@ -189,10 +188,19 @@ * malloc'ed but never free'd when closing the device. * -- Cleaned up the global namespace a bit by making more * functions static that should already have been. + * 4.11 Mar 12, 1998 -- Added support for the CDROM_SELECT_SPEED ioctl + * based on a patch for 2.0.33 by Jelle Foks + * , a patch for 2.0.33 + * by Toni Giorgino , the SCSI + * version, and my own efforts. -erik + * -- Fixed a stupid bug which egcs was kind enough to + * inform me of where "Illegal mode for this track" + * was never returned due to a comparison on data + * types of limited range. * *************************************************************************/ -#define IDECD_VERSION "4.10" +#define IDECD_VERSION "4.11" #include #include @@ -271,8 +279,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, printk (" Error code: 0x%02x\n", reqbuf->error_code); - if (reqbuf->sense_key >= 0 && - reqbuf->sense_key < ARY_LEN (sense_key_texts)) + if ( reqbuf->sense_key < ARY_LEN (sense_key_texts)) s = sense_key_texts[reqbuf->sense_key]; else s = "(bad sense key)"; @@ -285,7 +292,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive, s = buf; } else { int lo, hi; - int key = (reqbuf->asc << 8); + unsigned short key = (reqbuf->asc << 8); if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) key |= reqbuf->ascq; @@ -496,7 +503,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, } else if (sense_key == UNIT_ATTENTION) { /* Check for media change. */ cdrom_saw_media_change (drive); - printk ("%s: media changed\n", drive->name); + /*printk("%s: media changed\n",drive->name);*/ return 0; } else { /* Otherwise, print an error. */ @@ -1518,7 +1525,6 @@ cdrom_startstop (ide_drive_t *drive, int startflag, return cdrom_queue_packet_command (drive, &pc); } - static int cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, struct atapi_request_sense *reqbuf) @@ -1721,7 +1727,6 @@ cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag, return cdrom_queue_packet_command (drive, &pc); } - static int cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen, struct atapi_request_sense *reqbuf) @@ -1742,6 +1747,43 @@ cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen, } +/* Note that this takes speed in kbytes/second, so don't try requesting + silly speeds like 2 here. Common speeds include: + 176 kbytes/second -- 1x + 353 kbytes/second -- 2x + 387 kbytes/second -- 2.2x + 528 kbytes/second -- 3x + 706 kbytes/second -- 4x + 1400 kbytes/second -- 8x + 2800 kbytes/second -- 16x + ATAPI drives are free to select the speed you request or any slower + rate :-( Requesting too fast a speed will _not_ produce an error. */ +static int +cdrom_select_speed (ide_drive_t *drive, int speed, + struct atapi_request_sense *reqbuf) +{ + struct packet_command pc; + memset (&pc, 0, sizeof (pc)); + pc.sense_data = reqbuf; + + if (speed < 1) + speed = 0xffff; /* set to max */ + else + speed *= 177; /* Nx to kbytes/s */ + + pc.c[0] = SET_CD_SPEED; + /* Read Drive speed in kbytes/second MSB */ + pc.c[2] = (speed >> 8) & 0xff; + /* Read Drive speed in kbytes/second LSB */ + pc.c[3] = speed & 0xff; + /* Write Drive speed in kbytes/second MSB */ + //pc.c[4] = (speed >> 8) & 0xff; + /* Write Drive speed in kbytes/second LSB */ + //pc.c[5] = speed & 0xff; + + return cdrom_queue_packet_command (drive, &pc); +} + static int cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end, struct atapi_request_sense *reqbuf) @@ -2429,6 +2471,44 @@ int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) return cdrom_lockdoor (drive, lock, NULL); } +static +int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) +{ + int stat, attempts = 3; + struct { + char pad[8]; + struct atapi_capabilities_page cap; + } buf; + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct atapi_request_sense reqbuf; + stat=cdrom_select_speed (drive, speed, &reqbuf); + if (stat<0) + return stat; + + /* Now that that is done, update the speed fields */ + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + if (attempts-- <= 0) + return 0; + stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, + (char *)&buf, sizeof (buf), NULL); + } while (stat); + + /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ + if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { + CDROM_STATE_FLAGS (drive)->current_speed = + (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; + } else { + CDROM_STATE_FLAGS (drive)->current_speed = + (ntohs(buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (ntohs(buf.cap.maxspeed) + (176/2)) / 176; + } + cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed; + return 0; +} + static int ide_cdrom_select_disc (struct cdrom_device_info *cdi, int slot) @@ -2668,14 +2748,14 @@ struct cdrom_device_ops ide_cdrom_dops = { ide_cdrom_check_media_change_real, /* media_changed */ ide_cdrom_tray_move, /* tray_move */ ide_cdrom_lock_door, /* lock_door */ - NULL, /* select_speed */ + ide_cdrom_select_speed, /* select_speed */ ide_cdrom_select_disc, /* select_disc */ ide_cdrom_get_last_session, /* get_last_session */ ide_cdrom_get_mcn, /* get_mcn */ ide_cdrom_reset, /* reset */ ide_cdrom_audio_ioctl, /* audio_ioctl */ ide_cdrom_dev_ioctl, /* dev_ioctl */ - CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK + CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */ @@ -2691,7 +2771,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) devinfo->dev = MKDEV (HWIF(drive)->major, minor); devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; - *(int *)&devinfo->speed = CDROM_CONFIG_FLAGS (drive)->max_speed; + *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed; *(int *)&devinfo->capacity = nslots; devinfo->handle = (void *) drive; strcpy(devinfo->name, drive->name); @@ -2750,11 +2830,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { - CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; + CDROM_STATE_FLAGS (drive)->current_speed = + (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; } else { - CDROM_STATE_FLAGS (drive)->current_speed = (ntohs(buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176; + CDROM_STATE_FLAGS (drive)->current_speed = + (ntohs(buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (ntohs(buf.cap.maxspeed) + (176/2)) / 176; } printk ("%s: ATAPI %dX CDROM", diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 53e38e1b1ecc..140c4ccb6eeb 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -71,7 +71,7 @@ #define MODE_SENSE_10 0x5a #define MODE_SELECT_10 0x55 #define READ_CD 0xbe - +#define SET_CD_SPEED 0xbb #define LOAD_UNLOAD 0xa6 #define MECHANISM_STATUS 0xbd @@ -431,7 +431,7 @@ char *sense_key_texts[16] = { with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ struct { - short asc_ascq; + unsigned short asc_ascq; char *text; } sense_data_texts[] = { { 0x0000, "No additional sense information" }, diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 846b858efb3c..9edca16836b0 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -48,7 +48,6 @@ * this driver.) */ -#include #include #include #include diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index ed2652b9635b..6bd5be8b7f2c 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -213,7 +213,7 @@ insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'. - For a compiled in driver, somewhere in this file, place e.g. + For a compiled in driver, at or above line 526, place e.g. #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" Yes, I know full duplex isn't permissible on BNC or AUI; they're just @@ -371,11 +371,14 @@ 0.533 9-Jan-98 Fix more 64 bit bugs reported by . 0.534 24-Jan-98 Fix last (?) endian bug from + 0.535 21-Feb-98 Fix Ethernet Address PROM reset bug for DC21040. + 0.536 21-Mar-98 Change pci_probe() to use the pci_dev structure. + **Incompatible with 2.0.x from here.** ========================================================================= */ -static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n"; #include @@ -390,11 +393,15 @@ static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.co #include #include #include +#include +#include + #include #include #include #include #include +#include #include #include @@ -408,31 +415,6 @@ static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.co #include "de4x5.h" #define c_char const char - -#include -#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) -# define __initfunc(__arginit) __arginit -# define test_and_set_bit set_bit -# define net_device_stats enet_statistics -# define copy_to_user(a,b,c) memcpy_tofs(a,b,c) -# define copy_from_user(a,b,c) memcpy_fromfs(a,b,c) -# define le16_to_cpu(a) cpu_to_le16(a) -# define le32_to_cpu(a) cpu_to_le32(a) -# ifdef __powerpc__ -# define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8)) -# define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\ - (((a) & 0x0000ff00U) << 8) |\ - (((a) & 0x00ff0000U) >> 8) |\ - (((a) & 0xff000000U) >> 24)) -# else -# define cpu_to_le16(a) (a) -# define cpu_to_le32(a) (a) -# endif /* __powerpc__ */ -# include -#else -# include -# include -#endif /* LINUX_VERSION_CODE */ #define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) /* @@ -538,8 +520,8 @@ static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION); ** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'. ** ** For a compiled in driver, place e.g. -** #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" -** somewhere in this file above this point. +** #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" +** here */ #ifdef DE4X5_PARM static char *args = DE4X5_PARM; @@ -591,6 +573,12 @@ struct parameters { #define DE4X5_SIGNATURE {"DE425","DE434","DE435","DE450","DE500"} #define DE4X5_NAME_LENGTH 8 +/* +** Ethernet PROM defines for DC21040 +*/ +#define PROBE_LENGTH 32 +#define ETH_PROM_SIG 0xAA5500FFUL + /* ** PCI Bus defines */ @@ -912,6 +900,7 @@ static int test_tp(struct device *dev, s32 msec); static int EISA_signature(char *name, s32 eisa_id); static int PCI_signature(char *name, struct bus_type *lp); static void DevicePresent(u_long iobase); +static void enet_addr_rst(u_long aprom_addr); static int de4x5_bad_srom(struct bus_type *lp); static short srom_rd(u_long address, u_char offset); static void srom_latch(u_int command, u_long address); @@ -981,11 +970,9 @@ static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)); static int count_adapters(void); static int loading_module = 1; -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) MODULE_PARM(de4x5_debug, "i"); MODULE_PARM(dec_only, "i"); MODULE_PARM(args, "s"); -#endif /* LINUX_VERSION_CODE */ # else static int loading_module = 0; #endif /* MODULE */ @@ -1507,9 +1494,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) cli(); test_and_set_bit(0, (void*)&dev->tbusy); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); -#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) lp->stats.tx_bytes += skb->len; -#endif outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ lp->tx_new = (++lp->tx_new) % lp->txRingSize; @@ -1559,9 +1544,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) printk("%s: Re-entering the interrupt handler.\n", dev->name); DISABLE_IRQs; /* Ensure non re-entrancy */ -#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) synchronize_irq(); -#endif dev->interrupt = MASK_INTERRUPTS; for (limit=0; limit<8; limit++) { @@ -1659,9 +1642,7 @@ de4x5_rx(struct device *dev) /* Update stats */ lp->stats.rx_packets++; -#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) lp->stats.rx_bytes += pkt_len; -#endif de4x5_local_stats(dev, skb->data, pkt_len); } } @@ -2042,7 +2023,7 @@ eisa_probe(struct device *dev, u_long ioaddr)) outl(0x00006000, PCI_CFLT); outl(iobase, PCI_CBIO); - DevicePresent(DE4X5_APROM); + DevicePresent(EISA_APROM); if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { dev->irq = irq; if ((status = de4x5_hw_init(dev, iobase)) == 0) { @@ -2081,11 +2062,12 @@ eisa_probe(struct device *dev, u_long ioaddr)) __initfunc(static void pci_probe(struct device *dev, u_long ioaddr)) { - u_char pb, pbus, dev_num, dnum, dev_fn, timer, tirq; - u_short dev_id, vendor, index, status; - u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_char pb, pbus, dev_num, dnum, dev_fn, timer; + u_short vendor, index, status; + u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ struct bus_type *lp = &bus; + struct pci_dev *pdev; if (lastPCI == NO_MORE_PCI) return; @@ -2109,96 +2091,77 @@ pci_probe(struct device *dev, u_long ioaddr)) (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { dev_num = PCI_SLOT(dev_fn); - if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { -#ifdef __sparc_v9__ - struct pci_dev *pdev; - for (pdev = pci_devices; pdev; pdev = pdev->next) { - if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; - } -#endif - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } - - /* Search for an SROM on this bus */ - if (lp->bus_num != pb) { - lp->bus_num = pb; - srom_search(index); - } + if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue; + for (pdev = pci_devices; pdev; pdev = pdev->next) { + if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; + } - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + vendor = pdev->vendor; + device = pdev->device << 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; - /* Set the device number information */ - lp->device = dev_num; + /* Search for an SROM on this bus */ + if (lp->bus_num != pb) { lp->bus_num = pb; + srom_search(index); + } + + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + + /* Set the device number information */ + lp->device = dev_num; + lp->bus_num = pb; - /* Set the chipset information */ - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; + /* Set the chipset information */ + if (is_DC2114x) device |= (cfrv & CFRV_RN); + lp->chipset = device; - /* Get the board I/O address (64 bits on sparc64) */ -#ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); - iobase = tmp; -#else - iobase = pdev->base_address[0]; -#endif - iobase &= CBIO_MASK; + /* Get the board I/O address (64 bits on sparc64) */ + iobase = pdev->base_address[0] & CBIO_MASK; - /* Fetch the IRQ to be used */ -#ifndef __sparc_v9__ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq); - irq = tirq; -#else - irq = pdev->irq; -#endif - if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; + /* Fetch the IRQ to be used */ + irq = pdev->irq; + if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; - /* Check if I/O accesses and Bus Mastering are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + /* Check if I/O accesses and Bus Mastering are enabled */ + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); #ifdef __powerpc__ - if (!(status & PCI_COMMAND_IO)) { - status |= PCI_COMMAND_IO; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } + if (!(status & PCI_COMMAND_IO)) { + status |= PCI_COMMAND_IO; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } #endif /* __powerpc__ */ - if (!(status & PCI_COMMAND_IO)) continue; + if (!(status & PCI_COMMAND_IO)) continue; - if (!(status & PCI_COMMAND_MASTER)) { - status |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } - if (!(status & PCI_COMMAND_MASTER)) continue; + if (!(status & PCI_COMMAND_MASTER)) { + status |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } + if (!(status & PCI_COMMAND_MASTER)) continue; - /* Check the latency timer for values >= 0x60 */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); - if (timer < 0x60) { - pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); - } + /* Check the latency timer for values >= 0x60 */ + pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); + if (timer < 0x60) { + pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); + } - DevicePresent(DE4X5_APROM); - if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) { - link_modules(lastModule, dev); - lastPCI = index; - } - return; + DevicePresent(DE4X5_APROM); + if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) { + link_modules(lastModule, dev); + lastPCI = index; } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, - iobase); + return; } + } else if (ioaddr != 0) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, + iobase); } } @@ -2216,12 +2179,13 @@ pci_probe(struct device *dev, u_long ioaddr)) __initfunc(static void srom_search(int index)) { - u_char pb, dev_fn, tirq; - u_short dev_id, dev_num, vendor, status; - u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_char pb, dev_fn; + u_short dev_num, vendor, status; + u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; + struct pci_dev *pdev; for (; (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); @@ -2229,20 +2193,13 @@ srom_search(int index)) if (lp->bus_num != pb) return; dev_num = PCI_SLOT(dev_fn); -#ifdef __sparc_v9__ - struct pci_dev *pdev; for (pdev = pci_devices; pdev; pdev = pdev->next) { if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break; } -#endif - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } + + vendor = pdev->vendor; + device = pdev->device << 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; /* Get the chip configuration revision register */ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); @@ -2256,21 +2213,10 @@ srom_search(int index)) lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ -#ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); - iobase = tmp; -#else - iobase = pdev->base_address[0]; -#endif - iobase &= CBIO_MASK; + iobase = pdev->base_address[0] & CBIO_MASK; /* Fetch the IRQ to be used */ -#ifndef __sparc_v9__ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq); - irq = tirq; -#else irq = pdev->irq; -#endif if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses are enabled */ @@ -3982,7 +3928,11 @@ DevicePresent(u_long aprom_addr) struct bus_type *lp = &bus; if (lp->chipset == DC21040) { - outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ + if (lp->bus == EISA) { + enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */ + } else { + outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ + } } else { /* Read new srom */ u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD); for (i=0; i<(ETH_ALEN>>1); i++) { @@ -4005,6 +3955,45 @@ DevicePresent(u_long aprom_addr) return; } +/* +** Since the write on the Enet PROM register doesn't seem to reset the PROM +** pointer correctly (at least on my DE425 EISA card), this routine should do +** it...from depca.c. +*/ +static void +enet_addr_rst(u_long aprom_addr) +{ + union { + struct { + u32 a; + u32 b; + } llsig; + char Sig[sizeof(u32) << 1]; + } dev; + short sigLength=0; + s8 data; + int i, j; + + dev.llsig.a = ETH_PROM_SIG; + dev.llsig.b = ETH_PROM_SIG; + sigLength = sizeof(u32) << 1; + + for (i=0,j=0;j= LinuxVersionCode(2,1,0) MODULE_PARM(io, "i"); -#endif /* LINUX_VERSION_CODE */ int init_module(void) @@ -5730,16 +5717,18 @@ unlink_modules(struct device *p) static int count_adapters(void) { - int i, j; + int i, j=0; char name[DE4X5_STRLEN]; - u_char pb, dev_fn, dev_num; - u_short dev_id, vendor; + u_char pb, dev_fn; + u_short vendor; u_int class = DE4X5_CLASS_CODE; u_int device; + struct pci_dev *pdev; + #ifndef __sparc_v9__ u_long iobase = 0x1000; - for (j=0, i=1; inext) { + if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; + } + + vendor = pdev->vendor; + device = pdev->device << 8; if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++; } diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 9a33ea3a4a4f..156a07ba25b1 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1348,7 +1348,7 @@ speedo_rx(struct device *dev) #if (LINUX_VERSION_CODE >= VERSION(1,3,44)) if (! rx_in_place) { skb_reserve(skb, 2); /* 16 byte align the data fields */ -#if defined(__i386) && notyet +#if defined(__i386__) && notyet /* Packet is in one chunk -- we can copy + cksum. */ eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len, 0); diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index cb6b1bb69c05..0f1bdd3c72d5 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1,51 +1,77 @@ /* - ** hp100.c - ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters - ** - ** $Id: hp100.c,v 1.14 1997/11/16 13:57:28 alan Exp $ - ** - ** Based on the HP100 driver written by Jaroslav Kysela - ** Extended for new busmaster capable chipsets by - ** Siegfried "Frieder" Loeffler (dg1sek) - ** - ** Maintained by: Jaroslav Kysela - ** - ** This driver has only been tested with - ** -- HP J2585B 10/100 Mbit/s PCI Busmaster - ** -- HP J2585A 10/100 Mbit/s PCI - ** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC - ** -- HP J2973 10 Mbit/s PCI 10base-T - ** -- HP J2573 10/100 ISA - ** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA - ** - ** but it should also work with the other CASCADE based adapters. - ** - ** TODO: - ** - J2573 seems to hang sometimes when in shared memory mode. - ** - Mode for Priority TX - ** - Check PCI registers, performance might be improved? - ** - To reduce interrupt load in busmaster, one could switch off - ** the interrupts that are used to refill the queues whenever the - ** queues are filled up to more than a certain threshold. - ** - ** - ** This source/code is public free; you can distribute it and/or modify - ** it under terms of the GNU General Public License (published by the - ** Free Software Foundation) either version two of this License, or any - ** later version. - ** - */ - -#define HP100_DEFAULT_PRIORITY_TX 0 +** hp100.c +** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters +** +** $Id: hp100.c,v 1.56 1998/03/04 15:23:59 perex Exp perex $ +** +** Based on the HP100 driver written by Jaroslav Kysela +** Extended for new busmaster capable chipsets by +** Siegfried "Frieder" Loeffler (dg1sek) +** +** Maintained by: Jaroslav Kysela +** +** This driver has only been tested with +** -- HP J2585B 10/100 Mbit/s PCI Busmaster +** -- HP J2585A 10/100 Mbit/s PCI +** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC +** -- HP J2973 10 Mbit/s PCI 10base-T +** -- HP J2573 10/100 ISA +** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA +** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI +** +** but it should also work with the other CASCADE based adapters. +** +** TODO: +** - J2573 seems to hang sometimes when in shared memory mode. +** - Mode for Priority TX +** - Check PCI registers, performance might be improved? +** - To reduce interrupt load in busmaster, one could switch off +** the interrupts that are used to refill the queues whenever the +** queues are filled up to more than a certain threshold. +** - some updates for EISA version of card +** +** +** This source/code is public free; you can distribute it and/or modify +** it under terms of the GNU General Public License (published by the +** Free Software Foundation) either version two of this License, or any +** later version. +** +** 1.55 -> 1.56 +** - removed printk in misc. interrupt and update statistics to allow +** monitoring of card status +** - timing changes in xmit routines, relogin to 100VG hub added when +** driver does reset +** - included fix for Compex FreedomLine PCI adapter +** +** 1.54 -> 1.55 +** - fixed bad initialization in init_module +** - added Compex FreedomLine adapter +** - some fixes in card initialization +** +** 1.53 -> 1.54 +** - added hardware multicast filter support (doesn't work) +** - little changes in hp100_sense_lan routine +** - added support for Coax and AUI (J2970) +** - fix for multiple cards and hp100_mode parameter (insmod) +** - fix for shared IRQ +** +** 1.52 -> 1.53 +** - fixed bug in multicast support +** +*/ + +#define HP100_DEFAULT_PRIORITY_TX 0 #undef HP100_DEBUG -#undef HP100_DEBUG_B /* Trace */ -#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ +#undef HP100_DEBUG_B /* Trace */ +#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ -#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ -#undef HP100_DEBUG_TX -#undef HP100_DEBUG_IRQ -#undef HP100_DEBUG_RX +#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ +#undef HP100_DEBUG_TX +#undef HP100_DEBUG_IRQ +#undef HP100_DEBUG_RX + +#undef HP100_MULTICAST_FILTER /* Need to be debugged... */ #include #include @@ -58,7 +84,6 @@ #include #include #include -#include #include #include @@ -67,7 +92,7 @@ #include #include -#include /* for CONFIG_PCI */ +#include /* for CONFIG_PCI */ #include #if LINUX_VERSION_CODE < 0x020100 @@ -79,6 +104,12 @@ typedef struct enet_statistics hp100_stats_t; typedef struct net_device_stats hp100_stats_t; #endif +#ifndef __initfunc +#define __initfunc(__initarg) __initarg +#else +#include +#endif + #include "hp100.h" /* @@ -98,8 +129,14 @@ typedef struct net_device_stats hp100_stats_t; #ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4 #define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 #endif +#ifndef PCI_VENDOR_ID_COMPEX2 +#define PCI_VENDOR_ID_COMPEX2 0x101a +#endif +#ifndef PCI_DEVICE_ID_COMPEX2_100VG +#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 +#endif -#define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_REGION_SIZE 0x20 /* for ioports */ #define HP100_MAX_PACKET_SIZE (1536+4) #define HP100_MIN_PACKET_SIZE 60 @@ -119,135 +156,167 @@ typedef struct net_device_stats hp100_stats_t; */ struct hp100_eisa_id { - u_int id; - const char *name; - u_char bus; + u_int id; + const char *name; + u_char bus; +}; + +struct hp100_pci_id { + u_short vendor; + u_short device; }; struct hp100_private { - struct hp100_eisa_id *id; - u_short chip; - u_short soft_model; - u_int memory_size; - u_short rx_ratio; /* 1 - 99 */ - u_short priority_tx; /* != 0 - priority tx */ - u_short mode; /* PIO, Shared Mem or Busmaster */ - u_char bus; - u_char pci_bus; - u_char pci_device_fn; - short mem_mapped; /* memory mapped access */ - u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ - u_int *mem_ptr_phys; /* physical memory mapped area */ - short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ - int hub_status; /* was login to hub successful? */ - u_char mac1_mode; - u_char mac2_mode; - hp100_stats_t stats; - - /* Rings for busmaster mode: */ - hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ - hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ - hp100_ring_t *txrhead; /* Head (oldest) index into txring */ - hp100_ring_t *txrtail; /* Tail (newest) index into txring */ - - hp100_ring_t rxring[MAX_RX_PDL]; - hp100_ring_t txring[MAX_TX_PDL]; - - u_int *page_vaddr; /* Virtual address of allocated page */ - u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ - int rxrcommit; /* # Rx PDLs commited to adapter */ - int txrcommit; /* # Tx PDLs commited to adapter */ + struct hp100_eisa_id *id; + u_short chip; + u_short soft_model; + u_int memory_size; + u_int virt_memory_size; + u_short rx_ratio; /* 1 - 99 */ + u_short priority_tx; /* != 0 - priority tx */ + u_short mode; /* PIO, Shared Mem or Busmaster */ + u_char bus; + u_char pci_bus; + u_char pci_device_fn; + short mem_mapped; /* memory mapped access */ + u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + u_int *mem_ptr_phys; /* physical memory mapped area */ + short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ + int hub_status; /* was login to hub successful? */ + u_char mac1_mode; + u_char mac2_mode; + u_char hash_bytes[ 8 ]; + hp100_stats_t stats; + + /* Rings for busmaster mode: */ + hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ + hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ + hp100_ring_t *txrhead; /* Head (oldest) index into txring */ + hp100_ring_t *txrtail; /* Tail (newest) index into txring */ + + hp100_ring_t rxring[ MAX_RX_PDL ]; + hp100_ring_t txring[ MAX_TX_PDL ]; + + u_int *page_vaddr; /* Virtual address of allocated page */ + u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ + int rxrcommit; /* # Rx PDLs commited to adapter */ + int txrcommit; /* # Tx PDLs commited to adapter */ }; /* * variables */ -static struct hp100_eisa_id hp100_eisa_ids[] = -{ +static struct hp100_eisa_id hp100_eisa_ids[] = { /* 10/100 EISA card with revision A Cascade chip */ - {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, + { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA }, /* 10/100 ISA card with revision A Cascade chip */ - {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, + { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA }, /* 10 only EISA card with Cascade chip */ - {0x2019F022, "HP 27248B", HP100_BUS_EISA}, + { 0x2019F022, "HP 27248B", HP100_BUS_EISA }, /* 10/100 EISA card with Cascade chip */ - {0x4019F022, "HP J2577", HP100_BUS_EISA}, + { 0x4019F022, "HP J2577", HP100_BUS_EISA }, /* 10/100 ISA card with Cascade chip */ - {0x5019F022, "HP J2573", HP100_BUS_ISA}, + { 0x5019F022, "HP J2573", HP100_BUS_ISA }, /* 10/100 PCI card - old J2585A */ - {0x1030103c, "HP J2585A", HP100_BUS_PCI}, + { 0x1030103c, "HP J2585A", HP100_BUS_PCI }, /* 10/100 PCI card - new J2585B - master capable */ - {0x1041103c, "HP J2585B", HP100_BUS_PCI}, + { 0x1041103c, "HP J2585B", HP100_BUS_PCI }, /* 10 Mbit Combo Adapter */ - {0x1042103c, "HP J2970", HP100_BUS_PCI}, + { 0x1042103c, "HP J2970", HP100_BUS_PCI }, /* 10 Mbit 10baseT Adapter */ - {0x1040103c, "HP J2973", HP100_BUS_PCI}, + { 0x1040103c, "HP J2973", HP100_BUS_PCI }, /* 10/100 EISA card from Compex */ - {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, - + { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA }, + + /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */ + /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */ + /* version of adapter, too... */ + { 0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA }, + + /* 10/100 PCI card from Compex - FreedomLine + * + * I think this card doesn't like aic7178 scsi controller, but + * I haven't tested this much. It works fine on diskless machines. + * Jacek Lipkowski + */ + { 0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI }, + /* 10/100 PCI card from Compex (J2585A compatible) */ - {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI} + { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI } + }; +#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) + +static struct hp100_pci_id hp100_pci_ids[] = { + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A }, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B }, + { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4 }, + { PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG } +}; + +#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) + static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; static int hp100_mode = 1; #ifdef LINUX_2_1 -MODULE_PARM(hp100_rx_ratio, "1i"); -MODULE_PARM(hp100_priority_tx, "1i"); -MODULE_PARM(hp100_mode, "1i"); +MODULE_PARM( hp100_rx_ratio, "1i" ); +MODULE_PARM( hp100_priority_tx, "1i" ); +MODULE_PARM( hp100_mode, "1i" ); #endif /* * prototypes */ -static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn); -static int hp100_open(struct device *dev); -static int hp100_close(struct device *dev); -static int hp100_start_xmit(struct sk_buff *skb, struct device *dev); -static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev); -static void hp100_rx(struct device *dev); -static hp100_stats_t *hp100_get_stats(struct device *dev); -static void hp100_update_stats(struct device *dev); -static void hp100_clear_stats(int ioaddr); -static void hp100_set_multicast_list(struct device *dev); -static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void hp100_start_interface(struct device *dev); -static void hp100_stop_interface(struct device *dev); -static void hp100_load_eeprom(struct device *dev); -static int hp100_sense_lan(struct device *dev); -static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin); -static int hp100_down_vg_link(struct device *dev); -static void hp100_cascade_reset(struct device *dev, u_short enable); -static void hp100_BM_shutdown(struct device *dev); -static void hp100_mmuinit(struct device *dev); -static void hp100_init_pdls(struct device *dev); -static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u_int * pdlptr); -static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u_int * pdlptr); -static void hp100_rxfill(struct device *dev); -static void hp100_hwinit(struct device *dev); -static void hp100_clean_txring(struct device *dev); +static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); +static int hp100_open( struct device *dev ); +static int hp100_close( struct device *dev ); +static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); +static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev ); +static void hp100_rx( struct device *dev ); +static hp100_stats_t *hp100_get_stats( struct device *dev ); +static void hp100_misc_interrupt( struct device *dev ); +static void hp100_update_stats( struct device *dev ); +static void hp100_clear_stats( int ioaddr ); +static void hp100_set_multicast_list( struct device *dev); +static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ); +static void hp100_start_interface( struct device *dev ); +static void hp100_stop_interface( struct device *dev ); +static void hp100_load_eeprom( struct device *dev, u_short ioaddr ); +static int hp100_sense_lan( struct device *dev ); +static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ); +static int hp100_down_vg_link( struct device *dev ); +static void hp100_cascade_reset( struct device *dev, u_short enable ); +static void hp100_BM_shutdown( struct device *dev ); +static void hp100_mmuinit( struct device *dev ); +static void hp100_init_pdls( struct device *dev ); +static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u_int *pdlptr); +static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u_int *pdlptr); +static void hp100_rxfill( struct device *dev ); +static void hp100_hwinit( struct device *dev ); +static void hp100_clean_txring( struct device *dev ); #ifdef HP100_DEBUG -static void hp100_RegisterDump(struct device *dev); +static void hp100_RegisterDump( struct device *dev ); #endif /* TODO: This function should not really be needed in a good design... */ -static void wait(void) +static void wait( void ) { - udelay(1000); + udelay( 1000 ); } /* @@ -255,863 +324,984 @@ static void wait(void) * These functions should - if possible - avoid doing write operations * since this could cause problems when the card is not installed. */ - -__initfunc(int hp100_probe(struct device *dev)) + +__initfunc(int hp100_probe( struct device *dev )) { - int base_addr = dev ? dev->base_addr : 0; - int ioaddr = 0; + int base_addr = dev ? dev -> base_addr : 0; + int ioaddr = 0; #ifdef CONFIG_PCI - int pci_start_index = 0; + int pci_start_index = 0; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4200, TRACE); - printk("hp100: probe\n"); -#endif - - if (base_addr > 0xff) { /* Check a single specified location. */ - if (check_region(base_addr, HP100_REGION_SIZE)) - return -EINVAL; - if (base_addr < 0x400) - return hp100_probe1(dev, base_addr, HP100_BUS_ISA, 0, 0); - else - return hp100_probe1(dev, base_addr, HP100_BUS_EISA, 0, 0); - } else + hp100_outw( 0x4200, TRACE ); + printk( "hp100: %s: probe\n", dev->name ); +#endif + + if ( base_addr > 0xff ) /* Check a single specified location. */ + { + if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL; + if ( base_addr < 0x400 ) + return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 ); + if ( EISA_bus && base_addr >= 0x1c38 && ( (base_addr - 0x1c38) & 0x3ff ) == 0 ) + return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 ); +#ifdef CONFIG_PCI + printk( "hp100: %s: You may specify card # in i/o address parameter for PCI bus...", dev->name ); + return hp100_probe1( dev, base_addr, HP100_BUS_PCI, 0, 0 ); +#else + return -ENODEV; +#endif + } + else #ifdef CONFIG_PCI - if (base_addr > 0 && base_addr < 8 + 1) - pci_start_index = 0x100 | (base_addr - 1); - else + if ( base_addr > 0 && base_addr < 8 + 1 ) + pci_start_index = 0x100 | ( base_addr - 1 ); + else #endif - if (base_addr != 0) - return -ENXIO; + if ( base_addr != 0 ) return -ENXIO; - /* at first - scan PCI bus(es) */ + /* at first - scan PCI bus(es) */ #ifdef CONFIG_PCI - if (pcibios_present()) { - int pci_index; + if ( pcibios_present() ) + { + int pci_index; #ifdef HP100_DEBUG_PCI - printk("hp100: PCI BIOS is present, checking for devices..\n"); -#endif - for (pci_index = pci_start_index & 7; pci_index < 8; pci_index++) { - u_char pci_bus, pci_device_fn; - u_short pci_command; - - if ((pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, - pci_index, &pci_bus, - &pci_device_fn) != 0) && - (pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, - pci_index, &pci_bus, - &pci_device_fn) != 0) && - (pcibios_find_device(PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, - pci_index, &pci_bus, - &pci_device_fn) != 0)) - break; - - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &ioaddr); - - ioaddr &= ~3; /* remove I/O space marker in bit 0. */ - - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_MASTER)) { -#ifdef HP100_DEBUG - printk("hp100: PCI Master Bit has not been set. Setting...\n"); + printk( "hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name ); #endif - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, pci_command); - } -#ifdef HP100_DEBUG - printk("hp100: PCI adapter found at 0x%x\n", ioaddr); -#endif - if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn) == 0) - return 0; - } - } - if (pci_start_index > 0) - return -ENODEV; -#endif /* CONFIG_PCI */ - - /* Second: Probe all EISA possible port regions (if EISA bus present) */ - for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, 0, 0) == 0) - return 0; - } + for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ ) + { + u_char pci_bus, pci_device_fn; + u_short pci_command; + int pci_id_index; - /* Third Probe all ISA possible port regions */ - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, 0, 0) == 0) - return 0; - } + for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ ) + if ( pcibios_find_device( hp100_pci_ids[ pci_id_index ].vendor, + hp100_pci_ids[ pci_id_index ].device, + pci_index, &pci_bus, + &pci_device_fn ) == 0 ) goto __pci_found; + break; - return -ENODEV; + __pci_found: + pcibios_read_config_dword( pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &ioaddr ); + + ioaddr &= ~3; /* remove I/O space marker in bit 0. */ + + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + + pcibios_read_config_word( pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command ); + if ( !( pci_command & PCI_COMMAND_IO ) ) + { +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name ); +#endif + pci_command |= PCI_COMMAND_IO; + pcibios_write_config_word( pci_bus, pci_device_fn, + PCI_COMMAND, pci_command ); + } + if ( !( pci_command & PCI_COMMAND_MASTER ) ) + { +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name ); +#endif + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word( pci_bus, pci_device_fn, + PCI_COMMAND, pci_command ); + } +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr ); +#endif + if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 ) + return 0; + } + } + if ( pci_start_index > 0 ) return -ENODEV; +#endif /* CONFIG_PCI */ + + /* Second: Probe all EISA possible port regions (if EISA bus present) */ + for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 ) + { + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0; + } + + /* Third Probe all ISA possible port regions */ + for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 ) + { + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0; + } + + return -ENODEV; } - -__initfunc(static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn)) + +__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )) { - int i; - - u_char uc, uc_1; - u_int eisa_id; - u_int chip; - u_int memory_size = 0; - short mem_mapped; - u_int *mem_ptr_phys, *mem_ptr_virt; - struct hp100_private *lp; - struct hp100_eisa_id *eid; + int i; + + u_char uc, uc_1; + u_int eisa_id; + u_int chip; + u_int memory_size = 0, virt_memory_size = 0; + u_short local_mode, lsw; + short mem_mapped; + u_int *mem_ptr_phys, *mem_ptr_virt; + struct hp100_private *lp; + struct hp100_eisa_id *eid; #ifdef HP100_DEBUG_B - hp100_outw(0x4201, TRACE); - printk("hp100: probe1\n"); + hp100_outw( 0x4201, TRACE ); + printk("hp100: %s: probe1\n",dev->name); #endif - if (dev == NULL) { + if ( dev == NULL ) + { #ifdef HP100_DEBUG - printk("hp100_probe1: dev == NULL ?\n"); -#endif - return EIO; + printk( "hp100_probe1: %s: dev == NULL ?\n", dev->name ); +#endif + return EIO; + } + + if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE ) + { + return -ENODEV; + } + else + { + chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK; +#ifdef HP100_DEBUG + if ( chip == HP100_CHIPID_SHASTA ) + printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if ( chip == HP100_CHIPID_RAINIER ) + printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if ( chip == HP100_CHIPID_LASSEN ) + printk("hp100: %s: Lassen Chip detected.\n", dev->name); + else + printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n",dev->name,chip); +#endif + } + + dev->base_addr = ioaddr; + + hp100_page( ID_MAC_ADDR ); + for ( i = uc = eisa_id = 0; i < 4; i++ ) + { + eisa_id >>= 8; + uc_1 = hp100_inb( BOARD_ID + i ); + eisa_id |= uc_1 << 24; + uc += uc_1; + } + uc += hp100_inb( BOARD_ID + 4 ); + + if ( uc != 0xff ) /* bad checksum? */ + { + printk("hp100_probe: %s: bad EISA ID checksum at base port 0x%x\n", dev->name, ioaddr ); + return -ENODEV; + } + + for ( i=0; i < HP100_EISA_IDS_SIZE; i++) + if ( hp100_eisa_ids[ i ].id == eisa_id ) + break; + if ( i >= HP100_EISA_IDS_SIZE ) { + for ( i = 0; i < HP100_EISA_IDS_SIZE; i++) + if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) ) + break; + if ( i >= HP100_EISA_IDS_SIZE ) { + printk( "hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev -> name, ioaddr, eisa_id ); + return -ENODEV; + } + } + eid = &hp100_eisa_ids[ i ]; + if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) ) + { + printk( "hp100_probe: %s: newer version of card %s at port 0x%x - unsupported\n", + dev->name, eid->name, ioaddr ); + return -ENODEV; + } + + for ( i = uc = 0; i < 7; i++ ) + uc += hp100_inb( LAN_ADDR + i ); + if ( uc != 0xff ) + { + printk("hp100_probe: %s: bad lan address checksum (card %s at port 0x%x)\n", + dev->name, eid->name, ioaddr ); + return -EIO; + } + + /* Make sure, that all registers are correctly updated... */ + + hp100_load_eeprom( dev, ioaddr ); + wait(); + + /* + * Determine driver operation mode + * + * Use the variable "hp100_mode" upon insmod or as kernel parameter to + * force driver modes: + * hp100_mode=1 -> default, use busmaster mode if configured. + * hp100_mode=2 -> enable shared memory mode + * hp100_mode=3 -> force use of i/o mapped mode. + * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. + */ + + /* + * LSW values: + * 0x2278 -> J2585B, PnP shared memory mode + * 0x2270 -> J2585B, shared memory mode, 0xdc000 + * 0xa23c -> J2585B, I/O mapped mode + * 0x2240 -> EISA COMPEX, BusMaster (Shasta Chip) + * 0x2220 -> EISA HP, I/O (Shasta Chip) + * 0x2260 -> EISA HP, BusMaster (Shasta Chip) + */ + +#if 0 + local_mode = 0x2270; + hp100_outw(0xfefe,OPTION_LSW); + hp100_outw(local_mode|HP100_SET_LB|HP100_SET_HB,OPTION_LSW); +#endif + + /* hp100_mode value maybe used in future by another card */ + local_mode=hp100_mode; + if ( local_mode < 1 || local_mode > 4 ) + local_mode = 1; /* default */ +#ifdef HP100_DEBUG + printk( "hp100: %s: original LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) ); +#endif + + if(local_mode==3) + { + hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); + printk("hp100: %s: IO mapped mode forced.\n", dev->name); + } + else if(local_mode==2) + { + hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); + printk("hp100: %s: Shared memory mode requested.\n", dev->name); + } + else if(local_mode==4) + { + if(chip==HP100_CHIPID_LASSEN) + { + hp100_outw(HP100_BM_WRITE| + HP100_BM_READ | HP100_SET_HB, OPTION_LSW); + hp100_outw(HP100_IO_EN | + HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + printk("hp100: %s: Busmaster mode requested.\n",dev->name); } - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { - return -ENODEV; - } else { - chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; + local_mode=1; + } + + if(local_mode==1) /* default behaviour */ + { + lsw = hp100_inw(OPTION_LSW); + + if ( (lsw & HP100_IO_EN) && + (~lsw & HP100_MEM_EN) && + (~lsw & (HP100_BM_WRITE|HP100_BM_READ)) ) + { #ifdef HP100_DEBUG - if (chip == HP100_CHIPID_SHASTA) - printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n"); - else if (chip == HP100_CHIPID_RAINIER) - printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n"); - else if (chip == HP100_CHIPID_LASSEN) - printk("hp100: Lassen Chip detected.\n"); - else - printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n", chip); + printk("hp100: %s: IO_EN bit is set on card.\n",dev->name); #endif + local_mode=3; } - - dev->base_addr = ioaddr; - - hp100_page(ID_MAC_ADDR); - for (i = uc = eisa_id = 0; i < 4; i++) { - eisa_id >>= 8; - uc_1 = hp100_inb(BOARD_ID + i); - eisa_id |= uc_1 << 24; - uc += uc_1; + else if ( chip == HP100_CHIPID_LASSEN && + ( lsw & (HP100_BM_WRITE|HP100_BM_READ) ) == + (HP100_BM_WRITE|HP100_BM_READ) ) + { + printk("hp100: %s: Busmaster mode enabled.\n",dev->name); + hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); } - uc += hp100_inb(BOARD_ID + 4); - - if (uc != 0xff) { /* bad checksum? */ - printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr); - return -ENODEV; - } - for (i = 0; i < sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id); i++) - if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff)) - break; - if (i >= sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id)) { - printk("hp100_probe1: card at port 0x%x isn't known (id = 0x%x)\n", ioaddr, eisa_id); - return -ENODEV; - } - eid = &hp100_eisa_ids[i]; - if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) { - printk("hp100_probe1: newer version of card %s at port 0x%x - unsupported\n", - eid->name, ioaddr); - return -ENODEV; - } - for (i = uc = 0; i < 7; i++) - uc += hp100_inb(LAN_ADDR + i); - if (uc != 0xff) { - printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", - eid->name, ioaddr); - return -EIO; - } - /* Determine driver operation mode - - * Use the variable "hp100_mode" upon insmod or as kernel parameter to - * force driver modes: - * hp100_mode=1 -> default, use busmaster mode if configured. - * hp100_mode=2 -> enable shared memory mode - * hp100_mode=3 -> force use of i/o mapped mode. - * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. - */ - - if (hp100_mode == 3) { - hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: IO mapped mode forced.\n"); - } else if (hp100_mode == 2) { - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: Shared memory mode requested.\n"); - } else if (hp100_mode == 4) { - if (chip == HP100_CHIPID_LASSEN) { - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | HP100_SET_HB, OPTION_LSW); - hp100_outw(HP100_IO_EN | - HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: Busmaster mode requested.\n"); - } - hp100_mode = 1; - } - if (hp100_mode == 1) { /* default behaviour */ - if ((hp100_inw(OPTION_LSW) & HP100_IO_EN) && - (~hp100_inw(OPTION_LSW) & HP100_MEM_EN) && - (~hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) - ) { -#ifdef HP100_DEBUG - printk("hp100: IO_EN bit is set on card.\n"); -#endif - hp100_mode = 3; - } else if ((chip == HP100_CHIPID_LASSEN) && - ((hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) == - (HP100_BM_WRITE | HP100_BM_READ))) { - printk("hp100: Busmaster mode enabled.\n"); - hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - } else { + else + { #ifdef HP100_DEBUG - printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n"); + printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name ); + printk("hp100: %s: Trying shared memory mode.\n", dev->name); #endif - /* In this case, try shared memory mode */ - hp100_mode = 2; - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ - } + /* In this case, try shared memory mode */ + local_mode=2; + hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); + /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ } - /* Check for shared memory on the card, eventually remap it */ - hp100_page(HW_MAP); - mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0); - mem_ptr_phys = mem_ptr_virt = NULL; - memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); - - /* For memory mapped or busmaster mode, we want the memory address */ - if (mem_mapped || (hp100_mode == 1)) { - mem_ptr_phys = (u_int *) (hp100_inw(MEM_MAP_LSW) | - (hp100_inw(MEM_MAP_MSW) << 16)); - (u_int) mem_ptr_phys &= ~0x1fff; /* 8k alignment */ - - if (bus == HP100_BUS_ISA && ((u_long) mem_ptr_phys & ~0xfffff) != 0) { - printk("hp100: Can only use programmed i/o mode.\n"); - mem_ptr_phys = NULL; - mem_mapped = 0; - hp100_mode = 3; /* Use programmed i/o */ - } - /* We do not need access to shared memory in busmaster mode */ - /* However in slave mode we need to remap high (>1GB) card memory */ - if (hp100_mode != 1) { /* = not busmaster */ - if (bus == HP100_BUS_PCI) { - /* We try with smaller memory sizes, if ioremap fails */ - for (; memory_size > 16383; memory_size = memory_size / 2) { - if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, memory_size)) == NULL) { + } + #ifdef HP100_DEBUG - printk("hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long) mem_ptr_phys); + printk( "hp100: %s: new LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) ); +#endif + + /* Check for shared memory on the card, eventually remap it */ + hp100_page( HW_MAP ); + mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0); + mem_ptr_phys = mem_ptr_virt = NULL; + memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07)); + virt_memory_size = 0; + + /* For memory mapped or busmaster mode, we want the memory address */ + if ( mem_mapped || (local_mode==1)) + { + mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) | + ( hp100_inw( MEM_MAP_MSW ) << 16 ) ); + (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + + if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 ) + { + printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name); + mem_ptr_phys = NULL; + mem_mapped = 0; + local_mode=3; /* Use programmed i/o */ + } + + /* We do not need access to shared memory in busmaster mode */ + /* However in slave mode we need to remap high (>1GB) card memory */ + if(local_mode!=1) /* = not busmaster */ + { + if ( bus == HP100_BUS_PCI && mem_ptr_phys >= (u_int *)0x100000 ) + { + /* We try with smaller memory sizes, if ioremap fails */ + for(virt_memory_size = memory_size; virt_memory_size>16383; virt_memory_size>>=1) + { + if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,virt_memory_size))==NULL) + { +#ifdef HP100_DEBUG + printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys ); #endif - } else { + } + else + { #ifdef HP100_DEBUG - printk("hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long) mem_ptr_phys, (u_long) mem_ptr_virt); -#endif - break; - } - } - - if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ - printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); - hp100_mode = 3; - memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); - } - } + printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt); +#endif + break; + } } + + if(mem_ptr_virt==NULL) /* all ioremap tries failed */ + { + printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name); + local_mode=3; + virt_memory_size = 0; + } + } } - if (hp100_mode == 3) { /* io mapped forced */ - mem_mapped = 0; - mem_ptr_phys = mem_ptr_virt = NULL; - printk("hp100: Using (slow) programmed i/o mode.\n"); - } - /* Initialise the "private" data structure for this card. */ - if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct hp100_private)); - - lp = (struct hp100_private *) dev->priv; - lp->id = eid; - lp->chip = chip; - lp->mode = hp100_mode; - lp->pci_bus = pci_bus; - lp->bus = bus; - lp->pci_device_fn = pci_device_fn; - lp->priority_tx = hp100_priority_tx; - lp->rx_ratio = hp100_rx_ratio; - lp->mem_ptr_phys = mem_ptr_phys; - lp->mem_ptr_virt = mem_ptr_virt; - hp100_page(ID_MAC_ADDR); - lp->soft_model = hp100_inb(SOFT_MODEL); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; - - dev->base_addr = ioaddr; - - lp->memory_size = memory_size; - lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - - /* memory region for programmed i/o */ - request_region(dev->base_addr, HP100_REGION_SIZE, eid->name); - - dev->open = hp100_open; - dev->stop = hp100_close; - - if (lp->mode == 1) /* busmaster */ - dev->hard_start_xmit = hp100_start_xmit_bm; - else - dev->hard_start_xmit = hp100_start_xmit; - - dev->get_stats = hp100_get_stats; - dev->set_multicast_list = &hp100_set_multicast_list; - - /* Ask the card for which IRQ line it is configured */ - hp100_page(HW_MAP); - dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK; - if (dev->irq == 2) - dev->irq = 9; - - if (lp->mode == 1) /* busmaster */ - dev->dma = 4; - - /* Ask the card for its MAC address and store it for later use. */ - hp100_page(ID_MAC_ADDR); - for (i = uc = 0; i < 6; i++) - dev->dev_addr[i] = hp100_inb(LAN_ADDR + i); - - /* Reset statistics (counters) */ - hp100_clear_stats(ioaddr); - - ether_setup(dev); - - /* If busmaster mode is wanted, a dma-capable memory area is needed for - * the rx and tx PDLs - * PCI cards can access the whole PC memory. Therefore GFP_DMA is not - * needed for the allocation of the memory area. - */ - - /* TODO: We do not need this with old cards, where PDLs are stored - * in the cards shared memory area. But currently, busmaster has been - * implemented/tested only with the lassen chip anyway... */ - if (lp->mode == 1) { /* busmaster */ - /* Get physically continous memory for TX & RX PDLs */ - if ((lp->page_vaddr = kmalloc(MAX_RINGSIZE + 0x0f, GFP_KERNEL)) == NULL) - return -ENOMEM; - lp->page_vaddr_algn = ((u_int *) (((u_int) (lp->page_vaddr) + 0x0f) & ~0x0f)); - memset(lp->page_vaddr, 0, MAX_RINGSIZE + 0x0f); + + } + + if(local_mode==3) /* io mapped forced */ + { + mem_mapped = 0; + mem_ptr_phys = mem_ptr_virt = NULL; + printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name); + } + + /* Initialise the "private" data structure for this card. */ + if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset( dev->priv, 0, sizeof(struct hp100_private) ); + + lp = (struct hp100_private *)dev->priv; + lp->id = eid; + lp->chip = chip; + lp->mode = local_mode; + lp->pci_bus = pci_bus; + lp->bus = bus; + lp->pci_device_fn = pci_device_fn; + lp->priority_tx = hp100_priority_tx; + lp->rx_ratio = hp100_rx_ratio; + lp->mem_ptr_phys = mem_ptr_phys; + lp->mem_ptr_virt = mem_ptr_virt; + hp100_page( ID_MAC_ADDR ); + lp->soft_model = hp100_inb( SOFT_MODEL ); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + memset( &lp->hash_bytes, 0x00, 8 ); + + dev->base_addr = ioaddr; + + lp->memory_size = memory_size; + lp->virt_memory_size = virt_memory_size; + lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ + + /* memory region for programmed i/o */ + request_region( dev->base_addr, HP100_REGION_SIZE, eid->name ); + + dev->open = hp100_open; + dev->stop = hp100_close; + + if (lp->mode==1) /* busmaster */ + dev->hard_start_xmit = hp100_start_xmit_bm; + else + dev->hard_start_xmit = hp100_start_xmit; + + dev->get_stats = hp100_get_stats; + dev->set_multicast_list = &hp100_set_multicast_list; + + /* Ask the card for which IRQ line it is configured */ + hp100_page( HW_MAP ); + dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; + if ( dev->irq == 2 ) + dev->irq = 9; + + if(lp->mode==1) /* busmaster */ + dev->dma=4; + + /* Ask the card for its MAC address and store it for later use. */ + hp100_page( ID_MAC_ADDR ); + for ( i = uc = 0; i < 6; i++ ) + dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i ); + + /* Reset statistics (counters) */ + hp100_clear_stats( ioaddr ); + + ether_setup( dev ); + + /* If busmaster mode is wanted, a dma-capable memory area is needed for + * the rx and tx PDLs + * PCI cards can access the whole PC memory. Therefore GFP_DMA is not + * needed for the allocation of the memory area. + */ + + /* TODO: We do not need this with old cards, where PDLs are stored + * in the cards shared memory area. But currently, busmaster has been + * implemented/tested only with the lassen chip anyway... */ + if(lp->mode==1) /* busmaster */ + { + /* Get physically continous memory for TX & RX PDLs */ + if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL) + return -ENOMEM; + lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f)); + memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f); #ifdef HP100_DEBUG_BM - printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n", - (u_int) lp->page_vaddr_algn, - (u_int) lp->page_vaddr_algn + MAX_RINGSIZE); -#endif - lp->rxrcommit = lp->txrcommit = 0; - lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - lp->txrhead = lp->txrtail = &(lp->txring[0]); - } - /* Initialise the card. */ - /* (I'm not really sure if it's a good idea to do this during probing, but - * like this it's assured that the lan connection type can be sensed - * correctly) - */ - hp100_hwinit(dev); - - /* Try to find out which kind of LAN the card is connected to. */ - lp->lan_type = hp100_sense_lan(dev); - - /* Print out a message what about what we think we have probed. */ - printk("hp100: %s: %s at 0x%x, IRQ %d, ", - dev->name, lp->id->name, ioaddr, dev->irq); - switch (bus) { - case HP100_BUS_EISA: - printk("EISA"); - break; - case HP100_BUS_PCI: - printk("PCI"); - break; - default: - printk("ISA"); - break; - } - printk(" bus, %dk SRAM (rx/tx %d%%).\n", - lp->memory_size >> 10, lp->rx_ratio); - - if (lp->mode == 2) { /* memory mapped */ - printk("%s: Memory area at 0x%lx-0x%lx", - dev->name, (u_long) mem_ptr_phys, (u_long) mem_ptr_phys + (u_long) lp->memory_size); - if (mem_ptr_virt) - printk(" (virtual base 0x%lx)", (u_long) mem_ptr_virt); - printk(".\n"); - - /* Set for info when doing ifconfig */ - dev->mem_start = (u_long) mem_ptr_phys; - dev->mem_end = (u_long) mem_ptr_phys + (u_long) lp->memory_size; - } - printk("%s: ", dev->name); - if (lp->lan_type != HP100_LAN_ERR) - printk("Adapter is attached to "); - switch (lp->lan_type) { - case HP100_LAN_100: - printk("100Mb/s Voice Grade AnyLAN network.\n"); - break; - case HP100_LAN_10: - printk("10Mb/s network.\n"); - break; - default: - printk("Warning! Link down.\n"); - } - return 0; + printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", + dev->name, + (u_int)lp->page_vaddr_algn, + (u_int)lp->page_vaddr_algn+MAX_RINGSIZE); +#endif + lp->rxrcommit = lp->txrcommit = 0; + lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + lp->txrhead = lp->txrtail = &(lp->txring[0]); + } + + /* Initialise the card. */ + /* (I'm not really sure if it's a good idea to do this during probing, but + * like this it's assured that the lan connection type can be sensed + * correctly) + */ + hp100_hwinit( dev ); + + /* Try to find out which kind of LAN the card is connected to. */ + lp->lan_type = hp100_sense_lan( dev ); + + /* Print out a message what about what we think we have probed. */ + printk( "hp100: %s: %s at 0x%x, IRQ %d, ", + dev->name, lp->id->name, ioaddr, dev->irq ); + switch ( bus ) { + case HP100_BUS_EISA: printk( "EISA" ); break; + case HP100_BUS_PCI: printk( "PCI" ); break; + default: printk( "ISA" ); break; + } + printk( " bus, %dk SRAM (rx/tx %d%%).\n", + lp->memory_size >> 10, lp->rx_ratio ); + + if ( lp->mode==2 ) /* memory mapped */ + { + printk( "hp100: %s: Memory area at 0x%lx-0x%lx", + dev->name,(u_long)mem_ptr_phys, + ((u_long)mem_ptr_phys+(mem_ptr_phys>(u_int *)0x100000?(u_long)lp->memory_size:16*1024))-1 ); + if ( mem_ptr_virt ) + printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); + printk( ".\n" ); + + /* Set for info when doing ifconfig */ + dev->mem_start = (u_long)mem_ptr_phys; + dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size; + } + printk( "hp100: %s: ", dev->name ); + if ( lp->lan_type != HP100_LAN_ERR ) + printk( "Adapter is attached to " ); + switch ( lp->lan_type ) { + case HP100_LAN_100: + printk( "100Mb/s Voice Grade AnyLAN network.\n" ); + break; + case HP100_LAN_10: + printk( "10Mb/s network.\n" ); + break; + default: + printk( "Warning! Link down.\n" ); + } + + return 0; } - + /* This procedure puts the card into a stable init state */ -static void hp100_hwinit(struct device *dev) +static void hp100_hwinit( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4202, TRACE); - printk("hp100: hwinit\n"); -#endif - - /* Initialise the card. -------------------------------------------- */ - - /* Clear all pending Ints and disable Ints */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */ - - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if (lp->mode == 1) { - hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */ - wait(); - } else { - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - hp100_cascade_reset(dev, TRUE); - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); - } - - /* Initiate EEPROM reload */ - hp100_load_eeprom(dev); - - wait(); - - /* Go into reset again. */ - hp100_cascade_reset(dev, TRUE); - - /* Set Option Registers to a safe state */ - hp100_outw(HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | - HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB | - HP100_FAKE_INT | - HP100_INT_EN | - HP100_MEM_EN | - HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw(HP100_TRI_INT | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - - hp100_outb(HP100_PRIORITY_TX | - HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); - - /* TODO: Configure MMU for Ram Test. */ - /* TODO: Ram Test. */ - - /* Re-check if adapter is still at same i/o location */ - /* (If the base i/o in eeprom has been changed but the */ - /* registers had not been changed, a reload of the eeprom */ - /* would move the adapter to the address stored in eeprom */ - - /* TODO: Code to implement. */ - - /* Until here it was code from HWdiscover procedure. */ - /* Next comes code from mmuinit procedure of SCO BM driver which is - * called from HWconfigure in the SCO driver. */ - - /* Initialise MMU, eventually switch on Busmaster Mode, initialise - * multicast filter... - */ - hp100_mmuinit(dev); - - /* We don't turn the interrupts on here - this is done by start_interface. */ - wait(); /* TODO: Do we really need this? */ - - /* Enable Hardware (e.g. unreset) */ - hp100_cascade_reset(dev, FALSE); - - /* ------- initialisation complete ----------- */ - - /* Finally try to log in the Hub if there may be a VG connection. */ - if (lp->lan_type != HP100_LAN_10) - hp100_login_to_vg_hub(dev, FALSE); /* relogin */ + hp100_outw( 0x4202, TRACE ); + printk("hp100: %s: hwinit\n", dev->name); +#endif + + /* Initialise the card. -------------------------------------------- */ + + /* Clear all pending Ints and disable Ints */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */ + + hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW ); + + if(lp->mode==1) + { + hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */ + wait(); + } + else + { + hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + hp100_cascade_reset( dev, TRUE ); + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1); + } + + /* Initiate EEPROM reload */ + hp100_load_eeprom( dev, 0 ); + + wait(); + + /* Go into reset again. */ + hp100_cascade_reset( dev, TRUE ); + + /* Set Option Registers to a safe state */ + hp100_outw( HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | + HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB | + HP100_FAKE_INT | + HP100_INT_EN | + HP100_MEM_EN | + HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw( HP100_TRI_INT | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + + hp100_outb( HP100_PRIORITY_TX | + HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); + + /* TODO: Configure MMU for Ram Test. */ + /* TODO: Ram Test. */ + + /* Re-check if adapter is still at same i/o location */ + /* (If the base i/o in eeprom has been changed but the */ + /* registers had not been changed, a reload of the eeprom */ + /* would move the adapter to the address stored in eeprom */ + + /* TODO: Code to implement. */ + + /* Until here it was code from HWdiscover procedure. */ + /* Next comes code from mmuinit procedure of SCO BM driver which is + * called from HWconfigure in the SCO driver. */ + + /* Initialise MMU, eventually switch on Busmaster Mode, initialise + * multicast filter... + */ + hp100_mmuinit( dev ); + + /* We don't turn the interrupts on here - this is done by start_interface. */ + wait(); /* TODO: Do we really need this? */ + + /* Enable Hardware (e.g. unreset) */ + hp100_cascade_reset( dev, FALSE ); + + /* ------- initialisation complete ----------- */ + + /* Finally try to log in the Hub if there may be a VG connection. */ + if( lp->lan_type != HP100_LAN_10 ) + hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ } - + /* * mmuinit - Reinitialise Cascade MMU and MAC settings. * Note: Must already be in reset and leaves card in reset. */ -static void hp100_mmuinit(struct device *dev) +static void hp100_mmuinit( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int i; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int i; #ifdef HP100_DEBUG_B - hp100_outw(0x4203, TRACE); - printk("hp100: mmuinit\n"); + hp100_outw( 0x4203, TRACE ); + printk("hp100: %s: mmuinit\n",dev->name); #endif #ifdef HP100_DEBUG - if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { - printk("hp100: Not in reset when entering mmuinit. Fix me.\n"); - return; - } -#endif - - /* Make sure IRQs are masked off and ack'ed. */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ - - /* - * Enable Hardware - * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En - * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable - * - Clear Priority, Advance Pkt and Xmit Cmd - */ - - hp100_outw(HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | HP100_RESET_HB | - HP100_IO_EN | - HP100_FAKE_INT | - HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if (lp->mode == 1) { /* busmaster */ - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - } else if (lp->mode == 2) { /* memory mapped */ - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - } else if (lp->mode == 3) { /* i/o mapped mode */ - hp100_outw(HP100_MMAP_DIS | HP100_SET_HB | - HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - } - hp100_page(HW_MAP); - hp100_outb(0, EARLYRXCFG); - hp100_outw(0, EARLYTXCFG); - - /* - * Enable Bus Master mode - */ - if (lp->mode == 1) { /* busmaster */ - /* Experimental: Set some PCI configuration bits */ - hp100_page(HW_MAP); - hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */ - hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */ - - /* PCI Bus failures should result in a Misc. Interrupt */ - hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2); - - hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW); - hp100_page(HW_MAP); - /* Use Burst Mode and switch on PAGE_CK */ - hp100_orb(HP100_BM_BURST_RD | - HP100_BM_BURST_WR, BM); - if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) - hp100_orb(HP100_BM_PAGE_CK, BM); - hp100_orb(HP100_BM_MASTER, BM); - } else { /* not busmaster */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - } - - /* - * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs - */ - hp100_page(MMU_CFG); - if (lp->mode == 1) { /* only needed for Busmaster */ - int xmit_stop, recv_stop; - - if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) { - int pdl_stop; - - /* - * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and - * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded - * to the next higher 1k boundary) bytes for the rx-pdl's - * Note: For non-etr chips the transmit stop register must be - * programmed on a 1k boundary, i.e. bits 9:0 must be zero. - */ - pdl_stop = lp->memory_size; - xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff); - recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff); - hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP); + if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) ) + { + printk("hp100: %s: Not in reset when entering mmuinit. Fix me.\n",dev->name); + return; + } +#endif + + /* Make sure IRQs are masked off and ack'ed. */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ + + /* + * Enable Hardware + * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En + * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable + * - Clear Priority, Advance Pkt and Xmit Cmd + */ + + hp100_outw( HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | HP100_RESET_HB | + HP100_IO_EN | + HP100_FAKE_INT | + HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + + hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if(lp->mode==1) /* busmaster */ + { + hp100_outw( HP100_BM_WRITE | + HP100_BM_READ | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + } + else if(lp->mode==2) /* memory mapped */ + { + hp100_outw( HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB, OPTION_LSW ); + hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); + hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW ); + hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); + } + else if( lp->mode==3 ) /* i/o mapped mode */ + { + hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | + HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); + } + + hp100_page( HW_MAP ); + hp100_outb( 0, EARLYRXCFG ); + hp100_outw( 0, EARLYTXCFG ); + + /* + * Enable Bus Master mode + */ + if(lp->mode==1) /* busmaster */ + { + /* Experimental: Set some PCI configuration bits */ + hp100_page( HW_MAP ); + hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */ + hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */ + + /* PCI Bus failures should result in a Misc. Interrupt */ + hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2); + + hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW ); + hp100_page( HW_MAP ); + /* Use Burst Mode and switch on PAGE_CK */ + hp100_orb( HP100_BM_BURST_RD | + HP100_BM_BURST_WR, BM); + if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) + hp100_orb( HP100_BM_PAGE_CK, BM ); + hp100_orb( HP100_BM_MASTER, BM ); + } + else /* not busmaster */ + { + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM ); + } + + /* + * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs + */ + hp100_page( MMU_CFG ); + if(lp->mode==1) /* only needed for Busmaster */ + { + int xmit_stop, recv_stop; + + if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) + { + int pdl_stop; + + /* + * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and + * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded + * to the next higher 1k boundary) bytes for the rx-pdl's + * Note: For non-etr chips the transmit stop register must be + * programmed on a 1k boundary, i.e. bits 9:0 must be zero. + */ + pdl_stop = lp->memory_size; + xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff); + recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff); + hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP ); #ifdef HP100_DEBUG_BM - printk("hp100: PDL_STOP = 0x%x\n", pdl_stop); + printk("hp100: %s: PDL_STOP = 0x%x\n", dev->name, pdl_stop); #endif - } else { /* ETR chip (Lassen) in busmaster mode */ - xmit_stop = (lp->memory_size) - 1; - recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff); - } + } + else /* ETR chip (Lassen) in busmaster mode */ + { + xmit_stop = ( lp->memory_size ) - 1; + recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff); + } - hp100_outw(xmit_stop >> 4, TX_MEM_STOP); - hp100_outw(recv_stop >> 4, RX_MEM_STOP); + hp100_outw( xmit_stop>>4 , TX_MEM_STOP ); + hp100_outw( recv_stop>>4 , RX_MEM_STOP ); #ifdef HP100_DEBUG_BM - printk("hp100: TX_STOP = 0x%x\n", xmit_stop >> 4); - printk("hp100: RX_STOP = 0x%x\n", recv_stop >> 4); -#endif - } else { /* Slave modes (memory mapped and programmed io) */ - hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP); - hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP); + printk("hp100: %s: TX_STOP = 0x%x\n",dev->name,xmit_stop>>4); + printk("hp100: %s: RX_STOP = 0x%x\n",dev->name,recv_stop>>4); +#endif + } + else /* Slave modes (memory mapped and programmed io) */ + { + hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP ); + hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP ); #ifdef HP100_DEBUG - printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP)); - printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP)); -#endif - } - - /* Write MAC address into page 1 */ - hp100_page(MAC_ADDRESS); - for (i = 0; i < 6; i++) - hp100_outb(dev->dev_addr[i], MAC_ADDR + i); - - /* Zero the multicast hash registers */ - for (i = 0; i < 8; i++) - hp100_outb(0x0, HASH_BYTE0 + i); - - /* Set up MAC defaults */ - hp100_page(MAC_CTRL); - - /* Go to LAN Page and zero all filter bits */ - /* Zero accept error, accept multicast, accept broadcast and accept */ - /* all directed packet bits */ - hp100_andb(~(HP100_RX_EN | - HP100_TX_EN | - HP100_ACC_ERRORED | - HP100_ACC_MC | - HP100_ACC_BC | - HP100_ACC_PHY), MAC_CFG_1); - - hp100_outb(0x00, MAC_CFG_2); - - /* Zero the frame format bit. This works around a training bug in the */ - /* new hubs. */ - hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */ - - if (lp->priority_tx) - hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW); - else - hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW); - - hp100_outb(HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); - - /* If busmaster, initialize the PDLs */ - if (lp->mode == 1) - hp100_init_pdls(dev); - - /* Go to performance page and initalize isr and imr registers */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ + printk("hp100: %s: TX_MEM_STOP: 0x%x\n", dev->name,hp100_inw(TX_MEM_STOP)); + printk("hp100: %s: RX_MEM_STOP: 0x%x\n", dev->name,hp100_inw(RX_MEM_STOP)); +#endif + } + + /* Write MAC address into page 1 */ + hp100_page( MAC_ADDRESS ); + for ( i = 0; i < 6; i++ ) + hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i ); + + /* Zero the multicast hash registers */ + for ( i = 0; i < 8; i++ ) + hp100_outb( 0x0, HASH_BYTE0 + i ); + + /* Set up MAC defaults */ + hp100_page( MAC_CTRL ); + + /* Go to LAN Page and zero all filter bits */ + /* Zero accept error, accept multicast, accept broadcast and accept */ + /* all directed packet bits */ + hp100_andb( ~(HP100_RX_EN| + HP100_TX_EN| + HP100_ACC_ERRORED| + HP100_ACC_MC| + HP100_ACC_BC| + HP100_ACC_PHY), MAC_CFG_1 ); + + hp100_outb( 0x00, MAC_CFG_2 ); + + /* Zero the frame format bit. This works around a training bug in the */ + /* new hubs. */ + hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */ + + if(lp->priority_tx) + hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW ); + else + hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW ); + + hp100_outb( HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); + + /* If busmaster, initialize the PDLs */ + if(lp->mode==1) + hp100_init_pdls( dev ); + + /* Go to performance page and initalize isr and imr registers */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ } - + /* * open/close functions */ -static int hp100_open(struct device *dev) +static int hp100_open( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + int ioaddr=dev->base_addr; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4204, TRACE); - printk("hp100: open\n"); -#endif - - /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ - if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) { - if (request_irq(dev->irq, hp100_interrupt, SA_SHIRQ, lp->id->name, dev)) { - printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); - return -EAGAIN; - } - } else if (request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, dev)) { - printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); - return -EAGAIN; - } - MOD_INC_USE_COUNT; - - dev->tbusy = 0; - dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; - - lp->lan_type = hp100_sense_lan(dev); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; - - hp100_stop_interface(dev); - - hp100_hwinit(dev); - - hp100_start_interface(dev); /* sets mac modes, enables interrupts */ - - return 0; + hp100_outw( 0x4204, TRACE ); + printk("hp100: %s: open\n",dev->name); +#endif + + /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ + if ( request_irq(dev->irq, hp100_interrupt, + lp->bus==HP100_BUS_PCI||lp->bus==HP100_BUS_EISA?SA_SHIRQ:SA_INTERRUPT, + lp->id->name, dev)) + { + printk( "hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq ); + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + dev->tbusy = 0; + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; + + lp->lan_type = hp100_sense_lan( dev ); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + memset( &lp->hash_bytes, 0x00, 8 ); + + hp100_stop_interface( dev ); + + hp100_hwinit( dev ); + + hp100_start_interface( dev ); /* sets mac modes, enables interrupts */ + + return 0; } - + /* The close function is called when the interface is to be brought down */ -static int hp100_close(struct device *dev) +static int hp100_close( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4205, TRACE); - printk("hp100:close\n"); + hp100_outw( 0x4205, TRACE ); + printk("hp100: %s: close\n", dev->name); #endif - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all IRQs */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */ + + hp100_stop_interface( dev ); + + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status=hp100_login_to_vg_hub( dev, FALSE ); - hp100_stop_interface(dev); + dev->tbusy = 1; + dev->start = 0; - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); + free_irq( dev->irq, dev ); - dev->tbusy = 1; - dev->start = 0; +#ifdef HP100_DEBUG + printk( "hp100: %s: close LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) ); +#endif - if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) - free_irq(dev->irq, dev); - else - free_irq(dev->irq, NULL); - MOD_DEC_USE_COUNT; - return 0; + MOD_DEC_USE_COUNT; + return 0; } - + /* * Configure the PDL Rx rings and LAN */ -static void hp100_init_pdls(struct device *dev) +static void hp100_init_pdls( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ringptr; - u_int *pageptr; - int i; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; + u_int *pageptr; + int i; #ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4206, TRACE); - printk("hp100: init pdls\n"); -#endif - - if (0 == lp->page_vaddr_algn) - printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n"); - else { - /* pageptr shall point into the DMA accessible memory region */ - /* we use this pointer to status the upper limit of allocated */ - /* memory in the allocated page. */ - /* note: align the pointers to the pci cache line size */ - memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ - pageptr = lp->page_vaddr_algn; - - lp->rxrcommit = 0; - ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - - /* Initialise Rx Ring */ - for (i = MAX_RX_PDL - 1; i >= 0; i--) { - lp->rxring[i].next = ringptr; - ringptr = &(lp->rxring[i]); - pageptr += hp100_init_rxpdl(ringptr, pageptr); - } - - /* Initialise Tx Ring */ - lp->txrcommit = 0; - ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); - for (i = MAX_TX_PDL - 1; i >= 0; i--) { - lp->txring[i].next = ringptr; - ringptr = &(lp->txring[i]); - pageptr += hp100_init_txpdl(ringptr, pageptr); - } - } + hp100_outw( 0x4206, TRACE ); + printk("hp100: %s: init pdls\n", dev->name); +#endif + + if(0==lp->page_vaddr_algn) + printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n",dev->name); + else + { + /* pageptr shall point into the DMA accessible memory region */ + /* we use this pointer to status the upper limit of allocated */ + /* memory in the allocated page. */ + /* note: align the pointers to the pci cache line size */ + memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ + pageptr=lp->page_vaddr_algn; + + lp->rxrcommit =0; + ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]); + + /* Initialise Rx Ring */ + for (i=MAX_RX_PDL-1; i>=0; i--) + { + lp->rxring[i].next = ringptr; + ringptr=&(lp->rxring[i]); + pageptr+=hp100_init_rxpdl(dev, ringptr, pageptr); + } + + /* Initialise Tx Ring */ + lp->txrcommit = 0; + ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); + for (i=MAX_TX_PDL-1; i>=0; i--) + { + lp->txring[i].next = ringptr; + ringptr=&(lp->txring[i]); + pageptr+=hp100_init_txpdl(dev, ringptr, pageptr); + } + } } - + /* These functions "format" the entries in the pdl structure */ /* They return how much memory the fragments need. */ -static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u32 * pdlptr) +static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ) { - /* pdlptr is starting adress for this pdl */ + /* pdlptr is starting adress for this pdl */ - if (0 != (((unsigned) pdlptr) & 0xf)) - printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr); + if( 0!=( ((unsigned)pdlptr) & 0xf) ) + printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned)pdlptr); - ringptr->pdl = pdlptr + 1; - ringptr->pdl_paddr = virt_to_bus(pdlptr + 1); - ringptr->skb = (void *) NULL; + ringptr->pdl = pdlptr+1; + ringptr->pdl_paddr = virt_to_bus(pdlptr+1); + ringptr->skb = (void *) NULL; - /* - * Write address and length of first PDL Fragment (which is used for - * storing the RX-Header - * We use the 4 bytes _before_ the PDH in the pdl memory area to - * store this information. (PDH is at offset 0x04) - */ - /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ + /* + * Write address and length of first PDL Fragment (which is used for + * storing the RX-Header + * We use the 4 bytes _before_ the PDH in the pdl memory area to + * store this information. (PDH is at offset 0x04) + */ + /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ - *(pdlptr + 2) = (u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ - *(pdlptr + 3) = 4; /* Length Frag 1 */ + *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ + *(pdlptr+3) = 4; /* Length Frag 1 */ - return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4); + return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 ); } -static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u32 * pdlptr) +static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ) { - if (0 != (((unsigned) pdlptr) & 0xf)) - printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr); - - ringptr->pdl = pdlptr; /* +1; */ - ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ - ringptr->skb = (void *) NULL; - - return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4); + if( 0!=( ((unsigned)pdlptr) & 0xf) ) + printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned) pdlptr); + + ringptr->pdl = pdlptr; /* +1; */ + ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ + ringptr->skb = (void *) NULL; + + return((((MAX_TX_FRAG*2+2)+3)/4)*4); } - + /* * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes * for possible odd word alignment rounding up to next dword and set PDL @@ -1119,77 +1309,80 @@ static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u32 * pdlp * Returns: 0 if unable to allocate skb_buff * 1 if successful */ -int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct device *dev) +int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev ) { #ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_BM - u_int *p; + u_int *p; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4207, TRACE); - printk("hp100: build rx pdl\n"); -#endif - - /* Allocate skb buffer of maximum size */ - /* Note: This depends on the alloc_skb functions allocating more - * space than requested, i.e. aligning to 16bytes */ - - ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4); - - if (NULL != ringptr->skb) { - /* - * Reserve 2 bytes at the head of the buffer to land the IP header - * on a long word boundary (According to the Network Driver section - * in the Linux KHG, this should help to increase performance.) - */ - skb_reserve(ringptr->skb, 2); - - ringptr->skb->dev = dev; - ringptr->skb->data = (u_char *) skb_put(ringptr->skb, MAX_ETHER_SIZE); - - /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ - /* Note: 1st Fragment is used for the 4 byte packet status - * (receive header). Its PDL entries are set up by init_rxpdl. So - * here we only have to set up the PDL fragment entries for the data - * part. Those 4 bytes will be stored in the DMA memory region - * directly before the PDL. - */ + hp100_outw( 0x4207, TRACE ); + printk("hp100: %s: build rx pdl\n", dev->name); +#endif + + /* Allocate skb buffer of maximum size */ + /* Note: This depends on the alloc_skb functions allocating more + * space than requested, i.e. aligning to 16bytes */ + + ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 ); + + if(NULL!=ringptr->skb) + { + /* + * Reserve 2 bytes at the head of the buffer to land the IP header + * on a long word boundary (According to the Network Driver section + * in the Linux KHG, this should help to increase performance.) + */ + skb_reserve(ringptr->skb, 2); + + ringptr->skb->dev=dev; + ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE ); + + /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ + /* Note: 1st Fragment is used for the 4 byte packet status + * (receive header). Its PDL entries are set up by init_rxpdl. So + * here we only have to set up the PDL fragment entries for the data + * part. Those 4 bytes will be stored in the DMA memory region + * directly before the PDL. + */ #ifdef HP100_DEBUG_BM - printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", - (u_int) ringptr->pdl, - ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4, - (unsigned int) ringptr->skb->data); + printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", + dev->name, + (u_int) ringptr->pdl, + ((MAX_ETHER_SIZE+2+3)/4)*4, + (unsigned int) ringptr->skb->data); #endif - ringptr->pdl[0] = 0x00020000; /* Write PDH */ - ringptr->pdl[3] = ((u_int) virt_to_bus(ringptr->skb->data)); - ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ - + ringptr->pdl[0] = 0x00020000; /* Write PDH */ + ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data)); + ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ + #ifdef HP100_DEBUG_BM - for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++) - printk("Adr 0x%.8x = 0x%.8x\n", (u_int) p, (u_int) * p); -#endif - return (1); - } - /* else: */ - /* alloc_skb failed (no memory) -> still can receive the header - * fragment into PDL memory. make PDL safe by clearing msgptr and - * making the PDL only 1 fragment (i.e. the 4 byte packet status) - */ + for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++) + printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n",dev->name,(u_int) p,(u_int) *p ); +#endif + return(1); + } + /* else: */ + /* alloc_skb failed (no memory) -> still can receive the header + * fragment into PDL memory. make PDL safe by clearing msgptr and + * making the PDL only 1 fragment (i.e. the 4 byte packet status) + */ #ifdef HP100_DEBUG_BM - printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n", - (u_int) ringptr->pdl); + printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n", + dev->name, + (u_int) ringptr->pdl); #endif - ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */ + ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */ - return (0); + return(0); } - + /* * hp100_rxfill - attempt to fill the Rx Ring will empty skb's * @@ -1200,246 +1393,279 @@ int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct device *dev) * b. Put the physical address of the buffer into the PDL. * c. Output physical address of PDL to adapter. */ -static void hp100_rxfill(struct device *dev) +static void hp100_rxfill( struct device *dev ) { - int ioaddr = dev->base_addr; + int ioaddr=dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ringptr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; #ifdef HP100_DEBUG_B - hp100_outw(0x4208, TRACE); - printk("hp100: rxfill\n"); -#endif - - hp100_page(PERFORMANCE); - - while (lp->rxrcommit < MAX_RX_PDL) { - /* - ** Attempt to get a buffer and build a Rx PDL. - */ - ringptr = lp->rxrtail; - if (0 == hp100_build_rx_pdl(ringptr, dev)) { - return; /* None available, return */ - } - /* Hand this PDL over to the card */ - /* Note: This needs performance page selected! */ + hp100_outw( 0x4208, TRACE ); + printk("hp100: %s: rxfill\n",dev->name); +#endif + + hp100_page( PERFORMANCE ); + + while (lp->rxrcommit < MAX_RX_PDL) + { + /* + ** Attempt to get a buffer and build a Rx PDL. + */ + ringptr = lp->rxrtail; + if (0 == hp100_build_rx_pdl( ringptr, dev )) + { + return; /* None available, return */ + } + + /* Hand this PDL over to the card */ + /* Note: This needs performance page selected! */ #ifdef HP100_DEBUG_BM - printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", - lp->rxrcommit, - (u_int) ringptr->pdl, - (u_int) ringptr->pdl_paddr, - (u_int) ringptr->pdl[3]); -#endif - - hp100_outl((u32) ringptr->pdl_paddr, RX_PDA); - - lp->rxrcommit += 1; - lp->rxrtail = ringptr->next; - } + printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", + dev->name, + lp->rxrcommit, + (u_int)ringptr->pdl, + (u_int)ringptr->pdl_paddr, + (u_int)ringptr->pdl[3]); +#endif + + hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA); + + lp->rxrcommit += 1; + lp->rxrtail = ringptr->next; + } } - + /* * BM_shutdown - shutdown bus mastering and leave chip in reset state */ -static void hp100_BM_shutdown(struct device *dev) +static void hp100_BM_shutdown( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - unsigned long time; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + unsigned long time; #ifdef HP100_DEBUG_B - hp100_outw(0x4209, TRACE); - printk("hp100: bm shutdown\n"); -#endif - - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */ - - /* Ensure Interrupts are off */ - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - - /* Disable all MAC activity */ - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ - - /* If cascade MMU is not already in reset */ - if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { - /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so - * MMU pointers will not be reset out from underneath - */ - hp100_page(MAC_CTRL); - for (time = 0; time < 5000; time++) { - if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == - (HP100_TX_IDLE | HP100_RX_IDLE)) - break; - } - - /* Shutdown algorithm depends on the generation of Cascade */ - if (lp->chip == HP100_CHIPID_LASSEN) { /* ETR shutdown/reset */ - /* Disable Busmaster mode and wait for bit to go to zero. */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - /* 100 ms timeout */ - for (time = 0; time < 32000; time++) { - if (0 == (hp100_inb(BM) & HP100_BM_MASTER)) - break; - } - } else { /* Shasta or Rainier Shutdown/Reset */ - /* To ensure all bus master inloading activity has ceased, - * wait for no Rx PDAs or no Rx packets on card. - */ - hp100_page(PERFORMANCE); - /* 100 ms timeout */ - for (time = 0; time < 10000; time++) { - /* RX_PDL: PDLs not executed. */ - /* RX_PKT_CNT: RX'd packets on card. */ - if ((hp100_inb(RX_PDL) == 0) && - (hp100_inb(RX_PKT_CNT) == 0)) - break; - } - - if (time >= 10000) - printk("hp100: BM shutdown error.\n"); - - /* To ensure all bus master outloading activity has ceased, - * wait until the Tx PDA count goes to zero or no more Tx space - * available in the Tx region of the card. - */ - /* 100 ms timeout */ - for (time = 0; time < 10000; time++) { - if ((0 == hp100_inb(TX_PKT_CNT)) && - (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE))) - break; - } - - /* Disable Busmaster mode */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - } /* end of shutdown procedure for non-etr parts */ - - hp100_cascade_reset(dev, TRUE); - } - hp100_page(PERFORMANCE); - hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW); - /* Busmaster mode should be shut down now. */ + hp100_outw( 0x4209, TRACE ); + printk("hp100: %s: bm shutdown\n",dev->name); +#endif + + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */ + + /* Ensure Interrupts are off */ + hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW ); + + /* Disable all MAC activity */ + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ + + /* If cascade MMU is not already in reset */ + if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) ) + { + /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so + * MMU pointers will not be reset out from underneath + */ + hp100_page( MAC_CTRL ); + for(time=0; time<5000; time++) + { + if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))== + (HP100_TX_IDLE|HP100_RX_IDLE) ) break; + } + + /* Shutdown algorithm depends on the generation of Cascade */ + if( lp->chip==HP100_CHIPID_LASSEN ) + { /* ETR shutdown/reset */ + /* Disable Busmaster mode and wait for bit to go to zero. */ + hp100_page(HW_MAP); + hp100_andb( ~HP100_BM_MASTER, BM ); + /* 100 ms timeout */ + for(time=0; time<32000; time++) + { + if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break; + } + } + else + { /* Shasta or Rainier Shutdown/Reset */ + /* To ensure all bus master inloading activity has ceased, + * wait for no Rx PDAs or no Rx packets on card. + */ + hp100_page( PERFORMANCE ); + /* 100 ms timeout */ + for(time=0; time<10000; time++) + { + /* RX_PDL: PDLs not executed. */ + /* RX_PKT_CNT: RX'd packets on card. */ + if ( (hp100_inb( RX_PDL ) == 0) && + (hp100_inb( RX_PKT_CNT ) == 0) ) break; + } + + if(time>=10000) + printk("hp100: %s: BM shutdown error.\n", dev->name); + + /* To ensure all bus master outloading activity has ceased, + * wait until the Tx PDA count goes to zero or no more Tx space + * available in the Tx region of the card. + */ + /* 100 ms timeout */ + for(time=0; time<10000; time++) { + if ( (0 == hp100_inb( TX_PKT_CNT )) && + (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break; + } + + /* Disable Busmaster mode */ + hp100_page(HW_MAP); + hp100_andb( ~HP100_BM_MASTER, BM ); + } /* end of shutdown procedure for non-etr parts */ + + hp100_cascade_reset( dev, TRUE ); + } + hp100_page( PERFORMANCE ); + /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */ + /* Busmaster mode should be shut down now. */ } - + /* * transmit functions */ /* tx function for busmaster mode */ -static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev) +static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev ) { - int i, ok_flag; - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ringptr; + unsigned long flags; + int i, ok_flag; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; #ifdef HP100_DEBUG_B - hp100_outw(0x4210, TRACE); - printk("hp100: start_xmit_bm\n"); -#endif - - /* Get Tx ring tail pointer */ - if (lp->txrtail->next == lp->txrhead) { - /* No memory. */ + hp100_outw( 0x4210, TRACE ); + printk("hp100: %s: start_xmit_bm\n",dev->name); +#endif + + if ( skb==NULL ) + { +#ifndef LINUX_2_1 + dev_tint( dev ); +#endif + return 0; + } + + if ( skb->len <= 0 ) return 0; + + /* Get Tx ring tail pointer */ + if( lp->txrtail->next==lp->txrhead ) + { + /* No memory. */ #ifdef HP100_DEBUG - printk("hp100: start_xmit_bm: No TX PDL available.\n"); -#endif - /* not waited long enough since last tx? */ - if (jiffies - dev->trans_start < HZ / 10) - return -EAGAIN; - - if (lp->lan_type < 0) { /* no LAN type detected yet? */ - hp100_stop_interface(dev); - if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { - printk("%s: no connection found - check wire\n", dev->name); - hp100_start_interface(dev); /* 10Mb/s RX pkts maybe handled */ - return -EIO; - } - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */ - hp100_start_interface(dev); - } - if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) - /* we have a 100Mb/s adapter but it isn't connected to hub */ - { - printk("%s: login to 100Mb/s hub retry\n", dev->name); - hp100_stop_interface(dev); - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - hp100_ints_off(); - i = hp100_sense_lan(dev); - hp100_page(PERFORMANCE); - hp100_ints_on(); - if (i == HP100_LAN_ERR) - printk("%s: link down detected\n", dev->name); - else if (lp->lan_type != i) { /* cable change! */ - /* it's very hard - all network setting must be changed!!! */ - printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); - lp->lan_type = i; - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - printk("%s: interface reset\n", dev->name); - hp100_stop_interface(dev); - hp100_start_interface(dev); - } - } - - dev->trans_start = jiffies; - return -EAGAIN; + printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name); +#endif + /* not waited long enough since last tx? */ + if ( jiffies - dev->trans_start < HZ ) return -EAGAIN; + + if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ + { + hp100_stop_interface( dev ); + if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) + { + printk( "hp100: %s: no connection found - check wire\n", dev->name ); + hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */ + return -EIO; + } + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ + hp100_start_interface( dev ); } - /* - * we have to turn int's off before modifying this, otherwise - * a tx_pdl_cleanup could occur at the same time - */ - cli(); - ringptr = lp->txrtail; - lp->txrtail = ringptr->next; - - /* Check whether packet has minimal packet size */ - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - ringptr->skb = skb; - ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */ - ringptr->pdl[1] = (u32) virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ - if (lp->chip == HP100_CHIPID_SHASTA) { - /* TODO:Could someone who has the EISA card please check if this works? */ - ringptr->pdl[2] = i; - } else { /* Lassen */ - /* In the PDL, don't use the padded size but the real packet size: */ - ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */ + + if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name ); + hp100_stop_interface( dev ); + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + hp100_ints_off(); + i = hp100_sense_lan( dev ); + hp100_ints_on(); + if ( i == HP100_LAN_ERR ) + printk( "hp100: %s: link down detected\n", dev->name ); + else + if ( lp->lan_type != i ) /* cable change! */ + { + /* it's very hard - all network setting must be changed!!! */ + printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); + lp->lan_type = i; + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + printk( "hp100: %s: interface reset\n", dev->name ); + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } } - /* Hand this PDL to the card. */ - hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ - - lp->txrcommit++; - sti(); - - /* Update statistics */ - lp->stats.tx_packets++; + dev->trans_start = jiffies; + return -EAGAIN; + } + + /* + * we have to turn int's off before modifying this, otherwise + * a tx_pdl_cleanup could occur at the same time + */ + save_flags( flags ); + cli(); + ringptr=lp->txrtail; + lp->txrtail=ringptr->next; + + /* Check whether packet has minimal packet size */ + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + ringptr->skb=skb; + ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */ + ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ + if(lp->chip==HP100_CHIPID_SHASTA) + { + /* TODO:Could someone who has the EISA card please check if this works? */ + ringptr->pdl[2]=i; + } + else /* Lassen */ + { + /* In the PDL, don't use the padded size but the real packet size: */ + ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */ + } + + /* Hand this PDL to the card. */ + hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */ + + lp->txrcommit++; + restore_flags( flags ); + + /* Update statistics */ + lp->stats.tx_packets++; #ifdef LINUX_2_1 - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - dev->trans_start = jiffies; - - return 0; + dev->trans_start = jiffies; + + return 0; } - + /* clean_txring checks if packets have been sent by the card by reading * the TX_PDL register from the performance page and comparing it to the * number of commited packets. It then frees the skb's of the packets that @@ -1447,168 +1673,209 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev) * * Needs the PERFORMANCE page selected. */ -static void hp100_clean_txring(struct device *dev) +static void hp100_clean_txring( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr = dev->base_addr; - int donecount; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + int donecount; #ifdef HP100_DEBUG_B - hp100_outw(0x4211, TRACE); - printk("hp100: clean txring\n"); + hp100_outw( 0x4211, TRACE ); + printk("hp100: %s: clean txring\n", dev->name); #endif - /* How many PDLs have been transmitted? */ - donecount = (lp->txrcommit) - hp100_inb(TX_PDL); + /* How many PDLs have been transmitted? */ + donecount=(lp->txrcommit)-hp100_inb(TX_PDL); #ifdef HP100_DEBUG - if (donecount > MAX_TX_PDL) - printk("hp100: Warning: More PDLs transmitted than commited to card???\n"); + if(donecount>MAX_TX_PDL) + printk("hp100: %s: Warning: More PDLs transmitted than commited to card???\n",dev->name); #endif - for (; 0 != donecount; donecount--) { + for( ; 0!=donecount; donecount-- ) + { #ifdef HP100_DEBUG_BM - printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", - (u_int) lp->txrhead->skb->data, - lp->txrcommit, - hp100_inb(TX_PDL), - donecount); -#endif - dev_kfree_skb(lp->txrhead->skb); - lp->txrhead->skb = (void *) NULL; - lp->txrhead = lp->txrhead->next; - lp->txrcommit--; - } + printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", + dev->name, + (u_int) lp->txrhead->skb->data, + lp->txrcommit, + hp100_inb(TX_PDL), + donecount); +#endif +#ifdef LINUX_2_1 + dev_kfree_skb( lp->txrhead->skb ); +#else + dev_kfree_skb( lp->txrhead->skb, FREE_WRITE ); +#endif + lp->txrhead->skb=(void *)NULL; + lp->txrhead=lp->txrhead->next; + lp->txrcommit--; + } } - + /* tx function for slave modes */ -static int hp100_start_xmit(struct sk_buff *skb, struct device *dev) +static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ) { - int i, ok_flag; - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int i, ok_flag; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4212, TRACE); - printk("hp100: start_xmit\n"); -#endif - - if (lp->lan_type < 0) { /* no LAN type detected yet? */ - hp100_stop_interface(dev); - if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { - printk("%s: no connection found - check wire\n", dev->name); - hp100_start_interface(dev); /* 10Mb/s RX packets maybe handled */ - return -EIO; - } - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */ - hp100_start_interface(dev); - } - /* If there is not enough free memory on the card... */ - i = hp100_inl(TX_MEM_FREE) & 0x7fffffff; - if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) { + hp100_outw( 0x4212, TRACE ); + printk("hp100: %s: start_xmit\n", dev->name); +#endif + + if ( skb==NULL ) + { +#ifndef LINUX_2_1 + dev_tint( dev ); +#endif + return 0; + } + + if ( skb->len <= 0 ) return 0; + + if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ + { + hp100_stop_interface( dev ); + if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) + { + printk( "hp100: %s: no connection found - check wire\n", dev->name ); + hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */ + return -EIO; + } + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ + hp100_start_interface( dev ); + } + + /* If there is not enough free memory on the card... */ + i=hp100_inl(TX_MEM_FREE)&0x7fffffff; + if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) ) + { #ifdef HP100_DEBUG - printk("hp100_start_xmit: tx free mem = 0x%x\n", i); + printk( "hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i ); #endif - /* not waited long enough since last failed tx try? */ - if (jiffies - dev->trans_start < HZ / 2) { + /* not waited long enough since last failed tx try? */ + if ( jiffies - dev->trans_start < HZ ) + { #ifdef HP100_DEBUG - printk("hp100: trans_start timing problem\n"); + printk("hp100: %s: trans_start timing problem\n", dev->name); #endif - return -EAGAIN; - } - if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) - /* we have a 100Mb/s adapter but it isn't connected to hub */ - { - printk("%s: login to 100Mb/s hub retry\n", dev->name); - hp100_stop_interface(dev); - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - hp100_ints_off(); - i = hp100_sense_lan(dev); - hp100_page(PERFORMANCE); - hp100_ints_on(); - if (i == HP100_LAN_ERR) - printk("%s: link down detected\n", dev->name); - else if (lp->lan_type != i) { /* cable change! */ - /* it's very hard - all network setting must be changed!!! */ - printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); - lp->lan_type = i; - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - printk("%s: interface reset\n", dev->name); - hp100_stop_interface(dev); - hp100_start_interface(dev); - udelay(1000); - } - } - dev->trans_start = jiffies; - return -EAGAIN; + return -EAGAIN; } - for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) { + if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name ); + hp100_stop_interface( dev ); + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + hp100_ints_off(); + i = hp100_sense_lan( dev ); + hp100_ints_on(); + if ( i == HP100_LAN_ERR ) + printk( "hp100: %s: link down detected\n", dev->name ); + else + if ( lp->lan_type != i ) /* cable change! */ + { + /* it's very hard - all network setting must be changed!!! */ + printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); + lp->lan_type = i; + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + printk( "hp100: %s: interface reset\n", dev->name ); + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + udelay(1000); + } + } + dev->trans_start = jiffies; + return -EAGAIN; + } + + for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ ) + { #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: busy\n"); -#endif - } - - hp100_ints_off(); - val = hp100_inw(IRQ_STATUS); - /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set - * when the current packet being transmitted on the wire is completed. */ - hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS); + printk( "hp100: %s: start_xmit: busy\n", dev->name ); +#endif + } + + hp100_ints_off(); + val = hp100_inw( IRQ_STATUS ); + /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set + * when the current packet being transmitted on the wire is completed. */ + hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS ); #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n", val, hp100_inw(IRQ_MASK), (int) skb->len); -#endif - - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - hp100_outw(i, DATA32); /* tell card the total packet length */ - hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */ - - if (lp->mode == 2) { /* memory mapped */ - if (lp->mem_ptr_virt) { /* high pci memory was remapped */ - /* Note: The J2585B needs alignment to 32bits here! */ - memcpy(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); - if (!ok_flag) - memset(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); - } else { - memcpy_toio(lp->mem_ptr_phys, skb->data, skb->len); - if (!ok_flag) - memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len); - } - } else { /* programmed i/o */ - outsl(ioaddr + HP100_REG_DATA32, skb->data, (skb->len + 3) >> 2); - if (!ok_flag) - for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4) - hp100_outl(0, DATA32); + printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",dev->name,val,hp100_inw(IRQ_MASK),(int)skb->len ); +#endif + + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + hp100_outw( i, DATA32 ); /* tell card the total packet length */ + hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */ + + if ( lp->mode==2 ) /* memory mapped */ + { + if ( lp->mem_ptr_virt ) /* high pci memory was remapped */ + { + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 ); + if ( !ok_flag ) + memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); } - - hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */ - - lp->stats.tx_packets++; + else + { + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 ); + if ( !ok_flag ) + memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); + } + } + else /* programmed i/o */ + { + outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 ); + if ( !ok_flag ) + for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) + hp100_outl( 0, DATA32 ); + } + + hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ + + lp->stats.tx_packets++; #ifdef LINUX_2_1 - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - dev->trans_start = jiffies; - hp100_ints_on(); - - dev_kfree_skb(skb); - + dev->trans_start=jiffies; + hp100_ints_on(); + +#ifdef LINUX_2_1 + dev_kfree_skb( skb ); +#else + dev_kfree_skb( skb, FREE_WRITE ); +#endif + #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: end\n"); + printk( "hp100: %s: start_xmit: end\n", dev->name ); #endif - - return 0; + + return 0; } - + /* * Receive Function (Non-Busmaster mode) * Called when an "Receive Packet" interrupt occurs, i.e. the receive @@ -1618,981 +1885,1163 @@ static int hp100_start_xmit(struct sk_buff *skb, struct device *dev) * and netif_rx. */ -static void hp100_rx(struct device *dev) +static void hp100_rx( struct device *dev ) { - int packets, pkt_len; - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - u_int header; - struct sk_buff *skb; + int packets, pkt_len; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + u_int header; + struct sk_buff *skb; #ifdef DEBUG_B - hp100_outw(0x4213, TRACE); - printk("hp100: rx\n"); + hp100_outw( 0x4213, TRACE ); + printk("hp100: %s: rx\n", dev->name); #endif - /* First get indication of received lan packet */ - /* RX_PKT_CND indicates the number of packets which have been fully */ - /* received onto the card but have not been fully transfered of the card */ - packets = hp100_inb(RX_PKT_CNT); + /* First get indication of received lan packet */ + /* RX_PKT_CND indicates the number of packets which have been fully */ + /* received onto the card but have not been fully transfered of the card */ + packets = hp100_inb( RX_PKT_CNT ); #ifdef HP100_DEBUG_RX - if (packets > 1) - printk("hp100_rx: waiting packets = %d\n", packets); + if ( packets > 1 ) + printk( "hp100: %s: rx: waiting packets = %d\n", dev->name,packets ); #endif - while (packets-- > 0) { - /* If ADV_NXT_PKT is still set, we have to wait until the card has */ - /* really advanced to the next packet. */ - for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT); - pkt_len++) { + while ( packets-- > 0 ) + { + /* If ADV_NXT_PKT is still set, we have to wait until the card has */ + /* really advanced to the next packet. */ + for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT); + pkt_len++ ) + { #ifdef HP100_DEBUG_RX - printk("hp100_rx: busy, remaining packets = %d\n", packets); -#endif - } - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - if (lp->mode == 2) { /* memory mapped mode */ - if (lp->mem_ptr_virt) /* if memory was remapped */ - header = *(__u32 *) lp->mem_ptr_virt; - else - header = readl(lp->mem_ptr_phys); - } else /* programmed i/o */ - header = hp100_inl(DATA32); - - pkt_len = header & HP100_PKT_LEN_MASK; + printk( "hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets ); +#endif + } + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + if( lp->mode==2 ) /* memory mapped mode */ + { + if ( lp->mem_ptr_virt ) /* if memory was remapped */ + header = *(__u32 *)lp->mem_ptr_virt; + else + header = readl( lp->mem_ptr_phys ); + } + else /* programmed i/o */ + header = hp100_inl( DATA32 ); + + pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3; #ifdef HP100_DEBUG_RX - printk("hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", - header & HP100_PKT_LEN_MASK, (header >> 16) & 0xfff8, - (header >> 16) & 7); -#endif - - /* Now we allocate the skb and transfer the data into it. */ - /* NOTE! This (and the skb_put() below) depends on the skb-functions - * allocating more than asked (notably, aligning the request up to - * the next 16-byte length). - */ - skb = dev_alloc_skb(pkt_len); - if (skb == NULL) { /* Not enough memory->drop packet */ + printk( "hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", + dev->name, + header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8, + (header>>16)&7); +#endif + + /* Now we allocate the skb and transfer the data into it. */ + skb = dev_alloc_skb( pkt_len ); + if ( skb == NULL ) /* Not enough memory->drop packet */ + { #ifdef HP100_DEBUG - printk("hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len); + printk( "hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", dev->name, pkt_len ); #endif - lp->stats.rx_dropped++; - } else { /* skb successfully allocated */ - u_char *ptr; - - skb->dev = dev; - - /* ptr to start of the sk_buff data area */ - ptr = (u_char *) skb_put(skb, pkt_len); - - /* Now transfer the data from the card into that area */ - if (lp->mode == 2) { - if (lp->mem_ptr_virt) - memcpy(ptr, lp->mem_ptr_virt, (pkt_len + 3) & ~3); - /* Note alignment to 32bit transfers */ - else - memcpy_fromio(ptr, lp->mem_ptr_phys, (pkt_len + 3) & ~3); - } else /* io mapped */ - insl(ioaddr + HP100_REG_DATA32, ptr, (pkt_len + 3) >> 2); - - skb->protocol = eth_type_trans(skb, dev); - - netif_rx(skb); - lp->stats.rx_packets++; + lp->stats.rx_dropped++; + } + else /* skb successfully allocated */ + { + u_char *ptr; + + skb->dev = dev; + + /* ptr to start of the sk_buff data area */ + ptr = (u_char *)skb_put( skb, pkt_len ); + + /* Now transfer the data from the card into that area */ + if ( lp->mode==2 ) + { + if ( lp->mem_ptr_virt ) + memcpy( ptr, lp->mem_ptr_virt, pkt_len ); + /* Note alignment to 32bit transfers */ + else + memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len ); + } + else /* io mapped */ + insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 ); + + skb->protocol = eth_type_trans( skb, dev ); + + netif_rx( skb ); + lp->stats.rx_packets++; #ifdef LINUX_2_1 - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += skb->len; #endif - + #ifdef HP100_DEBUG_RX - printk("rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], - ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11]); + printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + dev->name, + ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], + ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); #endif - } - - /* Indicate the card that we have got the packet */ - hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW); - - switch (header & 0x00070000) { - case (HP100_MULTI_ADDR_HASH << 16): - case (HP100_MULTI_ADDR_NO_HASH << 16): - lp->stats.multicast++; - break; - } - } /* end of while(there are packets) loop */ + } + + /* Indicate the card that we have got the packet */ + hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW ); + + switch ( header & 0x00070000 ) { + case (HP100_MULTI_ADDR_HASH<<16): + case (HP100_MULTI_ADDR_NO_HASH<<16): + lp->stats.multicast++; break; + } + } /* end of while(there are packets) loop */ #ifdef HP100_DEBUG_RX - printk("hp100_rx: end\n"); + printk( "hp100_rx: %s: end\n", dev->name ); #endif } - + /* * Receive Function for Busmaster Mode */ -static void hp100_rx_bm(struct device *dev) +static void hp100_rx_bm( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ptr; - u_int header; - int pkt_len; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ptr; + u_int header; + int pkt_len; #ifdef HP100_DEBUG_B - hp100_outw(0x4214, TRACE); - printk("hp100: rx_bm\n"); + hp100_outw( 0x4214, TRACE ); + printk("hp100: %s: rx_bm\n", dev->name); #endif #ifdef HP100_DEBUG - if (0 == lp->rxrcommit) { - printk("hp100: rx_bm called although no PDLs were committed to adapter?\n"); - return; - } else - /* RX_PKT_CNT states how many PDLs are currently formatted and available to - * the cards BM engine */ - if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { - printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT) & 0x00ff, lp->rxrcommit); - return; - } -#endif - - while ((lp->rxrcommit > hp100_inb(RX_PDL))) { - /* - * The packet was received into the pdl pointed to by lp->rxrhead ( - * the oldest pdl in the ring - */ - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - - ptr = lp->rxrhead; - - header = *(ptr->pdl - 1); - pkt_len = (header & HP100_PKT_LEN_MASK); + if(0==lp->rxrcommit) + { + printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name); + return; + } + else + + /* RX_PKT_CNT states how many PDLs are currently formatted and available to + * the cards BM engine */ + if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit) + { + printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", dev->name, hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit); + return; + } +#endif + + while( (lp->rxrcommit > hp100_inb(RX_PDL)) ) + { + /* + * The packet was received into the pdl pointed to by lp->rxrhead ( + * the oldest pdl in the ring + */ + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + + ptr=lp->rxrhead; + + header = *(ptr->pdl-1); + pkt_len = (header & HP100_PKT_LEN_MASK); #ifdef HP100_DEBUG_BM - printk("hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", - (u_int) (ptr->pdl - 1), (u_int) header, - pkt_len, - (header >> 16) & 0xfff8, - (header >> 16) & 7); - printk("hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", - hp100_inb(RX_PDL), - hp100_inb(TX_PDL), - hp100_inb(RX_PKT_CNT), - (u_int) * (ptr->pdl), - (u_int) * (ptr->pdl + 3), - (u_int) * (ptr->pdl + 4)); -#endif - - if ((pkt_len >= MIN_ETHER_SIZE) && - (pkt_len <= MAX_ETHER_SIZE)) { - if (ptr->skb == NULL) { - printk("hp100: rx_bm: skb null\n"); - /* can happen if we only allocated room for the pdh due to memory shortage. */ - lp->stats.rx_dropped++; - } else { - skb_trim(ptr->skb, pkt_len); /* Shorten it */ - ptr->skb->protocol = eth_type_trans(ptr->skb, dev); - - netif_rx(ptr->skb); /* Up and away... */ - - lp->stats.rx_packets++; + printk( "hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", + dev->name, + (u_int) (ptr->pdl-1),(u_int) header, + pkt_len, + (header>>16)&0xfff8, + (header>>16)&7); + printk( "hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", + dev->name, + hp100_inb( RX_PDL ), + hp100_inb( TX_PDL ), + hp100_inb( RX_PKT_CNT ), + (u_int) *(ptr->pdl), + (u_int) *(ptr->pdl+3), + (u_int) *(ptr->pdl+4)); +#endif + + if( (pkt_len>=MIN_ETHER_SIZE) && + (pkt_len<=MAX_ETHER_SIZE) ) + { + if(ptr->skb==NULL) + { + printk("hp100: %s: rx_bm: skb null\n", dev->name); + /* can happen if we only allocated room for the pdh due to memory shortage. */ + lp->stats.rx_dropped++; + } + else + { + skb_trim( ptr->skb, pkt_len ); /* Shorten it */ + ptr->skb->protocol = eth_type_trans( ptr->skb, dev ); + + netif_rx( ptr->skb ); /* Up and away... */ + + lp->stats.rx_packets++; #ifdef LINUX_2_1 - lp->stats.rx_bytes += ptr->skb->len; -#endif - } - - switch (header & 0x00070000) { - case (HP100_MULTI_ADDR_HASH << 16): - case (HP100_MULTI_ADDR_NO_HASH << 16): - lp->stats.multicast++; - break; - } - } else { + lp->stats.rx_bytes += ptr->skb->len; +#endif + } + + switch ( header & 0x00070000 ) { + case (HP100_MULTI_ADDR_HASH<<16): + case (HP100_MULTI_ADDR_NO_HASH<<16): + lp->stats.multicast++; break; + } + } + else + { #ifdef HP100_DEBUG - printk("hp100: rx_bm: Received bad packet (length=%d)\n", pkt_len); + printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n",dev->name,pkt_len); #endif - if (ptr->skb != NULL) - dev_kfree_skb(ptr->skb); - lp->stats.rx_errors++; - } - - lp->rxrhead = lp->rxrhead->next; - - /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ - if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) { - /* No space for skb, header can still be received. */ -#ifdef HP100_DEBUG - printk("hp100: rx_bm: No space for new PDL.\n"); + if(ptr->skb!=NULL) +#ifdef LINUX_2_1 + dev_kfree_skb( ptr->skb ); +#else + dev_kfree_skb( ptr->skb, FREE_READ ); #endif - return; - } else { /* successfully allocated new PDL - put it in ringlist at tail. */ - hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA); - lp->rxrtail = lp->rxrtail->next; - } + lp->stats.rx_errors++; + } + + lp->rxrhead=lp->rxrhead->next; + /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ + if (0 == hp100_build_rx_pdl( lp->rxrtail, dev )) + { + /* No space for skb, header can still be received. */ +#ifdef HP100_DEBUG + printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name); +#endif + return; + } + else + { /* successfully allocated new PDL - put it in ringlist at tail. */ + hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA); + lp->rxrtail=lp->rxrtail->next; } + + } } - + /* * statistics */ -static hp100_stats_t *hp100_get_stats(struct device *dev) +static hp100_stats_t *hp100_get_stats( struct device *dev ) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #ifdef HP100_DEBUG_B - hp100_outw(0x4215, TRACE); + hp100_outw( 0x4215, TRACE ); #endif - hp100_ints_off(); - hp100_update_stats(dev); - hp100_ints_on(); - return &((struct hp100_private *) dev->priv)->stats; + hp100_ints_off(); + hp100_update_stats( dev ); + hp100_ints_on(); + return &((struct hp100_private *)dev->priv)->stats; } -static void hp100_update_stats(struct device *dev) +static void hp100_update_stats( struct device *dev ) { - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4216, TRACE); - printk("hp100: update-stats\n"); -#endif - - /* Note: Statistics counters clear when read. */ - hp100_page(MAC_CTRL); - val = hp100_inw(DROPPED) & 0x0fff; - lp->stats.rx_errors += val; - lp->stats.rx_over_errors += val; - val = hp100_inb(CRC); - lp->stats.rx_errors += val; - lp->stats.rx_crc_errors += val; - val = hp100_inb(ABORT); - lp->stats.tx_errors += val; - lp->stats.tx_aborted_errors += val; - hp100_page(PERFORMANCE); + hp100_outw( 0x4216, TRACE ); + printk("hp100: %s: update-stats\n", dev->name); +#endif + + /* Note: Statistics counters clear when read. */ + hp100_page( MAC_CTRL ); + val = hp100_inw( DROPPED ) & 0x0fff; + lp->stats.rx_errors += val; + lp->stats.rx_over_errors += val; + val = hp100_inb( CRC ); + lp->stats.rx_errors += val; + lp->stats.rx_crc_errors += val; + val = hp100_inb( ABORT ); + lp->stats.tx_errors += val; + lp->stats.tx_aborted_errors += val; + hp100_page( PERFORMANCE ); } -static void hp100_clear_stats(int ioaddr) +static void hp100_misc_interrupt( struct device *dev ) { + struct hp100_private *lp = (struct hp100_private *)dev->priv; + #ifdef HP100_DEBUG_B - hp100_outw(0x4217, TRACE); - printk("hp100: clear_stats\n"); + hp100_outw( 0x4216, TRACE ); + printk("hp100: %s: misc_interrupt\n", dev->name); #endif - cli(); - hp100_page(MAC_CTRL); /* get all statistics bytes */ - hp100_inw(DROPPED); - hp100_inb(CRC); - hp100_inb(ABORT); - hp100_page(PERFORMANCE); - sti(); + /* Note: Statistics counters clear when read. */ + lp->stats.rx_errors++; + lp->stats.tx_errors++; +} + +static void hp100_clear_stats( int ioaddr ) +{ + unsigned long flags; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4217, TRACE ); + printk("hp100: %s: clear_stats\n", dev->name); +#endif + + save_flags( flags ); + cli(); + hp100_page( MAC_CTRL ); /* get all statistics bytes */ + hp100_inw( DROPPED ); + hp100_inb( CRC ); + hp100_inb( ABORT ); + hp100_page( PERFORMANCE ); + restore_flags( flags ); } - + /* * multicast setup */ /* * Set or clear the multicast filter for this adapter. - * TODO: Currently when in multicast mode, card accepts all multicast packets - * for all MC addresses. Should better use the list on the card. */ - -static void hp100_set_multicast_list(struct device *dev) + +static void hp100_set_multicast_list( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4218, TRACE); - printk("hp100: set_mc_list\n"); -#endif - - cli(); - hp100_ints_off(); - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ - - if (dev->flags & IFF_PROMISC) { - lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ - lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ - } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { - lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ - lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ - } else { - lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ - lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ - } - - if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) || - (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) { - hp100_outb(lp->mac2_mode, MAC_CFG_2); - hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */ - hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */ - - if (lp->lan_type == HP100_LAN_100) { + hp100_outw( 0x4218, TRACE ); + printk("hp100: %s: set_mc_list\n", dev->name); +#endif + + save_flags( flags ); + cli(); + hp100_ints_off(); + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ + + if ( dev->flags & IFF_PROMISC ) + { + lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ + lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ + memset( &lp->hash_bytes, 0xff, 8 ); + } + else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) ) + { + lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ + lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ +#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ + if ( dev -> flags & IFF_ALLMULTI ) + { + /* set hash filter to receive all multicast packets */ + memset( &lp->hash_bytes, 0xff, 8 ); + } + else + { + int i, j, idx; + u_char *addrs; + struct dev_mc_list *dmi; + + memset( &lp->hash_bytes, 0x00, 8 ); +#ifdef HP100_DEBUG + printk("hp100: %s: computing hash filter - mc_count = %i\n", dev -> name, dev -> mc_count ); +#endif + for ( i = 0, dmi = dev -> mc_list; i < dev -> mc_count; i++, dmi = dmi -> next ) + { + addrs = dmi -> dmi_addr; + if ( ( *addrs & 0x01 ) == 0x01 ) /* multicast address? */ + { +#ifdef HP100_DEBUG + printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ", + dev -> name, + addrs[ 0 ], addrs[ 1 ], addrs[ 2 ], + addrs[ 3 ], addrs[ 4 ], addrs[ 5 ] ); +#endif + for ( j = idx = 0; j < 6; j++ ) + { + idx ^= *addrs++ & 0x3f; + printk( ":%02x:", idx ); + } #ifdef HP100_DEBUG - printk("hp100: 100VG MAC settings have changed - relogin.\n"); + printk("idx = %i\n", idx ); #endif - lp->hub_status = hp100_login_to_vg_hub(dev, TRUE); /* force a relogin to the hub */ - } - } - hp100_page(MAC_CTRL); - hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ - HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1); /* enable tx */ - - hp100_page(PERFORMANCE); - hp100_ints_on(); - sti(); + lp->hash_bytes[ idx >> 3 ] |= ( 1 << ( idx & 7 ) ); + } + } + } +#else + memset( &lp->hash_bytes, 0xff, 8 ); +#endif + } + else + { + lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ + lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ + memset( &lp->hash_bytes, 0x00, 8 ); + } + + if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) || + ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) + { + int i; + + hp100_outb( lp->mac2_mode, MAC_CFG_2 ); + hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */ + hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */ + + hp100_page( MAC_ADDRESS ); + for ( i = 0; i < 8; i++ ) + hp100_outb( lp->hash_bytes[ i ], HASH_BYTE0 + i ); +#ifdef HP100_DEBUG + printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, lp->mac1_mode, lp->mac2_mode, + lp->hash_bytes[ 0 ], lp->hash_bytes[ 1 ], + lp->hash_bytes[ 2 ], lp->hash_bytes[ 3 ], + lp->hash_bytes[ 4 ], lp->hash_bytes[ 5 ], + lp->hash_bytes[ 6 ], lp->hash_bytes[ 7 ] + ); +#endif + + if(lp->lan_type==HP100_LAN_100) + { +#ifdef HP100_DEBUG + printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); +#endif + lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */ + } + } + else + { + int i; + u_char old_hash_bytes[ 8 ]; + + hp100_page( MAC_ADDRESS ); + for ( i = 0; i < 8; i++ ) + old_hash_bytes[ i ] = hp100_inb( HASH_BYTE0 + i ); + if ( memcmp( old_hash_bytes, &lp->hash_bytes, 8 ) ) + { + for ( i = 0; i < 8; i++ ) + hp100_outb( lp->hash_bytes[ i ], HASH_BYTE0 + i ); +#ifdef HP100_DEBUG + printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + lp->hash_bytes[ 0 ], lp->hash_bytes[ 1 ], + lp->hash_bytes[ 2 ], lp->hash_bytes[ 3 ], + lp->hash_bytes[ 4 ], lp->hash_bytes[ 5 ], + lp->hash_bytes[ 6 ], lp->hash_bytes[ 7 ] + ); +#endif + + if(lp->lan_type==HP100_LAN_100) + { +#ifdef HP100_DEBUG + printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); +#endif + lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */ + } + } + } + + hp100_page( MAC_CTRL ); + hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ + HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */ + + hp100_page( PERFORMANCE ); + hp100_ints_on(); + restore_flags( flags ); } - + /* * hardware interrupt handling */ -static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ) { - struct device *dev = dev_id; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + struct device *dev = (struct device *)dev_id; + struct hp100_private *lp = (struct hp100_private *)dev->priv; - int ioaddr; - u_int val; + int ioaddr; + u_int val; - if (dev == NULL) - return; - ioaddr = dev->base_addr; + if ( dev == NULL ) return; + ioaddr = dev->base_addr; - if (dev->interrupt) - printk("%s: re-entering the interrupt handler\n", dev->name); - hp100_ints_off(); - dev->interrupt = 1; /* mark that we are inside the handler */ + if ( dev->interrupt ) + printk( "hp100: %s: re-entering the interrupt handler\n", dev->name ); + hp100_ints_off(); + dev->interrupt = 1; /* mark that we are inside the handler */ #ifdef HP100_DEBUG_B - hp100_outw(0x4219, TRACE); + hp100_outw( 0x4219, TRACE ); #endif - /* hp100_page( PERFORMANCE ); */ - val = hp100_inw(IRQ_STATUS); + /* hp100_page( PERFORMANCE ); */ + val = hp100_inw( IRQ_STATUS ); #ifdef HP100_DEBUG_IRQ - printk("hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", - lp->mode, - (u_int) val, - hp100_inb(RX_PKT_CNT), - hp100_inb(RX_PDL), - hp100_inb(TX_PKT_CNT), - hp100_inb(TX_PDL) - ); -#endif - - if (val == 0) { /* might be a shared interrupt */ - dev->interrupt = 0; - hp100_ints_on(); - return; + printk( "hp100: %s: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", + dev->name, + lp->mode, + (u_int)val, + hp100_inb( RX_PKT_CNT ), + hp100_inb( RX_PDL ), + hp100_inb( TX_PKT_CNT ), + hp100_inb( TX_PDL ) + ); +#endif + + if(val==0) /* might be a shared interrupt */ + { + dev->interrupt=0; + hp100_ints_on(); + return; + } + /* We're only interested in those interrupts we really enabled. */ + /* val &= hp100_inw( IRQ_MASK ); */ + + /* + * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL + * is considered executed whenever the RX_PDL data structure is no longer + * needed. + */ + if ( val & HP100_RX_PDL_FILL_COMPL ) + { + if(lp->mode==1) + hp100_rx_bm( dev ); + else + { + printk("hp100: %s: rx_pdl_fill_compl interrupt although not busmaster?\n", dev->name); } - /* We're only interested in those interrupts we really enabled. */ - /* val &= hp100_inw( IRQ_MASK ); */ - - /* - * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL - * is considered executed whenever the RX_PDL data structure is no longer - * needed. - */ - if (val & HP100_RX_PDL_FILL_COMPL) { - if (lp->mode == 1) - hp100_rx_bm(dev); - else - printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n"); + } + + /* + * The RX_PACKET interrupt is set, when the receive packet counter is + * non zero. We use this interrupt for receiving in slave mode. In + * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill + * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then + * we somehow have missed a rx_pdl_fill_compl interrupt. + */ + + if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */ + { + if(lp->mode!=1) /* non busmaster */ + hp100_rx( dev ); + else if ( !(val & HP100_RX_PDL_FILL_COMPL )) + { + /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ + hp100_rx_bm( dev ); } - /* - * The RX_PACKET interrupt is set, when the receive packet counter is - * non zero. We use this interrupt for receiving in slave mode. In - * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill - * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then - * we somehow have missed a rx_pdl_fill_compl interrupt. - */ - - if (val & HP100_RX_PACKET) { /* Receive Packet Counter is non zero */ - if (lp->mode != 1) /* non busmaster */ - hp100_rx(dev); - else if (!(val & HP100_RX_PDL_FILL_COMPL)) { - /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ - hp100_rx_bm(dev); - } - } - /* - * Ack. that we have noticed the interrupt and thereby allow next one. - * Note that this is now done after the slave rx function, since first - * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt - * on the J2573. - */ - hp100_outw(val, IRQ_STATUS); - - /* - * RX_ERROR is set when a packet is dropped due to no memory resources on - * the card or when a RCV_ERR occurs. - * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists - * only in the 802.3 MAC and happens when 16 collisions occur during a TX - */ - if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) { + } + + /* + * Ack. that we have noticed the interrupt and thereby allow next one. + * Note that this is now done after the slave rx function, since first + * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt + * on the J2573. + */ + hp100_outw( val, IRQ_STATUS ); + + /* + * RX_ERROR is set when a packet is dropped due to no memory resources on + * the card or when a RCV_ERR occurs. + * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists + * only in the 802.3 MAC and happens when 16 collisions occur during a TX + */ + if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) ) + { #ifdef HP100_DEBUG_IRQ - printk("hp100: TX/RX Error IRQ\n"); + printk("hp100: %s: TX/RX Error IRQ\n", dev->name); #endif - hp100_update_stats(dev); - if (lp->mode == 1) { - hp100_rxfill(dev); - hp100_clean_txring(dev); - } + hp100_update_stats( dev ); + if(lp->mode==1) + { + hp100_rxfill( dev ); + hp100_clean_txring( dev ); } - /* - * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. - */ - if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO))) - hp100_rxfill(dev); - - /* - * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire - * is completed - */ - if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE))) - hp100_clean_txring(dev); - - /* - * MISC_ERROR is set when either the LAN link goes down or a detected - * bus error occurs. - */ - if (val & HP100_MISC_ERROR) { /* New for J2585B */ - printk("hp100: Misc. Error Interrupt - Check cabling.\n"); - if (lp->mode == 1) { - hp100_clean_txring(dev); - hp100_rxfill(dev); - } + } + + /* + * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. + */ + if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) ) + hp100_rxfill( dev ); + + /* + * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire + * is completed + */ + if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) ) + hp100_clean_txring( dev ); + + /* + * MISC_ERROR is set when either the LAN link goes down or a detected + * bus error occurs. + */ + if ( val & HP100_MISC_ERROR ) /* New for J2585B */ + { +#ifdef HP100_DEBUG_IRQ + printk("hp100: %s: Misc. Error Interrupt - Check cabling.\n", dev->name); +#endif + if(lp->mode==1) + { + hp100_clean_txring( dev ); + hp100_rxfill( dev ); } - dev->interrupt = 0; - hp100_ints_on(); + hp100_misc_interrupt( dev ); + } + + dev->interrupt = 0; + hp100_ints_on(); } - + /* * some misc functions */ -static void hp100_start_interface(struct device *dev) +static void hp100_start_interface( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4220, TRACE); - printk("hp100: hp100_start_interface %s\n", dev->name); -#endif - - cli(); - - /* Ensure the adapter does not want to request an interrupt when */ - /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */ - hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ - hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW); - - if (lp->mode == 1) { - /* Make sure BM bit is set... */ - hp100_page(HW_MAP); - hp100_orb(HP100_BM_MASTER, BM); - hp100_rxfill(dev); - } else if (lp->mode == 2) { - /* Enable memory mapping. Note: Don't do this when busmaster. */ - hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); - } - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ - - /* enable a few interrupts: */ - if (lp->mode == 1) { /* busmaster mode */ - hp100_outw(HP100_RX_PDL_FILL_COMPL | - HP100_RX_PDA_ZERO | - HP100_RX_ERROR | - /* HP100_RX_PACKET | */ - /* HP100_RX_EARLY_INT | */ HP100_SET_HB | - /* HP100_TX_PDA_ZERO | */ - HP100_TX_COMPLETE | - /* HP100_MISC_ERROR | */ - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); - } else { - hp100_outw(HP100_RX_PACKET | - HP100_RX_ERROR | HP100_SET_HB | - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); - } - - /* Enable MAC Tx and RX, set MAC modes, ... */ - /* Note: This function also turns on the interrupts. */ - hp100_set_multicast_list(dev); + hp100_outw( 0x4220, TRACE ); + printk("hp100: %s: hp100_start_interface\n",dev->name); +#endif + + save_flags( flags ); + cli(); + + /* Ensure the adapter does not want to request an interrupt when */ + /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */ + hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW); + /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ + hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW ); + + if(lp->mode==1) + { + /* Make sure BM bit is set... */ + hp100_page(HW_MAP); + hp100_orb( HP100_BM_MASTER, BM ); + hp100_rxfill( dev ); + } + else if(lp->mode==2) + { + /* Enable memory mapping. Note: Don't do this when busmaster. */ + hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); + } + + hp100_page(PERFORMANCE); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ + + /* enable a few interrupts: */ + if(lp->mode==1) /* busmaster mode */ + { + hp100_outw( HP100_RX_PDL_FILL_COMPL | + HP100_RX_PDA_ZERO | + HP100_RX_ERROR | + /* HP100_RX_PACKET | */ + /* HP100_RX_EARLY_INT | */ HP100_SET_HB | + /* HP100_TX_PDA_ZERO | */ + HP100_TX_COMPLETE | + /* HP100_MISC_ERROR | */ + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK ); + } + else + { + hp100_outw( HP100_RX_PACKET | + HP100_RX_ERROR | HP100_SET_HB | + HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK ); + } + + /* Enable MAC Tx and RX, set MAC modes, ... */ + hp100_set_multicast_list( dev ); + + restore_flags( flags ); } - -static void hp100_stop_interface(struct device *dev) + +static void hp100_stop_interface( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr = dev->base_addr; - u_int val; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + u_int val; #ifdef HP100_DEBUG_B - printk("hp100: hp100_stop_interface %s\n", dev->name); - hp100_outw(0x4221, TRACE); -#endif - - if (lp->mode == 1) - hp100_BM_shutdown(dev); - else { - /* Note: MMAP_DIS will be reenabled by start_interface */ - hp100_outw(HP100_INT_EN | HP100_RESET_LB | - HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - val = hp100_inw(OPTION_LSW); - - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); - - if (!(val & HP100_HW_RST)) - return; /* If reset, imm. return ... */ - /* ... else: busy wait until idle */ - for (val = 0; val < 6000; val++) - if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == - (HP100_TX_IDLE | HP100_RX_IDLE)) { - hp100_page(PERFORMANCE); - return; - } - printk("%s: hp100_stop_interface - timeout\n", dev->name); - hp100_page(PERFORMANCE); - } + printk("hp100: %s: hp100_stop_interface\n",dev->name); + hp100_outw( 0x4221, TRACE ); +#endif + + if (lp->mode==1) + hp100_BM_shutdown( dev ); + else + { + /* Note: MMAP_DIS will be reenabled by start_interface */ + hp100_outw( HP100_INT_EN | HP100_RESET_LB | + HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + val = hp100_inw( OPTION_LSW ); + + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); + + if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */ + /* ... else: busy wait until idle */ + for ( val = 0; val < 6000; val++ ) + if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) == + (HP100_TX_IDLE | HP100_RX_IDLE) ) + { + hp100_page(PERFORMANCE); + return; + } + printk( "hp100: %s: hp100_stop_interface - timeout\n", dev->name ); + hp100_page(PERFORMANCE); + } } - -static void hp100_load_eeprom(struct device *dev) + +static void hp100_load_eeprom( struct device *dev, u_short probe_ioaddr ) { - int i; - int ioaddr = dev->base_addr; + int i; + int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr; #ifdef HP100_DEBUG_B - hp100_outw(0x4222, TRACE); + hp100_outw( 0x4222, TRACE ); #endif - hp100_page(EEPROM_CTRL); - hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL); - hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL); - for (i = 0; i < 10000; i++) - if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD)) - return; - printk("%s: hp100_load_eeprom - timeout\n", dev->name); + hp100_page( EEPROM_CTRL ); + hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL ); + hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL ); + for ( i = 0; i < 10000; i++ ) + if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return; + printk( "hp100: %s: hp100_load_eeprom - timeout\n", dev->name ); } - + /* Sense connection status. * return values: LAN_10 - Connected to 10Mbit/s network * LAN_100 - Connected to 100Mbit/s network * LAN_ERR - not connected or 100Mbit/s Hub down */ -static int hp100_sense_lan(struct device *dev) +static int hp100_sense_lan( struct device *dev ) { - int ioaddr = dev->base_addr; - u_short val_VG, val_10; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + u_short val_VG, val_10; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4223, TRACE); -#endif - - hp100_page(MAC_CTRL); - /* Enable Auto Selection */ - /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */ - /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */ - /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */ - /* Now we have to wait a while... */ - /* for(i=0; i<5000; i++) */ - /* { */ - val_10 = hp100_inb(10_LAN_CFG_1); - val_VG = hp100_inb(VG_LAN_CFG_1); - /* } */ + hp100_outw( 0x4223, TRACE ); +#endif + + hp100_page( MAC_CTRL ); + val_10 = hp100_inb( 10_LAN_CFG_1 ); + val_VG = hp100_inb( VG_LAN_CFG_1 ); + hp100_page( PERFORMANCE ); #ifdef HP100_DEBUG - printk("hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10); -#endif - if (val_10 & HP100_LINK_BEAT_ST) - return HP100_LAN_10; - if ((lp->id->id == 0x02019F022) || - (lp->id->id == 0x01042103c) || - (lp->id->id == 0x01040103c)) { - hp100_page(PERFORMANCE); - return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ - } - /* for ( i = 0; i < 2500; i++ ) */ - /* { */ - val_VG = hp100_inb(VG_LAN_CFG_1); - hp100_page(PERFORMANCE); - - if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ - return HP100_LAN_100; - /* } */ - return HP100_LAN_ERR; + printk( "hp100: %s: sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", dev->name, val_VG, val_10 ); +#endif + + if ( val_10 & HP100_LINK_BEAT_ST ) /* 10Mb connection is active */ + return HP100_LAN_10; + + if ( val_10 & HP100_AUI_ST ) /* have we BNC or AUI onboard? */ + { + val_10 |= HP100_AUI_SEL | HP100_LOW_TH; + hp100_page( MAC_CTRL ); + hp100_outb( val_10, 10_LAN_CFG_1 ); + hp100_page( PERFORMANCE ); + return HP100_LAN_10; + } + + if ( (lp->id->id == 0x02019F022) || + (lp->id->id == 0x01042103c) || + (lp->id->id == 0x01040103c) ) + return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ + + if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */ + return HP100_LAN_100; + return HP100_LAN_ERR; } - -static int hp100_down_vg_link(struct device *dev) + +static int hp100_down_vg_link( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr = dev->base_addr; - unsigned long time; - long savelan, newlan; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long time; + long savelan, newlan; #ifdef HP100_DEBUG_B - hp100_outw(0x4224, TRACE); - printk("hp100: down_vg_link\n"); + hp100_outw( 0x4224, TRACE ); + printk("hp100: %s: down_vg_link\n", dev->name); #endif - hp100_page(MAC_CTRL); - time = jiffies + (HZ / 4); - do { - if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) - break; - } while (time > jiffies); + hp100_page( MAC_CTRL ); + time=jiffies+(HZ/4); + do{ + if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; + } while (time>jiffies); - if (jiffies >= time) /* no signal->no logout */ - return 0; + if ( jiffies >= time ) /* no signal->no logout */ + return 0; - /* Drop the VG Link by clearing the link up cmd and load addr. */ + /* Drop the VG Link by clearing the link up cmd and load addr.*/ - hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1); - hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1); + hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1); + hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1); - /* Conditionally stall for >250ms on Link-Up Status (to go down) */ - time = jiffies + (HZ / 2); - do { - if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) - break; - } while (time > jiffies); + /* Conditionally stall for >250ms on Link-Up Status (to go down) */ + time=jiffies+(HZ/2); + do{ + if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break; + } while(time>jiffies); #ifdef HP100_DEBUG - if (jiffies >= time) - printk("hp100_down_vg_link: Link does not go down?\n"); -#endif - - /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ - /* logout under traffic (even though all the status bits are cleared), */ - /* do this workaround to get the Rev 1 MAC in its idle state */ - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Reset VG MAC to insure it leaves the logoff state even if */ - /* the Hub is still emitting tones */ - hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); - udelay(1500); /* wait for >1ms */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ - udelay(1500); - } - /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ - /* to get the VG mac to full reset. This is not req.d with later chips */ - /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ - /* selected again! This will be left to the connect hub function to */ - /* perform if desired. */ - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Have to write to 10 and 100VG control registers simultaneously */ - savelan = newlan = hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ - newlan &= ~(HP100_VG_SEL << 16); - newlan |= (HP100_DOT3_MAC) << 8; - hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ - hp100_outl(newlan, 10_LAN_CFG_1); - - /* Conditionally stall for 5sec on VG selected. */ - time = jiffies + (HZ * 5); - do { - if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) - break; - } while (time > jiffies); - - hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ - hp100_outl(savelan, 10_LAN_CFG_1); - } - time = jiffies + (3 * HZ); /* Timeout 3s */ - do { - if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) - break; - } while (time > jiffies); - - if (time <= jiffies) { + if (jiffies>=time) + printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name); +#endif + + /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ + /* logout under traffic (even though all the status bits are cleared), */ + /* do this workaround to get the Rev 1 MAC in its idle state */ + if ( lp->chip==HP100_CHIPID_LASSEN ) + { + /* Reset VG MAC to insure it leaves the logoff state even if */ + /* the Hub is still emitting tones */ + hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); + udelay(1500); /* wait for >1ms */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ + udelay(1500); + } + + /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ + /* to get the VG mac to full reset. This is not req.d with later chips */ + /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ + /* selected again! This will be left to the connect hub function to */ + /* perform if desired. */ + if (lp->chip==HP100_CHIPID_LASSEN) + { + /* Have to write to 10 and 100VG control registers simultaneously */ + savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ + newlan &= ~(HP100_VG_SEL<<16); + newlan |= (HP100_DOT3_MAC)<<8; + hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ + hp100_outl(newlan, 10_LAN_CFG_1); + + /* Conditionally stall for 5sec on VG selected. */ + time=jiffies+(HZ*5); + do{ + if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break; + } while(time>jiffies); + + hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ + hp100_outl(savelan, 10_LAN_CFG_1); + } + + time=jiffies+(3*HZ); /* Timeout 3s */ + do { + if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break; + } while (time>jiffies); + + if(time<=jiffies) + { #ifdef HP100_DEBUG - printk("hp100_down_vg_link: timeout\n"); -#endif - return -EIO; - } - time = jiffies + (2 * HZ); /* This seems to take a while.... */ - do { - } while (time > jiffies); - - return 0; + printk( "hp100: %s: down_vg_link: timeout\n", dev->name ); +#endif + return -EIO; + } + + time=jiffies+(2*HZ); /* This seems to take a while.... */ + do {} while (time>jiffies); + + return 0; } - -static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin) + +static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - u_short val = 0; - unsigned long time; - int startst; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + u_short val=0; + unsigned long time; + int startst; #ifdef HP100_DEBUG_B - hp100_outw(0x4225, TRACE); - printk("hp100: login_to_vg_hub\n"); -#endif - - /* Initiate a login sequence iff VG MAC is enabled and either Load Address - * bit is zero or the force relogin flag is set (e.g. due to MAC address or - * promiscuous mode change) - */ - hp100_page(MAC_CTRL); - startst = hp100_inb(VG_LAN_CFG_1); - if ((force_relogin == TRUE) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) { + hp100_outw( 0x4225, TRACE ); + printk("hp100: %s: login_to_vg_hub\n", dev->name); +#endif + + /* Initiate a login sequence iff VG MAC is enabled and either Load Address + * bit is zero or the force relogin flag is set (e.g. due to MAC address or + * promiscuous mode change) + */ + hp100_page( MAC_CTRL ); + startst=hp100_inb( VG_LAN_CFG_1 ); + if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST)) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Start training\n"); + printk("hp100: %s: Start training\n", dev->name); #endif - /* Ensure VG Reset bit is 1 (i.e., do not reset) */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); + /* Ensure VG Reset bit is 1 (i.e., do not reset)*/ + hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 ); - /* If Lassen AND auto-select-mode AND VG tones were sensed on */ - /* entry then temporarily put them into force 100Mbit mode */ - if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) - hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2); - - /* Drop the VG link by zeroing Link Up Command and Load Address */ - hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1); + /* If Lassen AND auto-select-mode AND VG tones were sensed on */ + /* entry then temporarily put them into force 100Mbit mode */ + if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) ) + hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 ); + + /* Drop the VG link by zeroing Link Up Command and Load Address */ + hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1); #ifdef HP100_DEBUG_TRAINING - printk("hp100: Bring down the link\n"); -#endif - - /* Wait for link to drop */ - time = jiffies + (HZ / 10); - do { - if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) - break; - } while (time > jiffies); - - /* Start an addressed training and optionally request promiscuous port */ - if ((dev->flags) & IFF_PROMISC) { - hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2); - if (lp->chip == HP100_CHIPID_LASSEN) - hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST); - } else { - hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2); - /* For ETR parts we need to reset the prom. bit in the training - * register, otherwise promiscious mode won't be disabled. - */ - if (lp->chip == HP100_CHIPID_LASSEN) { - hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST); - } - } - - /* With ETR parts, frame format request bits can be set. */ - if (lp->chip == HP100_CHIPID_LASSEN) - hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); - - hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1); + printk("hp100: %s: Bring down the link\n", dev->name); +#endif - /* Note: Next wait could be omitted for Hood and earlier chips under */ - /* certain circumstances */ - /* TODO: check if hood/earlier and skip wait. */ + /* Wait for link to drop */ + time = jiffies + (HZ/10); + do { + if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break; + } while (time>jiffies); - /* Wait for either short timeout for VG tones or long for login */ - /* Wait for the card hardware to signalise link cable status ok... */ - hp100_page(MAC_CTRL); - time = jiffies + (1 * HZ); /* 1 sec timeout for cable st */ - do { - if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) - break; - } while (jiffies < time); + /* Start an addressed training and optionally request promiscuous port */ + if ( (dev->flags) & IFF_PROMISC ) + { + hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2); + if(lp->chip==HP100_CHIPID_LASSEN) + hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST ); + } + else + { + hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2); + /* For ETR parts we need to reset the prom. bit in the training + * register, otherwise promiscious mode won't be disabled. + */ + if(lp->chip==HP100_CHIPID_LASSEN) + { + hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST ); + } + } - if (jiffies >= time) { + /* With ETR parts, frame format request bits can be set. */ + if(lp->chip==HP100_CHIPID_LASSEN) + hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); + + hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1); + + /* Note: Next wait could be omitted for Hood and earlier chips under */ + /* certain circumstances */ + /* TODO: check if hood/earlier and skip wait. */ + + /* Wait for either short timeout for VG tones or long for login */ + /* Wait for the card hardware to signalise link cable status ok... */ + hp100_page( MAC_CTRL ); + time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */ + do { + if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; + } while ( jiffies < time ); + + if ( jiffies >= time ) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Link cable status not ok? Training aborted.\n"); -#endif - } else { + printk( "hp100: %s: Link cable status not ok? Training aborted.\n", dev->name ); +#endif + } + else + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: HUB tones detected. Trying to train.\n"); + printk( "hp100: %s: HUB tones detected. Trying to train.\n", dev->name); #endif - time = jiffies + (2 * HZ); /* again a timeout */ - do { - val = hp100_inb(VG_LAN_CFG_1); - if ((val & (HP100_LINK_UP_ST))) { + time = jiffies + ( 2*HZ ); /* again a timeout */ + do { + val = hp100_inb( VG_LAN_CFG_1 ); + if ( (val & ( HP100_LINK_UP_ST )) ) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Passed training.\n"); + printk( "hp100: %s: Passed training.\n", dev->name); #endif - break; - } - } while (time > jiffies); - } - - /* If LINK_UP_ST is set, then we are logged into the hub. */ - if ((jiffies <= time) && (val & HP100_LINK_UP_ST)) { + break; + } + } while ( time > jiffies ); + } + + /* If LINK_UP_ST is set, then we are logged into the hub. */ + if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) ) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Successfully logged into the HUB.\n"); - if (lp->chip == HP100_CHIPID_LASSEN) { - val = hp100_inw(TRAIN_ALLOW); - printk("hp100: Card supports 100VG MAC Version \"%s\" ", - (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre"); - printk("Driver will use MAC Version \"%s\"\n", - (val & HP100_HUB_MACVER) ? "802.12" : "Pre"); - printk("hp100: Frame format is %s.\n", (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3"); - } -#endif - } else { - /* If LINK_UP_ST is not set, login was not successful */ - printk("hp100/%s: Problem logging into the HUB.\n", dev->name); - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Check allowed Register to find out why there is a problem. */ - val = hp100_inw(TRAIN_ALLOW); /* wont work on non-ETR card */ + printk( "hp100: %s: Successfully logged into the HUB.\n", dev->name); + if(lp->chip==HP100_CHIPID_LASSEN) + { + val = hp100_inw(TRAIN_ALLOW); + printk( "hp100: %s: Card supports 100VG MAC Version \"%s\" ", + dev->name,(hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre"); + printk( "Driver will use MAC Version \"%s\"\n", + ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" ); + printk( "hp100: %s: Frame format is %s.\n",dev->name,(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3"); + } +#endif + } + else + { + /* If LINK_UP_ST is not set, login was not successful */ + printk("hp100: %s: Problem logging into the HUB.\n",dev->name); + if(lp->chip==HP100_CHIPID_LASSEN) + { + /* Check allowed Register to find out why there is a problem. */ + val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */ #ifdef HP100_DEBUG_TRAINING - printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val); -#endif - if (val & HP100_MALLOW_ACCDENIED) - printk("hp100: HUB access denied.\n"); - if (val & HP100_MALLOW_CONFIGURE) - printk("hp100: MAC Configuration is incompatible with the Network.\n"); - if (val & HP100_MALLOW_DUPADDR) - printk("hp100: Duplicate MAC Address on the Network.\n"); - } - } - - /* If we have put the chip into forced 100 Mbit mode earlier, go back */ - /* to auto-select mode */ - - if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) { - hp100_page(MAC_CTRL); - hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2); - } - val = hp100_inb(VG_LAN_CFG_1); - - /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ - hp100_page(PERFORMANCE); - hp100_outw(HP100_MISC_ERROR, IRQ_STATUS); - - if (val & HP100_LINK_UP_ST) - return (0); /* login was ok */ - else { - printk("hp100: Training failed.\n"); - hp100_down_vg_link(dev); - return -EIO; - } - } - /* no forced relogin & already link there->no training. */ - return -EIO; + printk("hp100: %s: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", dev->name, hp100_inw(TRAIN_REQUEST), val); +#endif + if ( val & HP100_MALLOW_ACCDENIED ) + printk("hp100: %s: HUB access denied.\n", dev->name); + if ( val & HP100_MALLOW_CONFIGURE ) + printk("hp100: %s: MAC Configuration is incompatible with the Network.\n", dev->name); + if ( val & HP100_MALLOW_DUPADDR ) + printk("hp100: %s: Duplicate MAC Address on the Network.\n", dev->name); + } + } + + /* If we have put the chip into forced 100 Mbit mode earlier, go back */ + /* to auto-select mode */ + + if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) ) + { + hp100_page( MAC_CTRL ); + hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 ); + } + + val=hp100_inb(VG_LAN_CFG_1); + + /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ + hp100_page(PERFORMANCE); + hp100_outw( HP100_MISC_ERROR, IRQ_STATUS); + + if (val&HP100_LINK_UP_ST) + return(0); /* login was ok */ + else + { + printk("hp100: %s: Training failed.\n", dev->name); + hp100_down_vg_link( dev ); + return -EIO; + } + } + /* no forced relogin & already link there->no training. */ + return -EIO; } - -static void hp100_cascade_reset(struct device *dev, u_short enable) + +static void hp100_cascade_reset( struct device *dev, u_short enable ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int i; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int i; #ifdef HP100_DEBUG_B - hp100_outw(0x4226, TRACE); - printk("hp100: cascade_reset\n"); -#endif - - if (enable == TRUE) { - hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW); - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Lassen requires a PCI transmit fifo reset */ - hp100_page(HW_MAP); - hp100_andb(~HP100_PCI_RESET, PCICTRL2); - hp100_orb(HP100_PCI_RESET, PCICTRL2); - /* Wait for min. 300 ns */ - /* we cant use jiffies here, because it may be */ - /* that we have disabled the timer... */ - for (i = 0; i < 0xffff; i++); - hp100_andb(~HP100_PCI_RESET, PCICTRL2); - hp100_page(PERFORMANCE); - } - } else { /* bring out of reset */ - hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW); - for (i = 0; i < 0xffff; i++); - hp100_page(PERFORMANCE); - } + hp100_outw( 0x4226, TRACE ); + printk("hp100: %s: cascade_reset\n", dev->name); +#endif + + if (enable==TRUE) + { + hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW ); + if(lp->chip==HP100_CHIPID_LASSEN) + { + /* Lassen requires a PCI transmit fifo reset */ + hp100_page( HW_MAP ); + hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); + hp100_orb( HP100_PCI_RESET, PCICTRL2 ); + /* Wait for min. 300 ns */ + /* we cant use jiffies here, because it may be */ + /* that we have disabled the timer... */ + for (i=0; i<0xffff; i++); + hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); + hp100_page( PERFORMANCE ); + } + } + else + { /* bring out of reset */ + hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW); + for (i=0; i<0xffff; i++ ); + hp100_page(PERFORMANCE); + } } -#ifdef HP100_DEBUG -void hp100_RegisterDump(struct device *dev) +#ifdef HP100_DEBUG +void hp100_RegisterDump( struct device *dev ) { - int ioaddr = dev->base_addr; - int Page; - int Register; - - /* Dump common registers */ - printk("hp100: Cascade Register Dump\n"); - printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID)); - printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING)); - printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW)); - printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW)); - - /* Dump paged registers */ - for (Page = 0; Page < 8; Page++) { - /* Dump registers */ - printk("page: 0x%.2x\n", Page); - outw(Page, ioaddr + 0x02); - for (Register = 0x8; Register < 0x22; Register += 2) { - /* Display Register contents except data port */ - if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) { - printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register)); - } - } + int ioaddr=dev->base_addr; + int Page; + int Register; + + /* Dump common registers */ + printk("hp100: %s: Cascade Register Dump\n", dev->name); + printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID)); + printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING)); + printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW)); + printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW)); + + /* Dump paged registers */ + for (Page = 0; Page < 8; Page++) + { + /* Dump registers */ + printk("page: 0x%.2x\n",Page); + outw( Page, ioaddr+0x02); + for (Register = 0x8; Register < 0x22; Register += 2) + { + /* Display Register contents except data port */ + if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) + { + printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register)); + } } - hp100_page(PERFORMANCE); + } + hp100_page(PERFORMANCE); } #endif - + /* * module section */ - + #ifdef MODULE /* Parameters set by insmod */ -int hp100_port[5] = -{0, -1, -1, -1, -1}; +int hp100_port[5] = { 0, -1, -1, -1, -1 }; #ifdef LINUX_2_1 MODULE_PARM(hp100_port, "1-5i"); #endif #ifdef LINUX_2_1 -char hp100_name[5][IFNAMSIZ] = -{"", "", "", "", ""}; +char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); #else -static char devname[5][IFNAMSIZ] = -{"", "", "", "", ""}; -static char *hp100_name[5] = -{devname[0], devname[1], - devname[2], devname[3], - devname[4]}; +static char devname[5][IFNAMSIZ] = { "", "", "", "", "" }; +static char *hp100_name[5] = { devname[0], devname[1], + devname[2], devname[3], + devname[4] }; #endif /* List of devices */ -static struct device *hp100_devlist[5] = -{NULL, NULL, NULL, NULL, NULL}; +static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; /* * Note: if you have more than five 100vg cards in your pc, feel free to @@ -2606,61 +3055,64 @@ static struct device *hp100_devlist[5] = * option hp100 hp100_port=0x280 hp100_name=eth239 */ -int init_module(void) +int init_module( void ) { - int i; - int ret = 0; - - if (hp100_port == 0 && !EISA_bus && !pcibios_present()) - printk("HP100: You should not use auto-probing with insmod!\n"); - - /* Loop on all possible base addresses */ - i = -1; - while ((hp100_port[++i] != -1) && (i < 5)) { - /* Create device and set basics args */ - hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); - memset(hp100_devlist[i], 0x00, sizeof(struct device)); - hp100_devlist[i]->name = hp100_name[i]; - hp100_devlist[i]->base_addr = hp100_port[i]; - hp100_devlist[i]->init = &hp100_probe; - - /* Try to create the device */ - if (register_netdev(hp100_devlist[i]) != 0) { - /* DeAllocate everything */ - /* Note: if dev->priv is mallocated, there is no way to fail */ - kfree_s(hp100_devlist[i], sizeof(struct device)); - hp100_devlist[i] = (struct device *) NULL; - ret = -EIO; - } - } /* Loop over all devices */ + int i, cards; + + if (hp100_port == 0 && !EISA_bus && !pcibios_present()) + printk("hp100: You should not use auto-probing with insmod!\n"); + + /* Loop on all possible base addresses */ + i = -1; cards = 0; + while((hp100_port[++i] != -1) && (i < 5)) + { + /* Create device and set basics args */ + hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); + memset(hp100_devlist[i], 0x00, sizeof(struct device)); + hp100_devlist[i]->name = hp100_name[i]; + hp100_devlist[i]->base_addr = hp100_port[i]; + hp100_devlist[i]->init = &hp100_probe; + + /* Try to create the device */ + if(register_netdev(hp100_devlist[i]) != 0) + { + /* DeAllocate everything */ + /* Note: if dev->priv is mallocated, there is no way to fail */ + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + } + else + cards++; + } /* Loop over all devices */ - return ret; + return cards > 0 ? 0 : -ENODEV; } -void cleanup_module(void) +void cleanup_module( void ) { - int i; - - /* TODO: Check if all skb's are released/freed. */ - for (i = 0; i < 5; i++) - if (hp100_devlist[i] != (struct device *) NULL) { - unregister_netdev(hp100_devlist[i]); - release_region(hp100_devlist[i]->base_addr, HP100_REGION_SIZE); - if (((struct hp100_private *) hp100_devlist[i]->priv)->mode == 1) /* busmaster */ - kfree_s(((struct hp100_private *) hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE + 0x0f); - if (((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt) - iounmap(((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt); - kfree_s(hp100_devlist[i]->priv, sizeof(struct hp100_private)); - hp100_devlist[i]->priv = NULL; - kfree_s(hp100_devlist[i], sizeof(struct device)); - hp100_devlist[i] = (struct device *) NULL; - } + int i; + + /* TODO: Check if all skb's are released/freed. */ + for(i = 0; i < 5; i++) + if(hp100_devlist[i] != (struct device *) NULL) + { + unregister_netdev( hp100_devlist[i] ); + release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE ); + if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */ + kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f); + if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ) + iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ); + kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) ); + hp100_devlist[i]->priv = NULL; + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + } } -#endif /* MODULE */ - +#endif /* MODULE */ + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c" diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h index c1c62e6bbf4e..436dd37009f0 100644 --- a/drivers/net/hp100.h +++ b/drivers/net/hp100.h @@ -1,7 +1,7 @@ /* * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. * - * $Id: hp100.h,v 1.4 1997/05/26 21:09:19 davem Exp $ + * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $ * * Authors: Jaroslav Kysela, * Siegfried Loeffler diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index d036fabb3185..6dbaec6d2ee3 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -43,6 +43,7 @@ static const char *version = #include #include #include +#include #include #include #include diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c index f4484e225ce3..035c47a5cb3f 100644 --- a/drivers/net/tulip.c +++ b/drivers/net/tulip.c @@ -636,7 +636,7 @@ static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq, for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__i386) /* This BIOS bug doesn't exist on Alphas. */ +#if defined(__i386__) /* This BIOS bug doesn't exist on Alphas. */ irq = last_irq; #endif } @@ -1094,7 +1094,7 @@ tulip_open(struct device *dev) outl(0x00200000 | 0xE000, ioaddr + CSR0); #elif defined(__powerpc__) outl(0x00200080 | 0x8000, ioaddr + CSR0); -#elif defined(__i386) +#elif defined(__i386__) #if defined(MODULE) /* When a module we don't have 'x86' to check. */ outl(0x00200000 | 0x4800, ioaddr + CSR0); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index eafc5d3c41c3..04972ab55bca 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -9448,7 +9448,7 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, /* * Try to fix up PCI config according to wished features. */ -#if defined(__i386) && !defined(MODULE) +#if defined(__i386__) && !defined(MODULE) if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) && cache_line_size == 0) { #if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75) diff --git a/fs/coda/Makefile b/fs/coda/Makefile index 0a4140745ab0..1f2d0a94c7ab 100644 --- a/fs/coda/Makefile +++ b/fs/coda/Makefile @@ -3,7 +3,7 @@ # O_TARGET := coda.o -O_OBJS := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.o\ +O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\ symlink.o pioctl.o sysctl.o M_OBJS := $(O_TARGET) diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 7673bfbdd421..cdf5865071ed 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -24,16 +24,22 @@ #include #include -/* Keep various stats */ -struct cfsnc_statistics cfsnc_stat; +static void coda_ccinsert(struct coda_cache *el, struct super_block *sb); +static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii); +static void coda_ccremove(struct coda_cache *el); +static void coda_cnremove(struct coda_cache *el); +static void coda_cache_create(struct inode *inode, int mask); +static struct coda_cache * coda_cache_find(struct inode *inode); -/* we need to call INIT_LIST_HEAD on cnp->c_cnhead and sbi->sbi_cchead */ +/* Keep various stats */ +struct cfsnc_statistics cfsnc_stat; -void coda_ccinsert(struct coda_cache *el, struct super_block *sb) +/* insert a acl-cache entry in sb list */ +static void coda_ccinsert(struct coda_cache *el, struct super_block *sb) { struct coda_sb_info *sbi = coda_sbp(sb); -ENTRY; + ENTRY; if ( !sbi || !el) { printk("coda_ccinsert: NULL sbi or el!\n"); return ; @@ -42,17 +48,19 @@ ENTRY; list_add(&el->cc_cclist, &sbi->sbi_cchead); } -void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp) +/* insert a acl-cache entry in the inode list */ +static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii) { -ENTRY; - if ( !cnp || !el) { - printk("coda_cninsert: NULL cnp or el!\n"); + ENTRY; + if ( !cii || !el) { + printk("coda_cninsert: NULL cii or el!\n"); return ; } - list_add(&el->cc_cnlist, &cnp->c_cnhead); + list_add(&el->cc_cnlist, &cii->c_cnhead); } -void coda_ccremove(struct coda_cache *el) +/* remove a cache entry from the superblock list */ +static void coda_ccremove(struct coda_cache *el) { ENTRY; if (el->cc_cclist.next && el->cc_cclist.prev) @@ -61,7 +69,8 @@ void coda_ccremove(struct coda_cache *el) printk("coda_cnremove: trying to remove 0 entry!"); } -void coda_cnremove(struct coda_cache *el) +/* remove a cache entry from the inode's list */ +static void coda_cnremove(struct coda_cache *el) { ENTRY; if (el->cc_cnlist.next && el->cc_cnlist.prev) @@ -70,10 +79,10 @@ void coda_cnremove(struct coda_cache *el) printk("coda_cnremove: trying to remove 0 entry!"); } - -void coda_cache_create(struct inode *inode, int mask) +/* create a new cache entry and enlist it */ +static void coda_cache_create(struct inode *inode, int mask) { - struct coda_inode_info *cnp = ITOC(inode); + struct coda_inode_info *cii = ITOC(inode); struct super_block *sb = inode->i_sb; struct coda_cache *cc = NULL; ENTRY; @@ -85,17 +94,19 @@ void coda_cache_create(struct inode *inode, int mask) } coda_load_creds(&cc->cc_cred); cc->cc_mask = mask; - coda_cninsert(cc, cnp); + coda_cninsert(cc, cii); coda_ccinsert(cc, sb); } -struct coda_cache * coda_cache_find(struct inode *inode) +/* see if there is a match for the current + credentials already */ +static struct coda_cache * coda_cache_find(struct inode *inode) { - struct coda_inode_info *cnp = ITOC(inode); + struct coda_inode_info *cii = ITOC(inode); struct list_head *lh, *le; struct coda_cache *cc = NULL; - le = lh = &cnp->c_cnhead; + le = lh = &cii->c_cnhead; while( (le = le->next ) != lh ) { /* compare name and creds */ cc = list_entry(le, struct coda_cache, cc_cnlist); @@ -107,6 +118,7 @@ struct coda_cache * coda_cache_find(struct inode *inode) return NULL; } +/* create or extend an acl cache hit */ void coda_cache_enter(struct inode *inode, int mask) { struct coda_cache *cc; @@ -120,17 +132,21 @@ void coda_cache_enter(struct inode *inode, int mask) } } -void coda_cache_clear_cnp(struct coda_inode_info *cnp) +/* remove all cached acl matches from an inode */ +void coda_cache_clear_inode(struct inode *inode) { struct list_head *lh, *le; + struct coda_inode_info *cii; struct coda_cache *cc; + ENTRY; - if ( !cnp ) { - printk("coda_cache_cnp_clear: NULL cnode\n"); + if ( !inode ) { + CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n"); return; } + cii = ITOC(inode); - lh = le = &cnp->c_cnhead; + lh = le = &cii->c_cnhead; while ( (le = le->next ) != lh ) { cc = list_entry(le, struct coda_cache, cc_cnlist); coda_cnremove(cc); @@ -139,6 +155,7 @@ void coda_cache_clear_cnp(struct coda_inode_info *cnp) } } +/* remove all acl caches */ void coda_cache_clear_all(struct super_block *sb) { struct list_head *lh, *le; @@ -150,6 +167,9 @@ void coda_cache_clear_all(struct super_block *sb) return; } + if ( list_empty(&sbi->sbi_cchead) ) + return; + lh = le = &sbi->sbi_cchead; while ( (le = le->next ) != lh ) { cc = list_entry(le, struct coda_cache, cc_cclist); @@ -159,6 +179,7 @@ void coda_cache_clear_all(struct super_block *sb) } } +/* remove all acl caches for a principal */ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) { struct list_head *lh, *le; @@ -170,6 +191,9 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) return; } + if (list_empty(&sbi->sbi_cchead)) + return; + lh = le = &sbi->sbi_cchead; while ( (le = le->next ) != lh ) { cc = list_entry(le, struct coda_cache, cc_cclist); @@ -180,15 +204,17 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) } } } - + +/* check if the mask has been matched against the acl + already */ int coda_cache_check(struct inode *inode, int mask) { - struct coda_inode_info *cnp = ITOC(inode); + struct coda_inode_info *cii = ITOC(inode); struct list_head *lh, *le; struct coda_cache *cc = NULL; - le = lh = &cnp->c_cnhead; + le = lh = &cii->c_cnhead; while( (le = le->next ) != lh ) { /* compare name and creds */ cc = list_entry(le, struct coda_cache, cc_cnlist); @@ -204,110 +230,70 @@ int coda_cache_check(struct inode *inode, int mask) } -/* DENTRY related stuff */ +/* DCACHE & ZAPPING related stuff */ -/* when the dentry count falls to 0 this is called. If Venus has - asked for it to be flushed, we take it out of the dentry hash - table with d_drop */ - -static void coda_flag_children(struct dentry *parent) +/* the following routines set flags in the inodes. They are + detected by: + - a dentry method: coda_dentry_revalidate (for lookups) + if the flag is C_PURGE + - an inode method coda_revalidate (for attributes) if the + flag is C_ATTR +*/ +static void coda_flag_children(struct dentry *parent, int flag) { struct list_head *child; - struct coda_inode_info *cnp; struct dentry *de; child = parent->d_subdirs.next; while ( child != &parent->d_subdirs ) { de = list_entry(child, struct dentry, d_child); - cnp = ITOC(de->d_inode); - if (cnp) - cnp->c_flags |= C_ZAPFID; - CDEBUG(D_CACHE, "ZAPFID for %s\n", coda_f2s(&cnp->c_fid)); - + coda_flag_inode(de->d_inode, flag); + CDEBUG(D_CACHE, "%d for %*s/%*s\n", flag, + de->d_name.len, de->d_name.name, + de->d_parent->d_name.len, de->d_parent->d_name.name); child = child->next; + if ( !de->d_inode ) + d_drop(de); } return; } -/* flag dentry and possibly children of a dentry with C_ZAPFID */ -void coda_dentry_delete(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - struct coda_inode_info *cnp = NULL; - ENTRY; - if (inode) { - cnp = ITOC(inode); - if ( cnp ) - CHECK_CNODE(cnp); - } else { - CDEBUG(D_CACHE, "No inode for dentry_delete!\n"); - return; - } - - - if ( !cnp ) { - printk("No cnode for dentry_delete!\n"); - return; - } - - if ( cnp->c_flags & (C_ZAPFID | C_ZAPDIR) ) - d_drop(dentry); - if ( (cnp->c_flags & C_ZAPDIR) && S_ISDIR(inode->i_mode) ) { - coda_flag_children(dentry); - } - return; -} - -static void coda_zap_cnode(struct coda_inode_info *cnp, int flags) +void coda_flag_alias_children(struct inode *inode, int flag) { - cnp->c_flags |= flags; - coda_cache_clear_cnp(cnp); + struct list_head *alias; + struct dentry *alias_de; + + if ( !inode ) + return; + alias = inode->i_dentry.next; + while ( alias != &inode->i_dentry ) { + alias_de = list_entry(alias, struct dentry, d_alias); + if ( !alias_de ) { + printk("Corrupt alias list for %*s\n", + alias_de->d_name.len, alias_de->d_name.name); + return; + } + coda_flag_children(alias_de, flag); + alias= alias->next; + } } - - -/* the dache will notice the flags and drop entries (possibly with - children) the moment they are no longer in use */ -void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag) +void coda_flag_inode(struct inode *inode, int flag) { - struct inode *inode = NULL; - struct coda_inode_info *cnp; + struct coda_inode_info *cii; - ENTRY; - - if ( !sb ) { - printk("coda_zapfid: no sb!\n"); + if ( !inode ) { + CDEBUG(D_CACHE, " no inode!\n"); return; } + cii = ITOC(inode); + cii->c_flags |= flag; +} - if ( !fid ) { - printk("coda_zapfid: no fid!\n"); - return; - } - if ( coda_fid_is_volroot(fid) ) { - struct list_head *lh, *le; - struct coda_sb_info *sbi = coda_sbp(sb); - le = lh = &sbi->sbi_volroothead; - while ( (le = le->next) != lh ) { - cnp = list_entry(le, struct coda_inode_info, c_volrootlist); - if ( cnp->c_fid.Volume == fid->Volume) - coda_zap_cnode(cnp, flag); - } - return; - } - inode = coda_fid_to_inode(fid, sb); - if ( !inode ) { - CDEBUG(D_CACHE, "coda_zapfid: no inode!\n"); - return; - } - cnp = ITOC(inode); - coda_zap_cnode(cnp, flag); -} - int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy) diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 67133f275cf8..aa67a22e4b3f 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -15,8 +15,6 @@ extern int coda_print_entry; /* cnode.c */ - - static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr) { CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino); @@ -56,8 +54,8 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) ENTRY; /* - * We get inode numbers from Venus -- see venus source - */ + * We get inode numbers from Venus -- see venus source + */ error = venus_getattr(sb, fid, &attr); if ( error ) { @@ -79,7 +77,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) memset(cnp, 0, (int) sizeof(struct coda_inode_info)); cnp->c_fid = *fid; cnp->c_magic = CODA_CNODE_MAGIC; - cnp->c_flags = C_VATTR; + cnp->c_flags = 0; cnp->c_vnode = *inode; INIT_LIST_HEAD(&(cnp->c_cnhead)); INIT_LIST_HEAD(&(cnp->c_volrootlist)); @@ -111,20 +109,51 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2) -/* convert a fid to an inode. Avoids having a hash table - such as present in the Mach minicache */ +/* convert a fid to an inode. Mostly we can compute + the inode number from the FID, but not for volume + mount points: those are in a list */ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) { ino_t nr; struct inode *inode; struct coda_inode_info *cnp; -ENTRY; + ENTRY; CDEBUG(D_INODE, "%s\n", coda_f2s(fid)); + if ( !sb ) { + printk("coda_fid_to_inode: no sb!\n"); + return NULL; + } + + if ( !fid ) { + printk("coda_fid_to_inode: no fid!\n"); + return NULL; + } + + + if ( coda_fid_is_volroot(fid) ) { + struct coda_inode_info *cii; + struct list_head *lh, *le; + struct coda_sb_info *sbi = coda_sbp(sb); + le = lh = &sbi->sbi_volroothead; + + while ( (le = le->next) != lh ) { + cii = list_entry(le, struct coda_inode_info, + c_volrootlist); + if ( cii->c_fid.Volume == fid->Volume) { + inode = cii->c_vnode; + CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino); + return cii->c_vnode; + } + + } + return NULL; + } + + /* fid is not volume root, hence ino is computable */ nr = coda_f2i(fid); inode = iget(sb, nr); - if ( !inode ) { printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n", sb, nr); @@ -133,19 +162,25 @@ ENTRY; /* check if this inode is linked to a cnode */ cnp = ITOC(inode); - if ( cnp->c_magic != CODA_CNODE_MAGIC ) { + CDEBUG(D_INODE, "uninitialized inode. Return.\n"); iput(inode); return NULL; } - /* make sure fid is the one we want */ - if ( !coda_fideq(fid, &(cnp->c_fid)) ) { + /* make sure fid is the one we want; + unfortunately Venus will shamelessly send us mount-symlinks. + These have the same inode as the root of the volume they + mount, but the fid will be wrong. + */ + if ( !coda_fideq(fid, &(cnp->c_fid)) && + !coda_fid_is_volroot(&(cnp->c_fid))) { printk("coda_fid2inode: bad cnode! Tell Peter.\n"); iput(inode); return NULL; } + CDEBUG(D_INODE, "found %ld\n", inode->i_ino); iput(inode); return inode; } diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index e968f3addb90..4fe096df91dc 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c @@ -32,14 +32,15 @@ int coda_access_cache = 1; /* caller must allocate 36 byte string ! */ char * coda_f2s(ViceFid *f) { - static char s[50]; + static char s[60]; if ( f ) { - sprintf(s, "(%10lx,%10lx,%10lx)", + sprintf(s, "(%-#lx,%-#lx,%-#lx)", f->Volume, f->Vnode, f->Unique); } return s; } +/* recognize special .CONTROL name */ int coda_iscontrol(const char *name, size_t length) { if ((CFS_CONTROLLEN == length) && @@ -48,16 +49,23 @@ int coda_iscontrol(const char *name, size_t length) return 0; } +/* recognize /coda inode */ int coda_isroot(struct inode *i) { if ( i->i_sb->s_root->d_inode == i ) { - return 1; + return 1; } else { - return 0; + return 0; } } - +/* is this a volume root FID */ +int coda_fid_is_volroot(struct ViceFid *fid) +{ + return ( (fid->Vnode == 1) && (fid->Unique == 1 ) ); +} + +/* put the current process credentials in the cred */ void coda_load_creds(struct coda_cred *cred) { cred->cr_uid = (vuid_t) current->uid; @@ -98,11 +106,6 @@ unsigned short coda_flags_to_cflags(unsigned short flags) } -int coda_fid_is_volroot(struct ViceFid *fid) -{ - return ( (fid->Vnode == 1) && (fid->Unique == 1 ) ); -} - /* utility functions below */ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr) { diff --git a/fs/coda/dir.c b/fs/coda/dir.c index dd20499dcb2b..8fed69242a69 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -40,17 +40,21 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, /* dir file-ops */ static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); +/* dentry ops */ +int coda_dentry_revalidate(struct dentry *de); + /* support routines */ static int coda_venus_readdir(struct file *filp, void *dirent, filldir_t filldir); int coda_fsync(struct file *, struct dentry *dentry); +static int coda_refresh_inode(struct dentry *dentry); struct dentry_operations coda_dentry_operations = { - NULL, /* revalidate */ + coda_dentry_revalidate, /* revalidate */ NULL, /* hash */ NULL, - coda_dentry_delete + NULL, }; struct inode_operations coda_dir_inode_operations = @@ -74,7 +78,7 @@ struct inode_operations coda_dir_inode_operations = coda_permission, /* permission */ NULL, /* smap */ NULL, /* update page */ - NULL /* revalidate */ + coda_revalidate_inode /* revalidate */ }; struct file_operations coda_dir_operations = { @@ -117,7 +121,6 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) } dircnp = ITOC(dir); - CHECK_CNODE(dircnp); if ( length > CFS_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", @@ -141,9 +144,13 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) (const char *)name, length, &type, &resfid); res_inode = NULL; - if (!error || (error == -CFS_NOCACHE) ) { - if (error == -CFS_NOCACHE) + if (!error) { + if (type & CFS_NOCACHE) { + type &= (~CFS_NOCACHE); + CDEBUG(D_INODE, "dropme set for %s\n", + coda_f2s(&resfid)); dropme = 1; + } error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); if (error) return -error; @@ -152,7 +159,7 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) coda_f2s(&dircnp->c_fid), length, name, error); return error; } - CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n", + CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", name, coda_f2s(&resfid), type, error, dropme); exit: @@ -228,7 +235,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) CHECK_CNODE(dircnp); if ( length > CFS_MAXNAMLEN ) { - char str[50]; printk("name too long: create, %s(%s)\n", coda_f2s(&dircnp->c_fid), name); return -ENAMETOOLONG; @@ -238,7 +244,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) 0, mode, &newfid, &attrs); if ( error ) { - char str[50]; CDEBUG(D_INODE, "create: %s, result %d\n", coda_f2s(&newfid), error); d_drop(de); @@ -321,7 +326,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, const char * name = de->d_name.name; int len = de->d_name.len; struct coda_inode_info *dir_cnp, *cnp; - char str[50]; int error; ENTRY; @@ -408,7 +412,6 @@ int coda_unlink(struct inode *dir, struct dentry *de) int error; const char *name = de->d_name.name; int len = de->d_name.len; - char fidstr[50]; ENTRY; @@ -781,3 +784,82 @@ exit: CODA_FREE(buff, size); return error; } + +int coda_dentry_revalidate(struct dentry *de) +{ + int valid = 1; + struct inode *inode = de->d_inode; + struct coda_inode_info *cii; + ENTRY; + + if (inode) { + if (is_bad_inode(inode)) + return 0; + cii = ITOC(de->d_inode); + if (cii->c_flags & C_PURGE) + valid = 0; + } + return valid || coda_isroot(de->d_inode); +} + + +static int coda_refresh_inode(struct dentry *dentry) +{ + struct coda_vattr attr; + int error; + int old_mode; + ino_t old_ino; + struct inode *inode = dentry->d_inode; + struct coda_inode_info *cii = ITOC(inode); + + ENTRY; + error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr); + if ( error ) { + make_bad_inode(inode); + return -EIO; + } + + /* this baby may be lost if: + - it's type changed + - it's ino changed + */ + old_mode = inode->i_mode; + old_ino = inode->i_ino; + coda_vattr_to_iattr(inode, &attr); + + if ((inode->i_ino != old_ino) || + ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) { + make_bad_inode(inode); + inode->i_mode = old_mode; + return -EIO; + } + + cii->c_flags &= ~C_VATTR; + return 0; +} + + +/* + * This is called when we want to check if the inode has + * changed on the server. Coda makes this easy since the + * cache manager Venus issues a downcall to the kernel when this + * happens + */ + +int coda_revalidate_inode(struct dentry *dentry) +{ + int error = 0; + struct coda_inode_info *cii = ITOC(dentry->d_inode); + + ENTRY; + CDEBUG(D_INODE, "revalidating: %*s/%*s\n", + dentry->d_name.len, dentry->d_name.name, + dentry->d_parent->d_name.len, dentry->d_parent->d_name.name); + + if ( cii->c_flags & (C_VATTR | C_PURGE )) { + error = coda_refresh_inode(dentry); + } + + return error; +} + diff --git a/fs/coda/file.c b/fs/coda/file.c index b33680cc3ffb..ae1dd9776839 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -30,7 +30,7 @@ static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *o static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off); static int coda_file_mmap(struct file * file, struct vm_area_struct * vma); -/* exported from this file */ +/* also exported from this file (used for dirs) */ int coda_fsync(struct file *, struct dentry *dentry); struct inode_operations coda_file_inode_operations = { @@ -43,7 +43,7 @@ struct inode_operations coda_file_inode_operations = { NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ - NULL, /* rename */ + NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ coda_readpage, /* readpage */ @@ -53,7 +53,7 @@ struct inode_operations coda_file_inode_operations = { coda_permission, /* permission */ NULL, /* smap */ NULL, /* update page */ - NULL /* revalidate */ + coda_revalidate_inode /* revalidate */ }; struct file_operations coda_file_operations = { @@ -74,41 +74,47 @@ struct file_operations coda_file_operations = { }; /* File file operations */ -static int coda_readpage(struct file * file, struct page * page) +static int coda_readpage(struct file * coda_file, struct page * page) { - struct dentry *de = file->f_dentry; - struct inode *inode = de->d_inode; + struct dentry *de = coda_file->f_dentry; + struct inode *coda_inode = de->d_inode; struct dentry cont_dentry; - struct inode *cont_inode; - struct coda_inode_info *cnp; + struct file cont_file; + struct coda_inode_info *cii; ENTRY; - cnp = ITOC(inode); - CHECK_CNODE(cnp); + cii = ITOC(coda_inode); - if ( ! cnp->c_ovp ) { - printk("coda_readpage: no open inode for ino %ld\n", inode->i_ino); + if ( ! cii->c_ovp ) { + printk("coda_readpage: no open inode for ino %ld, %s\n", + coda_inode->i_ino, de->d_name.name); return -ENXIO; } + + coda_prepare_openfile(coda_inode, coda_file, cii->c_ovp, + &cont_file, &cont_dentry); - cont_inode = cnp->c_ovp; - cont_dentry.d_inode = cont_inode; - - CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, cont_inode->i_ino, page->offset); + CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", + coda_inode->i_ino, cii->c_ovp->i_ino, page->offset); - generic_readpage(&cont_dentry, page); + generic_readpage(&cont_file, page); EXIT; return 0; } static int coda_file_mmap(struct file * file, struct vm_area_struct * vma) { - struct coda_inode_info *cnp; - cnp = ITOC(file->f_dentry->d_inode); - cnp->c_mmcount++; + struct coda_inode_info *cii; + int res; + + ENTRY; + cii = ITOC(file->f_dentry->d_inode); + cii->c_mmcount++; - return generic_file_mmap(file, vma); + res =generic_file_mmap(file, vma); + EXIT; + return res; } static ssize_t coda_file_read(struct file *coda_file, char *buff, @@ -120,7 +126,6 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff, struct file cont_file; struct dentry cont_dentry; int result = 0; - ENTRY; cnp = ITOC(coda_inode); diff --git a/fs/coda/super.c b/fs/coda/inode.c similarity index 92% rename from fs/coda/super.c rename to fs/coda/inode.c index 5410fb50d81c..96d07e265c05 100644 --- a/fs/coda/super.c +++ b/fs/coda/inode.c @@ -4,7 +4,7 @@ * Copryright (C) 1996 Peter J. Braam and * Michael Callahan * - * Rewritten for Linux 2.1.?? Peter Braam + * Rewritten for Linux 2.1. Peter Braam * Copyright (C) Carnegie Mellon University */ @@ -81,7 +81,6 @@ static struct super_block * coda_read_super(struct super_block *sb, ViceFid fid; kdev_t dev = sb->s_dev; int error; - char str[50]; ENTRY; MOD_INC_USE_COUNT; @@ -180,10 +179,10 @@ static void coda_put_super(struct super_block *sb) /* all filling in of inodes postponed until lookup */ static void coda_read_inode(struct inode *inode) { - struct coda_inode_info *cnp; + struct coda_inode_info *cii; ENTRY; - cnp = ITOC(inode); - cnp->c_magic = 0; + cii = ITOC(inode); + cii->c_magic = 0; return; } @@ -200,32 +199,32 @@ static void coda_put_inode(struct inode *in) static void coda_delete_inode(struct inode *inode) { - struct coda_inode_info *cnp; + struct coda_inode_info *cii; struct inode *open_inode; ENTRY; CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", inode->i_ino, inode->i_count); - cnp = ITOC(inode); - if ( inode->i_ino == CTL_INO || cnp->c_magic != CODA_CNODE_MAGIC ) { + cii = ITOC(inode); + if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) { clear_inode(inode); return; } - if ( coda_fid_is_volroot(&cnp->c_fid) ) - list_del(&cnp->c_volrootlist); + if ( coda_fid_is_volroot(&cii->c_fid) ) + list_del(&cii->c_volrootlist); - open_inode = cnp->c_ovp; + open_inode = cii->c_ovp; if ( open_inode ) { CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n", open_inode->i_ino, open_inode->i_count); - cnp->c_ovp = NULL; + cii->c_ovp = NULL; iput(open_inode); } - coda_cache_clear_cnp(cnp); + coda_cache_clear_inode(inode); inode->u.generic_ip = NULL; clear_inode(inode); @@ -235,24 +234,24 @@ static void coda_delete_inode(struct inode *inode) static int coda_notify_change(struct dentry *de, struct iattr *iattr) { struct inode *inode = de->d_inode; - struct coda_inode_info *cnp; + struct coda_inode_info *cii; struct coda_vattr vattr; int error; ENTRY; memset(&vattr, 0, sizeof(vattr)); - cnp = ITOC(inode); - CHECK_CNODE(cnp); + cii = ITOC(inode); + CHECK_CNODE(cii); coda_iattr_to_vattr(iattr, &vattr); vattr.va_type = C_VNON; /* cannot set type */ CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode); - error = venus_setattr(inode->i_sb, &cnp->c_fid, &vattr); + error = venus_setattr(inode->i_sb, &cii->c_fid, &vattr); if ( !error ) { coda_vattr_to_iattr(inode, &vattr); - coda_cache_clear_cnp(cnp); + coda_cache_clear_inode(inode); } CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error); diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 04333e046508..119d14f5101d 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -65,7 +65,7 @@ extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, i /* statistics */ struct coda_upcallstats coda_callstats; int coda_hard = 0; /* introduces a timeout on upcalls */ -unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */ +unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ extern struct coda_sb_info coda_super_info[MAX_CODADEVS]; struct vcomm psdev_vcomm[MAX_CODADEVS]; @@ -447,7 +447,7 @@ MODULE_AUTHOR("Peter J. Braam "); int init_module(void) { int status; - printk(KERN_INFO "Coda Kernel/User communications module 1.0\n"); + printk(KERN_INFO "Coda Kernel/User communications module 2.0\n"); status = init_coda_psdev(); if ( status ) { diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index ac625ad1781d..13d3127c6e62 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -500,7 +500,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, union outputArgs *outp; int insize, outsize, error; int iocsize; - char str[50]; insize = VC_MAXMSGSIZE; UPARG(CFS_IOCTL); @@ -587,7 +586,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, static inline void coda_waitfor_upcall(struct vmsg *vmp) { struct wait_queue wait = { current, NULL }; - old_sigset_t pending; vmp->vm_posttime = jiffies; @@ -608,13 +606,9 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp) if ( jiffies > vmp->vm_posttime + coda_timeout * HZ ) break; - spin_lock_irq(¤t->sigmask_lock); - pending = current->blocked.sig[0] & current->signal.sig[0]; - spin_unlock_irq(¤t->sigmask_lock); - /* if this process really wants to die, let it go */ - if ( sigismember(&pending, SIGKILL) || - sigismember(&pending, SIGINT) ) + if ( sigismember(¤t->signal, SIGKILL) || + sigismember(¤t->signal, SIGINT) ) break; else schedule(); @@ -765,10 +759,14 @@ ENTRY; * This call is a result of token expiration. * * The next arise as the result of callbacks on a file or directory. - * CFS_ZAPDIR -- flush the attributes for the dir from its cnode. - * Zap all children of this directory from the namecache. * CFS_ZAPFILE -- flush the cached attributes for a file. - * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. Not used? + + * CFS_ZAPDIR -- flush the attributes for the dir and + * force a new lookup for all the children + of this dir. + + * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. + Not used? * * The next is a result of Venus detecting an inconsistent file. * CFS_PURGEFID -- flush the attribute for the file @@ -803,53 +801,48 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) return(0); } case CFS_ZAPDIR : { + struct inode *inode; ViceFid *fid = &out->cfs_zapdir.CodaFid; - char str[50]; if ( !fid ) { printk("ZAPDIR: Null fid\n"); return 0; } CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid)); clstats(CFS_ZAPDIR); - coda_zapfid(fid, sb, C_ZAPDIR); - return(0); - } - case CFS_ZAPVNODE : { - ViceFid *fid = &out->cfs_zapvnode.VFid; - char str[50]; - struct coda_cred *cred = &out->cfs_zapvnode.cred; - if ( !fid || !cred ) { - printk("ZAPVNODE: Null fid or cred\n"); - return 0; - } - CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid)); - coda_zapfid(fid, sb, C_ZAPFID); - coda_cache_clear_cred(sb, cred); - clstats(CFS_ZAPVNODE); + inode = coda_fid_to_inode(fid, sb); + coda_flag_inode(inode, C_VATTR); + coda_cache_clear_inode(inode); + coda_flag_alias_children(inode, C_PURGE); return(0); } + + case CFS_ZAPVNODE : case CFS_ZAPFILE : { + struct inode *inode; struct ViceFid *fid = &out->cfs_zapfile.CodaFid; - char str[50]; clstats(CFS_ZAPFILE); if ( !fid ) { printk("ZAPFILE: Null fid\n"); return 0; } CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid)); - coda_zapfid(fid, sb, C_ZAPFID); + inode = coda_fid_to_inode(fid, sb); + coda_flag_inode(inode, C_VATTR); + coda_cache_clear_inode(inode); return 0; } case CFS_PURGEFID : { + struct inode *inode; ViceFid *fid = &out->cfs_purgefid.CodaFid; - char str[50]; if ( !fid ) { printk("PURGEFID: Null fid\n"); return 0; } CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid)); clstats(CFS_PURGEFID); - coda_zapfid(fid, sb, C_ZAPDIR); + inode = coda_fid_to_inode(fid, sb); + coda_flag_inode(inode, C_PURGE); + coda_cache_clear_inode(inode); return 0; } case CFS_REPLACE : { diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in index 48cf4aa868c9..bdb973e4178a 100644 --- a/fs/ncpfs/Config.in +++ b/fs/ncpfs/Config.in @@ -1,7 +1,7 @@ # # NCP Filesystem configuration # -# bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING +bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile index 5c83ada1196e..9c33bc515a53 100644 --- a/fs/ncpfs/Makefile +++ b/fs/ncpfs/Makefile @@ -8,7 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := ncpfs.o -O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o +O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \ + ncpsign_kernel.o M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index b535e30e7d42..c872c2b84dc9 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -284,6 +284,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) server->buffer_size = 0; server->conn_status = 0; server->root_dentry = NULL; + server->root_setuped = 0; #ifdef CONFIG_NCPFS_PACKET_SIGNING server->sign_wanted = 0; server->sign_active = 0; diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 078d26596d74..2df6fee09510 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -32,6 +32,22 @@ int ncp_ioctl(struct inode *inode, struct file *filp, struct ncp_ioctl_request request; struct ncp_fs_info info; +#ifdef NCP_IOC_GETMOUNTUID_INT + /* remove after ncpfs-2.0.13/2.2.0 gets released */ + if ((NCP_IOC_GETMOUNTUID != NCP_IOC_GETMOUNTUID_INT) && + (cmd == NCP_IOC_GETMOUNTUID_INT)) { + int tmp = server->m.mounted_uid; + + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if (put_user(tmp, (unsigned int*) arg)) return -EFAULT; + return 0; + } +#endif /* NCP_IOC_GETMOUNTUID_INT */ + switch (cmd) { case NCP_IOC_NCPREQUEST: @@ -80,6 +96,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp, && (current->uid != server->m.mounted_uid)) { return -EACCES; } + if (server->root_setuped) return -EBUSY; + server->root_setuped = 1; return ncp_conn_logged_in(server); case NCP_IOC_GET_FS_INFO: @@ -121,19 +139,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp, put_user(server->m.mounted_uid, (uid_t *) arg); return 0; - case NCP_IOC_GETMOUNTUID_INT: - if ( (permission(inode, MAY_READ) != 0) - && (current->uid != server->m.mounted_uid)) - { - return -EACCES; - } - - { - unsigned int tmp=server->m.mounted_uid; - if (put_user(tmp, (unsigned long*) arg)) return -EFAULT; - } - return 0; - #ifdef CONFIG_NCPFS_MOUNT_SUBDIR case NCP_IOC_GETROOT: { @@ -168,6 +173,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { return -EACCES; } + if (server->root_setuped) return -EBUSY; if (copy_from_user(&sr, (struct ncp_setroot_ioctl*)arg, sizeof(sr))) return -EFAULT; @@ -184,6 +190,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, } } dentry = server->root_dentry; + server->root_setuped = 1; if (dentry) { struct inode* inode = dentry->d_inode; diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c new file mode 100644 index 000000000000..bae89c197b0d --- /dev/null +++ b/fs/ncpfs/ncpsign_kernel.c @@ -0,0 +1,114 @@ +/* + * ncpsign_kernel.c + * + * Arne de Bruijn (arne@knoware.nl), 1997 + * + */ + +#include + +#ifdef CONFIG_NCPFS_PACKET_SIGNING + +#include +#include +#include "ncpsign_kernel.h" + +#define rol32(i,c) (((((i)&0xffffffff)<>(32-c))) +/* i386: 32-bit, little endian, handles mis-alignment */ +#ifdef __i386__ +#define GET_LE32(p) (*(int *)(p)) +#define PUT_LE32(p,v) { *(int *)(p)=v; } +#else +/* from include/ncplib.h */ +#define BVAL(buf,pos) (((__u8 *)(buf))[pos]) +#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos)) +#define BSET(buf,pos,val) (BVAL(buf,pos) = (val)) + +static inline word +WVAL_LH(__u8 * buf, int pos) +{ + return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8; +} +static inline dword +DVAL_LH(__u8 * buf, int pos) +{ + return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16; +} +static inline void +WSET_LH(__u8 * buf, int pos, word val) +{ + BSET(buf, pos, val & 0xff); + BSET(buf, pos + 1, val >> 8); +} +static inline void +DSET_LH(__u8 * buf, int pos, dword val) +{ + WSET_LH(buf, pos, val & 0xffff); + WSET_LH(buf, pos + 2, val >> 16); +} + +#define GET_LE32(p) DVAL_LH(p,0) +#define PUT_LE32(p,v) DSET_LH(p,0,v) +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) + +static void nwsign(char *r_data1, char *r_data2, char *outdata) { + int i; + unsigned int w0,w1,w2,w3; + static int rbit[4]={0, 2, 1, 3}; +#ifdef __i386__ + unsigned int *data2=(int *)r_data2; +#else + unsigned int data2[16]; + for (i=0;i<16;i++) + data2[i]=GET_LE32(r_data2+(i<<2)); +#endif + w0=GET_LE32(r_data1); + w1=GET_LE32(r_data1+4); + w2=GET_LE32(r_data1+8); + w3=GET_LE32(r_data1+12); + for (i=0;i<16;i+=4) { + w0=rol32(w0 + ((w1 & w2) | ((~w1) & w3)) + data2[i+0],3); + w3=rol32(w3 + ((w0 & w1) | ((~w0) & w2)) + data2[i+1],7); + w2=rol32(w2 + ((w3 & w0) | ((~w3) & w1)) + data2[i+2],11); + w1=rol32(w1 + ((w2 & w3) | ((~w2) & w0)) + data2[i+3],19); + } + for (i=0;i<4;i++) { + w0=rol32(w0 + (((w2 | w3) & w1) | (w2 & w3)) + 0x5a827999 + data2[i+0],3); + w3=rol32(w3 + (((w1 | w2) & w0) | (w1 & w2)) + 0x5a827999 + data2[i+4],5); + w2=rol32(w2 + (((w0 | w1) & w3) | (w0 & w1)) + 0x5a827999 + data2[i+8],9); + w1=rol32(w1 + (((w3 | w0) & w2) | (w3 & w0)) + 0x5a827999 + data2[i+12],13); + } + for (i=0;i<4;i++) { + w0=rol32(w0 + ((w1 ^ w2) ^ w3) + 0x6ed9eba1 + data2[rbit[i]+0],3); + w3=rol32(w3 + ((w0 ^ w1) ^ w2) + 0x6ed9eba1 + data2[rbit[i]+8],9); + w2=rol32(w2 + ((w3 ^ w0) ^ w1) + 0x6ed9eba1 + data2[rbit[i]+4],11); + w1=rol32(w1 + ((w2 ^ w3) ^ w0) + 0x6ed9eba1 + data2[rbit[i]+12],15); + } + PUT_LE32(outdata,(w0+GET_LE32(r_data1)) & 0xffffffff); + PUT_LE32(outdata+4,(w1+GET_LE32(r_data1+4)) & 0xffffffff); + PUT_LE32(outdata+8,(w2+GET_LE32(r_data1+8)) & 0xffffffff); + PUT_LE32(outdata+12,(w3+GET_LE32(r_data1+12)) & 0xffffffff); +} + +/* Make a signature for the current packet and add it at the end of the */ +/* packet. */ +void sign_packet(struct ncp_server *server, int *size) { + char data[64]; + + memset(data,0,64); + memcpy(data,server->sign_root,8); + PUT_LE32(data+8,(*size)); + memcpy(data+12,server->packet+sizeof(struct ncp_request_header)-1, + min((*size)-sizeof(struct ncp_request_header)+1,52)); + + nwsign(server->sign_last,data,server->sign_last); + + memcpy(server->packet+(*size),server->sign_last,8); + (*size)+=8; +} + +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ + diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h new file mode 100644 index 000000000000..85974f346365 --- /dev/null +++ b/fs/ncpfs/ncpsign_kernel.h @@ -0,0 +1,16 @@ +/* + * ncpsign_kernel.h + * + * Arne de Bruijn (arne@knoware.nl), 1997 + * + */ + +#ifndef _NCPSIGN_KERNEL_H +#define _NCPSIGN_KERNEL_H + +#include +#include + +void sign_packet(struct ncp_server *server, int *size); + +#endif diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt index e48a4d184307..ddc2911fcc76 100644 --- a/fs/umsdos/README-WIP.txt +++ b/fs/umsdos/README-WIP.txt @@ -32,34 +32,42 @@ Notes: possible very minor problems with dentry/inode/... kernel structures (ver - long file names - works - read file - works - switching MSDOS/UMSDOS - works? -- switching UMSDOS/MSDOS - untested -- pseudo root things - commented out mostly currently. To be fixed when +- switching UMSDOS/MSDOS - UNTESTED +- pseudo root things - COMMENTED OUT mostly currently. To be fixed when dentries stuff is straightened out. - resolve symlink - seems to work fully now! - dereference symlink - seems to work fully now! - hard links - seems to work now - special files (block/char device, fifos, sockets...) - seems to work ok. -- other ioctls - mostly untested +- other ioctls - MOSTLY UNTESTED - dangling symlink - UNTESTED ! -- create symlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- create hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- create file - creates, but corrupts. after reboot seem ok ? -- create special file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- write to file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename file (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename file (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename dir (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename dir (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- delete file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- delete hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- mkdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rmdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- umssyncing - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- create symlink - works on short names, but fails (gets + truncated on long ones) (also + due to some dentries problems, it may not + be visible right away always - eg. before + umount/mount) +- create hardlink - WARNING: NOT FIXED YET! +- create file - creates short names, but probs with long ones ? +- create special file - seems to work on short names. +- write to file - seems to work on short names. +- rename file (same dir) - WARNING: NOT FIXED YET! +- rename file (dif. dir) - WARNING: NOT FIXED YET! +- rename dir (same dir) - WARNING: NOT FIXED YET! +- rename dir (dif. dir) - WARNING: NOT FIXED YET! +- delete file - WARNING: NOT FIXED YET! +- notify_change (chown,perms) - seems to work! +- delete hardlink - WARNING: NOT FIXED YET! +- mkdir - seems to work, even with long names ! (but + due to some dentries problems, it may not + be visible right away always - eg. before + umount/mount) +- rmdir - WARNING: NOT FIXED YET! +- umssyncing - does something :-), but NEEDS EXTENSIVE TESTING Notes: moderate dentry/inode kernel structures trashing. Probably some other kernel structures compromised. Have SysRq support compiled in, and use -Sync/Emergency-remount-RO. And don't try mounting read/write yet - and then +Sync/Emergency-remount-RO. And if you don't try mounting read/write - you should have no big problems... Notes2: kernel structures trashing seems to be _MUCH_ lower if no @@ -69,6 +77,17 @@ Notes3: Notes2 is probably somewhat outdated now that hardlink/symlink stuff is supposed to be fixed enough to work, but I haven't got the time to test it. +Note4: on failure of creating of long filenames: MSDOS filename gets +created, and EMD entry gets created. Check: either they mismatch, or EMD +entry contains some wrong flags. + +Note5: rmdir(2) probably fails because do_rmdir calls lock_parent, which +uses dentry->d_parent, which we neglect to set, so it returns -ENOENT. +Probably same problem on unlink(2) ? What to do ? How to set +dentry->d_parent to something useful ?? Must I recurse down whole pathname +and set one by one all directory components ?! or only last one is really +needed ? help ! + ------------------------------------------------------------------------------ Some general notes: @@ -85,7 +104,7 @@ compile/test/reboot/set_environment/recompile cycle by removing 'reboot/set_environment' component that now occures every few cycles. But I need some help from someone knowing about dentries/inodes use more -than I. If you can help, please contact me... I'm mostly worries about +than I. If you can help, please contact me... I'm mostly worried about iget/iput and dget/dput, and deallocating temporary dentries we create. should we destroy temp dentries ? using d_invalidate ? using d_drop ? just dput them ? @@ -96,9 +115,9 @@ any direct Email in few days. If I don't - probably I never got your message. You can try mnalis@open.hr or mnalis@voyager.hr; however mnalis@jagor.srce.hr is preferable one. ------------------------------------------------------------------------------- -some of my notes for myself: +------------------------------------------------------------------------------ +some of my notes for myself /mn/: + hardlinks/symlinks. test with files in not_the_same_dir - also test not_the_same_dir for other file operations like rename etc. @@ -108,3 +127,17 @@ some of my notes for myself: - what about .dotfiles ? working ? multiple dots ? etc.... - fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular? + +- umsdos_create_any - calling msdos_create will create dentry for shor name. Hmmmm..? +- kill_dentry - put it where is needed. Also dput() at needed places. + +- when should dput()/iput() be used ?!! + +- probably problem with filename mangling somewhere, since both create and + write to file work on short filenames, but fail on long ones. Path + components may be of any size (eg. mkfifo /mnt/Very_long_dir2/blah1 will + succeed, but mkfifo /mnt/very_long_filename.txt won't) + + +- what is dir->i_count++ ? locking directory ? should this be lock_parent or +something ? diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index be1af20f70bc..52a72367e9aa 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -31,7 +31,7 @@ extern struct inode *pseudo_root; uses. It's easier to do once than hack all the other instances. Probably safer as well */ -int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct inode **inode) +int compat_umsdos_real_lookup (struct inode *dir,const char *name,int len, struct inode **inode) { int rv; struct dentry *dentry; @@ -39,6 +39,7 @@ int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct dentry = creat_dentry (name, len, NULL); rv = umsdos_real_lookup(dir,dentry); if (inode) *inode = dentry->d_inode; + kill_dentry (dentry); return rv; } @@ -458,6 +459,7 @@ void umsdos_lookup_patch ( if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n"); } } + struct UMSDOS_DIRENT_K{ off_t f_pos; /* will hold the offset of the entry in EMD */ ino_t ino; @@ -533,6 +535,9 @@ int umsdos_inode2entry ( /* This is a DOS directory */ struct UMSDOS_DIR_SEARCH bufk; struct file filp; + + fill_new_filp (&filp, NULL); + Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n")); filp.f_reada = 1; filp.f_pos = 0; @@ -548,6 +553,8 @@ int umsdos_inode2entry ( }else{ /* skip . and .. see umsdos_readdir_x() */ struct file filp; + fill_new_filp (&filp, NULL); + filp.f_reada = 1; filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n")); @@ -856,6 +863,9 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result) struct file filp; loff_t offs = 0; + fill_new_filp (&filp, NULL); + + dentry_src = creat_dentry ("hlink-mn", 8, hlink); memset (&filp, 0, sizeof (filp)); diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 169a75a45b54..8ba6571eb16c 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -22,6 +23,29 @@ #define PRINTK(x) #define Printk(x) printk x +/* + * makes empty filp + * + */ + +void fill_new_filp (struct file *filp, struct dentry *dentry) +{ + Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp)); + if (dentry) + Printk ((" dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); + else + Printk ((" dentry is NULL ! you must fill it later...\n")); + + memset (filp, 0, sizeof (struct file)); + + filp->f_pos = 0; + filp->f_reada = 1; + filp->f_flags = O_RDWR; + filp->f_dentry = dentry; + filp->f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with SOMETHING */ +} + + /* * makes dentry. for name name with length len. /mn/ * if inode is not NULL, puts it also. @@ -34,19 +58,49 @@ struct dentry *creat_dentry (const char *name, const int len, struct inode *inod struct qstr qname; if (inode) - Printk (("/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); + Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); else - Printk (("/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name)); + Printk ((KERN_DEBUG "/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name)); qname.name = name; qname.len = len; qname.hash = 0; ret = d_alloc (parent,&qname); /* create new dentry */ - ret->d_inode = inode; + ret->d_inode = NULL; + + if (inode) d_add (ret, inode); + +/* ret->d_inode = inode; /mn/ FIXME this was old, replaced by d_add, delete this ! */ return ret; } +/* + * removes temporary dentry created by creat_dentry + * + */ + +void kill_dentry (struct dentry *dentry) +{ + if (dentry) { + Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name)); + if (dentry->d_inode) + Printk (("inode=%lu\n", dentry->d_inode->i_ino)); + else + Printk (("inode is NULL\n")); + + /* FIXME: is this ok ?! /mn/ */ + /* d_invalidate (dentry); */ + /*dput (dentry);*/ + } else { + Printk (("/mn/ kill_dentry: dentry is NULL ?!\n")); + } + + + Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n")); + return; +} + /* @@ -126,23 +180,24 @@ ssize_t umsdos_file_read_kmem (struct inode *emd_dir, /* - Write to a file from kernel space -*/ -ssize_t umsdos_file_write_kmem (struct inode *emd_dir, - struct file *filp, + * Write to file from kernel space. + * Does the real job, assumes all structures are initialized ! + */ + + +ssize_t umsdos_file_write_kmem_real (struct file *filp, const char *buf, size_t count, - loff_t *offs - ) + loff_t *offs) { - int ret; + ssize_t ret; mm_segment_t old_fs = get_fs(); - struct dentry *old_dentry; - Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); + set_fs (KERNEL_DS); Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); - Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + Printk ((KERN_ERR " struct dentry=%p\n", filp->f_dentry)); + Printk ((KERN_ERR " struct inode=%p\n", filp->f_dentry->d_inode)); Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs)); Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos)); @@ -152,23 +207,49 @@ ssize_t umsdos_file_write_kmem (struct inode *emd_dir, Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid)); Printk ((KERN_ERR " f_version=%ld\n", filp->f_version)); Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + + ret = fat_file_write (filp, buf, count, offs); + PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); + + set_fs (old_fs); + return ret; +} + + +/* + * Write to a file from kernel space + */ + +ssize_t umsdos_file_write_kmem (struct inode *emd_dir, + struct file *filp, + const char *buf, + size_t count, + loff_t *offs + ) +{ + int ret; + struct dentry *old_dentry; + - set_fs (KERNEL_DS); + Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); + Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + old_dentry=filp->f_dentry; /* save it */ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); - *offs = filp->f_pos; - ret = fat_file_write (filp, buf, count, offs); - PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); + *offs = filp->f_pos; /* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */ + + ret=umsdos_file_write_kmem_real (filp, buf, count, offs); filp->f_pos = *offs; filp->f_dentry=old_dentry; - set_fs (old_fs); return ret; } + + /* Write a block of bytes into one EMD file. The block of data is NOT in user space. @@ -201,7 +282,7 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir, #endif if (offs) myofs=*offs; /* if offs is not NULL, read it */ - Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %ld, %Ld\n", emd_dir, filp, buf, count, myofs)); + Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %d, %Ld\n", emd_dir, filp, buf, count, myofs)); written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs); Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n")); if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ @@ -216,6 +297,12 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir, d->rdev = le16_to_cpu (d->rdev); d->mode = le16_to_cpu (d->mode); #endif + +#ifdef 1 + if (written != count) Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count)); +#endif + + return written != count ? -EIO : 0; } @@ -409,7 +496,9 @@ int umsdos_writeentry ( struct file filp; struct umsdos_dirent *entry = &info->entry; struct umsdos_dirent entry0; - + + fill_new_filp (&filp, NULL); + Printk (("umsdos_writeentry /mn/: entering...\n")); emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir); @@ -444,7 +533,7 @@ int umsdos_writeentry ( filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ ret = umsdos_emd_dir_write (emd_dir, &filp, (char*)entry, info->recsize, NULL); - Printk (("emd_dir_write returned !\n")); + Printk (("emd_dir_write returned with %d!\n", ret)); if (ret != 0){ printk ("UMSDOS: problem with EMD file. Can't write\n"); }else{ @@ -452,7 +541,7 @@ int umsdos_writeentry ( /* dir->i_dirt = 1; FIXME iput/dput ??? */ } - Printk (("umsdos_writeentry /mn/: returning...\n")); + Printk (("umsdos_writeentry /mn/: returning %d...\n", ret)); return ret; } @@ -541,10 +630,13 @@ static int umsdos_find ( record, multiple contiguous record are allocated. */ int ret = -ENOENT; - /* FIXME -- /mn/ fixed ? */ - struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1); + struct inode *emd_dir; + struct umsdos_dirent *entry = &info->entry; + + Printk (("umsdos_find: locating %.*s in dir %lu\n", entry->name_len, entry->name, dir->i_ino)); + + emd_dir = umsdos_emd_dir_lookup (dir, 1); if (emd_dir != NULL){ - struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; struct { off_t posok; /* Position available to store the entry */ @@ -560,11 +652,7 @@ static int umsdos_find ( dentry = creat_dentry ("umsfind-mn", 10, emd_dir); - buf.filp.f_pos = 0; - buf.filp.f_reada = 1; - buf.filp.f_flags = O_RDONLY; - buf.filp.f_dentry = dentry; - buf.filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + fill_new_filp (&buf.filp, dentry); buf.pos = 0; buf.size = 0; @@ -631,6 +719,8 @@ static int umsdos_find ( umsdos_manglename(info); } *pt_emd_dir = emd_dir; + + Printk (("umsdos_find: returning %d\n", ret)); return ret; } @@ -651,7 +741,7 @@ int umsdos_newentry ( ret = -EEXIST; }else if (ret == -ENOENT){ ret = umsdos_writeentry(dir,emd_dir,info,0); - Printk (("umsdos_newentry EDM ret = %d\n",ret)); + Printk (("umsdos_newentry EMD ret = %d\n",ret)); } iput (emd_dir); return ret; @@ -729,6 +819,8 @@ int umsdos_isempty (struct inode *dir) /* If the EMD file does not exist, it is certainly empty :-) */ if (emd_dir != NULL){ struct file filp; + fill_new_filp (&filp, NULL); + /* Find an empty slot */ memset (&filp, 0, sizeof (filp)); @@ -779,6 +871,7 @@ int umsdos_findentry ( } } iput (emd_dir); + Printk (("umsdos_findentry: returning %d\n", ret)); return ret; } diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 059a780e3114..e8b65558c30d 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -105,7 +105,7 @@ void umsdos_setup_dir_inode (struct inode *inode) inode->i_op = &umsdos_dir_inode_operations; } - iput (emd_dir); +/* iput (emd_dir); FIXME /mn/ ! */ } } @@ -119,9 +119,10 @@ void umsdos_set_dirinfo( off_t f_pos) { struct inode *emd_owner; - /* FIXME, I don't have a clue on this one */ - Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue\n")); + /* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */ +/* Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino));*/ emd_owner = umsdos_emd_dir_lookup(dir,1); + Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino)); inode->u.umsdos_i.i_dir_owner = dir->i_ino; inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; iput (emd_owner); @@ -317,10 +318,10 @@ void UMSDOS_write_inode(struct inode *inode) /* FIXME inode->i_dirt = 0; */ } -int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) + +int internal_notify_change(struct inode *inode, struct iattr *attr) { int ret = 0; - struct inode *inode = dentry->d_inode; Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n")); @@ -362,10 +363,15 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) }else{ struct file filp; struct umsdos_dirent entry; + struct dentry *emd_dentry; loff_t offs; - offs = 0; + + emd_dentry = creat_dentry ("notify_emd", 10, emd_owner); + fill_new_filp (&filp, emd_dentry); + filp.f_pos = inode->u.umsdos_i.pos; filp.f_reada = 0; + offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ Printk (("pos = %Lu ", filp.f_pos)); /* Read only the start of the entry since we don't touch */ /* the name */ @@ -386,7 +392,7 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) entry.nlink = inode->i_nlink; filp.f_pos = inode->u.umsdos_i.pos; - offs = 0; /* FIXME */ + offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); Printk (("notify pos %lu ret %d nlink %d " @@ -407,6 +413,15 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) return ret; } + +int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) +{ + return internal_notify_change (dentry->d_inode, attr); +} + + + + /* #Specification: function name / convention A simple convention for function name has been used in the UMSDOS file system. First all function use the prefix @@ -457,7 +472,7 @@ struct super_block *UMSDOS_read_super( PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb)); res = msdos_read_super(sb,data,silent); PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res)); - printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-1 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); + printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-2 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; } @@ -504,7 +519,7 @@ struct super_block *UMSDOS_read_super( The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h in the macro UMSDOS_PSDROOT_NAME. */ - struct dentry *root, *etc, *etc_rc, *init, *sbin; /* FIXME */ + struct dentry *root, *etc, *etc_rc, *init, *sbin; root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL); sbin = creat_dentry ("sbin", 4, NULL); diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index 76c48640578f..dcea137fe2fc 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -39,6 +39,7 @@ static int umsdos_waitcreate(struct inode *dir) } return ret; } + /* Wait for any lookup process to finish */ @@ -48,6 +49,7 @@ static void umsdos_waitlookup (struct inode *dir) sleep_on(&dir->u.umsdos_i.u.dir_info.p); } } + /* Lock all other process out of this directory. */ @@ -90,6 +92,7 @@ void umsdos_lockcreate (struct inode *dir) dir->u.umsdos_i.u.dir_info.pid = current->pid; umsdos_waitlookup (dir); } + /* Lock all other process out of those two directories. */ @@ -115,6 +118,7 @@ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) umsdos_waitlookup(dir1); umsdos_waitlookup(dir2); } + /* Wait until creation is finish in this directory. */ @@ -157,6 +161,7 @@ void umsdos_startlookup (struct inode *dir){} static void umsdos_unlockcreate (struct inode *dir){} void umsdos_endlookup (struct inode *dir){} #endif + static int umsdos_nevercreat( struct inode *dir, struct dentry *dentry, @@ -210,7 +215,11 @@ static int umsdos_create_any ( /* file */ { - int ret = umsdos_nevercreat(dir,dentry,-EEXIST); + int ret; + + Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino)); + ret = umsdos_nevercreat(dir,dentry,-EEXIST); + Printk (("%d/\n", ret)); if (ret == 0){ struct umsdos_info info; ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info); @@ -237,8 +246,8 @@ static int umsdos_create_any ( if (ret == 0){ struct inode *inode = dentry->d_inode; umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - Printk (("inode %p[%d] ",inode,inode->i_count)); - Printk (("Creation OK: [%lu] %.*s %d pos %ld\n", dir->i_ino, + Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count)); + Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino, info.fake.len, info.fake.fname, current->pid, info.f_pos)); }else{ /* #Specification: create / file exist in DOS @@ -276,9 +285,10 @@ static int umsdos_create_any ( umsdos_unlockcreate(dir); } } - d_add(dentry,dir); + /* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */ return ret; } + /* Initialise the new_entry from the old for a rename operation. (Only useful for umsdos_rename_f() below). @@ -425,6 +435,7 @@ static int umsdos_rename_f( Printk (("\n")); return ret; } + /* Setup un Symbolic link or a (pseudo) hard link Return a negative error code or 0 if ok. @@ -456,11 +467,13 @@ static int umsdos_symlink_x( if (ret == 0){ int len = strlen(symname); struct file filp; - filp.f_pos = 0; + loff_t myofs=0; + fill_new_filp (&filp, dentry); + /* Make the inode acceptable to MSDOS FIXME */ Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n")); - ret = umsdos_file_write_kmem (dentry->d_inode, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... - PTW dentry->d_inode is "less incorrect" */ + Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino)); + ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs); /* dput(dentry); ?? where did this come from FIXME */ if (ret >= 0){ if (ret != len){ @@ -480,6 +493,7 @@ static int umsdos_symlink_x( Printk (("\n")); return ret; } + /* Setup un Symbolic link. Return a negative error code or 0 if ok. @@ -492,6 +506,7 @@ int UMSDOS_symlink( { return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0); } + /* Add a link to an inode in a directory */ @@ -671,6 +686,9 @@ int UMSDOS_link ( Printk (("umsdos_link %d\n",ret)); return ret; } + + + /* Add a new file into the alternate directory. The file is added to the real MSDOS directory. If successful, it @@ -680,13 +698,16 @@ int UMSDOS_link ( */ int UMSDOS_create ( struct inode *dir, - struct dentry *dentry, /* Length of the name */ + struct dentry *dentry, int mode /* Permission bit + file type ??? */ ) /* Will hold the inode of the newly created */ /* file */ { return umsdos_create_any (dir,dentry,mode,0,0); } + + + /* Add a sub-directory in a directory */ @@ -735,7 +756,7 @@ int UMSDOS_mkdir( ret = compat_umsdos_real_lookup (dir,info.fake.fname, info.fake.len,&subdir); if (ret == 0){ - struct inode *result; +/* struct inode *result; FIXME /mn/ hmmm what is this supposed to be ? */ struct dentry *tdentry; tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); @@ -753,9 +774,10 @@ int UMSDOS_mkdir( } } Printk (("umsdos_mkdir %d\n",ret)); - dput (dentry); +/* dput (dentry); FIXME /mn/ */ return ret; } + /* Add a new device special file into a directory. */ @@ -779,8 +801,9 @@ int UMSDOS_mknod( for ordinary files was causing major trouble with hard link in particular and other parts of the kernel I guess. */ + int ret = umsdos_create_any (dir,dentry,mode,rdev,0); - dput(dentry); +/* dput(dentry); /mn/ FIXME! */ return ret; } @@ -952,13 +975,20 @@ int UMSDOS_unlink ( struct inode * dir, struct dentry *dentry) { - int ret = umsdos_nevercreat(dir,dentry,-EPERM); + int ret; + Printk ((" *** UMSDOS_unlink entering /mn/ *** \n")); + + ret = umsdos_nevercreat(dir,dentry,-EPERM); + + Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret)); + if (ret == 0){ struct umsdos_info info; ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); if (ret == 0){ umsdos_lockcreate(dir); ret = umsdos_findentry(dir,&info,1); + Printk (("UMSDOS_unlink: findentry returned %d\n", ret)); if (ret == 0){ Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname)); /* check sticky bit */ diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c index 38baba6ca2e5..3ed5507422d1 100644 --- a/fs/umsdos/symlink.c +++ b/fs/umsdos/symlink.c @@ -39,7 +39,8 @@ static int umsdos_readlink_x ( int ret; loff_t loffs = 0; struct file filp; - + + fill_new_filp (&filp, NULL); ret = dentry->d_inode->i_size; diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h index ab9b28f6e24c..333e5caebada 100644 --- a/include/asm-alpha/fpu.h +++ b/include/asm-alpha/fpu.h @@ -37,21 +37,21 @@ * compatibly. The corresponding definitions are in * /usr/include/machine/fpu.h under OSF/1. */ -#define IEEE_TRAP_ENABLE_INV (1<<1) /* invalid op */ -#define IEEE_TRAP_ENABLE_DZE (1<<2) /* division by zero */ -#define IEEE_TRAP_ENABLE_OVF (1<<3) /* overflow */ -#define IEEE_TRAP_ENABLE_UNF (1<<4) /* underflow */ -#define IEEE_TRAP_ENABLE_INE (1<<5) /* inexact */ +#define IEEE_TRAP_ENABLE_INV (1UL<<1) /* invalid op */ +#define IEEE_TRAP_ENABLE_DZE (1UL<<2) /* division by zero */ +#define IEEE_TRAP_ENABLE_OVF (1UL<<3) /* overflow */ +#define IEEE_TRAP_ENABLE_UNF (1UL<<4) /* underflow */ +#define IEEE_TRAP_ENABLE_INE (1UL<<5) /* inexact */ #define IEEE_TRAP_ENABLE_MASK (IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |\ IEEE_TRAP_ENABLE_OVF | IEEE_TRAP_ENABLE_UNF |\ IEEE_TRAP_ENABLE_INE) /* status bits coming from fpcr: */ -#define IEEE_STATUS_INV (1<<17) -#define IEEE_STATUS_DZE (1<<18) -#define IEEE_STATUS_OVF (1<<19) -#define IEEE_STATUS_UNF (1<<20) -#define IEEE_STATUS_INE (1<<21) +#define IEEE_STATUS_INV (1UL<<17) +#define IEEE_STATUS_DZE (1UL<<18) +#define IEEE_STATUS_OVF (1UL<<19) +#define IEEE_STATUS_UNF (1UL<<20) +#define IEEE_STATUS_INE (1UL<<21) #define IEEE_STATUS_MASK (IEEE_STATUS_INV | IEEE_STATUS_DZE | \ IEEE_STATUS_OVF | IEEE_STATUS_UNF | \ @@ -64,7 +64,7 @@ #define IEEE_INHERIT (1UL<<63) /* inherit on thread create? */ /* - * Convert the spftware IEEE trap enable and status bits into the + * Convert the software IEEE trap enable and status bits into the * hardware fpcr format. */ diff --git a/include/linux/coda.h b/include/linux/coda.h index 3faa2e9caaa5..5c3cb563e1fc 100644 --- a/include/linux/coda.h +++ b/include/linux/coda.h @@ -587,9 +587,9 @@ struct cfs_open_by_path_out { }; /* - * Occasionally, don't cache the fid returned by CFS_LOOKUP. For instance, if - * the fid is inconsistent. This case is handled by setting the top bit of the - * return result parameter. + * Occasionally, we don't cache the fid returned by CFS_LOOKUP. + * For instance, if the fid is inconsistent. + * This case is handled by setting the top bit of the type result parameter. */ #define CFS_NOCACHE 0x80000000 diff --git a/include/linux/coda_cache.h b/include/linux/coda_cache.h index 44251867fb82..fc607fdbadac 100644 --- a/include/linux/coda_cache.h +++ b/include/linux/coda_cache.h @@ -21,19 +21,16 @@ struct coda_cache { struct coda_cred cc_cred; }; -void coda_ccinsert(struct coda_cache *el, struct super_block *sb); -void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp); -void coda_ccremove(struct coda_cache *el); -void coda_cnremove(struct coda_cache *el); -void coda_cache_create(struct inode *inode, int mask); -struct coda_cache *coda_cache_find(struct inode *inode); +/* credential cache */ void coda_cache_enter(struct inode *inode, int mask); -void coda_cache_clear_cnp(struct coda_inode_info *cnp); +void coda_cache_clear_inode(struct inode *); void coda_cache_clear_all(struct super_block *sb); void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred); int coda_cache_check(struct inode *inode, int mask); -void coda_dentry_delete(struct dentry *dentry); -void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag); + +/* for downcalls and attributes and lookups */ +void coda_flag_inode(struct inode *inode, int flag); +void coda_flag_alias_children(struct inode *inode, int flag); /* diff --git a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h index 1277445b9e7f..d312013d5d9c 100644 --- a/include/linux/coda_fs_i.h +++ b/include/linux/coda_fs_i.h @@ -17,7 +17,7 @@ #define CODA_CNODE_MAGIC 0x47114711 /* - * smb fs inode data (in memory only) + * coda fs inode data */ struct coda_inode_info { struct ViceFid c_fid; /* Coda identifier */ @@ -36,7 +36,7 @@ struct coda_inode_info { #define C_VATTR 0x1 /* Validity of vattr in the cnode */ #define C_SYMLINK 0x2 /* Validity of symlink pointer in the cnode */ #define C_DYING 0x4 /* Set for outstanding cnodes from venus (which died) */ -#define C_ZAPFID 0x8 +#define C_PURGE 0x8 #define C_ZAPDIR 0x10 #define C_INITED 0x20 @@ -44,9 +44,6 @@ int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *); int coda_cnode_makectl(struct inode **inode, struct super_block *sb); struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb); -/* inode to cnode */ -#define ITOC(inode) ((struct coda_inode_info *)&((inode)->u.coda_i)) - #endif #endif diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h index fa477cb52a5f..9dd30eaeb3ea 100644 --- a/include/linux/coda_linux.h +++ b/include/linux/coda_linux.h @@ -36,6 +36,7 @@ extern struct file_operations coda_ioctl_operations; int coda_open(struct inode *i, struct file *f); int coda_release(struct inode *i, struct file *f); int coda_permission(struct inode *inode, int mask); +int coda_revalidate_inode(struct dentry *); /* global variables */ extern int coda_debug; @@ -43,10 +44,13 @@ extern int coda_print_entry; extern int coda_access_cache; /* this file: heloers */ +static __inline__ struct ViceFid *coda_i2f(struct inode *); char *coda_f2s(ViceFid *f); int coda_isroot(struct inode *i); int coda_fid_is_volroot(struct ViceFid *); int coda_iscontrol(const char *name, size_t length); + + void coda_load_creds(struct coda_cred *cred); int coda_mycred(struct coda_cred *); void coda_vattr_to_iattr(struct inode *, struct coda_vattr *); @@ -112,4 +116,18 @@ do { \ #define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %x at %x.\n", (int) size, (int) ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %x at %x.\n", (int) size, (int) ptr);} } while (0) +/* inode to cnode */ + +static __inline__ struct ViceFid *coda_i2f(struct inode *inode) +{ + return &(inode->u.coda_i.c_fid); +} + +#define ITOC(inode) (&((inode)->u.coda_i)) + + + + + + #endif diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h index 7eeb34a2c928..9b43579c0b80 100644 --- a/include/linux/hfs_fs.h +++ b/include/linux/hfs_fs.h @@ -301,6 +301,7 @@ extern int hfs_mac2seven(char *, const struct hfs_name *); extern int hfs_mac2eight(char *, const struct hfs_name *); extern int hfs_mac2alpha(char *, const struct hfs_name *); extern int hfs_mac2triv(char *, const struct hfs_name *); +extern void hfs_tolower(unsigned char *, int); #define HFS_I(X) (&((X)->u.hfs_i)) #define HFS_SB(X) (&((X)->u.hfs_sb)) diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index 03904df7163a..eb83cfe0191c 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -83,8 +83,15 @@ struct ncp_privatedata_ioctl }; #define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request) -#define NCP_IOC_GETMOUNTUID _IOW('n', 2, uid_t) -#define NCP_IOC_GETMOUNTUID_INT _IOW('n', 2, unsigned int) +#define NCP_IOC_GETMOUNTUID _IOW('n', 2, __kernel_uid_t) + +#if 1 +#ifdef __KERNEL__ +/* remove after ncpfs-2.0.13 gets released or at the beginning of kernel-2.1. codefreeze */ +#define NCP_IOC_GETMOUNTUID_INT _IOW('n', 2, unsigned int) +#endif +#endif + #define NCP_IOC_CONN_LOGGED_IN _IO('n', 3) #define NCP_GET_FS_INFO_VERSION (1) diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h index efcc20556dcc..38492fc92390 100644 --- a/include/linux/ncp_fs_sb.h +++ b/include/linux/ncp_fs_sb.h @@ -51,11 +51,9 @@ struct ncp_server { int ncp_reply_size; struct ncp_inode_info root; -#if 0 - char root_path; /* '\0' */ -#else struct dentry* root_dentry; -#endif + + int root_setuped; /* info for packet signing */ int sign_wanted; /* 1=Server needs signed packets */ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 7152aead4a88..b7550ba2cd00 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -169,6 +169,7 @@ enum NET_IPV4_IP_MASQ_DEBUG, NET_TCP_SYNCOOKIES, NET_TCP_STDURG, + NET_TCP_RFC1337, NET_TCP_SYN_TAILDROP, NET_TCP_MAX_SYN_BACKLOG, NET_IPV4_LOCAL_PORT_RANGE, diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p index 62ce67d0c5a7..7c0e64ec31ec 100644 --- a/include/linux/umsdos_fs.p +++ b/include/linux/umsdos_fs.p @@ -1,9 +1,6 @@ /* check.c 23/01/95 03.38.30 */ void check_page_tables (void); /* dir.c 22/06/95 00.22.12 */ -struct dentry *creat_dentry (const char *name, - const int len, - struct inode *inode); int compat_msdos_create(struct inode *dir, const char *name, int len, @@ -30,6 +27,16 @@ int UMSDOS_lookup(struct inode *dir,struct dentry *dentry); int umsdos_hlink2inode (struct inode *hlink, struct inode **result); /* emd.c 22/06/95 00.22.04 */ +void fill_new_filp (struct file *filp, struct dentry *dentry); +void kill_dentry (struct dentry *dentry); +struct dentry *creat_dentry (const char *name, + const int len, + struct inode *inode); +ssize_t umsdos_file_write_kmem_real (struct file *filp, + const char *buf, + size_t count, + loff_t *offs); + ssize_t umsdos_file_read_kmem (struct inode *emd_dir, struct file *filp, char *buf, diff --git a/include/net/dst.h b/include/net/dst.h index dc4b8ce670a4..0d18f60d2021 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -120,7 +120,7 @@ extern void dst_destroy(struct dst_entry * dst); extern __inline__ void dst_free(struct dst_entry * dst) { - if (dst->obsolete > 0) + if (dst->obsolete > 1) return; if (!atomic_read(&dst->use)) { dst_destroy(dst); diff --git a/include/net/tcp.h b/include/net/tcp.h index 3b04b7e4f4b3..cec01dfe6a4c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -552,6 +552,7 @@ extern void tcp_send_probe0(struct sock *); extern void tcp_send_partial(struct sock *); extern void tcp_write_wakeup(struct sock *); extern void tcp_send_fin(struct sock *sk); +extern void tcp_send_active_reset(struct sock *sk); extern int tcp_send_synack(struct sock *); extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue); extern void tcp_send_ack(struct sock *sk); @@ -804,9 +805,19 @@ extern __inline__ int tcp_syn_build_options(struct sk_buff *skb, int mss, int ts unsigned char *optr = skb_put(skb,count); __u32 *ptr = (__u32 *)optr; - /* - * We always get an MSS option. + /* We always get an MSS option. + * The option bytes which will be seen in normal data + * packets should timestamps be used, must be in the MSS + * advertised. But we subtract them from sk->mss so + * that calculations in tcp_sendmsg are simpler etc. + * So account for this fact here if necessary. If we + * don't do this correctly, as a receiver we won't + * recognize data packets as being full sized when we + * should, and thus we won't abide by the delayed ACK + * rules correctly. */ + if(ts) + mss += TCPOLEN_TSTAMP_ALIGNED; *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss); if (ts) { *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | diff --git a/ipc/msg.c b/ipc/msg.c index 806f692dd580..30fe31239804 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -40,39 +40,6 @@ __initfunc(void msg_init (void)) return; } -/* - * If the send queue is full, try to free any old messages. - * These are most probably unwanted, since no one has picked them up... - */ -#define MSG_FLUSH_TIME 10 /* seconds */ -static void flush_msg(struct msqid_ds *msq) -{ - struct msg *nmsg; - unsigned long flags; - int flushed = 0; - - save_flags(flags); - cli(); - - /* messages were put on the queue in time order */ - while ( (nmsg = msq->msg_first) && - ((CURRENT_TIME - nmsg->msg_stime) > MSG_FLUSH_TIME)) { - msgbytes -= nmsg->msg_ts; - msghdrs--; - msq->msg_cbytes -= nmsg->msg_ts; - msq->msg_qnum--; - msq->msg_first = nmsg->msg_next; - ++flushed; - kfree(nmsg); - } - - if (msq->msg_qnum == 0) - msq->msg_first = msq->msg_last = NULL; - restore_flags(flags); - if (flushed) - printk(KERN_WARNING "flushed %d old SYSVIPC messages", flushed); -} - static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { int id, err; diff --git a/kernel/sched.c b/kernel/sched.c index 09e0a31d9d5c..a86cb0413fdc 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -155,9 +155,9 @@ static inline void move_last_runqueue(struct task_struct * p) * The run-queue lock locks the parts that actually access * and change the run-queues, and have to be interrupt-safe. */ -rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; -spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED; -spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; +spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED; /* should be aquired first */ +spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; /* second */ +rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; /* third */ /* * Wake up a process. Put it on the run-queue if it's not @@ -1272,50 +1272,70 @@ static int setscheduler(pid_t pid, int policy, { struct sched_param lp; struct task_struct *p; + int retval; + retval = -EINVAL; if (!param || pid < 0) - return -EINVAL; + goto out_nounlock; + retval = -EFAULT; if (copy_from_user(&lp, param, sizeof(struct sched_param))) - return -EFAULT; + goto out_nounlock; + /* + * We play safe to avoid deadlocks. + */ + spin_lock_irq(&scheduler_lock); + spin_lock(&runqueue_lock); read_lock(&tasklist_lock); + p = find_process_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!!! */ + + retval = -ESRCH; if (!p) - return -ESRCH; + goto out_unlock; if (policy < 0) policy = p->policy; - else if (policy != SCHED_FIFO && policy != SCHED_RR && - policy != SCHED_OTHER) - return -EINVAL; + else { + retval = -EINVAL; + if (policy != SCHED_FIFO && policy != SCHED_RR && + policy != SCHED_OTHER) + goto out_unlock; + } /* * Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid * priority for SCHED_OTHER is 0. */ + retval = -EINVAL; if (lp.sched_priority < 0 || lp.sched_priority > 99) - return -EINVAL; + goto out_unlock; if ((policy == SCHED_OTHER) != (lp.sched_priority == 0)) - return -EINVAL; + goto out_unlock; + retval = -EPERM; if ((policy == SCHED_FIFO || policy == SCHED_RR) && !suser()) - return -EPERM; + goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && !suser()) - return -EPERM; + goto out_unlock; + retval = 0; p->policy = policy; p->rt_priority = lp.sched_priority; - spin_lock(&scheduler_lock); - spin_lock_irq(&runqueue_lock); if (p->next_run) move_last_runqueue(p); - spin_unlock_irq(&runqueue_lock); - spin_unlock(&scheduler_lock); + need_resched = 1; - return 0; + +out_unlock: + read_unlock(&tasklist_lock); + spin_unlock(&runqueue_lock); + spin_unlock_irq(&scheduler_lock); + +out_nounlock: + return retval; } asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, @@ -1332,35 +1352,57 @@ asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param) asmlinkage int sys_sched_getscheduler(pid_t pid) { struct task_struct *p; + int retval; + retval = -EINVAL; if (pid < 0) - return -EINVAL; + goto out_nounlock; read_lock(&tasklist_lock); + + retval = -ESRCH; p = find_process_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!!! */ if (!p) - return -ESRCH; + goto out_unlock; - return p->policy; + retval = p->policy; + +out_unlock: + read_unlock(&tasklist_lock); + +out_nounlock: + return retval; } asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param) { struct task_struct *p; struct sched_param lp; + int retval; + retval = -EINVAL; if (!param || pid < 0) - return -EINVAL; + goto out_nounlock; read_lock(&tasklist_lock); p = find_process_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!!! */ + retval = -ESRCH; if (!p) - return -ESRCH; - + goto out_unlock; lp.sched_priority = p->rt_priority; - return copy_to_user(param, &lp, sizeof(struct sched_param)) ? -EFAULT : 0; + read_unlock(&tasklist_lock); + + /* + * This one might sleep, we cannot do it with a spinlock held ... + */ + retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0; + +out_nounlock: + return retval; + +out_unlock: + read_unlock(&tasklist_lock); + return retval; } asmlinkage int sys_sched_yield(void) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c3aef902f073..caafa61c5889 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -330,9 +330,9 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e i = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT+7); if (i < 48) i = 48; - min_free_pages = i; - free_pages_low = i + (i>>1); - free_pages_high = i + i; + freepages.min = i; + freepages.low = i + (i>>1); + freepages.high = i + i; mem_map = (mem_map_t *) LONG_ALIGN(start_mem); p = mem_map + MAP_NR(end_mem); start_mem = LONG_ALIGN((unsigned long) p); diff --git a/net/802/tr.c b/net/802/tr.c index 5f7dc656d526..3550b81ed8ff 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -532,4 +532,3 @@ __initfunc(void rif_init(struct net_proto *unused)) proc_net_register(&tr_rif_proc); #endif } -} diff --git a/net/core/dst.c b/net/core/dst.c index e94ef29675da..4cad680c2564 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -101,7 +101,7 @@ void * dst_alloc(int size, struct dst_ops * ops) void __dst_free(struct dst_entry * dst) { start_bh_atomic(); - dst->obsolete = 1; + dst->obsolete = 2; dst->next = dst_garbage_list; dst_garbage_list = dst; if (dst_gc_timer_inc > DST_GC_INC) { diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 9edb759b9a1b..a8d72604d775 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1240,7 +1240,7 @@ struct neigh_sysctl_table &proc_dointvec}, {0}}, - {{1, "default", NULL, 0, 0555, NULL},{0}}, + {{NET_PROTO_CONF_DEFAULT, "default", NULL, 0, 0555, NULL},{0}}, {{0, "neigh", NULL, 0, 0555, NULL},{0}}, {{0, NULL, NULL, 0, 0555, NULL},{0}}, {{CTL_NET, "net", NULL, 0, 0555, NULL},{0}} @@ -1255,10 +1255,11 @@ int neigh_sysctl_register(struct device *dev, struct neigh_parms *p, if (t == NULL) return -ENOBUFS; memcpy(t, &neigh_sysctl_template, sizeof(*t)); + t->neigh_vars[0].data = &p->mcast_probes; t->neigh_vars[1].data = &p->ucast_probes; t->neigh_vars[2].data = &p->app_probes; t->neigh_vars[3].data = &p->retrans_time; - t->neigh_vars[4].data = &p->reachable_time; + t->neigh_vars[4].data = &p->base_reachable_time; t->neigh_vars[5].data = &p->delay_probe_time; t->neigh_vars[6].data = &p->gc_staletime; t->neigh_vars[7].data = &p->queue_len; @@ -1268,7 +1269,7 @@ int neigh_sysctl_register(struct device *dev, struct neigh_parms *p, t->neigh_vars[11].data = &p->locktime; if (dev) { t->neigh_dev[0].procname = dev->name; - t->neigh_dev[0].ctl_name = dev->ifindex+1; + t->neigh_dev[0].ctl_name = dev->ifindex; memset(&t->neigh_vars[12], 0, sizeof(ctl_table)); } else { t->neigh_vars[12].data = (&p->locktime) + 1; diff --git a/net/ipv4/ip_fw.c b/net/ipv4/ip_fw.c index 7502f6e4aa21..2618d2a42448 100644 --- a/net/ipv4/ip_fw.c +++ b/net/ipv4/ip_fw.c @@ -6,7 +6,7 @@ * license in recognition of the original copyright. * -- Alan Cox. * - * $Id: ip_fw.c,v 1.32 1998/02/23 02:50:17 davem Exp $ + * $Id: ip_fw.c,v 1.33 1998/03/15 03:31:43 davem Exp $ * * Ported from BSD to Linux, * Alan Cox 22/Nov/1994. @@ -392,6 +392,39 @@ int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_ continue; /* Mismatch */ } + /* This looks stupid, because we scan almost static + list, searching for static key. However, this way seems + to be only reasonable way of handling fw_via rules + (btw bsd makes the same thing). + + It will not affect performance if you will follow + the following simple rules: + + - if inteface is aliased, ALWAYS specify fw_viadev, + so that previous check will guarantee, that we will + not waste time when packet arrive on another interface. + + - avoid using fw_via.s_addr if fw_via.s_addr is owned + by an aliased interface. + + --ANK + */ + if (f->fw_via.s_addr && rif) { + struct in_ifaddr *ifa; + + if (rif->ip_ptr == NULL) + continue; /* Mismatch */ + + for (ifa = ((struct in_device*)(rif->ip_ptr))->ifa_list; + ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_local == f->fw_via.s_addr) + goto ifa_ok; + } + continue; /* Mismatch */ + + ifa_ok: + } + /* * Ok the chain addresses match. */ diff --git a/net/ipv4/ip_nat_dumb.c b/net/ipv4/ip_nat_dumb.c index 06e9be8fb2fc..07a7afc23cb0 100644 --- a/net/ipv4/ip_nat_dumb.c +++ b/net/ipv4/ip_nat_dumb.c @@ -5,7 +5,7 @@ * * Dumb Network Address Translation. * - * Version: $Id: ip_nat_dumb.c,v 1.2 1997/10/10 22:41:05 davem Exp $ + * Version: $Id: ip_nat_dumb.c,v 1.3 1998/03/15 03:31:44 davem Exp $ * * Authors: Alexey Kuznetsov, * @@ -14,6 +14,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * + * Fixes: + * Rani Assaf : A zero checksum is a special case + * only in UDP * * NOTE: It is just working model of real NAT. */ @@ -49,7 +52,6 @@ ip_do_nat(struct sk_buff *skb) u32 odaddr = iph->daddr; u32 osaddr = iph->saddr; u16 check; - u16 *cksum = NULL; IPCB(skb)->flags |= IPSKB_TRANSLATED; @@ -62,17 +64,23 @@ ip_do_nat(struct sk_buff *skb) /* If it is the first fragment, rewrite protocol headers */ if (!(iph->frag_off & htons(IP_OFFSET))) { - /* Only plain TCP/UDP headers rewriting is implemented :-( */ - if (iph->protocol == IPPROTO_TCP) - cksum = (u16*)&((struct tcphdr*)(((char*)iph) + iph->ihl*4))->check; - else if (iph->protocol == IPPROTO_UDP) - cksum = (u16*)&((struct udphdr*)(((char*)iph) + iph->ihl*4))->check; - if (cksum && (check = *cksum) != 0) { - check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check); - check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); - if (!check) - check = 0xFFFF; - *cksum = check; + u16 *cksum; + + switch(iph->protocol) { + case IPPROTO_TCP: + cksum = (u16*)&((struct tcphdr*)(((char*)iph) + iph->ihl*4))->check; + check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum)); + *cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); + break; + case IPPROTO_UDP: + cksum = (u16*)&((struct udphdr*)(((char*)iph) + iph->ihl*4))->check; + if ((check = *cksum) != 0) { + check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check); + check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check); + *cksum = check ? : 0xFFFF; + } + default: + break; } } return 0; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 31c0a71eef7e..1fb796a74e10 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.27 1998/03/12 00:03:31 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.28 1998/03/15 03:23:21 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -55,7 +55,8 @@ extern int sysctl_tcp_retries2; extern int sysctl_tcp_fin_timeout; extern int sysctl_tcp_syncookies; extern int sysctl_tcp_syn_retries; -extern int sysctl_tcp_stdurg; +extern int sysctl_tcp_stdurg; +extern int sysctl_tcp_rfc1337; extern int sysctl_tcp_syn_taildrop; extern int sysctl_max_syn_backlog; @@ -154,6 +155,8 @@ ctl_table ipv4_table[] = { #endif {NET_TCP_STDURG, "tcp_stdurg", &sysctl_tcp_stdurg, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_RFC1337, "tcp_rfc1337", &sysctl_tcp_rfc1337, + sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_SYN_TAILDROP, "tcp_syn_taildrop", &sysctl_tcp_syn_taildrop, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_MAX_SYN_BACKLOG, "tcp_max_syn_backlog", &sysctl_max_syn_backlog, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 133bda9d9069..b20df83d25ad 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.94 1998/03/13 14:15:52 davem Exp $ + * Version: $Id: tcp.c,v 1.96 1998/03/16 02:25:55 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1044,7 +1044,8 @@ static void cleanup_rbuf(struct sock *sk, int copied) /* We send an ACK if we can now advertise a non-zero window * which has been raised "significantly". */ - if(copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp)) + if((copied > 0) && + (copied >= tcp_receive_window(&sk->tp_pinfo.af_tcp))) tcp_read_wakeup(sk); } @@ -1372,6 +1373,7 @@ static inline int closing(struct sock * sk) void tcp_close(struct sock *sk, unsigned long timeout) { struct sk_buff *skb; + int data_was_unread = 0; /* We need to grab some memory, and put together a FIN, * and then put it into the queue to be sent. @@ -1396,14 +1398,30 @@ void tcp_close(struct sock *sk, unsigned long timeout) * descriptor close, not protocol-sourced closes, because the * reader process may not have drained the data yet! */ - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) + while((skb=skb_dequeue(&sk->receive_queue))!=NULL) { + data_was_unread++; kfree_skb(skb); + } - /* Timeout is not the same thing - however the code likes - * to send both the same way (sigh). + /* As outlined in draft-ietf-tcpimpl-prob-03.txt, section + * 3.10, we send a RST here because data was lost. To + * witness the awful effects of the old behavior of always + * doing a FIN, run an older 2.1.x kernel or 2.0.x, start + * a bulk GET in an FTP client, suspend the process, wait + * for the client to advertise a zero window, then kill -9 + * the FTP client, wheee... Note: timeout is always zero + * in such a case. */ - if (tcp_close_state(sk,1)) + if(data_was_unread != 0) { + /* Unread data was tossed, zap the connection. */ + tcp_set_state(sk, TCP_CLOSE); + tcp_send_active_reset(sk); + } else if (tcp_close_state(sk,1)) { + /* We FIN if the application ate all the data before + * zapping the connection. + */ tcp_send_fin(sk); + } if (timeout) { struct task_struct *tsk = current; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3263d2dac4af..4b7dcc9e9ac2 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.81 1998/03/14 06:09:54 davem Exp $ + * Version: $Id: tcp_input.c,v 1.84 1998/03/15 03:23:20 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -77,6 +77,7 @@ int sysctl_tcp_cong_avoidance; int sysctl_tcp_hoe_retransmits; int sysctl_tcp_syncookies = SYNC_INIT; int sysctl_tcp_stdurg; +int sysctl_tcp_rfc1337; static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj; @@ -451,9 +452,8 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup) * not indicate a packet left the system. * We can test this by just checking * if ack changed from snd_una, since - * the only way to get here without changing - * advancing from snd_una is if this was a - * window update. + * the only way to get here without advancing + * from snd_una is if this was a window update. */ if (ack != tp->snd_una && before(ack,tp->high_seq)) { tcp_do_retransmit(sk, 0); @@ -599,13 +599,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq, int acked = 0; while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) { -#ifdef TCP_DEBUG - /* Check for a bug. */ - if (skb->next != (struct sk_buff*) &sk->write_queue && - after(skb->end_seq, skb->next->seq)) - printk(KERN_DEBUG "INET: tcp_input.c: *** " - "bug send_list out of order.\n"); -#endif /* If our packet is before the ack sequence we can * discard it as it's confirmed to have arrived the * other end. @@ -613,11 +606,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq, if (after(skb->end_seq, ack)) break; -#if 0 - SOCK_DEBUG(sk, "removing seg %x-%x from retransmit queue\n", - skb->seq, skb->end_seq); -#endif - acked = FLAG_DATA_ACKED; + /* Initial outgoing SYN's get put onto the write_queue + * just like anything else we transmit. It is not + * true data, and if we misinform our callers that + * this ACK acks real data, we will erroneously exit + * connection startup slow start one packet too + * quickly. This is severely frowned upon behavior. + */ + if(!skb->h.th->syn) + acked = FLAG_DATA_ACKED; /* FIXME: packet counting may break if we have to * do packet "repackaging" for stacks that don't @@ -918,7 +915,8 @@ int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb, * Oh well... nobody has a sufficient solution to this * protocol bug yet. */ - tcp_timewait_kill((unsigned long)tw); + if(sysctl_tcp_rfc1337 == 0) + tcp_timewait_kill((unsigned long)tw); if(!th->rst) return 1; /* toss a reset back */ @@ -1725,9 +1723,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, /* Can't be earlier, doff would be wrong. */ tcp_send_ack(sk); - if (tp->in_mss) - sk->mss = min(sk->mss, tp->in_mss); - /* Check for the case where we tried to advertise * a window including timestamp options, but did not * end up using them for this connection. @@ -1735,6 +1730,21 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if((tp->tstamp_ok == 0) && sysctl_tcp_timestamps) sk->mss += TCPOLEN_TSTAMP_ALIGNED; + /* Now limit it if the other end negotiated a smaller + * value. + */ + if (tp->in_mss) { + int real_mss = tp->in_mss; + + /* We store MSS locally with the timestamp bytes + * subtracted, TCP's advertise it with them + * included. Account for this fact. + */ + if(tp->tstamp_ok) + real_mss -= TCPOLEN_TSTAMP_ALIGNED; + sk->mss = min(sk->mss, real_mss); + } + sk->dummy_th.dest = th->source; tp->copied_seq = tp->rcv_nxt; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ced7f998be84..91f21ff75518 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.106 1998/03/13 14:15:54 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.109 1998/03/15 07:24:15 davem Exp $ * * IPv4 specific functions * @@ -213,16 +213,17 @@ go_like_smoke: unsigned short tcp_good_socknum(void) { struct tcp_bind_bucket *tb; - int remaining = sysctl_local_port_range[1] - sysctl_local_port_range[0]; + int low = sysctl_local_port_range[0]; + int high = sysctl_local_port_range[1]; + int remaining = high - low; int rover; SOCKHASH_LOCK(); rover = tcp_port_rover; do { rover += 1; - if(rover < sysctl_local_port_range[0] || - rover > sysctl_local_port_range[1]) - rover = sysctl_local_port_range[0]; + if((rover < low) || (rover > high)) + rover = low; tb = tcp_bound_hash[tcp_bhashfn(rover)]; for( ; tb; tb = tb->next) { if(tb->port == rover) @@ -1072,6 +1073,10 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req) mss = (skb->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr)); if (sk->user_mss) mss = min(mss, sk->user_mss); + if(req->tstamp_ok) + mss -= TCPOLEN_TSTAMP_ALIGNED; + else + req->mss += TCPOLEN_TSTAMP_ALIGNED; /* tcp_syn_build_options will do an skb_put() to obtain the TCP * options bytes below. @@ -1238,9 +1243,11 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0; tp.in_mss = 536; tcp_parse_options(th,&tp,want_cookie); - if (tp.saw_tstamp) - req->ts_recent = tp.rcv_tsval; req->mss = tp.in_mss; + if (tp.saw_tstamp) { + req->mss -= TCPOLEN_TSTAMP_ALIGNED; + req->ts_recent = tp.rcv_tsval; + } req->tstamp_ok = tp.tstamp_ok; req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; @@ -1802,6 +1809,9 @@ struct tcp_func ipv4_specific = { sizeof(struct sockaddr_in) }; +/* NOTE: A lot of things set to zero explicitly by call to + * sk_alloc() so need not be done here. + */ static int tcp_v4_init_sock(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -1809,23 +1819,11 @@ static int tcp_v4_init_sock(struct sock *sk) skb_queue_head_init(&tp->out_of_order_queue); tcp_init_xmit_timers(sk); - tp->srtt = 0; tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/ tp->mdev = TCP_TIMEOUT_INIT; - - tp->ato = 0; - - /* FIXME: tie this to sk->rcvbuf? (May be unnecessary) */ - /* tp->rcv_wnd = 8192; */ - tp->tstamp_ok = 0; - tp->wscale_ok = 0; tp->in_mss = 536; - tp->snd_wscale = 0; - tp->saw_tstamp = 0; - tp->syn_backlog = 0; - /* - * See draft-stevens-tcpca-spec-01 for discussion of the + /* See draft-stevens-tcpca-spec-01 for discussion of the * initialization of these values. */ tp->snd_cwnd = 1; @@ -1833,9 +1831,7 @@ static int tcp_v4_init_sock(struct sock *sk) sk->priority = 1; sk->state = TCP_CLOSE; - sk->max_ack_backlog = SOMAXCONN; - sk->mtu = 576; sk->mss = 536; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2d278aa73ab0..d8c3c64805ff 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.63 1998/03/13 14:15:55 davem Exp $ + * Version: $Id: tcp_output.c,v 1.65 1998/03/15 12:07:03 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -291,7 +291,8 @@ void tcp_write_xmit(struct sock *sk) size = skb->len - (((unsigned char*)th) - skb->data); } - tp->last_ack_sent = th->ack_seq = htonl(tp->rcv_nxt); + tp->last_ack_sent = tp->rcv_nxt; + th->ack_seq = htonl(tp->rcv_nxt); th->window = rcv_wnd; tcp_update_options((__u32 *)(th + 1),tp); @@ -675,6 +676,41 @@ update_write_seq: tp->write_seq++; } +/* We get here when a process closes a file descriptor (either due to + * an explicit close() or as a byproduct of exit()'ing) and there + * was unread data in the receive queue. This behavior is recommended + * by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM + */ +void tcp_send_active_reset(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + struct sk_buff *skb; + struct tcphdr *th; + +again: + /* NOTE: No TCP options attached and we never retransmit this. */ + skb = sock_wmalloc(sk, (BASE_ACK_SIZE + sizeof(*th)), 1, GFP_KERNEL); + if(skb == NULL) + goto again; + skb->csum = 0; + if(tp->af_specific->build_net_header(sk, skb) < 0) { + kfree_skb(skb); + } else { + th = (struct tcphdr *) skb_put(skb, sizeof(*th)); + memcpy(th, &(sk->dummy_th), sizeof(*th)); + th->seq = htonl(tp->write_seq); + th->rst = 1; + th->doff = sizeof(*th) / 4; + tp->last_ack_sent = tp->rcv_nxt; + th->ack_seq = htonl(tp->rcv_nxt); + th->window = htons(tcp_select_window(sk)); + tp->af_specific->send_check(sk, th, sizeof(*th), skb); + tp->af_specific->queue_xmit(skb); + tcp_statistics.TcpOutSegs++; + tcp_statistics.TcpOutRsts++; + } +} + /* WARNING: This routine must only be called when we have already sent * a SYN packet that crossed the incoming SYN that caused this routine * to get called. If this assumption fails then the initial rcv_wnd diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 498d4d5b4fab..5188de8648ef 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: route.c,v 1.24 1998/03/08 20:52:50 davem Exp $ + * $Id: route.c,v 1.25 1998/03/15 03:31:47 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -709,7 +709,7 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err) if (rt == NULL) { RDBG(("dalloc fails, ")); *err = -ENOMEM; - goto out; + return NULL; } rt->u.dst.obsolete = -1; @@ -751,7 +751,7 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err) dev = dev_get("lo"); rt->u.dst.output = ip6_pkt_discard; rt->u.dst.input = ip6_pkt_discard; - rt->u.dst.error = -EHOSTUNREACH; + rt->u.dst.error = -ENETUNREACH; rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; rt->rt6i_metric = rtmsg->rtmsg_metric; rt->rt6i_dev = dev; @@ -788,7 +788,7 @@ struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err) } dev = grt->rt6i_dev; } - if (dev == NULL) { + if (dev == NULL || (dev->flags&IFF_LOOPBACK)) { *err = -EINVAL; goto out; } @@ -1688,7 +1688,8 @@ static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, rtmsg->rtmsg_dst_len = r->rtm_dst_len; rtmsg->rtmsg_src_len = r->rtm_src_len; rtmsg->rtmsg_flags = RTF_UP; - rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; + if (r->rtm_type == RTN_UNREACHABLE) + rtmsg->rtmsg_flags |= RTF_REJECT; if (rta[RTA_GATEWAY-1]) { if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16)) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bfaaa93bfd14..1d082c1958dd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.59 1998/03/13 08:02:20 davem Exp $ + * $Id: tcp_ipv6.c,v 1.60 1998/03/15 02:59:32 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -475,15 +475,20 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, release_sock(sk); - buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL); - - if (buff == NULL) + buff = sock_wmalloc(sk, (MAX_SYN_SIZE + sizeof(struct sk_buff)), + 0, GFP_KERNEL); + if (buff == NULL) { + /* FIXME: Free route references etc??? */ return(-ENOMEM); + } lock_sock(sk); tcp_v6_build_header(sk, buff); + tp->tcp_header_len = sizeof(struct tcphdr) + + (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); + /* build the tcp header */ th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr)); buff->h.th = th; @@ -498,7 +503,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, sk->mtu = dst->pmtu; - sk->mss = sk->mtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr); + sk->mss = (sk->mtu - sizeof(struct ipv6hdr) - tp->tcp_header_len); if (sk->mss < 1) { printk(KERN_DEBUG "intial ipv6 sk->mss below 1\n"); @@ -542,12 +547,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, tp->packets_out++; buff->when = jiffies; skb1 = skb_clone(buff, GFP_KERNEL); - skb_set_owner_w(skb1, sk); - - tcp_v6_xmit(skb1); + if(skb1 != NULL) { + skb_set_owner_w(skb1, sk); + tcp_v6_xmit(skb1); + } /* Timer for repeating the SYN until an answer */ - tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto); tcp_statistics.TcpActiveOpens++; tcp_statistics.TcpOutSegs++; @@ -660,11 +665,14 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info, ip6_dst_store(sk, dst); } - if (sk->dst_cache->error) + if (sk->dst_cache->error) { sk->err_soft = sk->dst_cache->error; - else + } else { + /* FIXME: Reset sk->mss, taking into account TCP option + * bytes for timestamps. -DaveM + */ sk->mtu = sk->dst_cache->pmtu; - + } if (sk->sock_readers) { /* remove later */ printk(KERN_DEBUG "tcp_v6_err: pmtu disc: socket locked.\n"); return; @@ -777,11 +785,10 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req) * match what happens under IPV4. Figure out the right thing to do. */ req->mss = min(sk->mss, req->mss); - - if (req->mss < 1) { - printk(KERN_DEBUG "initial req->mss below 1\n"); - req->mss = 1; - } + if(sk->user_mss) + req->mss = min(req->mss, sk->user_mss); + if(req->tstamp_ok == 0) + req->mss += TCPOLEN_TSTAMP_ALIGNED; if (req->rcv_wnd == 0) { __u8 rcv_wscale; @@ -872,9 +879,11 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, tp.tstamp_ok = tp.wscale_ok = tp.snd_wscale = 0; tp.in_mss = 536; tcp_parse_options(skb->h.th,&tp,0); - if (tp.saw_tstamp) - req->ts_recent = tp.rcv_tsval; req->mss = tp.in_mss; + if (tp.saw_tstamp) { + req->mss -= TCPOLEN_TSTAMP_ALIGNED; + req->ts_recent = tp.rcv_tsval; + } req->tstamp_ok = tp.tstamp_ok; req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; @@ -993,8 +1002,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (newtp->tstamp_ok) { newtp->ts_recent = req->ts_recent; newtp->ts_recent_stamp = jiffies; - newtp->tcp_header_len = sizeof(struct tcphdr) + 12; /* FIXME: define constant! */ - newsk->dummy_th.doff += 3; + newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; + newsk->dummy_th.doff += (TCPOLEN_TSTAMP_ALIGNED >> 2); } else { newtp->tcp_header_len = sizeof(struct tcphdr); } @@ -1391,6 +1400,9 @@ static struct tcp_func ipv6_mapped = { sizeof(struct sockaddr_in6) }; +/* NOTE: A lot of things set to zero explicitly by call to + * sk_alloc() so need not be done here. + */ static int tcp_v6_init_sock(struct sock *sk) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); @@ -1398,41 +1410,24 @@ static int tcp_v6_init_sock(struct sock *sk) skb_queue_head_init(&tp->out_of_order_queue); tcp_init_xmit_timers(sk); - tp->srtt = 0; tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/ tp->mdev = TCP_TIMEOUT_INIT; - - tp->ato = 0; - - /* FIXME: right thing? */ - tp->rcv_wnd = 0; tp->in_mss = 536; - /* tp->rcv_wnd = 8192; */ - tp->tstamp_ok = 0; - tp->wscale_ok = 0; - tp->snd_wscale = 0; - tp->saw_tstamp = 0; - tp->syn_backlog = 0; - - /* start with only sending one packet at a time. */ + + /* See draft-stevens-tcpca-spec-01 for discussion of the + * initialization of these values. + */ tp->snd_cwnd = 1; tp->snd_ssthresh = 0x7fffffff; - - sk->priority = 1; sk->state = TCP_CLOSE; - sk->max_ack_backlog = SOMAXCONN; - sk->mtu = 576; sk->mss = 536; - sk->dummy_th.doff = sizeof(sk->dummy_th)/4; - /* - * Speed up by setting some standard state for the dummy_th. - */ + /* Speed up by setting some standard state for the dummy_th. */ sk->dummy_th.ack=1; sk->dummy_th.doff=sizeof(struct tcphdr)>>2; -- 2.39.5