From 971c8cf06019d4ef23b5e730dd6188ffc8db8544 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:40:27 -0500 Subject: [PATCH] - Andries Brouwer: final isofs pieces. - Kai Germaschewski: ISDN - play CD audio correctly, don't stop after 12 minutes. - Anton Altaparmakov: disable NTFS mmap for now, as it doesn't work. - Stephen Tweedie: fix inode dirty block handling - Bill Hartner: reschedule_idle - prefer right cpu - Johannes Erdfelt: USB updates - Alan Cox: synchronize - Richard Henderson: alpha updates and optimizations - Geert Uytterhoeven: fbdev could be fooled into crashing fix - Trond Myklebust: NFS filehandles in inode rather than dentry --- Documentation/SubmittingDrivers | 18 +- Documentation/SubmittingPatches | 286 +++++++++++++++++ Documentation/filesystems/devfs/README | 4 +- Documentation/initrd.txt | 350 +++++++++++--------- Documentation/sound/CMI8330 | 2 +- Makefile | 1 - arch/alpha/Makefile | 12 +- arch/alpha/config.in | 15 +- arch/alpha/kernel/pci.c | 6 +- arch/alpha/lib/Makefile | 43 ++- arch/alpha/lib/ev6-clear_user.S | 228 +++++++++++++ arch/alpha/lib/ev6-copy_user.S | 262 +++++++++++++++ arch/alpha/lib/ev6-csum_ipv6_magic.S | 126 ++++++++ arch/alpha/lib/ev6-divide.S | 259 +++++++++++++++ arch/alpha/lib/ev6-strcpy.S | 23 ++ arch/alpha/lib/ev6-strncpy.S | 36 +++ arch/alpha/lib/ev6-strncpy_from_user.S | 425 +++++++++++++++++++++++++ arch/alpha/lib/ev67-strcat.S | 54 ++++ arch/alpha/lib/ev67-strchr.S | 88 +++++ arch/alpha/lib/ev67-strlen.S | 49 +++ arch/alpha/lib/ev67-strlen_user.S | 109 +++++++ arch/alpha/lib/ev67-strncat.S | 94 ++++++ arch/arm/kernel/traps.c | 6 - arch/i386/kernel/irq.c | 2 +- arch/i386/kernel/setup.c | 2 +- arch/i386/kernel/smpboot.c | 8 +- arch/i386/kernel/traps.c | 12 - arch/ia64/kernel/irq.c | 2 +- arch/m68k/mac/baboon.c | 2 - arch/m68k/mac/config.c | 2 - arch/m68k/mac/macints.c | 2 - arch/m68k/mac/oss.c | 1 - arch/m68k/mac/psc.c | 2 - arch/m68k/mac/via.c | 1 - arch/mips/kernel/traps.c | 13 - arch/mips64/kernel/traps.c | 13 - arch/s390/kernel/traps.c | 6 - arch/sh/kernel/traps.c | 6 - drivers/block/ll_rw_blk.c | 8 +- drivers/char/adbmouse.c | 1 - drivers/char/applicom.c | 2 +- drivers/char/drm/mga_dma.c | 6 +- drivers/char/drm/mga_drv.c | 2 +- drivers/char/drm/mga_drv.h | 4 +- drivers/char/mixcomwd.c | 2 +- drivers/char/moxa.c | 2 +- drivers/char/rio/host.h | 2 +- drivers/char/riscom8.c | 72 +++-- drivers/char/riscom8.h | 2 +- drivers/char/sysrq.c | 1 - drivers/ide/ide-cd.c | 6 +- drivers/isdn/hisax/avm_pci.c | 6 +- drivers/isdn/hisax/bkm_a4t.c | 6 +- drivers/isdn/hisax/bkm_a8.c | 16 +- drivers/isdn/hisax/config.c | 18 +- drivers/isdn/hisax/diva.c | 10 +- drivers/isdn/hisax/gazel.c | 6 +- drivers/isdn/hisax/niccy.c | 6 +- drivers/isdn/hisax/nj_s.c | 6 +- drivers/isdn/hisax/nj_u.c | 6 +- drivers/isdn/hisax/sedlbauer.c | 6 +- drivers/isdn/hisax/telespci.c | 6 +- drivers/isdn/hisax/w6692.c | 6 +- drivers/macintosh/mac_keyb.c | 2 - drivers/macintosh/via-macii.c | 1 - drivers/media/video/bttv-cards.c | 18 ++ drivers/media/video/bttv-driver.c | 18 ++ drivers/media/video/msp3400.c | 2 +- drivers/media/video/tvaudio.c | 2 +- drivers/mtd/Config.in | 1 + drivers/mtd/cfi_cmdset_0002.c | 2 +- drivers/mtd/doc1000.c | 71 ++--- drivers/mtd/ftl.c | 24 +- drivers/mtd/pmc551.c | 344 +++++++++++++++----- drivers/net/8139too.c | 230 +++++++------ drivers/net/8390.c | 123 ++++--- drivers/net/appletalk/cops.c | 68 ++-- drivers/net/appletalk/ipddp.c | 19 +- drivers/net/appletalk/ltpc.c | 34 +- drivers/net/daynaport.c | 2 - drivers/net/dummy.c | 23 +- drivers/net/eql.c | 14 +- drivers/net/hamradio/6pack.h | 3 +- drivers/net/hamradio/mkiss.h | 3 +- drivers/net/shaper.c | 136 ++++---- drivers/net/slip.c | 4 +- drivers/net/slip.h | 2 +- drivers/net/tulip/eeprom.c | 1 + drivers/net/tun.c | 4 +- drivers/nubus/nubus.c | 9 +- drivers/pci/pci.c | 9 +- drivers/pci/setup-bus.c | 14 +- drivers/sound/maestro.c | 12 +- drivers/sound/sound_core.c | 7 +- drivers/usb/bluetooth.c | 30 +- drivers/usb/printer.c | 76 ++++- drivers/usb/serial/usbserial.c | 5 +- drivers/usb/uhci.c | 18 +- drivers/usb/usb-uhci.c | 12 +- drivers/video/aty128fb.c | 21 +- drivers/video/atyfb.c | 19 +- drivers/video/platinumfb.c | 24 +- drivers/video/tdfxfb.c | 42 ++- fs/buffer.c | 7 +- fs/ext2/ialloc.c | 60 ++-- fs/ext2/namei.c | 24 +- fs/inode.c | 12 +- fs/isofs/dir.c | 2 +- fs/isofs/inode.c | 197 +++++++----- fs/isofs/namei.c | 9 +- fs/isofs/rock.c | 44 +-- fs/isofs/util.c | 2 +- fs/lockd/clntproc.c | 2 +- fs/locks.c | 2 +- fs/namei.c | 22 +- fs/nfs/dir.c | 184 +++++------ fs/nfs/file.c | 19 +- fs/nfs/inode.c | 178 +++-------- fs/nfs/nfs3proc.c | 127 ++++---- fs/nfs/proc.c | 87 +++-- fs/nfs/read.c | 55 ++-- fs/nfs/symlink.c | 16 +- fs/nfs/write.c | 130 ++++---- fs/ntfs/fs.c | 24 +- include/asm-alpha/bitops.h | 153 +++------ include/asm-alpha/byteorder.h | 38 +++ include/asm-alpha/fpu.h | 33 +- include/asm-alpha/pgtable.h | 19 +- include/asm-i386/hardirq.h | 2 +- include/asm-i386/page.h | 2 - include/asm-ia64/hardirq.h | 2 +- include/asm-sh/page.h | 2 - include/linux/agpgart.h | 2 +- include/linux/ext2_fs.h | 2 +- include/linux/fs.h | 1 + include/linux/kernel.h | 13 + include/linux/mtd/cfi.h | 3 +- include/linux/mtd/pmc551.h | 52 +-- include/linux/nfs_fs.h | 11 +- include/linux/nfs_fs_i.h | 7 + include/linux/nfs_page.h | 3 +- include/linux/nfs_xdr.h | 40 +-- include/linux/pci_ids.h | 4 - include/linux/signal.h | 4 +- init/main.c | 8 +- ipc/shm.c | 2 +- kernel/exit.c | 10 +- kernel/ksyms.c | 2 +- kernel/sched.c | 8 +- kernel/sysctl.c | 2 +- mm/filemap.c | 6 +- mm/vmscan.c | 3 +- net/core/skbuff.c | 2 +- net/ipx/af_ipx.c | 2 +- scripts/kernel-doc | 5 +- 155 files changed, 4030 insertions(+), 1843 deletions(-) create mode 100644 Documentation/SubmittingPatches create mode 100644 arch/alpha/lib/ev6-clear_user.S create mode 100644 arch/alpha/lib/ev6-copy_user.S create mode 100644 arch/alpha/lib/ev6-csum_ipv6_magic.S create mode 100644 arch/alpha/lib/ev6-divide.S create mode 100644 arch/alpha/lib/ev6-strcpy.S create mode 100644 arch/alpha/lib/ev6-strncpy.S create mode 100644 arch/alpha/lib/ev6-strncpy_from_user.S create mode 100644 arch/alpha/lib/ev67-strcat.S create mode 100644 arch/alpha/lib/ev67-strchr.S create mode 100644 arch/alpha/lib/ev67-strlen.S create mode 100644 arch/alpha/lib/ev67-strlen_user.S create mode 100644 arch/alpha/lib/ev67-strncat.S diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers index 29c5973851e7..92a169ac2d03 100644 --- a/Documentation/SubmittingDrivers +++ b/Documentation/SubmittingDrivers @@ -6,13 +6,17 @@ Linux 2.2 and 2.4test kernel trees. Note that if you are interested in video card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) instead. +Also read the Documentation/SubmittingPatches document. + + Allocating Device Numbers ------------------------- -Major and minor numbers for devices are allocated by the Linux assigned name -and number authority (currently better known as H Peter Anvin). The -site is http://www.lanana.org/. This also deals with allocating numbers for -devices that are not going to be submitted to the mainstream kernel. +Major and minor numbers for block and character devices are allocated +by the Linux assigned name and number authority (currently better +known as H Peter Anvin). The site is http://www.lanana.org/. This +also deals with allocating numbers for devices that are not going to +be submitted to the mainstream kernel. If you don't use assigned numbers then when you device is submitted it will get given an assigned number even if that is different from values you may @@ -76,7 +80,8 @@ Control: In general if there is active maintainance of a driver by the author then patches will be redirected to them unless they are totally obvious and without need of checking. If you want to be the contact and update point for the - driver it is a good idea to state this in the comments. + driver it is a good idea to state this in the comments, + and include an entry in MAINTAINERS for your driver. What Criteria Do Not Determine Acceptance ----------------------------------------- @@ -97,7 +102,8 @@ Resources --------- Linux kernel master tree: - ftp.kernel.org:/pub/linux/kernel/... + ftp.??.kernel.org:/pub/linux/kernel/... + ?? == your country code, such as "us", "uk", "fr", etc. Linux kernel mailing list: linux-kernel@vger.kernel.org diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches new file mode 100644 index 000000000000..4f48032c79dd --- /dev/null +++ b/Documentation/SubmittingPatches @@ -0,0 +1,286 @@ + + How to Get Your Change Into the Linux Kernel + or + Care And Operation Of Your Linus Torvalds + + + +For a person or company who wishes to submit a change to the Linux +kernel, the process can sometimes be daunting if you're not familiar +with "the system." This text is a collection of suggestions which +can greatly increase the chances of your change being accepted. + +If you are submitting a driver, also read Documentation/SubmittingDrivers. + + + +-------------------------------------------- +SECTION 1 - CREATING AND SENDING YOUR CHANGE +-------------------------------------------- + + + +1) "diff -u" +------------ + +Use "diff -u" or "diff -urN" to create patches. + +All changes to the Linux kernel occur in the form of patches, as +generated by diff(1). When creating your patch, make sure to create it +in "unified diff" format, as supplied by the '-u' argument to diff(1). +Patches should be based in the root kernel source directory, not in +any lower subdirectory. + +To create a patch for a single file, it is often sufficient to do: + + SRCTREE= /devel/linux-2.4 + MYFILE= drivers/net/mydriver.c + + cd $SRCTREE + cp $MYFILE $MYFILE.orig + vi $MYFILE # make your change + diff -u $MYFILE.orig $MYFILE > /tmp/patch + +To create a patch for multiple files, you should unpack a "vanilla", +or unmodified kernel source tree, and generate a diff against your +own source tree. For example: + + MYSRC= /devel/linux-2.4 + + tar xvfz linux-2.4.0-test11.tar.gz + mv linux linux-vanilla + wget http://www.moses.uklinux.net/patches/dontdiff + diff -urN -X dontdiff linux-vanilla $MYSRC > /tmp/patch + rm -f dontdiff + +"dontdiff" is a list of files which are generated by the kernel during +the build process, and should be ignored in any diff(1)-generated +patch. dontdiff is maintained by Tigran Aivazian + +Make sure your patch does not include any extra files which do not +belong in a patch submission. Make sure to review your patch -after- +generated it with diff(1), to ensure accuracy. + + +2) Describe your changes. + +Describe the technical detail of the change(s) your patch includes. + +Be as specific as possible. The WORST descriptions possible include +things like "update driver X", "bug fix for driver X", or "this patch +includes updates for subsystem X. Please apply." + +If your description starts to get long, that's a sign that you probably +need to split up your patch. See #3, next. + + + +3) Separate your changes. + +Separate each logical change into its own patch. + +For example, if your changes include both bug fixes and performance +enhancements for a single driver, separate those changes into two +or more patches. If your changes include an API update, and a new +driver which uses that new API, separate those into two patches. + +On the other hand, if you make a single change to numerous files, +group those changes into a single patch. Thus a single logical change +is contained within a single patch. + +If one patch depends on another patch in order for a change to be +complete, that is OK. Simply note "this patch depends on patch X" +in your patch description. + + +4) Select e-mail destination. + +Look through the MAINTAINERS file and the source code, and determine +if your change applies to a specific subsystem of the kernel, with +an assigned maintainer. If so, e-mail that person. + +If no maintainer is listed, or the maintainer does not respond, send +your patch to the primary Linux kernel developer's mailing list, +linux-kernel@vger.kernel.org. Most kernel developers monitor this +e-mail list, and can comment on your changes. + +Linus Torvalds is the final arbiter of all changes accepted into the +Linux kernel. His e-mail address is torvalds@transmeta.com. He gets +a lot of e-mail, so typically you should do your best to -avoid- sending +him e-mail. + +Patches which are bug fixes, are "obvious" changes, or similarly +require little discussion should be sent or CC'd to Linus. Patches +which require discussion or do not have a clear advantage should +usually be sent first to linux-kernel. Only after the patch is +discussed should the patch then be submitted to Linus. + + + +5) Select your CC (e-mail carbon copy) list. + +Unless you have a reason NOT to do so, CC linux-kernel@vger.kernel.org. + +Other kernel developers besides Linus need to be aware of your change, +so that they may comment on it and offer code review and suggestions. +linux-kernel is the primary Linux kernel developer mailing list. +Other mailing lists are available for specific subsystems, such as +USB, framebuffer devices, the VFS, the SCSI subsystem, etc. See the +MAINTAINERS file for a mailing list that relates specifically to +your change. + +Even if the maintainer did not respond in step #4, make sure to ALWAYS +copy the maintainer when you change their code. + + + +6) No MIME, no links, no compression, no attachments. Just plain text. + +Linus and other kernel developers need to be able to read and comment +on the changes you are submitting. It is important for a kernel +developer to be able to "quote" your changes, using standard e-mail +tools, so that they may comment on specific portions of your code. + +For this reason, all patches should be submitting e-mail "inline". +WARNING: Be wary of your editor's word-wrap corrupting your patch, +if you choose to cut-n-paste your patch. + +Do not attach the patch as a MIME attachment, compressed or not. +Many popular e-mail applications will not always transmit a MIME +attachment as plain text, making it impossible to comment on your +code. A MIME attachment also takes Linus a bit more time to process, +decreasing the likelihood of your MIME-attached change being accepted. + +Exception: If your mailer is mangling patches then someone may ask +you to re-send them using MIME. + + + +7) E-mail size. + +When sending patches to Linus, always follow step #6. + +Large changes are not appropriate for mailing lists, and some +maintainers. If your patch, uncompressed, exceeds 40Kb in size, +it is preferred that you store your patch on an Internet-accessible +server, and provide instead a URL (link) pointing to your patch. + + + +8) Name your kernel version. + +It is important to note, either in the subject line or in the patch +description, the kernel version to which this patch applies. + +If the patch does not apply cleanly to the latest kernel version, +Linus will not apply it. + + + +9) Don't get discouraged. Re-submit. + +After you have submitted your change, be patient and wait. If Linus +likes your change and applies it, it will appear in the next version +of the kernel that he releases. + +However, if your change doesn't appear in the next version of the +kernel, there could be any number of reasons. It's YOUR job to +narrow down those reasons, correct what was wrong, and submit your +updated change. + +It is quite common for Linus to "drop" your patch without comment. +That's the nature of the system. If he drops your patch, it could be +due to +* Your patch did not apply cleanly to the latest kernel version +* Your patch was not sufficiently discussed on linux-kernel. +* A style issue (see section 2), +* An e-mail formatting issue (re-read this section) +* A technical problem with your change +* He gets tons of e-mail, and yours got lost in the shuffle +* You are being annoying (See Figure 1) + +When in doubt, solicit comments on linux-kernel mailing list. + + + +10) Include PATCH in the subject + +Due to high e-mail traffic to Linus, and to linux-kernel, it is common +convention to prefix your subject line with [PATCH]. This lets Linus +and other kernel developers more easily distinguish patches from other +e-mail discussions. + + + +----------------------------------- +SECTION 2 - HINTS, TIPS, AND TRICKS +----------------------------------- + +This section lists many of the common "rules" associated with code +submitted to the kernel. There are always exceptions... but you must +have a really good reason for doing so. You could probably call this +section Linus Computer Science 101. + + + +1) Read Documentation/CodingStyle + +Nuff said. If your code deviates too much from this, it is likely +to be rejected without further review, and without comment. + + + +2) #ifdefs are ugly + +Code cluttered with ifdefs is difficult to read and maintain. Don't do +it. Instead, put your ifdefs in a header, and conditionally define +'static inline' functions, or macros, which are used in the code. +Let the compiler optimize away the "no-op" case. + +Simple example, of poor code: + + dev = init_etherdev (NULL, 0); + if (!dev) + return -ENODEV; + #ifdef CONFIG_NET_FUNKINESS + init_funky_net(dev); + #endif + +Cleaned-up example: + +(in header) + #ifndef CONFIG_NET_FUNKINESS + static inline void init_funky_net (struct net_device *d) {} + #endif + +(in the code itself) + dev = init_etherdev (NULL, 0); + if (!dev) + return -ENODEV; + init_funky_net(dev); + + + +3) 'static inline' is better than a macro + +Static inline functions are greatly preferred over macros. +They provide type safety, have no length limitations, no formatting +limitations, and under gcc they are as cheap as macros. + +Macros should only be used for cases where a static inline is clearly +suboptimal [there a few, isolated cases of this in fast paths], +or where it is impossible to use a static inline function [such as +string-izing]. + +'static inline' is preferred over 'static __inline__', 'extern inline', +and 'extern __inline__'. + + + +4) Don't over-design. + +Don't try to anticipate nebulous future cases which may or may not +be useful: "Make it as simple as you can, and no simpler" + + + diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README index 6febda525427..0c6fde510600 100644 --- a/Documentation/filesystems/devfs/README +++ b/Documentation/filesystems/devfs/README @@ -529,7 +529,7 @@ yielded code size reductions and simplifications. If you want to construct a minimal chroot() gaol, the following command should suffice: -mount -t bind /dev/null /gaol/dev/null +mount --bind /dev/null /gaol/dev/null Repeat for other device nodes you want to expose. Simple! @@ -739,7 +739,7 @@ create the /dev-state directory add the following lines near the very beginning of your boot scripts: -mount -t bind /dev /dev-state +mount --bind /dev /dev-state mount -t devfs none /dev devfsd /dev diff --git a/Documentation/initrd.txt b/Documentation/initrd.txt index acc2315a451d..941f9ddd0fbc 100644 --- a/Documentation/initrd.txt +++ b/Documentation/initrd.txt @@ -1,25 +1,28 @@ Using the initial RAM disk (initrd) =================================== -Written 1996 by Werner Almesberger and - Hans Lermen +Written 1996,2000 by Werner Almesberger and + Hans Lermen -initrd adds the capability to load a RAM disk by the boot loader. This -RAM disk can then be mounted as the root file system and programs can be -run from it. Afterwards, a new root file system can be mounted from a -different device. The previous root (from initrd) is then either moved -to the directory /initrd or it is unmounted. +initrd provides the capability to load a RAM disk by the boot loader. +This RAM disk can then be mounted as the root file system and programs +can be run from it. Afterwards, a new root file system can be mounted +from a different device. The previous root (from initrd) is then moved +to a directory and can be subsequently unmounted. initrd is mainly designed to allow system startup to occur in two phases, where the kernel comes up with a minimum set of compiled-in drivers, and where additional modules are loaded from initrd. +This document gives a brief overview of the use of initrd. A more detailed +discussion of the boot process can be found in [1]. + Operation --------- -When using initrd, the system boots as follows: +When using initrd, the system typically boots as follows: 1) the boot loader loads the kernel and the initial RAM disk 2) the kernel converts initrd into a "normal" RAM disk and @@ -28,28 +31,17 @@ When using initrd, the system boots as follows: 4) /linuxrc is executed (this can be any valid executable, including shell scripts; it is run with uid 0 and can do basically everything init can do) - 5) when linuxrc terminates, the "real" root file system is mounted - 6) if a directory /initrd exists, the initrd is moved there - otherwise, initrd is unmounted + 5) linuxrc mounts the "real" root file system + 6) linuxrc places the root file system at the root directory using the + pivot_root system call 7) the usual boot sequence (e.g. invocation of /sbin/init) is performed on the root file system + 8) the initrd file system is removed -Note that moving initrd from / to /initrd does not involve unmounting it. -It is therefore possible to leave processes running on initrd (or leave -file systems mounted, but see below) during that procedure. However, if -/initrd doesn't exist, initrd can only be unmounted if it is not used by -anything. If it can't be unmounted, it will stay in memory. - -Also note that file systems mounted under initrd continue to be accessible, -but their /proc/mounts entries are not updated. Also, if /initrd doesn't -exist, initrd can't be unmounted and will "disappear" and take those file -systems with it, thereby preventing them from being re-mounted. It is -therefore strongly suggested to generally unmount all file systems (except -of course for the root file system, but including /proc) before switching -from initrd to the "normal" root file system. - -In order to deallocate the memory used for the initial RAM disk, you have -to execute freeramdisk (see 'Resources' below) after unmounting /initrd. +Note that changing the root directory does not involve unmounting it. +It is therefore possible to leave processes running on initrd during that +procedure. Also note that file systems mounted under initrd continue to +be accessible. Boot command-line options @@ -57,7 +49,7 @@ Boot command-line options initrd adds the following new options: - initrd= (LOADLIN only) + initrd= (e.g. LOADLIN) Loads the specified file as the initial RAM disk. When using LILO, you have to specify the RAM disk image file in /etc/lilo.conf, using the @@ -71,40 +63,38 @@ initrd adds the following new options: in this case and doesn't necessarily have to be a file system image. This option is used mainly for debugging. - Note that /dev/initrd is read-only and that it can only be used once. - As soon as the last process has closed it, all data is freed and - /dev/initrd can't be opened any longer. + Note: /dev/initrd is read-only and it can only be used once. As soon + as the last process has closed it, all data is freed and /dev/initrd + can't be opened anymore. - root=/dev/ram + root=/dev/ram0 (without devfs) + root=/dev/rd/0 (with devfs) - initrd is mounted as root, and /linuxrc is started. If no /linuxrc - exists, the normal boot procedure is followed, with the RAM disk - still mounted as root. This option is mainly useful when booting from - a floppy disk. Compared to directly mounting an on-disk file system, - the intermediate step of going via initrd adds a little speed - advantage and it allows the use of a compressed file system. - Also, together with LOADLIN you may load the RAM disk directly from - CDROM or disk, hence having a floppyless boot from CD, - e.g.: E:\loadlin E:\bzImage root=/dev/ram initrd=E:\rdimage + initrd is mounted as root, and the normal boot procedure is followed, + with the RAM disk still mounted as root. Installation ------------ -First, the "normal" root file system has to be prepared as follows: +First, a directory for the initrd file system has to be created on the +"normal" root file system, e.g. -# mknod /dev/initrd b 1 250 -# chmod 400 /dev/initrd # mkdir /initrd +The name is not relevant. More details can be found on the pivot_root(2) +man page. + If the root file system is created during the boot procedure (i.e. if -you're creating an install floppy), the root file system creation -procedure should perform these operations. +you're building an install floppy), the root file system creation +procedure should create the /initrd directory. + +If initrd will not be mounted in some cases, its content is still +accessible if the following device has been created (note that this +does not work if using devfs): -Note that neither /dev/initrd nor /initrd are strictly required for -correct operation of initrd, but it is a lot easier to experiment with -initrd if you have them, and you may also want to use /initrd to pass -data to the "real" system. +# mknod /dev/initrd b 1 250 +# chmod 400 /dev/initrd Second, the kernel has to be compiled with RAM disk support and with support for the initial RAM disk enabled. Also, at least all components @@ -112,100 +102,148 @@ needed to execute programs from initrd (e.g. executable format and file system) must be compiled into the kernel. Third, you have to create the RAM disk image. This is done by creating a -file system on a block device and then by copying files to it as needed. -With recent kernels, at least three types of devices are suitable for -that: +file system on a block device, copying files to it as needed, and then +copying the content of the block device to the initrd file. With recent +kernels, at least three types of devices are suitable for that: - a floppy disk (works everywhere but it's painfully slow) - a RAM disk (fast, but allocates physical memory) - - a loopback device (the most elegant solution, but currently requires a - modified mount) + - a loopback device (the most elegant solution) -We'll describe the RAM disk method: +We'll describe the loopback device method: - 1) make sure you have a RAM disk device /dev/ram (block, major 1, minor 0) + 1) make sure loopback block devices are configured into the kernel 2) create an empty file system of the appropriate size, e.g. - # mke2fs -m0 /dev/ram 300 + # dd if=/dev/zero of=initrd bs=300k count=1 + # mke2fs -F -m0 initrd (if space is critical, you may want to use the Minix FS instead of Ext2) - 3) mount the file system on an appropriate directory, e.g. - # mount -t ext2 /dev/ram /mnt - 4) create the console device: + 3) mount the file system, e.g. + # mount -t ext2 -o loop initrd /mnt + 4) create the console device (not necessary if using devfs, but it can't + hurt to do it anyway): # mkdir /mnt/dev - # mknod /mnt/dev/tty1 c 4 1 + # mknod /mnt/dev/console c 5 1 5) copy all the files that are needed to properly use the initrd environment. Don't forget the most important file, /linuxrc Note that /linuxrc's permissions must include "x" (execute). - 6) unmount the RAM disk - # umount /dev/ram - 7) copy the image to a file - # dd if=/dev/ram bs=1k count=300 of=/boot/initrd - 8) deallocate the RAM disk - # freeramdisk /dev/ram - -For experimenting with initrd, you may want to take a rescue floppy (e.g. -rescue.gz from Slackware) and only add a symbolic link from /linuxrc to -/bin/sh, e.g. - - # gunzip /dev/ram - # mount -t minix /dev/ram /mnt - # ln -s /bin/sh /mnt/linuxrc - # umount /dev/ram - # dd if=/dev/ram bs=1k count=1440 of=/boot/initrd - # freeramdisk /dev/ram - -Finally, you have to boot the kernel and load initrd. Currently, -preliminary versions of LOADLIN 1.6 and LILO 18 support initrd (see -below for where to get them). With LOADLIN, you simply execute + 6) correct operation the initrd environment can frequently be tested + even without rebooting with the command + # chroot /mnt /linuxrc + This is of course limited to initrds that do not interfere with the + general system state (e.g. by reconfiguring network interfaces, + overwriting mounted devices, trying to start already running demons, + etc. Note however that it is usually possible to use pivot_root in + such a chroot'ed initrd environment.) + 7) unmount the file system + # umount /mnt + 8) the initrd is now in the file "initrd". Optionally, it can now be + compressed + # gzip -9 initrd + +For experimenting with initrd, you may want to take a rescue floppy and +only add a symbolic link from /linuxrc to /bin/sh. Alternatively, you +can try the experimental newlib environment [2] to create a small +initrd. + +Finally, you have to boot the kernel and load initrd. Almost all Linux +boot loaders support initrd. Since the boot process is still compatible +with an older mechanism, the following boot command line parameters +have to be given: + + root=/dev/ram0 init=/linuxrc rw + +if not using devfs, or + + root=/dev/rd/0 init=/linuxrc rw + +if using devfs. (rw is only necessary if writing to the initrd file +system.) + +With LOADLIN, you simply execute LOADLIN initrd= -e.g. LOADLIN C:\LINUX\VMLINUZ initrd=C:\LINUX\INITRD +e.g. LOADLIN C:\LINUX\BZIMAGE initrd=C:\LINUX\INITRD.GZ root=/dev/ram0 + init=/linuxrc rw With LILO, you add the option INITRD= to either the global section -or to the section of the respective kernel in /etc/lilo.conf, e.g. +or to the section of the respective kernel in /etc/lilo.conf, and pass +the options using APPEND, e.g. - image = /vmlinuz - initrd = /boot/initrd + image = /bzImage + initrd = /boot/initrd.gz + append = "root=/dev/ram0 init=/linuxrc rw" and run /sbin/lilo +For other boot loaders, please refer to the respective documentation. + Now you can boot and enjoy using initrd. -Setting the root device ------------------------ +Changing the root device +------------------------ -By default, the standard settings in the kernel are used for the root -device, i.e. the default compiled in or set with rdev, or what was passed -with root=xxx on the command line, or, with LILO, what was specified in -/etc/lilo.conf It is also possible to use initrd with an NFS-mounted -root; you have to use the nfs_root_name and nfs_root_addrs boot options -for this. +When finished with its duties, linuxrc typically changes the root device +and proceeds with starting the Linux system on the "real" root device. -It is also possible to change the root device from within the initrd -environment. In order to do so, /proc has to be mounted. Then, the -following files are available: +The procedure involves the following steps: + - mounting the new root file system + - turning it into the root file system + - removing all accesses to the old (initrd) root file system + - unmounting the initrd file system and de-allocating the RAM disk - /proc/sys/kernel/real-root-dev - /proc/sys/kernel/nfs-root-name - /proc/sys/kernel/nfs-root-addrs +Mounting the new root file system is easy: it just needs to be mounted on +a directory under the current root. Example: -real-root-dev can be changed by writing the number of the new root FS -device to it, e.g. +# mkdir /new-root +# mount -o ro /dev/hda1 /new-root - # echo 0x301 >/proc/sys/kernel/real-root-dev +The root change is accomplished with the pivot_root system call, which +is also available via the pivot_root utility (see pivot_root(8) man +page; pivot_root is distributed with util-linux version 2.10h or higher +[3]). pivot_root moves the current root to a directory under the new +root, and puts the new root at its place. The directory for the old root +must exist before calling pivot_root. Example: + +# cd /new-root +# mkdir initrd +# pivot_root . initrd + +Now, the linuxrc process may still access the old root via its +executable, shared libraries, standard input/output/error, and its +current root directory. All these references are dropped by the +following command: + +# exec chroot . what-follows dev/console 2>&1 + +Where what-follows is a program under the new root, e.g. /sbin/init +If the new root file system will be used with devfs and has no valid +/dev directory, devfs must be mounted before invoking chroot in order to +provide /dev/console. -for /dev/hda1. When using an NFS-mounted root, nfs-root-name and -nfs-root-addrs have to be set accordingly and then real-root-dev has to -be set to 0xff, e.g. +Note: implementation details of pivot_root may change with time. In order +to ensure compatibility, the following points should be observed: - # echo /var/nfsroot >/proc/sys/kernel/nfs-root-name - # echo 193.8.232.2:193.8.232.7::255.255.255.0:idefix \ - >/proc/sys/kernel/nfs-root-addrs - # echo 255 >/proc/sys/kernel/real-root-dev + - before calling pivot_root, the current directory of the invoking + process should point to the new root directory + - use . as the first argument, and the _relative_ path of the directory + for the old root as the second argument + - a chroot program must be available under the old and the new root + - chroot to the new root afterwards + - use relative paths for dev/console in the exec command -If the root device is set to the RAM disk, the root file system is not -moved to /initrd, but the boot procedure is simply continued by starting -init on the initial RAM disk. +Now, the initrd can be unmounted and the memory allocated by the RAM +disk can be freed: + +# umount /initrd +# blockdev --flushbufs /dev/ram0 # /dev/rd/0 if using devfs + +It is also possible to use initrd with an NFS-mounted root, see the +pivot_root(8) man page for details. + +Note: if linuxrc or any program exec'ed from it terminates for some +reason, the old change_root mechanism is invoked (see section "Obsolete +root change mechanism"). Usage scenarios @@ -215,32 +253,30 @@ The main motivation for implementing initrd was to allow for modular kernel configuration at system installation. The procedure would work as follows: - 1) systems boots from floppy or other media with a minimal kernel - (e.g. support for RAM disks, initrd, a.out, and the ext2 FS) and + 1) system boots from floppy or other media with a minimal kernel + (e.g. support for RAM disks, initrd, a.out, and the Ext2 FS) and loads initrd 2) /linuxrc determines what is needed to (1) mount the "real" root FS (i.e. device type, device drivers, file system) and (2) the distribution media (e.g. CD-ROM, network, tape, ...). This can be done by asking the user, by auto-probing, or by using a hybrid approach. - 3) /linuxrc loads the necessary modules + 3) /linuxrc loads the necessary kernel modules 4) /linuxrc creates and populates the root file system (this doesn't have to be a very usable system yet) - 5) /linuxrc unmounts the root file system and possibly any other file - systems it has mounted, sets /proc/sys/kernel/..., and terminates - 6) the root file system is mounted - 7) now that we're sure that the file system is accessible and intact, - the boot loader can be installed - 8) the boot loader is configured to load an initrd with the set of + 5) /linuxrc invokes pivot_root to change the root file system and + execs - via chroot - a program that continues the installation + 6) the boot loader is installed + 7) the boot loader is configured to load an initrd with the set of modules that was used to bring up the system (e.g. /initrd can be modified, then unmounted, and finally, the image is written from - /dev/ram to a file) - 9) now the system is bootable and additional installation tasks can be + /dev/ram0 or /dev/rd/0 to a file) + 8) now the system is bootable and additional installation tasks can be performed The key role of initrd here is to re-use the configuration data during normal system operation without requiring the use of a bloated "generic" -kernel or re-compilation or re-linking of the kernel. +kernel or re-compiling or re-linking the kernel. A second scenario is for installations where Linux runs on systems with different hardware configurations in a single administrative domain. In @@ -252,35 +288,53 @@ read by it would have to be different. A third scenario are more convenient recovery disks, because information like the location of the root FS partition doesn't have to be provided at -boot time, but the system loaded from initrd can use a user-friendly +boot time, but the system loaded from initrd can invoke a user-friendly dialog and it can also perform some sanity checks (or even some form of auto-detection). -Last not least, CDROM distributors may use it for better installation from CD, -either using a LILO boot floppy and bootstrapping a bigger RAM disk via -initrd from CD, or using LOADLIN to directly load the RAM disk from CD -without need of floppies. +Last not least, CD-ROM distributors may use it for better installation +from CD, e.g. by using a boot floppy and bootstrapping a bigger RAM disk +via initrd from CD; or by booting via a loader like LOADLIN or directly +from the CD-ROM, and loading the RAM disk from CD without need of +floppies. -Since initrd is a fairly generic mechanism, it is likely that additional -uses will be found. +Obsolete root change mechanism +------------------------------ -Resources ---------- +The following mechanism was used before the introduction of pivot_root. +Current kernels still support it, but you should _not_ rely on its +continued availability. + +It works by mounting the "real" root device (i.e. the one set with rdev +in the kernel image or with root=... at the boot command line) as the +root file system when linuxrc exits. The initrd file system is then +unmounted, or, if it is still busy, moved to a directory /initrd, if +such a directory exists on the new root file system. + +In order to use this mechanism, you do not have to specify the boot +command options root, init, or rw. (If specified, they will affect +the real root file system, not the initrd environment.) + +If /proc is mounted, the "real" root device can be changed from within +linuxrc by writing the number of the new root FS device to the special +file /proc/sys/kernel/real-root-dev, e.g. + + # echo 0x301 >/proc/sys/kernel/real-root-dev + +Note that the mechanism is incompatible with NFS and similar file +systems. -The bzImage+initrd patch (bzImage is an extension to load kernels directly -above 1 MB, which allows kernels sizes of up to approximately 2 MB) can be -found at -ftp://lrcftp.epfl.ch/pub/people/almesber/lilo/bzImage+initrd-1.3.71.patch.gz -and -ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/bzImage+initrd-1.3.71.patch.gz +This old, deprecated mechanism is commonly called "change_root", while +the new, supported mechanism is called "pivot_root". -A preliminary version of LOADLIN 1.6 is available on -ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/loadlin-1.6-pre8-bin.tgz -A preliminary version of LILO 18 is available on -ftp://lrcftp.epfl.ch/pub/people/almesber/lilo/lilo.18dev3.tar.gz +Resources +--------- -A very simple example for building an image for initrd, also including -the program 'freeramdisk', can be found on -ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/initrd-example.tgz +[1] Almesberger, Werner; "Booting Linux: The History and the Future" + ftp://icaftp.epfl.ch/pub/people/almesber/booting/bootinglinux-current.ps.gz +[2] newlib package (experimental), with initrd example + ftp://icaftp.epfl.ch/pub/people/almesber/misc/newlib-linux/ +[3] Brouwer, Andries; "util-linux: Miscellaneous utilities for Linux" + ftp://ftp.win.tue.nl/pub/linux-local/utils/util-linux/ diff --git a/Documentation/sound/CMI8330 b/Documentation/sound/CMI8330 index 8885d3307bc8..28779988406a 100644 --- a/Documentation/sound/CMI8330 +++ b/Documentation/sound/CMI8330 @@ -57,7 +57,7 @@ How to enable CMI 8330 (SOUNDPRO) soundchip on Linux ------------------------------------------ Stefan Laudat -[Note: The CMI 8338 is unrelated and right now unsupported] +[Note: The CMI 8338 is unrelated and is supported by cmpci.o] In order to use CMI8330 under Linux you just have to use a proper isapnp.conf, a good isapnp and a little bit of patience. I use isapnp 1.17, but diff --git a/Makefile b/Makefile index de12c264b1f3..00615a37aef3 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,6 @@ MRPROPER_FILES = \ drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \ drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \ drivers/net/hamradio/soundmodem/gentbl \ - drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h \ drivers/sound/*_boot.h drivers/sound/.*.boot \ drivers/sound/msndinit.c \ drivers/sound/msndperm.c \ diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index 44ae94a99b43..c07b2576491e 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -36,6 +36,10 @@ ifeq ($(have_mcpu),y) CFLAGS := $(CFLAGS) -mcpu=ev5 mcpu_done := y endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_SX164)$(have_mcpu_pca56),nyy) + CFLAGS := $(CFLAGS) -mcpu=pca56 + mcpu_done := y + endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny) CFLAGS := $(CFLAGS) -mcpu=ev56 mcpu_done := y @@ -48,14 +52,14 @@ ifeq ($(have_mcpu),y) endif mcpu_done := y endif - ifeq ($(mcpu_done)$(CONFIG_ALPHA_NAUTILUS)$(have_mcpu_ev67),nyy) - CFLAGS := $(CFLAGS) -mcpu=ev67 - mcpu_done := y - endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny) CFLAGS := $(CFLAGS) -mcpu=ev4 mcpu_done := y endif + ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV67)$(have_mcpu_ev67),nyy) + CFLAGS := $(CFLAGS) -mcpu=ev67 + mcpu_done := y + endif ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV6),ny) ifeq ($(have_mcpu_ev6),y) CFLAGS := $(CFLAGS) -mcpu=ev6 diff --git a/arch/alpha/config.in b/arch/alpha/config.in index da5c361c9a7a..649047e6659e 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -56,7 +56,7 @@ choice 'Alpha system type' \ Wildfire CONFIG_ALPHA_WILDFIRE" Generic # clear all implied options (don't want default values for those): -unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 CONFIG_ALPHA_EV67 unset CONFIG_ALPHA_EISA unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS @@ -138,16 +138,12 @@ if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ] then define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_TSUNAMI y + bool 'EV67 (or later) CPU (speed > 600MHz)?' CONFIG_ALPHA_EV67 fi -if [ "$CONFIG_ALPHA_WILDFIRE" = "y" ] +if [ "$CONFIG_ALPHA_WILDFIRE" = "y" -o "$CONFIG_ALPHA_TITAN" = "y" ] then - define_bool CONFIG_PCI y - define_bool CONFIG_ALPHA_EV6 y -fi -if [ "$CONFIG_ALPHA_TITAN" = "y" ] -then - define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV6 y + define_bool CONFIG_ALPHA_EV67 y fi if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] then @@ -165,8 +161,9 @@ then fi if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ] then - define_bool CONFIG_ALPHA_EV6 y define_bool CONFIG_ALPHA_IRONGATE y + define_bool CONFIG_ALPHA_EV6 y + define_bool CONFIG_ALPHA_EV67 y fi if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index b06c6bd80682..e17cbcd70892 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -56,13 +56,13 @@ struct pci_controler *pci_isa_hose; static void __init quirk_eisa_bridge(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_EISA; + dev->class = PCI_CLASS_BRIDGE_EISA << 8; } static void __init quirk_isa_bridge(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_ISA; + dev->class = PCI_CLASS_BRIDGE_ISA << 8; } static void __init @@ -282,7 +282,7 @@ pcibios_fixup_bus(struct pci_bus *bus) } } -void __init +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 913331a95525..5de58a6ad2ad 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -3,32 +3,45 @@ # .S.s: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< + $(CPP) -D__ASSEMBLY__ $(CFLAGS) -o $*.s $< .S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + $(CC) -D__ASSEMBLY__ $(CFLAGS) -c -o $*.o $< + +# Many of these routines have implementations tuned for ev6. +# Choose them iff we're targeting ev6 specifically. +ev6 := +ifeq ($(CONFIG_ALPHA_EV6),y) + ev6 := ev6- +endif + +# Several make use of the cttz instruction introduced in ev67. +ev67 := +ifeq ($(CONFIG_ALPHA_EV67),y) + ev67 := ev67- +endif OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \ - checksum.o csum_partial_copy.o strlen.o \ - strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ - strchr.o strrchr.o memchr.o \ - copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ - csum_ipv6_magic.o strcasecmp.o fpreg.o \ + checksum.o csum_partial_copy.o $(ev67)strlen.o \ + $(ev67)strcat.o $(ev6)strcpy.o $(ev67)strncat.o $(ev6)strncpy.o \ + stxcpy.o stxncpy.o $(ev67)strchr.o strrchr.o memchr.o \ + $(ev6)copy_user.o $(ev6)clear_user.o $(ev6)strncpy_from_user.o \ + $(ev67)strlen_user.o $(ev6)csum_ipv6_magic.o strcasecmp.o fpreg.o \ callback_srm.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) -__divqu.o: divide.S - $(CC) $(AFLAGS) -DDIV -c -o __divqu.o divide.S +__divqu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DDIV -c -o __divqu.o $(ev6)divide.S -__remqu.o: divide.S - $(CC) $(AFLAGS) -DREM -c -o __remqu.o divide.S +__remqu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DREM -c -o __remqu.o $(ev6)divide.S -__divlu.o: divide.S - $(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o divide.S +__divlu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o $(ev6)divide.S -__remlu.o: divide.S - $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o divide.S +__remlu.o: $(ev6)divide.S + $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o $(ev6)divide.S dep: diff --git a/arch/alpha/lib/ev6-clear_user.S b/arch/alpha/lib/ev6-clear_user.S new file mode 100644 index 000000000000..090f060637ef --- /dev/null +++ b/arch/alpha/lib/ev6-clear_user.S @@ -0,0 +1,228 @@ +/* + * arch/alpha/lib/ev6-clear_user.S + * 21264 version contributed by Rick Gorton + * + * Zero user space, handling exceptions as we go. + * + * We have to make sure that $0 is always up-to-date and contains the + * right "bytes left to zero" value (and that it is updated only _after_ + * a successful copy). There is also some rather minor exception setup + * stuff. + * + * NOTE! This is not directly C-callable, because the calling semantics + * are different: + * + * Inputs: + * length in $0 + * destination address in $6 + * exception pointer in $7 + * return address in $28 (exceptions expect it there) + * + * Outputs: + * bytes left to copy in $0 + * + * Clobbers: + * $1,$2,$3,$4,$5,$6 + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + * Determining actual stalls (other than slotting) doesn't appear to be easy to do. + * From perusing the source code context where this routine is called, it is + * a fair assumption that significant fractions of entire pages are zeroed, so + * it's going to be worth the effort to hand-unroll a big loop, and use wh64. + * ASSUMPTION: + * The believed purpose of only updating $0 after a store is that a signal + * may come along during the execution of this chunk of code, and we don't + * want to leave a hole (and we also want to avoid repeating lots of work) + */ + +/* Allow an exception for an insn; exit if we get one. */ +#define EX(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exception-99b($31); \ + .previous + + .set noat + .set noreorder + .align 4 + + .globl __do_clear_user + .ent __do_clear_user + .frame $30, 0, $28 + .prologue 0 + + # Pipeline info : Slotting & Comments +__do_clear_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. + # Macro instruction becomes ldah/lda + # .. .. E E : + and $6, 7, $4 # .. E .. .. : find dest head misalignment + beq $0, $zerolength # U .. .. .. : U L U L + + addq $0, $4, $1 # .. .. .. E : bias counter + and $1, 7, $2 # .. .. E .. : number of misaligned bytes in tail +# Note - we never actually use $2, so this is a moot computation +# and we can rewrite this later... + srl $1, 3, $1 # .. E .. .. : number of quadwords to clear + beq $4, $headalign # U .. .. .. : U L U L + +/* + * Head is not aligned. Write (8 - $4) bytes to head of destination + * This means $6 is known to be misaligned + */ + EX( ldq_u $5, 0($6) ) # .. .. .. L : load dst word to mask back in + beq $1, $onebyte # .. .. U .. : sub-word store? + mskql $5, $6, $5 # .. U .. .. : take care of misaligned head + addq $6, 8, $6 # E .. .. .. : L U U L + + EX( stq_u $5, -8($6) ) # .. .. .. L : + subq $1, 1, $1 # .. .. E .. : + addq $0, $4, $0 # .. E .. .. : bytes left -= 8 - misalignment + subq $0, 8, $0 # E .. .. .. : U L U L + + .align 4 +/* + * (The .align directive ought to be a moot point) + * values upon initial entry to the loop + * $1 is number of quadwords to clear (zero is a valid value) + * $2 is number of trailing bytes (0..7) ($2 never used...) + * $6 is known to be aligned 0mod8 + */ +$headalign: + subq $1, 16, $4 # .. .. .. E : If < 16, we can not use the huge loop + and $6, 0x3f, $2 # .. .. E .. : Forward work for huge loop + subq $2, 0x40, $3 # .. E .. .. : bias counter (huge loop) + blt $4, $trailquad # U .. .. .. : U L U L + +/* + * We know that we're going to do at least 16 quads, which means we are + * going to be able to use the large block clear loop at least once. + * Figure out how many quads we need to clear before we are 0mod64 aligned + * so we can use the wh64 instruction. + */ + + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $3, $bigalign # U .. .. .. : U L U L : Aligned 0mod64 + +$alignmod64: + EX( stq_u $31, 0($6) ) # .. .. .. L + addq $3, 8, $3 # .. .. E .. + subq $0, 8, $0 # .. E .. .. + nop # E .. .. .. : U L U L + + nop # .. .. .. E + subq $1, 1, $1 # .. .. E .. + addq $6, 8, $6 # .. E .. .. + blt $3, $alignmod64 # U .. .. .. : U L U L + +$bigalign: +/* + * $0 is the number of bytes left + * $1 is the number of quads left + * $6 is aligned 0mod64 + * we know that we'll be taking a minimum of one trip through + * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle + * We are _not_ going to update $0 after every single store. That + * would be silly, because there will be cross-cluster dependencies + * no matter how the code is scheduled. By doing it in slightly + * staggered fashion, we can still do this loop in 5 fetches + * The worse case will be doing two extra quads in some future execution, + * in the event of an interrupted clear. + * Assumes the wh64 needs to be for 2 trips through the loop in the future + * The wh64 is issued on for the starting destination address for trip +2 + * through the loop, and if there are less than two trips left, the target + * address will be for the current trip. + */ + nop # E : + nop # E : + nop # E : + bis $6,$6,$3 # E : U L U L : Initial wh64 address is dest + /* This might actually help for the current trip... */ + +$do_wh64: + wh64 ($3) # .. .. .. L1 : memory subsystem hint + subq $1, 16, $4 # .. .. E .. : Forward calculation - repeat the loop? + EX( stq_u $31, 0($6) ) # .. L .. .. + subq $0, 8, $0 # E .. .. .. : U L U L + + addq $6, 128, $3 # E : Target address of wh64 + EX( stq_u $31, 8($6) ) # L : + EX( stq_u $31, 16($6) ) # L : + subq $0, 16, $0 # E : U L L U + + nop # E : + EX( stq_u $31, 24($6) ) # L : + EX( stq_u $31, 32($6) ) # L : + subq $0, 168, $5 # E : U L L U : two trips through the loop left? + /* 168 = 192 - 24, since we've already completed some stores */ + + subq $0, 16, $0 # E : + EX( stq_u $31, 40($6) ) # L : + EX( stq_u $31, 48($6) ) # L : + cmovlt $5, $6, $3 # E : U L L U : Latency 2, extra mapping cycle + + subq $1, 8, $1 # E : + subq $0, 16, $0 # E : + EX( stq_u $31, 56($6) ) # L : + nop # E : U L U L + + nop # E : + subq $0, 8, $0 # E : + addq $6, 64, $6 # E : + bge $4, $do_wh64 # U : U L U L + +$trailquad: + # zero to 16 quadwords left to store, plus any trailing bytes + # $1 is the number of quadwords left to go. + # + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $1, $trailbytes # U .. .. .. : U L U L : Only 0..7 bytes to go + +$onequad: + EX( stq_u $31, 0($6) ) # .. .. .. L + subq $1, 1, $1 # .. .. E .. + subq $0, 8, $0 # .. E .. .. + nop # E .. .. .. : U L U L + + nop # .. .. .. E + nop # .. .. E .. + addq $6, 8, $6 # .. E .. .. + bgt $1, $onequad # U .. .. .. : U L U L + + # We have an unknown number of bytes left to go. +$trailbytes: + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $0, $zerolength # U .. .. .. : U L U L + + # $0 contains the number of bytes left to copy (0..31) + # so we will use $0 as the loop counter + # We know for a fact that $0 > 0 zero due to previous context +$onebyte: + EX( stb $31, 0($6) ) # .. .. .. L + subq $0, 1, $0 # .. .. E .. : + addq $6, 1, $6 # .. E .. .. : + bgt $0, $onebyte # U .. .. .. : U L U L + +$zerolength: +$exception: # Destination for exception recovery(?) + nop # .. .. .. E : + nop # .. .. E .. : + nop # .. E .. .. : + ret $31, ($28), 1 # L0 .. .. .. : L U L U + .end __do_clear_user + diff --git a/arch/alpha/lib/ev6-copy_user.S b/arch/alpha/lib/ev6-copy_user.S new file mode 100644 index 000000000000..a30f7324c845 --- /dev/null +++ b/arch/alpha/lib/ev6-copy_user.S @@ -0,0 +1,262 @@ +/* + * arch/alpha/lib/ev6-copy_user.S + * + * 21264 version contributed by Rick Gorton + * + * Copy to/from user space, handling exceptions as we go.. This + * isn't exactly pretty. + * + * This is essentially the same as "memcpy()", but with a few twists. + * Notably, we have to make sure that $0 is always up-to-date and + * contains the right "bytes left to copy" value (and that it is updated + * only _after_ a successful copy). There is also some rather minor + * exception setup stuff.. + * + * NOTE! This is not directly C-callable, because the calling semantics are + * different: + * + * Inputs: + * length in $0 + * destination address in $6 + * source address in $7 + * return address in $28 + * + * Outputs: + * bytes left to copy in $0 + * + * Clobbers: + * $1,$2,$3,$4,$5,$6,$7 + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + */ + +/* Allow an exception for an insn; exit if we get one. */ +#define EXI(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exitin-99b($31); \ + .previous + +#define EXO(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exitout-99b($31); \ + .previous + + .set noat + .align 4 + .globl __copy_user + .ent __copy_user + # Pipeline info: Slotting & Comments +__copy_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. + # Macro instruction becomes ldah/lda + # .. .. E E + .prologue 1 + subq $0, 32, $1 # .. E .. .. : Is this going to be a small copy? + beq $0, $zerolength # U .. .. .. : U L U L + + and $6,7,$3 # .. .. .. E : is leading dest misalignment + ble $1, $onebyteloop # .. .. U .. : 1st branch : small amount of data + beq $3, $destaligned # .. U .. .. : 2nd (one cycle fetcher stall) + subq $3, 8, $3 # E .. .. .. : L U U L : trip counter +/* + * The fetcher stall also hides the 1 cycle cross-cluster stall for $3 (L --> U) + * This loop aligns the destination a byte at a time + * We know we have at least one trip through this loop + */ +$aligndest: + EXI( ldbu $1,0($7) ) # .. .. .. L : Keep loads separate from stores + addq $6,1,$6 # .. .. E .. : Section 3.8 in the CWG + addq $3,1,$3 # .. E .. .. : + nop # E .. .. .. : U L U L + +/* + * the -1 is to compensate for the inc($6) done in a previous quadpack + * which allows us zero dependencies within either quadpack in the loop + */ + EXO( stb $1,-1($6) ) # .. .. .. L : + addq $7,1,$7 # .. .. E .. : Section 3.8 in the CWG + subq $0,1,$0 # .. E .. .. : + bne $3, $aligndest # U .. .. .. : U L U L + +/* + * If we fell through into here, we have a minimum of 33 - 7 bytes + * If we arrived via branch, we have a minimum of 32 bytes + */ +$destaligned: + and $7,7,$1 # .. .. .. E : Check _current_ source alignment + bic $0,7,$4 # .. .. E .. : number bytes as a quadword loop + EXI( ldq_u $3,0($7) ) # .. L .. .. : Forward fetch for fallthrough code + beq $1,$quadaligned # U .. .. .. : U L U L + +/* + * In the worst case, we've just executed an ldq_u here from 0($7) + * and we'll repeat it once if we take the branch + */ + +/* Misaligned quadword loop - not unrolled. Leave it that way. */ +$misquad: + EXI( ldq_u $2,8($7) ) # .. .. .. L : + subq $4,8,$4 # .. .. E .. : + extql $3,$7,$3 # .. U .. .. : + extqh $2,$7,$1 # U .. .. .. : U U L L + + bis $3,$1,$1 # .. .. .. E : + EXO( stq $1,0($6) ) # .. .. L .. : + addq $7,8,$7 # .. E .. .. : + subq $0,8,$0 # E .. .. .. : U L L U + + addq $6,8,$6 # .. .. .. E : + bis $2,$2,$3 # .. .. E .. : + nop # .. E .. .. : + bne $4,$misquad # U .. .. .. : U L U L + + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + beq $0,$zerolength # U .. .. .. : U L U L + +/* We know we have at least one trip through the byte loop */ + EXI ( ldbu $2,0($7) ) # .. .. .. L : No loads in the same quad + addq $6,1,$6 # .. .. E .. : as the store (Section 3.8 in CWG) + nop # .. E .. .. : + br $31, $dirtyentry # L0 .. .. .. : L U U L +/* Do the trailing byte loop load, then hop into the store part of the loop */ + +/* + * A minimum of (33 - 7) bytes to do a quad at a time. + * Based upon the usage context, it's worth the effort to unroll this loop + * $0 - number of bytes to be moved + * $4 - number of bytes to move as quadwords + * $6 is current destination address + * $7 is current source address + */ +$quadaligned: + subq $4, 32, $2 # .. .. .. E : do not unroll for small stuff + nop # .. .. E .. + nop # .. E .. .. + blt $2, $onequad # U .. .. .. : U L U L + +/* + * There is a significant assumption here that the source and destination + * addresses differ by more than 32 bytes. In this particular case, a + * sparsity of registers further bounds this to be a minimum of 8 bytes. + * But if this isn't met, then the output result will be incorrect. + * Furthermore, due to a lack of available registers, we really can't + * unroll this to be an 8x loop (which would enable us to use the wh64 + * instruction memory hint instruction). + */ +$unroll4: + EXI( ldq $1,0($7) ) # .. .. .. L + EXI( ldq $2,8($7) ) # .. .. L .. + subq $4,32,$4 # .. E .. .. + nop # E .. .. .. : U U L L + + addq $7,16,$7 # .. .. .. E + EXO( stq $1,0($6) ) # .. .. L .. + EXO( stq $2,8($6) ) # .. L .. .. + subq $0,16,$0 # E .. .. .. : U L L U + + addq $6,16,$6 # .. .. .. E + EXI( ldq $1,0($7) ) # .. .. L .. + EXI( ldq $2,8($7) ) # .. L .. .. + subq $4, 32, $3 # E .. .. .. : U U L L : is there enough for another trip? + + EXO( stq $1,0($6) ) # .. .. .. L + EXO( stq $2,8($6) ) # .. .. L .. + subq $0,16,$0 # .. E .. .. + addq $7,16,$7 # E .. .. .. : U L L U + + nop # .. .. .. E + nop # .. .. E .. + addq $6,16,$6 # .. E .. .. + bgt $3,$unroll4 # U .. .. .. : U L U L + + nop + nop + nop + beq $4, $noquads + +$onequad: + EXI( ldq $1,0($7) ) + subq $4,8,$4 + addq $7,8,$7 + nop + + EXO( stq $1,0($6) ) + subq $0,8,$0 + addq $6,8,$6 + bne $4,$onequad + +$noquads: + nop + nop + nop + beq $0,$zerolength + +/* + * For small copies (or the tail of a larger copy), do a very simple byte loop. + * There's no point in doing a lot of complex alignment calculations to try to + * to quadword stuff for a small amount of data. + * $0 - remaining number of bytes left to copy + * $6 - current dest addr + * $7 - current source addr + */ + +$onebyteloop: + EXI ( ldbu $2,0($7) ) # .. .. .. L : No loads in the same quad + addq $6,1,$6 # .. .. E .. : as the store (Section 3.8 in CWG) + nop # .. E .. .. : + nop # E .. .. .. : U L U L + +$dirtyentry: +/* + * the -1 is to compensate for the inc($6) done in a previous quadpack + * which allows us zero dependencies within either quadpack in the loop + */ + EXO ( stb $2,-1($6) ) # .. .. .. L : + addq $7,1,$7 # .. .. E .. : quadpack as the load + subq $0,1,$0 # .. E .. .. : change count _after_ copy + bgt $0,$onebyteloop # U .. .. .. : U L U L + +$zerolength: +$exitout: # Destination for exception recovery(?) + nop # .. .. .. E + nop # .. .. E .. + nop # .. E .. .. + ret $31,($28),1 # L0 .. .. .. : L U L U + +$exitin: + + /* A stupid byte-by-byte zeroing of the rest of the output + buffer. This cures security holes by never leaving + random kernel data around to be copied elsewhere. */ + + nop + nop + nop + mov $0,$1 + +$101: + EXO ( stb $31,0($6) ) # L + subq $1,1,$1 # E + addq $6,1,$6 # E + bgt $1,$101 # U + + nop + nop + nop + ret $31,($28),1 # L0 + + .end __copy_user + diff --git a/arch/alpha/lib/ev6-csum_ipv6_magic.S b/arch/alpha/lib/ev6-csum_ipv6_magic.S new file mode 100644 index 000000000000..de1948a69118 --- /dev/null +++ b/arch/alpha/lib/ev6-csum_ipv6_magic.S @@ -0,0 +1,126 @@ +/* + * arch/alpha/lib/ev6-csum_ipv6_magic.S + * 21264 version contributed by Rick Gorton + * + * unsigned short csum_ipv6_magic(struct in6_addr *saddr, + * struct in6_addr *daddr, + * __u32 len, + * unsigned short proto, + * unsigned int csum); + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + * Determining actual stalls (other than slotting) doesn't appear to be easy to do. + * + * unsigned short csum_ipv6_magic(struct in6_addr *saddr, + * struct in6_addr *daddr, + * __u32 len, + * unsigned short proto, + * unsigned int csum); + * + * Swap (takes form 0xaabb) + * Then shift it left by 48, so result is: + * 0xbbaa0000 00000000 + * Then turn it back into a sign extended 32-bit item + * 0xbbaa0000 + * + * Swap (an unsigned int) using Mike Burrows' 7-instruction sequence + * (we can't hide the 3-cycle latency of the unpkbw in the 6-instruction sequence) + * Assume input takes form 0xAABBCCDD + * + * Finally, original 'folding' approach is to split the long into 4 unsigned shorts + * add 4 ushorts, resulting in ushort/carry + * add carry bits + ushort --> ushort + * add carry bits + ushort --> ushort (in case the carry results in an overflow) + * Truncate to a ushort. (took 13 instructions) + * From doing some testing, using the approach in checksum.c:from64to16() + * results in the same outcome: + * split into 2 uints, add those, generating a ulong + * add the 3 low ushorts together, generating a uint + * a final add of the 2 lower ushorts + * truncating the result. + */ + + .globl csum_ipv6_magic + .align 4 + .ent csum_ipv6_magic + .frame $30,0,$26,0 +csum_ipv6_magic: + .prologue 0 + + ldq $0,0($16) # L : Latency: 3 + inslh $18,7,$4 # U : 0000000000AABBCC + ldq $1,8($16) # L : Latency: 3 + sll $19,8,$7 # U : U L U L : 0x00000000 00aabb00 + + zapnot $20,15,$20 # U : zero extend incoming csum + ldq $2,0($17) # L : Latency: 3 + sll $19,24,$19 # U : U L L U : 0x000000aa bb000000 + inswl $18,3,$18 # U : 000000CCDD000000 + + ldq $3,8($17) # L : Latency: 3 + bis $18,$4,$18 # E : 000000CCDDAABBCC + addl $19,$7,$19 # E : bbaabb00 + nop # E : U L U L + + addq $20,$0,$20 # E : begin summing the words + srl $18,16,$4 # U : 0000000000CCDDAA + zap $19,0x3,$19 # U : bbaa0000 + nop # E : L U U L + + cmpult $20,$0,$0 # E : + addq $20,$1,$20 # E : + zapnot $18,0xa,$18 # U : 00000000DD00BB00 + zap $4,0xa,$4 # U : U U L L : 0000000000CC00AA + + or $18,$4,$18 # E : 00000000DDCCBBAA + nop # E : + cmpult $20,$1,$1 # E : + addq $20,$2,$20 # E : U L U L + + cmpult $20,$2,$2 # E : + addq $20,$3,$20 # E : + cmpult $20,$3,$3 # E : (1 cycle stall on $20) + addq $20,$18,$20 # E : U L U L (1 cycle stall on $20) + + cmpult $20,$18,$18 # E : + addq $20,$19,$20 # E : (1 cycle stall on $20) + addq $0,$1,$0 # E : merge the carries back into the csum + addq $2,$3,$2 # E : + + cmpult $20,$19,$19 # E : + addq $18,$19,$18 # E : (1 cycle stall on $19) + addq $0,$2,$0 # E : + addq $20,$18,$20 # E : U L U L : + /* (1 cycle stall on $18, 2 cycles on $20) */ + + addq $0,$20,$0 # E : + zapnot $0,15,$1 # U : Start folding output (1 cycle stall on $0) + nop # E : + srl $0,32,$0 # U : U L U L : (1 cycle stall on $0) + + addq $1,$0,$1 # E : Finished generating ulong + extwl $1,2,$2 # U : ushort[1] (1 cycle stall on $1) + zapnot $1,3,$0 # U : ushort[0] (1 cycle stall on $1) + extwl $1,4,$1 # U : ushort[2] (1 cycle stall on $1) + + addq $0,$2,$0 # E + addq $0,$1,$3 # E : Finished generating uint + /* (1 cycle stall on $0) */ + extwl $3,2,$1 # U : ushort[1] (1 cycle stall on $3) + nop # E : L U L U + + addq $1,$3,$0 # E : Final carry + not $0,$4 # E : complement (1 cycle stall on $0) + zapnot $4,3,$0 # U : clear upper garbage bits + /* (1 cycle stall on $4) */ + ret # L0 : L U L U + + .end csum_ipv6_magic diff --git a/arch/alpha/lib/ev6-divide.S b/arch/alpha/lib/ev6-divide.S new file mode 100644 index 000000000000..2a82b9be93fa --- /dev/null +++ b/arch/alpha/lib/ev6-divide.S @@ -0,0 +1,259 @@ +/* + * arch/alpha/lib/ev6-divide.S + * + * 21264 version contributed by Rick Gorton + * + * Alpha division.. + */ + +/* + * The alpha chip doesn't provide hardware division, so we have to do it + * by hand. The compiler expects the functions + * + * __divqu: 64-bit unsigned long divide + * __remqu: 64-bit unsigned long remainder + * __divqs/__remqs: signed 64-bit + * __divlu/__remlu: unsigned 32-bit + * __divls/__remls: signed 32-bit + * + * These are not normal C functions: instead of the normal + * calling sequence, these expect their arguments in registers + * $24 and $25, and return the result in $27. Register $28 may + * be clobbered (assembly temporary), anything else must be saved. + * + * In short: painful. + * + * This is a rather simple bit-at-a-time algorithm: it's very good + * at dividing random 64-bit numbers, but the more usual case where + * the divisor is small is handled better by the DEC algorithm + * using lookup tables. This uses much less memory, though, and is + * nicer on the cache.. Besides, I don't know the copyright status + * of the DEC code. + */ + +/* + * My temporaries: + * $0 - current bit + * $1 - shifted divisor + * $2 - modulus/quotient + * + * $23 - return address + * $24 - dividend + * $25 - divisor + * + * $27 - quotient/modulus + * $28 - compare status + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#define halt .long 0 + +/* + * Select function type and registers + */ +#define mask $0 +#define divisor $1 +#define compare $28 +#define tmp1 $3 +#define tmp2 $4 + +#ifdef DIV +#define DIV_ONLY(x,y...) x,##y +#define MOD_ONLY(x,y...) +#define func(x) __div##x +#define modulus $2 +#define quotient $27 +#define GETSIGN(x) xor $24,$25,x +#define STACK 48 +#else +#define DIV_ONLY(x,y...) +#define MOD_ONLY(x,y...) x,##y +#define func(x) __rem##x +#define modulus $27 +#define quotient $2 +#define GETSIGN(x) bis $24,$24,x +#define STACK 32 +#endif + +/* + * For 32-bit operations, we need to extend to 64-bit + */ +#ifdef INTSIZE +#define ufunction func(lu) +#define sfunction func(l) +#define LONGIFY(x) zapnot x,15,x +#define SLONGIFY(x) addl x,0,x +#else +#define ufunction func(qu) +#define sfunction func(q) +#define LONGIFY(x) +#define SLONGIFY(x) +#endif + +.set noat +.align 4 +.globl ufunction +.ent ufunction +ufunction: + subq $30,STACK,$30 # E : + .frame $30,STACK,$23 + .prologue 0 + +7: stq $1, 0($30) # L : + bis $25,$25,divisor # E : + stq $2, 8($30) # L : L U L U + + bis $24,$24,modulus # E : + stq $0,16($30) # L : + bis $31,$31,quotient # E : + LONGIFY(divisor) # E : U L L U + + stq tmp1,24($30) # L : + LONGIFY(modulus) # E : + bis $31,1,mask # E : + DIV_ONLY(stq tmp2,32($30)) # L : L U U L + + beq divisor, 9f /* div by zero */ + /* + * In spite of the DIV_ONLY being either a non-instruction + * or an actual stq, the addition of the .align directive + * below ensures that label 1 is going to be nicely aligned + */ + + .align 4 +#ifdef INTSIZE + /* + * shift divisor left, using 3-bit shifts for + * 32-bit divides as we can't overflow. Three-bit + * shifts will result in looping three times less + * here, but can result in two loops more later. + * Thus using a large shift isn't worth it (and + * s8add pairs better than a sll..) + */ +1: cmpult divisor,modulus,compare # E : + s8addq divisor,$31,divisor # E : + s8addq mask,$31,mask # E : + bne compare,1b # U : U L U L +#else +1: cmpult divisor,modulus,compare # E : + nop # E : + nop # E : + blt divisor, 2f # U : U L U L + + addq divisor,divisor,divisor # E : + addq mask,mask,mask # E : + unop # E : + bne compare,1b # U : U L U L +#endif + + /* ok, start to go right again.. */ +2: + /* + * Keep things nicely bundled... use a nop instead of not + * having an instruction for DIV_ONLY + */ +#ifdef DIV + DIV_ONLY(addq quotient,mask,tmp2) # E : +#else + nop # E : +#endif + srl mask,1,mask # U : + cmpule divisor,modulus,compare # E : + subq modulus,divisor,tmp1 # E : + +#ifdef DIV + DIV_ONLY(cmovne compare,tmp2,quotient) # E : Latency 2, extra map slot + nop # E : as part of the cmovne + srl divisor,1,divisor # U : + nop # E : L U L U + + nop # E : + cmovne compare,tmp1,modulus # E : Latency 2, extra map slot + nop # E : as part of the cmovne + bne mask,2b # U : U L U L +#else + srl divisor,1,divisor # U : + cmovne compare,tmp1,modulus # E : Latency 2, extra map slot + nop # E : as part of the cmovne + bne mask,2b # U : U L L U +#endif + +9: ldq $1, 0($30) # L : + ldq $2, 8($30) # L : + nop # E : + nop # E : U U L L + + ldq $0,16($30) # L : + ldq tmp1,24($30) # L : + nop # E : + nop # E : + +#ifdef DIV + DIV_ONLY(ldq tmp2,32($30)) # L : +#else + nop # E : +#endif + addq $30,STACK,$30 # E : + ret $31,($23),1 # L0 : L U U L + .end ufunction + +/* + * Uhh.. Ugly signed division. I'd rather not have it at all, but + * it's needed in some circumstances. There are different ways to + * handle this, really. This does: + * -a / b = a / -b = -(a / b) + * -a % b = -(a % b) + * a % -b = a % b + * which is probably not the best solution, but at least should + * have the property that (x/y)*y + (x%y) = x. + */ +.align 4 +.globl sfunction +.ent sfunction +sfunction: + subq $30,STACK,$30 # E : + .frame $30,STACK,$23 + .prologue 0 + bis $24,$25,$28 # E : + SLONGIFY($28) # E : + bge $28,7b # U : + + stq $24,0($30) # L : + subq $31,$24,$28 # E : + stq $25,8($30) # L : + nop # E : U L U L + + cmovlt $24,$28,$24 /* abs($24) */ # E : Latency 2, extra map slot + nop # E : as part of the cmov + stq $23,16($30) # L : + subq $31,$25,$28 # E : U L U L + + stq tmp1,24($30) # L : + cmovlt $25,$28,$25 /* abs($25) */ # E : Latency 2, extra map slot + nop # E : + bsr $23,ufunction # L0: L U L U + + ldq $24,0($30) # L : + ldq $25,8($30) # L : + GETSIGN($28) # E : + subq $31,$27,tmp1 # E : U U L L + + SLONGIFY($28) # E : + ldq $23,16($30) # L : + cmovlt $28,tmp1,$27 # E : Latency 2, extra map slot + nop # E : U L L U : as part of the cmov + + ldq tmp1,24($30) # L : + nop # E : as part of the cmov + addq $30,STACK,$30 # E : + ret $31,($23),1 # L0 : L U U L + .end sfunction diff --git a/arch/alpha/lib/ev6-strcpy.S b/arch/alpha/lib/ev6-strcpy.S new file mode 100644 index 000000000000..8a6673dbe4bb --- /dev/null +++ b/arch/alpha/lib/ev6-strcpy.S @@ -0,0 +1,23 @@ +/* + * arch/alpha/lib/strcpy.S + * Contributed by Richard Henderson (rth@tamu.edu) + * + * Copy a null-terminated string from SRC to DST. Return a pointer + * to the null-terminator in the source. + */ + + .text + + .align 4 + .globl strcpy + .ent strcpy +strcpy: + .frame $30, 0, $26 + .prologue 0 + + mov $16, $0 # set up return value + mov $26, $23 # set up return address + br __stxcpy # do the copy + nop + + .end strcpy diff --git a/arch/alpha/lib/ev6-strncpy.S b/arch/alpha/lib/ev6-strncpy.S new file mode 100644 index 000000000000..053146bf5c04 --- /dev/null +++ b/arch/alpha/lib/ev6-strncpy.S @@ -0,0 +1,36 @@ +/* + * arch/alpha/lib/strncpy.S + * Contributed by Richard Henderson (rth@tamu.edu) + * + * Copy no more than COUNT bytes of the null-terminated string from + * SRC to DST. If SRC does not cover all of COUNT, the balance is + * zeroed. + * + * Or, rather, if the kernel cared about that weird ANSI quirk. This + * version has cropped that bit o' nastiness as well as assuming that + * __stxncpy is in range of a branch. + */ + + .set noat + .set noreorder + + .text + + .align 4 + .globl strncpy + .ent strncpy +strncpy: + .frame $30, 0, $26 + .prologue 0 + + mov $16, $0 # set return value now + beq $18, 0f + mov $26, $23 # set return address + br __stxncpy # do the work of the copy + +0: ret + nop + nop + nop + + .end strncpy diff --git a/arch/alpha/lib/ev6-strncpy_from_user.S b/arch/alpha/lib/ev6-strncpy_from_user.S new file mode 100644 index 000000000000..8d446778bf47 --- /dev/null +++ b/arch/alpha/lib/ev6-strncpy_from_user.S @@ -0,0 +1,425 @@ +/* + * arch/alpha/lib/ev6-strncpy_from_user.S + * 21264 version contributed by Rick Gorton + * + * Just like strncpy except in the return value: + * + * -EFAULT if an exception occurs before the terminator is copied. + * N if the buffer filled. + * + * Otherwise the length of the string is returned. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * A bunch of instructions got moved and temp registers were changed + * to aid in scheduling. Control flow was also re-arranged to eliminate + * branches, and to provide longer code sequences to enable better scheduling. + * A total rewrite (using byte load/stores for start & tail sequences) + * is desirable, but very difficult to do without a from-scratch rewrite. + * Save that for the future. + */ + + +#include +#include + + +/* Allow an exception for an insn; exit if we get one. */ +#define EX(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda $31, $exception-99b($0); \ + .previous + + + .set noat + .set noreorder + .text + + .globl __strncpy_from_user + .ent __strncpy_from_user + .frame $30, 0, $26 + .prologue 1 + + .align 4 +__strncpy_from_user: + ldgp $29, 0($27) # E E : becomes 2 instructions (for exceptions) + and a0, 7, t3 # E : find dest misalignment + beq a2, $zerolength # U : + + /* Are source and destination co-aligned? */ + mov a0, v0 # E : save the string start + xor a0, a1, t4 # E : + EX( ldq_u t1, 0(a1) ) # L : Latency=3 load first quadword + ldq_u t0, 0(a0) # L : load first (partial) aligned dest quadword + + addq a2, t3, a2 # E : bias count by dest misalignment + subq a2, 1, a3 # E : + addq zero, 1, t10 # E : + and t4, 7, t4 # E : misalignment between the two + + and a3, 7, t6 # E : number of tail bytes + sll t10, t6, t10 # E : t10 = bitmask of last count byte + bne t4, $unaligned # U : + lda t2, -1 # E : build a mask against false zero + + /* + * We are co-aligned; take care of a partial first word. + * On entry to this basic block: + * t0 == the first destination word for masking back in + * t1 == the first source word. + */ + + srl a3, 3, a2 # E : a2 = loop counter = (count - 1)/8 + addq a1, 8, a1 # E : + mskqh t2, a1, t2 # U : detection in the src word + nop + + /* Create the 1st output word and detect 0's in the 1st input word. */ + mskqh t1, a1, t3 # U : + mskql t0, a1, t0 # U : assemble the first output word + ornot t1, t2, t2 # E : + nop + + cmpbge zero, t2, t8 # E : bits set iff null found + or t0, t3, t0 # E : + beq a2, $a_eoc # U : + bne t8, $a_eos # U : 2nd branch in a quad. Bad. + + /* On entry to this basic block: + * t0 == a source quad not containing a null. + * a0 - current aligned destination address + * a1 - current aligned source address + * a2 - count of quadwords to move. + * NOTE: Loop improvement - unrolling this is going to be + * a huge win, since we're going to stall otherwise. + * Fix this later. For _really_ large copies, look + * at using wh64 on a look-ahead basis. See the code + * in clear_user.S and copy_user.S. + * Presumably, since (a0) and (a1) do not overlap (by C definition) + * Lots of nops here: + * - Separate loads from stores + * - Keep it to 1 branch/quadpack so the branch predictor + * can train. + */ +$a_loop: + stq_u t0, 0(a0) # L : + addq a0, 8, a0 # E : + nop + subq a2, 1, a2 # E : + + EX( ldq_u t0, 0(a1) ) # L : + addq a1, 8, a1 # E : + cmpbge zero, t0, t8 # E : Stall 2 cycles on t0 + beq a2, $a_eoc # U : + + beq t8, $a_loop # U : + nop + nop + nop + + /* Take care of the final (partial) word store. At this point + * the end-of-count bit is set in t8 iff it applies. + * + * On entry to this basic block we have: + * t0 == the source word containing the null + * t8 == the cmpbge mask that found it. + */ +$a_eos: + negq t8, t12 # E : find low bit set + and t8, t12, t12 # E : + + /* We're doing a partial word store and so need to combine + our source and original destination words. */ + ldq_u t1, 0(a0) # L : + subq t12, 1, t6 # E : + + or t12, t6, t8 # E : + zapnot t0, t8, t0 # U : clear src bytes > null + zap t1, t8, t1 # U : clear dst bytes <= null + or t0, t1, t0 # E : + + stq_u t0, 0(a0) # L : + br $finish_up # L0 : + nop + nop + + /* Add the end-of-count bit to the eos detection bitmask. */ + .align 4 +$a_eoc: + or t10, t8, t8 + br $a_eos + nop + nop + + +/* The source and destination are not co-aligned. Align the destination + and cope. We have to be very careful about not reading too much and + causing a SEGV. */ + + .align 4 +$u_head: + /* We know just enough now to be able to assemble the first + full source word. We can still find a zero at the end of it + that prevents us from outputting the whole thing. + + On entry to this basic block: + t0 == the first dest word, unmasked + t1 == the shifted low bits of the first source word + t6 == bytemask that is -1 in dest word bytes */ + + EX( ldq_u t2, 8(a1) ) # L : load second src word + addq a1, 8, a1 # E : + mskql t0, a0, t0 # U : mask trailing garbage in dst + extqh t2, a1, t4 # U : + + or t1, t4, t1 # E : first aligned src word complete + mskqh t1, a0, t1 # U : mask leading garbage in src + or t0, t1, t0 # E : first output word complete + or t0, t6, t6 # E : mask original data for zero test + + cmpbge zero, t6, t8 # E : + beq a2, $u_eocfin # U : + bne t8, $u_final # U : bad news - 2nd branch in a quad + lda t6, -1 # E : mask out the bits we have + + mskql t6, a1, t6 # U : already seen + stq_u t0, 0(a0) # L : store first output word + or t6, t2, t2 # E : + cmpbge zero, t2, t8 # E : find nulls in second partial + + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + bne t8, $u_late_head_exit # U : + nop + + /* Finally, we've got all the stupid leading edge cases taken care + of and we can set up to enter the main loop. */ + + extql t2, a1, t1 # U : position hi-bits of lo word + EX( ldq_u t2, 8(a1) ) # L : read next high-order source word + addq a1, 8, a1 # E : + cmpbge zero, t2, t8 # E : + + beq a2, $u_eoc # U : + bne t8, $u_eos # U : + nop + nop + + /* Unaligned copy main loop. In order to avoid reading too much, + the loop is structured to detect zeros in aligned source words. + This has, unfortunately, effectively pulled half of a loop + iteration out into the head and half into the tail, but it does + prevent nastiness from accumulating in the very thing we want + to run as fast as possible. + + On entry to this basic block: + t1 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word + + We further know that t2 does not contain a null terminator. */ + + /* + * Extra nops here: + * separate load quads from store quads + * only one branch/quad to permit predictor training + */ + + .align 4 +$u_loop: + extqh t2, a1, t0 # U : extract high bits for current word + addq a1, 8, a1 # E : + extql t2, a1, t3 # U : extract low bits for next time + addq a0, 8, a0 # E : + + or t0, t1, t0 # E : current dst word now complete + EX( ldq_u t2, 0(a1) ) # L : load high word for next time + subq a2, 1, a2 # E : + nop + + stq_u t0, -8(a0) # L : save the current word + mov t3, t1 # E : + cmpbge zero, t2, t8 # E : test new word for eos + beq a2, $u_eoc # U : + + beq t8, $u_loop # U : + nop + nop + nop + + /* We've found a zero somewhere in the source word we just read. + If it resides in the lower half, we have one (probably partial) + word to write out, and if it resides in the upper half, we + have one full and one partial word left to write out. + + On entry to this basic block: + t1 == the shifted high-order bits from the previous source word + t2 == the unshifted current source word. */ + .align 4 +$u_eos: + extqh t2, a1, t0 # U : + or t0, t1, t0 # E : first (partial) source word complete + cmpbge zero, t0, t8 # E : is the null in this first bit? + nop + + bne t8, $u_final # U : + stq_u t0, 0(a0) # L : the null was in the high-order bits + addq a0, 8, a0 # E : + subq a2, 1, a2 # E : + + .align 4 +$u_late_head_exit: + extql t2, a1, t0 # U : + cmpbge zero, t0, t8 # E : + or t8, t10, t6 # E : + cmoveq a2, t6, t8 # E : + + /* Take care of a final (probably partial) result word. + On entry to this basic block: + t0 == assembled source word + t8 == cmpbge mask that found the null. */ + .align 4 +$u_final: + negq t8, t6 # E : isolate low bit set + and t6, t8, t12 # E : + ldq_u t1, 0(a0) # L : + subq t12, 1, t6 # E : + + or t6, t12, t8 # E : + zapnot t0, t8, t0 # U : kill source bytes > null + zap t1, t8, t1 # U : kill dest bytes <= null + or t0, t1, t0 # E : + + stq_u t0, 0(a0) # E : + br $finish_up # U : + nop + nop + + .align 4 +$u_eoc: # end-of-count + extqh t2, a1, t0 # U : + or t0, t1, t0 # E : + cmpbge zero, t0, t8 # E : + nop + + .align 4 +$u_eocfin: # end-of-count, final word + or t10, t8, t8 # E : + br $u_final # U : + nop + nop + + /* Unaligned copy entry point. */ + .align 4 +$unaligned: + + srl a3, 3, a2 # U : a2 = loop counter = (count - 1)/8 + and a0, 7, t4 # E : find dest misalignment + and a1, 7, t5 # E : find src misalignment + mov zero, t0 # E : + + /* Conditionally load the first destination word and a bytemask + with 0xff indicating that the destination byte is sacrosanct. */ + + mov zero, t6 # E : + beq t4, 1f # U : + ldq_u t0, 0(a0) # L : + lda t6, -1 # E : + + mskql t6, a0, t6 # E : + nop + nop + nop + + .align 4 +1: + subq a1, t4, a1 # E : sub dest misalignment from src addr + /* If source misalignment is larger than dest misalignment, we need + extra startup checks to avoid SEGV. */ + cmplt t4, t5, t12 # E : + extql t1, a1, t1 # U : shift src into place + lda t2, -1 # E : for creating masks later + + beq t12, $u_head # U : + mskqh t2, t5, t2 # U : begin src byte validity mask + cmpbge zero, t1, t8 # E : is there a zero? + nop + + extql t2, a1, t2 # U : + or t8, t10, t5 # E : test for end-of-count too + cmpbge zero, t2, t3 # E : + cmoveq a2, t5, t8 # E : Latency=2, extra map slot + + nop # E : goes with cmov + andnot t8, t3, t8 # E : + beq t8, $u_head # U : + nop + + /* At this point we've found a zero in the first partial word of + the source. We need to isolate the valid source data and mask + it into the original destination data. (Incidentally, we know + that we'll need at least one byte of that original dest word.) */ + + ldq_u t0, 0(a0) # L : + negq t8, t6 # E : build bitmask of bytes <= zero + mskqh t1, t4, t1 # U : + and t6, t8, t12 # E : + + subq t12, 1, t6 # E : + or t6, t12, t8 # E : + zapnot t2, t8, t2 # U : prepare source word; mirror changes + zapnot t1, t8, t1 # U : to source validity mask + + andnot t0, t2, t0 # E : zero place for source to reside + or t0, t1, t0 # E : and put it there + stq_u t0, 0(a0) # L : + nop + + .align 4 +$finish_up: + zapnot t0, t12, t4 # U : was last byte written null? + and t12, 0xf0, t3 # E : binary search for the address of the + cmovne t4, 1, t4 # E : Latency=2, extra map slot + nop # E : with cmovne + + and t12, 0xcc, t2 # E : last byte written + and t12, 0xaa, t1 # E : + cmovne t3, 4, t3 # E : Latency=2, extra map slot + nop # E : with cmovne + + bic a0, 7, t0 + cmovne t2, 2, t2 # E : Latency=2, extra map slot + nop # E : with cmovne + nop + + cmovne t1, 1, t1 # E : Latency=2, extra map slot + nop # E : with cmovne + addq t0, t3, t0 # E : + addq t1, t2, t1 # E : + + addq t0, t1, t0 # E : + addq t0, t4, t0 # add one if we filled the buffer + subq t0, v0, v0 # find string length + ret # L0 : + + .align 4 +$zerolength: + nop + nop + nop + clr v0 + +$exception: + nop + nop + nop + ret + + .end __strncpy_from_user diff --git a/arch/alpha/lib/ev67-strcat.S b/arch/alpha/lib/ev67-strcat.S new file mode 100644 index 000000000000..c426fe3ed72f --- /dev/null +++ b/arch/alpha/lib/ev67-strcat.S @@ -0,0 +1,54 @@ +/* + * arch/alpha/lib/ev67-strcat.S + * 21264 version contributed by Rick Gorton + * + * Append a null-terminated string from SRC to DST. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + * Commentary: It seems bogus to walk the input string twice - once + * to determine the length, and then again while doing the copy. + * A significant (future) enhancement would be to only read the input + * string once. + */ + + + .text + + .align 4 + .globl strcat + .ent strcat +strcat: + .frame $30, 0, $26 + .prologue 0 + + mov $16, $0 # E : set up return value + /* Find the end of the string. */ + ldq_u $1, 0($16) # L : load first quadword (a0 may be misaligned) + lda $2, -1 # E : + insqh $2, $16, $2 # U : + + andnot $16, 7, $16 # E : + or $2, $1, $1 # E : + cmpbge $31, $1, $2 # E : bits set iff byte == 0 + bne $2, $found # U : + +$loop: ldq $1, 8($16) # L : + addq $16, 8, $16 # E : + cmpbge $31, $1, $2 # E : + beq $2, $loop # U : + +$found: cttz $2, $3 # U0 : + addq $16, $3, $16 # E : + /* Now do the append. */ + mov $26, $23 # E : + br __stxcpy # L0 : + + .end strcat diff --git a/arch/alpha/lib/ev67-strchr.S b/arch/alpha/lib/ev67-strchr.S new file mode 100644 index 000000000000..b817f82a0c73 --- /dev/null +++ b/arch/alpha/lib/ev67-strchr.S @@ -0,0 +1,88 @@ +/* + * arch/alpha/lib/ev67-strchr.S + * 21264 version contributed by Rick Gorton + * + * Return the address of a given character within a null-terminated + * string, or null if it is not found. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#include + + .set noreorder + .set noat + + .align 4 + .globl strchr + .ent strchr +strchr: + .frame sp, 0, ra + .prologue 0 + + ldq_u t0, 0(a0) # L : load first quadword Latency=3 + and a1, 0xff, t3 # E : 00000000000000ch + insbl a1, 1, t5 # U : 000000000000ch00 + insbl a1, 7, a2 # U : ch00000000000000 + + insbl t3, 6, a3 # U : 00ch000000000000 + or t5, t3, a1 # E : 000000000000chch + andnot a0, 7, v0 # E : align our loop pointer + lda t4, -1 # E : build garbage mask + + mskqh t4, a0, t4 # U : only want relevant part of first quad + or a2, a3, a2 # E : chch000000000000 + inswl a1, 2, t5 # E : 00000000chch0000 + inswl a1, 4, a3 # E : 0000chch00000000 + + or a1, a2, a1 # E : chch00000000chch + or a3, t5, t5 # E : 0000chchchch0000 + cmpbge zero, t0, t2 # E : bits set iff byte == zero + cmpbge zero, t4, t4 # E : bits set iff byte is garbage + + /* This quad is _very_ serialized. Lots of stalling happens */ + or t5, a1, a1 # E : chchchchchchchch + xor t0, a1, t1 # E : make bytes == c zero + cmpbge zero, t1, t3 # E : bits set iff byte == c + or t2, t3, t0 # E : bits set iff char match or zero match + + andnot t0, t4, t0 # E : clear garbage bits + cttz t3, a2 # U0 : speculative (in case we get a match) + nop # E : + bne t0, $found # U : Stall on t0 + + /* + * Yuk. This loop is going to stall like crazy waiting for the + * data to be loaded. Not much can be done about it unless it's + * unrolled multiple times - is that safe to do in kernel space? + * Or would exception handling recovery code do the trick here? + */ +$loop: ldq t0, 8(v0) # L : Latency=3 + addq v0, 8, v0 # E : + xor t0, a1, t1 # E : + cmpbge zero, t0, t2 # E : bits set iff byte == 0 + + cmpbge zero, t1, t3 # E : bits set iff byte == c + or t2, t3, t0 # E : + cttz t3, a2 # U0 : speculative (in case we get a match) + beq t0, $loop # U : + +$found: negq t0, t1 # E : clear all but least set bit + and t0, t1, t0 # E : + and t0, t3, t1 # E : bit set iff byte was the char + addq v0, a2, v0 # E : Add in the bit number from above + + cmoveq t1, $31, v0 # E : Two mapping slots, latency = 2 + nop + nop + ret # L0 : + + .end strchr diff --git a/arch/alpha/lib/ev67-strlen.S b/arch/alpha/lib/ev67-strlen.S new file mode 100644 index 000000000000..503928072523 --- /dev/null +++ b/arch/alpha/lib/ev67-strlen.S @@ -0,0 +1,49 @@ +/* + * arch/alpha/lib/ev67-strlen.S + * 21264 version by Rick Gorton + * + * Finds length of a 0-terminated string. Optimized for the + * Alpha architecture: + * + * - memory accessed as aligned quadwords only + * - uses bcmpge to compare 8 bytes in parallel + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + */ + + .set noreorder + .set noat + + .globl strlen + .ent strlen + .align 4 +strlen: + ldq_u $1, 0($16) # L : load first quadword ($16 may be misaligned) + lda $2, -1($31) # E : + insqh $2, $16, $2 # U : + andnot $16, 7, $0 # E : + + or $2, $1, $1 # E : + cmpbge $31, $1, $2 # E : $2 <- bitmask: bit i == 1 <==> i-th byte == 0 + nop # E : + bne $2, $found # U : + +$loop: ldq $1, 8($0) # L : + addq $0, 8, $0 # E : addr += 8 + cmpbge $31, $1, $2 # E : + beq $2, $loop # U : + +$found: + cttz $2, $3 # U0 : + addq $0, $3, $0 # E : + subq $0, $16, $0 # E : + ret $31, ($26) # L0 : + + .end strlen diff --git a/arch/alpha/lib/ev67-strlen_user.S b/arch/alpha/lib/ev67-strlen_user.S new file mode 100644 index 000000000000..67f1e9426a3b --- /dev/null +++ b/arch/alpha/lib/ev67-strlen_user.S @@ -0,0 +1,109 @@ +/* + * arch/alpha/lib/ev67-strlen_user.S + * 21264 version contributed by Rick Gorton + * + * Return the length of the string including the NULL terminator + * (strlen+1) or zero if an error occurred. + * + * In places where it is critical to limit the processing time, + * and the data is not trusted, strnlen_user() should be used. + * It will return a value greater than its second argument if + * that limit would be exceeded. This implementation is allowed + * to access memory beyond the limit, but will not cross a page + * boundary when doing so. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + +#include + + +/* Allow an exception for an insn; exit if we get one. */ +#define EX(x,y...) \ + 99: x,##y; \ + .section __ex_table,"a"; \ + .gprel32 99b; \ + lda v0, $exception-99b(zero); \ + .previous + + + .set noreorder + .set noat + .text + + .globl __strlen_user + .ent __strlen_user + .frame sp, 0, ra + + .align 4 +__strlen_user: + ldah a1, 32767(zero) # do not use plain strlen_user() for strings + # that might be almost 2 GB long; you should + # be using strnlen_user() instead + nop + nop + nop + + .globl __strnlen_user + + .align 4 +__strnlen_user: + ldgp $29,0($27) # E E : we do exceptions -- we need the gp. + /* Decomposes into lda/ldah */ + .prologue 1 + EX( ldq_u t0, 0(a0) ) # L : load first quadword (a0 may be misaligned) + lda t1, -1(zero) # E : + + insqh t1, a0, t1 # U : + andnot a0, 7, v0 # E : + or t1, t0, t0 # E : + subq a0, 1, a0 # E : get our +1 for the return + + cmpbge zero, t0, t1 # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0 + subq a1, 7, t2 # E : + subq a0, v0, t0 # E : + bne t1, $found # U : + + addq t2, t0, t2 # E : + addq a1, 1, a1 # E : + nop # E : + nop # E : + + .align 4 +$loop: ble t2, $limit # U : + EX( ldq t0, 8(v0) ) # L : + nop # E : + nop # E : + + cmpbge zero, t0, t1 # E : + subq t2, 8, t2 # E : + addq v0, 8, v0 # E : addr += 8 + beq t1, $loop # U : + +$found: cttz t1, t2 # U0 : + addq v0, t2, v0 # E : + subq v0, a0, v0 # E : + ret # L0 : + +$exception: + nop + nop + nop + ret + + .align 4 # currently redundant +$limit: + nop + nop + subq a1, t2, v0 + ret + + .end __strlen_user diff --git a/arch/alpha/lib/ev67-strncat.S b/arch/alpha/lib/ev67-strncat.S new file mode 100644 index 000000000000..4ae716cd2bfb --- /dev/null +++ b/arch/alpha/lib/ev67-strncat.S @@ -0,0 +1,94 @@ +/* + * arch/alpha/lib/ev67-strncat.S + * 21264 version contributed by Rick Gorton + * + * Append no more than COUNT characters from the null-terminated string SRC + * to the null-terminated string DST. Always null-terminate the new DST. + * + * This differs slightly from the semantics in libc in that we never write + * past count, whereas libc may write to count+1. This follows the generic + * implementation in lib/string.c and is, IMHO, more sensible. + * + * Much of the information about 21264 scheduling/coding comes from: + * Compiler Writer's Guide for the Alpha 21264 + * abbreviated as 'CWG' in other comments here + * ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html + * Scheduling notation: + * E - either cluster + * U - upper subcluster; U0 - subcluster U0; U1 - subcluster U1 + * L - lower subcluster; L0 - subcluster L0; L1 - subcluster L1 + * Try not to change the actual algorithm if possible for consistency. + */ + + + .text + + .align 4 + .globl strncat + .ent strncat +strncat: + .frame $30, 0, $26 + .prologue 0 + + mov $16, $0 # set up return value + beq $18, $zerocount # U : + /* Find the end of the string. */ + ldq_u $1, 0($16) # L : load first quadword ($16 may be misaligned) + lda $2, -1($31) # E : + + insqh $2, $0, $2 # U : + andnot $16, 7, $16 # E : + nop # E : + or $2, $1, $1 # E : + + nop # E : + nop # E : + cmpbge $31, $1, $2 # E : bits set iff byte == 0 + bne $2, $found # U : + +$loop: ldq $1, 8($16) # L : + addq $16, 8, $16 # E : + cmpbge $31, $1, $2 # E : + beq $2, $loop # U : + +$found: cttz $2, $3 # U0 : + addq $16, $3, $16 # E : + nop # E : + bsr $23, __stxncpy # L0 :/* Now do the append. */ + + /* Worry about the null termination. */ + + zapnot $1, $27, $2 # U : was last byte a null? + cmplt $27, $24, $5 # E : did we fill the buffer completely? + bne $2, 0f # U : + ret # L0 : + +0: or $5, $18, $2 # E : + nop + bne $2, 2f # U : + and $24, 0x80, $3 # E : no zero next byte + + nop # E : + bne $3, 1f # U : + /* Here there are bytes left in the current word. Clear one. */ + addq $24, $24, $24 # E : end-of-count bit <<= 1 + nop # E : + +2: zap $1, $24, $1 # U : + nop # E : + stq_u $1, 0($16) # L : + ret # L0 : + +1: /* Here we must clear the first byte of the next DST word */ + stb $31, 8($16) # L : + nop # E : + nop # E : + ret # L0 : + +$zerocount: + nop # E : + nop # E : + nop # E : + ret # L0 : + + .end strncat diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 76db09e765b1..9d0cc5c698a0 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -42,12 +42,6 @@ const char *processor_modes[]= static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - /* * Stack pointers should always be within the kernels view of * physical memory. If it is not there, then we can't dump diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 92ddd01f5dea..cf68787873d0 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -179,7 +179,7 @@ int get_irq_list(char *buf) #ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile int global_irq_lock; +unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */ extern void show_stack(unsigned long* esp); diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 4871aa2ae39e..eef85b801d3f 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -2172,7 +2172,7 @@ int get_cpuinfo(char * buffer) "fpu_exception\t: %s\n" "cpuid level\t: %d\n" "wp\t\t: %s\n" - "features\t:", + "flags\t:", c->fdiv_bug ? "yes" : "no", c->hlt_works_ok ? "no" : "yes", c->f00f_bug ? "yes" : "no", diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 57a07765ec49..858e7dda0bc7 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -886,8 +886,10 @@ void __init smp_boot_cpus(void) /* * If we couldn't find a local APIC, then get out of here now! */ - if (!verify_local_APIC()) { - printk(KERN_ERR "BIOS bug, local APIC at 0x%lX not detected!...\n", mp_lapic_addr); + if (APIC_INTEGRATED(apic_version[boot_cpu_id]) && + !test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)) { + printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", + boot_cpu_id); printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); #ifndef CONFIG_VISWS io_apic_irqs = 0; @@ -897,6 +899,8 @@ void __init smp_boot_cpus(void) goto smp_done; } + verify_local_APIC(); + /* * If SMP should be disabled, then really disable it! */ diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index b8442137454d..f2077f2f274d 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -62,20 +62,8 @@ struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, */ struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; -extern int console_loglevel; extern void bust_spinlocks(void); -static inline void console_silent(void) -{ - console_loglevel = 0; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = 15; -} - asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 30d4def40c8c..b3646e275c94 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -181,7 +181,7 @@ int get_irq_list(char *buf) #ifdef CONFIG_SMP unsigned int global_irq_holder = NO_PROC_ID; -volatile unsigned int global_irq_lock; +volatile unsigned long global_irq_lock; /* long for set_bit --RR */ extern void show_stack(unsigned long* esp); diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index 445a99780dc7..9b9bab2bdcbc 100644 --- a/arch/m68k/mac/baboon.c +++ b/arch/m68k/mac/baboon.c @@ -27,8 +27,6 @@ volatile struct baboon *baboon; void baboon_irq(int, void *, struct pt_regs *); -extern int console_loglevel; - extern int macide_ack_intr(ide_hwif_t *); /* diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index ef02d9bb98b9..1a1a38e60149 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -115,8 +115,6 @@ static void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) via_init_clock(vector); } -extern int console_loglevel; - #if 0 void mac_waitbut (void) { diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index febba19824db..061b01bd8ec9 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -211,8 +211,6 @@ static void scc_irq_disable(int); * console_loglevel determines NMI handler function */ -extern int console_loglevel; - extern void mac_bang(int, void *, struct pt_regs *); void mac_nmi_handler(int, void *, struct pt_regs *); diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index c405fc0dad09..87d155ee0a7b 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -35,7 +35,6 @@ void oss_nubus_irq(int, void *, struct pt_regs *); extern void via1_irq(int, void *, struct pt_regs *); extern void mac_scc_dispatch(int, void *, struct pt_regs *); -extern int console_loglevel; /* * Initialize the OSS diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index 86bbf72cc90c..d792ef9874bf 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -32,8 +32,6 @@ volatile __u8 *psc; void psc_irq(int, void *, struct pt_regs *); -extern int console_loglevel; - /* * Debugging dump, used in various places to see what's going on. */ diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index af001907d828..ec0b2ce19373 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -74,7 +74,6 @@ void via_irq_clear(int irq); extern void mac_bang(int, void *, struct pt_regs *); extern void mac_scc_dispatch(int, void *, struct pt_regs *); -extern int console_loglevel; extern int oss_present; /* diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 1d8bb4b282f7..82cd94fad2bd 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -27,19 +27,6 @@ #include #include -extern int console_loglevel; - -static inline void console_silent(void) -{ - console_loglevel = 0; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = 15; -} - /* * Machine specific interrupt handlers */ diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c index 997aee0c79bb..c6777f938695 100644 --- a/arch/mips64/kernel/traps.c +++ b/arch/mips64/kernel/traps.c @@ -27,19 +27,6 @@ #include #include -extern int console_loglevel; - -static inline void console_silent(void) -{ - console_loglevel = 0; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = 15; -} - extern asmlinkage void __xtlb_mod(void); extern asmlinkage void __xtlb_tlbl(void); extern asmlinkage void __xtlb_tlbs(void); diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 71fbe4665106..4af4f6565b90 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -47,12 +47,6 @@ extern pgm_check_handler_t do_page_fault; asmlinkage int system_call(void); -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void name(struct pt_regs * regs, long error_code) \ { \ diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index db11c1247072..4aeaf8efa0c7 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -28,12 +28,6 @@ #include #include -static inline void console_verbose(void) -{ - extern int console_loglevel; - console_loglevel = 15; -} - #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(unsigned long r4, unsigned long r5, \ unsigned long r6, unsigned long r7, \ diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index cca4ec269e42..96c5b2b3961b 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -347,9 +347,10 @@ static void generic_plug_device(request_queue_t *q, kdev_t dev) */ static inline void __generic_unplug_device(request_queue_t *q) { - if (!list_empty(&q->queue_head)) { + if (q->plugged) { q->plugged = 0; - q->request_fn(q); + if (!list_empty(&q->queue_head)) + q->request_fn(q); } } @@ -383,6 +384,8 @@ static void blk_init_free_list(request_queue_t *q) spin_lock_init(&q->request_lock); } +static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); + /** * blk_init_queue - prepare a request queue for use with a block device * @q: The &request_queue_t to be initialised @@ -416,7 +419,6 @@ static void blk_init_free_list(request_queue_t *q) * blk_init_queue() must be paired with a blk_cleanup-queue() call * when the block device is deactivated (such as at module unload). **/ -static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) { INIT_LIST_HEAD(&q->queue_head); diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c index a4108cf0ec42..f3c098b43a6d 100644 --- a/drivers/char/adbmouse.c +++ b/drivers/char/adbmouse.c @@ -53,7 +53,6 @@ extern void (*adb_mouse_interrupt_hook)(unsigned char *, int); extern int adb_emulate_buttons; extern int adb_button2_keycode; extern int adb_button3_keycode; -extern int console_loglevel; /* * XXX: need to figure out what ADB mouse packets mean ... diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index c109c5965320..63f26cc0fdfb 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -63,8 +63,8 @@ #define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 #define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 -#define MAX_PCI_DEVICE_NUM 3 #endif +#define MAX_PCI_DEVICE_NUM 3 static char *applicom_pci_devnames[] = { "PCI board", diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 6adffb8a9273..2b293c5ffc0d 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -143,7 +143,7 @@ static inline void mga_dma_quiescent(drm_device_t *dev) unsigned long end; int i; - DRM_DEBUG("dispatch_status = 0x%02x\n", dev_priv->dispatch_status); + DRM_DEBUG("dispatch_status = 0x%02lx\n", dev_priv->dispatch_status); end = jiffies + (HZ*3); while(1) { if(!test_and_set_bit(MGA_IN_DISPATCH, @@ -154,7 +154,7 @@ static inline void mga_dma_quiescent(drm_device_t *dev) DRM_ERROR("irqs: %d wanted %d\n", atomic_read(&dev->total_irq), atomic_read(&dma->total_lost)); - DRM_ERROR("lockup: dispatch_status = 0x%02x," + DRM_ERROR("lockup: dispatch_status = 0x%02lx," " jiffies = %lu, end = %lu\n", dev_priv->dispatch_status, jiffies, end); return; @@ -177,7 +177,7 @@ static inline void mga_dma_quiescent(drm_device_t *dev) sarea_priv->dirty |= MGA_DMA_FLUSH; clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); - DRM_DEBUG("exit, dispatch_status = 0x%02x\n", + DRM_DEBUG("exit, dispatch_status = 0x%02lx\n", dev_priv->dispatch_status); } diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 883eb75ca031..3937d97174ed 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -502,7 +502,7 @@ int mga_release(struct inode *inode, struct file *filp) if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.pid == current->pid) { mga_reclaim_buffers(dev, priv->pid); - DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02x)\n", + DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02lx)\n", current->pid, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock), dev->dev_private ? diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index e37cc2ef4ce1..59bb9c24773a 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -38,7 +38,7 @@ #define MGA_BUF_NEEDS_OVERFLOW 3 typedef struct { - u32 buffer_status; + long buffer_status; /* long req'd for set_bit() --RR */ int num_dwords; int max_dwords; u32 *current_dma_ptr; @@ -62,7 +62,7 @@ typedef struct _drm_mga_freelist { #define MGA_IN_GETBUF 3 typedef struct _drm_mga_private { - u32 dispatch_status; + long dispatch_status; /* long req'd for set_bit() --RR */ unsigned int next_prim_age; __volatile__ unsigned int last_prim_age; int reserved_map_idx; diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c index 90f16ca350ee..8b156f69c83a 100644 --- a/drivers/char/mixcomwd.c +++ b/drivers/char/mixcomwd.c @@ -54,7 +54,7 @@ static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 }; #define FLASHCOM_WATCHDOG_OFFSET 0x4 #define FLASHCOM_ID 0x18 -static int mixcomwd_opened; +static long mixcomwd_opened; /* long req'd for setbit --RR */ static int watchdog_port; diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index b2d959f369ea..7ceccdcbc443 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -152,7 +152,7 @@ struct moxa_str { unsigned short closing_wait; int count; int blocked_open; - int event; + long event; /* long req'd for set_bit --RR */ int asyncflags; long session; long pgrp; diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h index 12c47eae2116..4c65963870a4 100644 --- a/drivers/char/rio/host.h +++ b/drivers/char/rio/host.h @@ -110,7 +110,7 @@ struct Host struct UnixRup UnixRups[MAX_RUP+LINKS_PER_UNIT]; int timeout_id; /* For calling 100 ms delays */ int timeout_sem;/* For calling 100 ms delays */ - int locks; + long locks; /* long req'd for set_bit --RR */ char ____end_marker____; }; #define Control CardP->DpControl diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index d00e3c4fe382..c4511137c078 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -77,7 +77,7 @@ #define RS_EVENT_WRITE_WAKEUP 0 -DECLARE_TASK_QUEUE(tq_riscom); +static DECLARE_TASK_QUEUE(tq_riscom); #define RISCOM_TYPE_NORMAL 1 #define RISCOM_TYPE_CALLOUT 2 @@ -146,38 +146,38 @@ static inline int rc_paranoia_check(struct riscom_port const * port, */ /* Get board number from pointer */ -extern inline int board_No (struct riscom_board const * bp) +static inline int board_No (struct riscom_board const * bp) { return bp - rc_board; } /* Get port number from pointer */ -extern inline int port_No (struct riscom_port const * port) +static inline int port_No (struct riscom_port const * port) { return RC_PORT(port - rc_port); } /* Get pointer to board from pointer to port */ -extern inline struct riscom_board * port_Board(struct riscom_port const * port) +static inline struct riscom_board * port_Board(struct riscom_port const * port) { return &rc_board[RC_BOARD(port - rc_port)]; } /* Input Byte from CL CD180 register */ -extern inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg) +static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg) { return inb(bp->base + RC_TO_ISA(reg)); } /* Output Byte to CL CD180 register */ -extern inline void rc_out(struct riscom_board const * bp, unsigned short reg, +static inline void rc_out(struct riscom_board const * bp, unsigned short reg, unsigned char val) { outb(val, bp->base + RC_TO_ISA(reg)); } /* Wait for Channel Command Register ready */ -extern inline void rc_wait_CCR(struct riscom_board const * bp) +static inline void rc_wait_CCR(struct riscom_board const * bp) { unsigned long delay; @@ -193,7 +193,7 @@ extern inline void rc_wait_CCR(struct riscom_board const * bp) * RISCom/8 probe functions. */ -extern inline int rc_check_io_range(struct riscom_board * const bp) +static inline int rc_check_io_range(struct riscom_board * const bp) { int i; @@ -206,7 +206,7 @@ extern inline int rc_check_io_range(struct riscom_board * const bp) return 0; } -extern inline void rc_request_io_range(struct riscom_board * const bp) +static inline void rc_request_io_range(struct riscom_board * const bp) { int i; @@ -214,7 +214,7 @@ extern inline void rc_request_io_range(struct riscom_board * const bp) request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8" ); } -extern inline void rc_release_io_range(struct riscom_board * const bp) +static inline void rc_release_io_range(struct riscom_board * const bp) { int i; @@ -224,7 +224,7 @@ extern inline void rc_release_io_range(struct riscom_board * const bp) /* Must be called with enabled interrupts */ -extern inline void rc_long_delay(unsigned long delay) +static inline void rc_long_delay(unsigned long delay) { unsigned long i; @@ -326,7 +326,7 @@ static int __init rc_probe(struct riscom_board *bp) * */ -extern inline void rc_mark_event(struct riscom_port * port, int event) +static inline void rc_mark_event(struct riscom_port * port, int event) { /* * I'm not quite happy with current scheme all serial @@ -341,7 +341,7 @@ extern inline void rc_mark_event(struct riscom_port * port, int event) mark_bh(RISCOM8_BH); } -extern inline struct riscom_port * rc_get_port(struct riscom_board const * bp, +static inline struct riscom_port * rc_get_port(struct riscom_board const * bp, unsigned char const * what) { unsigned char channel; @@ -359,7 +359,7 @@ extern inline struct riscom_port * rc_get_port(struct riscom_board const * bp, return NULL; } -extern inline void rc_receive_exc(struct riscom_board const * bp) +static inline void rc_receive_exc(struct riscom_board const * bp) { struct riscom_port *port; struct tty_struct *tty; @@ -422,7 +422,7 @@ extern inline void rc_receive_exc(struct riscom_board const * bp) queue_task(&tty->flip.tqueue, &tq_timer); } -extern inline void rc_receive(struct riscom_board const * bp) +static inline void rc_receive(struct riscom_board const * bp) { struct riscom_port *port; struct tty_struct *tty; @@ -452,7 +452,7 @@ extern inline void rc_receive(struct riscom_board const * bp) queue_task(&tty->flip.tqueue, &tq_timer); } -extern inline void rc_transmit(struct riscom_board const * bp) +static inline void rc_transmit(struct riscom_board const * bp) { struct riscom_port *port; struct tty_struct *tty; @@ -521,7 +521,7 @@ extern inline void rc_transmit(struct riscom_board const * bp) rc_mark_event(port, RS_EVENT_WRITE_WAKEUP); } -extern inline void rc_check_modem(struct riscom_board const * bp) +static inline void rc_check_modem(struct riscom_board const * bp) { struct riscom_port *port; struct tty_struct *tty; @@ -634,7 +634,7 @@ static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs) */ /* Called with disabled interrupts */ -extern inline int rc_setup_board(struct riscom_board * bp) +static inline int rc_setup_board(struct riscom_board * bp) { int error; @@ -657,7 +657,7 @@ extern inline int rc_setup_board(struct riscom_board * bp) } /* Called with disabled interrupts */ -extern inline void rc_shutdown_board(struct riscom_board *bp) +static inline void rc_shutdown_board(struct riscom_board *bp) { if (!(bp->flags & RC_BOARD_ACTIVE)) return; @@ -1399,7 +1399,7 @@ static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd, return 0; } -extern inline void rc_send_break(struct riscom_port * port, unsigned long length) +static inline void rc_send_break(struct riscom_port * port, unsigned long length) { struct riscom_board *bp = port_Board(port); unsigned long flags; @@ -1417,7 +1417,7 @@ extern inline void rc_send_break(struct riscom_port * port, unsigned long length restore_flags(flags); } -extern inline int rc_set_serial_info(struct riscom_port * port, +static inline int rc_set_serial_info(struct riscom_port * port, struct serial_struct * newinfo) { struct serial_struct tmp; @@ -1467,7 +1467,7 @@ extern inline int rc_set_serial_info(struct riscom_port * port, return 0; } -extern inline int rc_get_serial_info(struct riscom_port * port, +static inline int rc_get_serial_info(struct riscom_port * port, struct serial_struct * retinfo) { struct serial_struct tmp; @@ -1820,7 +1820,7 @@ static void rc_release_drivers(void) * addresses in this case. * */ -void __init riscom8_setup(char *str, int * ints) +static void __init riscom8_setup(char *str, int * ints) { int i; @@ -1831,12 +1831,14 @@ void __init riscom8_setup(char *str, int * ints) rc_board[i].base = 0; } } + +__setup("riscom8=", riscom8_setup); #endif /* * This routine must be called by kernel at boot time */ -int __init riscom8_init(void) +static int __init riscom8_init(void) { int i; int found = 0; @@ -1859,22 +1861,24 @@ int __init riscom8_init(void) } #ifdef MODULE -int iobase = 0; -int iobase1 = 0; -int iobase2 = 0; -int iobase3 = 0; +static int iobase; +static int iobase1; +static int iobase2; +static int iobase3; MODULE_PARM(iobase, "i"); MODULE_PARM(iobase1, "i"); MODULE_PARM(iobase2, "i"); MODULE_PARM(iobase3, "i"); +#endif /* MODULE */ /* * You can setup up to 4 boards (current value of RC_NBOARD) * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter. * */ -int init_module(void) +static int __init riscom8_init_module (void) { +#ifdef MODULE int i; if (iobase || iobase1 || iobase2 || iobase3) { @@ -1890,11 +1894,12 @@ int init_module(void) rc_board[2].base = iobase2; if (iobase3) rc_board[3].base = iobase3; - +#endif /* MODULE */ + return riscom8_init(); } -void cleanup_module(void) +static void __exit riscom8_exit_module (void) { int i; @@ -1904,4 +1909,7 @@ void cleanup_module(void) rc_release_io_range(&rc_board[i]); } -#endif /* MODULE */ + +module_init(riscom8_init_module); +module_exit(riscom8_exit_module); + diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h index 3b2b9e78df6e..da6a8b1b60a6 100644 --- a/drivers/char/riscom8.h +++ b/drivers/char/riscom8.h @@ -71,7 +71,7 @@ struct riscom_port { struct tty_struct * tty; int count; int blocked_open; - int event; + long event; /* long req'd for set_bit --RR */ int timeout; int close_delay; long session; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 3c05aa042306..71773fa6c8db 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -27,7 +27,6 @@ extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); -extern int console_loglevel; extern struct list_head super_blocks; /* Whether we react on sysrq keys or just ignore them */ diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index d2a5ae37ef87..f00c68ed450c 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1841,9 +1841,9 @@ static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end) memset(&pc, 0, sizeof (pc)); pc.sense = &sense; - pc.c[0] = GPCMD_PLAY_AUDIO_10; - put_unaligned(cpu_to_be32(lba_start), (unsigned int *) &pc.c[2]); - put_unaligned(cpu_to_be16(lba_end - lba_start), (unsigned int *) &pc.c[7]); + pc.c[0] = GPCMD_PLAY_AUDIO_MSF; + lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); + lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); return cdrom_queue_packet_command(drive, &pc); } diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index e03992b45def..79f96fe18823 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.22.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: avm_pci.c,v 1.22.6.2 2000/11/29 16:00:14 kai Exp $ * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -18,7 +18,7 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.22.6.1 $"; +static const char *avm_pci_rev = "$Revision: 1.22.6.2 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -758,7 +758,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_avm __initdata; +static struct pci_dev *dev_avm __initdata = NULL; int __init setup_avm_pcipnp(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index 777a787af689..c8a4896a9f02 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.13.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: bkm_a4t.c,v 1.13.6.2 2000/11/29 16:00:14 kai Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -24,7 +24,7 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.13.6.1 $"; +const char *bkm_a4t_revision = "$Revision: 1.13.6.2 $"; static inline u_char @@ -264,7 +264,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return (0); } -static struct pci_dev *dev_a4t __initdata; +static struct pci_dev *dev_a4t __initdata = NULL; int __init setup_bkm_a4t(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 86042a9badf9..45011d356a7f 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.14.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: bkm_a8.c,v 1.14.6.2 2000/11/29 16:00:14 kai Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -27,7 +27,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.14.6.1 $"; +const char sct_quadro_revision[] = "$Revision: 1.14.6.2 $"; static const char *sct_quadro_subtypes[] = { @@ -283,12 +283,12 @@ sct_alloc_io(u_int adr, u_int len) return(0); } -static struct pci_dev *dev_a8 __initdata; -static u16 sub_vendor_id __initdata; -static u16 sub_sys_id __initdata; -static u_char pci_bus __initdata; -static u_char pci_device_fn __initdata; -static u_char pci_irq __initdata; +static struct pci_dev *dev_a8 __initdata = NULL; +static u16 sub_vendor_id __initdata = 0; +static u16 sub_sys_id __initdata = 0; +static u_char pci_bus __initdata = 0; +static u_char pci_device_fn __initdata = 0; +static u_char pci_irq __initdata = 0; #endif /* CONFIG_PCI */ diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index f498a197c43e..499970ea202a 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,4 +1,4 @@ -/* $Id: config.c,v 2.57.6.2 2000/11/28 23:45:42 kai Exp $ +/* $Id: config.c,v 2.57.6.3 2000/11/29 17:48:59 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -340,14 +340,14 @@ struct IsdnCard cards[] = EMPTY_CARD, }; -static char HiSaxID[64] __devinitdata; +static char HiSaxID[64] __devinitdata = { 0, }; char *HiSax_id __devinitdata = HiSaxID; #ifdef MODULE /* Variables for insmod */ -static int type[8] __devinitdata; -static int protocol[8] __devinitdata; -static int io[8] __devinitdata; +static int type[8] __devinitdata = { 0, }; +static int protocol[8] __devinitdata = { 0, }; +static int io[8] __devinitdata = { 0, }; #undef IO0_IO1 #ifdef CONFIG_HISAX_16_3 #define IO0_IO1 @@ -357,11 +357,11 @@ static int io[8] __devinitdata; #define IO0_IO1 #endif #ifdef IO0_IO1 -static int io0[8] __devinitdata; -static int io1[8] __devinitdata; +static int io0[8] __devinitdata = { 0, }; +static int io1[8] __devinitdata = { 0, }; #endif -static int irq[8] __devinitdata; -static int mem[8] __devinitdata; +static int irq[8] __devinitdata = { 0, }; +static int mem[8] __devinitdata = { 0, }; static char *id __devinitdata = HiSaxID; MODULE_AUTHOR("Karsten Keil"); diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 43c9a2727306..8967accde776 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.25.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: diva.c,v 1.25.6.2 2000/11/29 16:00:14 kai Exp $ * * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -24,7 +24,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.25.6.1 $"; +const char *Diva_revision = "$Revision: 1.25.6.2 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -820,9 +820,9 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_diva __initdata; -static struct pci_dev *dev_diva_u __initdata; -static struct pci_dev *dev_diva201 __initdata; +static struct pci_dev *dev_diva __initdata = NULL; +static struct pci_dev *dev_diva_u __initdata = NULL; +static struct pci_dev *dev_diva201 __initdata = NULL; int __init setup_diva(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 065ca9fea11f..11db6b9eedf4 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -1,4 +1,4 @@ -/* $Id: gazel.c,v 2.11.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: gazel.c,v 2.11.6.2 2000/11/29 16:00:14 kai Exp $ * * gazel.c low level stuff for Gazel isdn cards * @@ -19,7 +19,7 @@ #include extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.11.6.1 $"; +const char *gazel_revision = "$Revision: 2.11.6.2 $"; #define R647 1 #define R685 2 @@ -544,7 +544,7 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) return (0); } -static struct pci_dev *dev_tel __initdata; +static struct pci_dev *dev_tel __initdata = NULL; static int setup_gazelpci(struct IsdnCardState *cs) diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 5a451ef1dfc3..b22ed23e73ab 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -1,4 +1,4 @@ -/* $Id: niccy.c,v 1.15.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: niccy.c,v 1.15.6.2 2000/11/29 16:00:14 kai Exp $ * * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) @@ -22,7 +22,7 @@ #include extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.15.6.1 $"; +const char *niccy_revision = "$Revision: 1.15.6.2 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -235,7 +235,7 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *niccy_dev __initdata; +static struct pci_dev *niccy_dev __initdata = NULL; int __init setup_niccy(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index a3ca8aaa8ab8..4aaf9e1857a7 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -1,4 +1,4 @@ -// $Id: nj_s.c,v 2.7 2000/11/24 17:05:38 kai Exp $ +// $Id: nj_s.c,v 2.7.6.1 2000/11/29 16:00:14 kai Exp $ // // This file is (c) under GNU PUBLIC LICENSE // @@ -14,7 +14,7 @@ #include #include "netjet.h" -const char *NETjet_S_revision = "$Revision: 2.7 $"; +const char *NETjet_S_revision = "$Revision: 2.7.6.1 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { @@ -140,7 +140,7 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_netjet __initdata; +static struct pci_dev *dev_netjet __initdata = NULL; int __init setup_netjet_s(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c index 27964ca99e14..a98724bd1a79 100644 --- a/drivers/isdn/hisax/nj_u.c +++ b/drivers/isdn/hisax/nj_u.c @@ -1,4 +1,4 @@ -/* $Id: nj_u.c,v 2.8 2000/11/24 17:05:38 kai Exp $ +/* $Id: nj_u.c,v 2.8.6.1 2000/11/29 16:00:14 kai Exp $ * * This file is (c) under GNU PUBLIC LICENSE * @@ -15,7 +15,7 @@ #include #include "netjet.h" -const char *NETjet_U_revision = "$Revision: 2.8 $"; +const char *NETjet_U_revision = "$Revision: 2.8.6.1 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { @@ -142,7 +142,7 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_netjet __initdata; +static struct pci_dev *dev_netjet __initdata = NULL; int __init setup_netjet_u(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 3dc342c8d8ef..abe4d21986be 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.25.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: sedlbauer.c,v 1.25.6.2 2000/11/29 17:48:59 kai Exp $ * * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -52,7 +52,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.25.6.1 $"; +const char *Sedlbauer_revision = "$Revision: 1.25.6.2 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", @@ -529,7 +529,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_sedl __devinitdata; +static struct pci_dev *dev_sedl __devinitdata = NULL; int __devinit setup_sedlbauer(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 174f7fa93a70..83b640f8fe2a 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -1,4 +1,4 @@ -/* $Id: telespci.c,v 2.16.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: telespci.c,v 2.16.6.2 2000/11/29 16:00:14 kai Exp $ * * telespci.c low level stuff for Teles PCI isdn cards * @@ -18,7 +18,7 @@ #include extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.16.6.1 $"; +const char *telespci_revision = "$Revision: 2.16.6.2 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 @@ -275,7 +275,7 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_tel __initdata; +static struct pci_dev *dev_tel __initdata = NULL; int __init setup_telespci(struct IsdnCard *card) diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 8b714ffbcf76..9afb73f90f5f 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.12.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: w6692.c,v 1.12.6.2 2000/11/29 16:00:14 kai Exp $ * * w6692.c Winbond W6692 specific routines * @@ -35,7 +35,7 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.12.6.1 $"; +const char *w6692_revision = "$Revision: 1.12.6.2 $"; #define DBUSY_TIMER_VALUE 80 @@ -957,7 +957,7 @@ w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg) static int id_idx ; -static struct pci_dev *dev_w6692 __initdata; +static struct pci_dev *dev_w6692 __initdata = NULL; int __init setup_w6692(struct IsdnCard *card) diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index 662f4a7f5e06..80616affaa4f 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -255,8 +255,6 @@ int adb_button2_keycode = 0x7d; /* right control key */ int adb_button3_keycode = 0x7c; /* right option key */ #endif -extern int console_loglevel; - extern struct kbd_struct kbd_table[]; extern wait_queue_head_t keypress_wait; diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index f4670f1dbb2c..c6e84f66f112 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -125,7 +125,6 @@ static int last_status; static int driver_running = 0; /* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ -extern int console_loglevel; /* Check for MacII style ADB */ static int macii_probe(void) diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 11c6474c79d7..886782f18f00 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -1319,6 +1319,24 @@ terratv_audio(struct bttv *btv, struct video_audio *v, int set) } } +#ifndef MODULE + +static int __init bttv_card_setup(char *str) +{ + int i,number,res = 2; + + for (i = 0; res == 2 && i < BTTV_MAX; i++) { + res = get_option(&str,&number); + if (res) + card[i] = number; + } + return 1; +} + +__setup("bttv_card=", bttv_card_setup); + +#endif /* not MODULE */ + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 6bc9c554ecb2..248bda8a02f0 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3082,6 +3082,24 @@ void bttv_cleanup_module(void) module_init(bttv_init_module); module_exit(bttv_cleanup_module); +#ifndef MODULE + +static int __init bttv_radio_setup(char *str) +{ + int i,number,res = 2; + + for (i = 0; res == 2 && i < BTTV_MAX; i++) { + res = get_option(&str,&number); + if (res) + radio[i] = number; + } + return 1; +} + +__setup("bttv_radio=", bttv_radio_setup); + +#endif /* not MODULE */ + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 385beb49c64e..b6ae3f62c4f4 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -912,7 +912,7 @@ done: msp->thread = NULL; if(msp->notify != NULL) - up(msp->notify); + up_and_exit(msp->notify, 0); return 0; } diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 5ed1a1097ea7..da052eff57e6 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -291,7 +291,7 @@ static int chip_thread(void *data) chip->thread = NULL; dprintk("%s: thread exiting\n", chip->c.name); if(chip->notify != NULL) - up(chip->notify); + up_and_exit(chip->notify,0); return 0; } diff --git a/drivers/mtd/Config.in b/drivers/mtd/Config.in index 9023f0a81bbb..c9747479a1f5 100644 --- a/drivers/mtd/Config.in +++ b/drivers/mtd/Config.in @@ -23,6 +23,7 @@ if [ "$CONFIG_MTD" != "n" ]; then dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI if [ "$CONFIG_MTD_PMC551" != "n" ]; then bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX + bool ' PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG fi dep_tristate ' Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD if [ "$CONFIG_MTD_MTDRAM" != "n" ]; then diff --git a/drivers/mtd/cfi_cmdset_0002.c b/drivers/mtd/cfi_cmdset_0002.c index d6cce6474775..6cb0de4e960d 100644 --- a/drivers/mtd/cfi_cmdset_0002.c +++ b/drivers/mtd/cfi_cmdset_0002.c @@ -437,7 +437,7 @@ static int cfi_amdext_erase_2_by_16 (struct mtd_info *mtd, struct erase_info *in adr = instr->addr - (chipnum << cfi->chipshift) * (cfi->interleave); len = instr->len; -printk("erase : 0x%lx 0x%lx 0x%x 0x%x\n", adr, len, chipnum, mtd->size); + printk("erase : 0x%lx 0x%lx 0x%x 0x%lx\n", adr, len, chipnum, mtd->size); while(len) { //printk("erase : 0x%x 0x%x 0x%x 0x%x\n", chipnum, adr, len, cfi->chipshift); diff --git a/drivers/mtd/doc1000.c b/drivers/mtd/doc1000.c index ce1b6fdd8292..584745359dbd 100644 --- a/drivers/mtd/doc1000.c +++ b/drivers/mtd/doc1000.c @@ -1,16 +1,7 @@ /*====================================================================== - $Id: doc1000.c,v 1.8 2000/07/03 10:01:38 dwmw2 Exp $ + $Id: doc1000.c,v 1.11 2000/11/24 13:43:16 dwmw2 Exp $ - A general driver for accessing PCMCIA card memory via Bulk - Memory Services. - - This driver provides the equivalent of /dev/mem for a PCMCIA - card's attribute and common memory. It includes character - and block devices. - - Written by David Hinds, dhinds@allegro.stanford.edu - ======================================================================*/ @@ -295,10 +286,9 @@ int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen static inline int byte_write (volatile u_char *addr, u_char byte) { register u_char status; - register u_short i; - - for (i = 0; i < max_tries; i++) - { + register u_short i = 0; + + do { status = readb(addr); if (status & CSR_WR_READY) { @@ -306,7 +296,9 @@ static inline int byte_write (volatile u_char *addr, u_char byte) writeb(byte, addr); return 0; } - } + i++; + } while(i < max_tries); + printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status); return -EIO; @@ -314,11 +306,10 @@ static inline int byte_write (volatile u_char *addr, u_char byte) static inline int word_write (volatile u_char *addr, __u16 word) { - register u_short status = 0; - register u_short i; + register u_short status; + register u_short i = 0; - for (i = 0; i < max_tries; i++) - { + do { status = readw(addr); if ((status & CSR_WR_READY) == CSR_WR_READY) { @@ -326,7 +317,8 @@ static inline int word_write (volatile u_char *addr, __u16 word) writew(word, addr); return 0; } - } + i++; + } while(i < max_tries); printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status); return -EIO; @@ -362,24 +354,22 @@ static inline int check_erase(volatile u_char *addr) static inline int suspend_erase(volatile u_char *addr) { - __u16 status = 0; - u_long i; + __u16 status; + u_long i = 0; writew(IF_ERASE_SUSPEND, addr); writew(IF_READ_CSR, addr); - for (i = 0; i < max_tries; i++) - { + do { status = readw(addr); - if ((status & CSR_WR_READY) == CSR_WR_READY) break; - } - if (i == max_tries) - { - printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status); - return -EIO; - } - - return 0; + if ((status & CSR_WR_READY) == CSR_WR_READY) + return 0; + i++; + } while(i < max_tries); + + printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status); + return -EIO; + } static inline void resume_erase(volatile u_char *addr) @@ -413,12 +403,11 @@ static inline void reset_block(volatile u_char *addr) static inline int check_write(volatile u_char *addr) { - u_short status = 0, i; + u_short status, i = 0; writew(IF_READ_CSR, addr); - for (i=0; i < max_tries; i++) - { + do { status = readw(addr); if (status & (CSR_WR_ERR | CSR_VPP_LOW)) { @@ -428,7 +417,9 @@ static inline int check_write(volatile u_char *addr) } if ((status & CSR_WR_READY) == CSR_WR_READY) return 0; - } + i++; + } while (i < max_tries); + printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status); return -EIO; } @@ -519,7 +510,7 @@ static void flashcard_periodic(unsigned long data) } -#if defined (MODULE) && LINUX_VERSION_CODE < 0x20300 +#if defined (MODULE) && LINUX_VERSION_CODE < 0x20211 #define init_doc1000 init_module #define cleanup_doc1000 cleanup_module #endif @@ -600,3 +591,7 @@ static void __init cleanup_doc1000(void) kfree(mymtd); } +#if LINUX_VERSION_CODE >= 0x20211 +module_init(init_doc1000); +module_exit(cleanup_doc1000); +#endif diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 1cf4a5f160a0..21ed0cecdafd 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1,6 +1,10 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.20 2000/06/23 15:17:53 dwmw2 Exp $ - * Based on: + * + * - Based on Id: ftl.c,v 1.21 2000/08/01 13:07:49 dwmw2 Exp + * - With the Franz Galiana's set_bam_entry fix from v1.23 + * - Perhaps it's about time I made a branch for the 2.4 series. + + * Originally based on: */ /*====================================================================== @@ -263,12 +267,13 @@ static struct block_device_operations ftl_blk_fops = { static int scan_header(partition_t *part) { erase_unit_header_t header; - loff_t offset; + loff_t offset, max_offset; int ret; part->header.FormattedSize = 0; + max_offset = (0x100000mtd->size)?0x100000:part->mtd->size; /* Search first megabyte for a valid FTL header */ for (offset = 0; - offset < 0x100000; + offset < max_offset; offset += part->mtd->erasesize?part->mtd->erasesize:0x2000) { ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, @@ -280,7 +285,7 @@ static int scan_header(partition_t *part) if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; } - if (offset == 0x100000) { + if (offset == max_offset) { printk(KERN_NOTICE "ftl_cs: FTL header not found.\n"); return -ENOENT; } @@ -998,7 +1003,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, static int set_bam_entry(partition_t *part, u_int32_t log_addr, u_int32_t virt_addr) { - u_int32_t bsize, blk; + u_int32_t bsize, blk, le_virt_addr; #ifdef PSYCHO_DEBUG u_int32_t old_addr; #endif @@ -1035,6 +1040,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, return -EIO; } #endif + le_virt_addr = cpu_to_le32(virt_addr); if (part->bam_index == eun) { #ifdef PSYCHO_DEBUG if (le32_to_cpu(part->bam_cache[blk]) != old_addr) { @@ -1049,10 +1055,10 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, return -EIO; } #endif - part->bam_cache[blk] = cpu_to_le32(virt_addr); + part->bam_cache[blk] = le_virt_addr; } ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), - &retlen, (u_char *)&part->bam_cache[blk]); + &retlen, (u_char *)&le_virt_addr); if (ret) { printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n"); @@ -1410,8 +1416,6 @@ mod_init_t init_ftl(void) memset(myparts, 0, sizeof(myparts)); - DEBUG(0, "$Id: ftl.c,v 1.20 2000/06/23 15:17:53 dwmw2 Exp $\n"); - if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { printk(KERN_NOTICE "ftl_cs: unable to grab major " "device number!\n"); diff --git a/drivers/mtd/pmc551.c b/drivers/mtd/pmc551.c index fdc80cbcfd20..ab9049356ade 100644 --- a/drivers/mtd/pmc551.c +++ b/drivers/mtd/pmc551.c @@ -1,17 +1,17 @@ /* - * $Id: pmc551.c,v 1.8 2000/07/14 07:53:31 dwmw2 Exp $ + * $Id: pmc551.c,v 1.11 2000/11/23 13:40:12 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * * Author: - * Mark Ferrell + * Mark Ferrell * Copyright 1999,2000 Nortel Networks * - * License: + * License: * As part of this driver was derrived from the slram.c driver it falls * under the same license, which is GNU General Public License v2 * - * Description: + * Description: * This driver is intended to support the PMC551 PCI Ram device from * Ramix Inc. The PMC551 is a PMC Mezzanine module for cPCI embeded * systems. The device contains a single SROM that initally programs the @@ -24,6 +24,23 @@ * it as a block device allows us to use it as high speed swap or for a * high speed disk device of some sort. Which becomes very usefull on * diskless systems in the embeded market I might add. + * + * Notes: + * Due to what I assume is more buggy SROM, the 64M PMC551 I have + * available claims that all 4 of it's DRAM banks have 64M of ram + * configured (making a grand total of 256M onboard). This is slightly + * annoying since the BAR0 size reflects the aperture size, not the dram + * size, and the V370PDC supplies no other method for memory size + * discovery. This problem is mostly only relivant when compiled as a + * module, as the unloading of the module with an aperture size smaller + * then the ram will cause the driver to detect the onboard memory size + * to be equal to the aperture size when the module is reloaded. Soooo, + * to help, the module supports an msize option to allow the + * specification of the onboard memory, and an asize option, to allow the + * specification of the aperture size. The aperture must be equal to or + * less then the memory size, the driver will correct this if you screw + * it up. This problem is not relivant for compiled in drivers as + * compiled in drivers only init once. * * Credits: * Saeed Karamooz of Ramix INC. for the initial @@ -31,7 +48,7 @@ * questions I had concerning operation of the device. * * Most of the MTD code for this driver was originally written for the - * slram.o module in the MTD drivers package written by David Hinds + * slram.o module in the MTD drivers package written by David Hinds * which allows the mapping of system * memory into an mtd device. Since the PMC551 memory module is * accessed in the same fashion as system memory, the slram.c code @@ -44,9 +61,9 @@ * * Modified driver to utilize a sliding apature instead of mapping all * memory into kernel space which turned out to be very wastefull. * * Located a bug in the SROM's initialization sequence that made the - * memory unussable, added a fix to code to touch up the DRAM some. + * memory unusable, added a fix to code to touch up the DRAM some. * - * Bugs/FIXME's: + * Bugs/FIXME's: * * MUST fix the init function to not spin on a register * waiting for it to set .. this does not safely handle busted devices * that never reset the register correctly which will cause the system to @@ -73,6 +90,10 @@ #include #include +#ifndef CONFIG_PCI +#error Enable PCI in your kernel config +#endif + #include #include #include @@ -347,14 +368,70 @@ static u32 fixup_pmc551 (struct pci_dev *dev) #ifdef CONFIG_MTD_PMC551_BUGFIX u32 dram_data; #endif - u32 size, dcmd; - u16 cmd, i; + u32 size, dcmd, cfg, dtmp; + u16 cmd, tmp, i; + u8 bcmd, counter; /* Sanity Check */ if(!dev) { return -ENODEV; } + /* + * Attempt to reset the card + * FIXME: Stop Spinning registers + */ + counter=0; + /* unlock registers */ + pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 ); + /* read in old data */ + pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); + /* bang the reset line up and down for a few */ + for(i=0;i<10;i++) { + counter=0; + bcmd &= ~0x80; + while(counter++ < 100) { + pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); + } + counter=0; + bcmd |= 0x80; + while(counter++ < 100) { + pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); + } + } + bcmd |= (0x40|0x20); + pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); + + /* + * Take care and turn off the memory on the device while we + * tweak the configurations + */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, tmp); + + /* + * Disable existing aperture before probing memory size + */ + pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd); + dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN); + pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp); + /* + * Grab old BAR0 config so that we can figure out memory size + * This is another bit of kludge going on. The reason for the + * redundancy is I am hoping to retain the original configuration + * previously assigned to the card by the BIOS or some previous + * fixup routine in the kernel. So we read the old config into cfg, + * then write all 1's to the memory space, read back the result into + * "size", and then write back all the old config. + */ + pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg ); +#ifndef CONFIG_MTD_PMC551_BUGFIX + pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 ); + pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size ); + pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg ); + size=~(size&PCI_BASE_ADDRESS_MEM_MASK)+1; +#else /* * Get the size of the memory by reading all the DRAM size values * and adding them up. @@ -363,7 +440,6 @@ static u32 fixup_pmc551 (struct pci_dev *dev) * row mux values. We fix them here, but this will break other * memory configurations. */ -#ifdef CONFIG_MTD_PMC551_BUGFIX pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data); size = PMC551_DRAM_BLK_GET_SIZE(dram_data); dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5); @@ -387,7 +463,6 @@ static u32 fixup_pmc551 (struct pci_dev *dev) dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5); dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9); pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data); -#endif /* CONFIG_MTD_PMC551_BUGFIX */ /* * Oops .. something went wrong @@ -395,34 +470,14 @@ static u32 fixup_pmc551 (struct pci_dev *dev) if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) { return -ENODEV; } +#endif /* CONFIG_MTD_PMC551_BUGFIX */ - /* - * Set to be prefetchable - */ - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dcmd ); - dcmd |= 0x8; - - /* - * Put it back the way it was - */ - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dcmd ); - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dcmd ); - - /* - * Some screen fun - */ - printk(KERN_NOTICE "pmc551: %dM (0x%x) of %sprefetchable memory at 0x%lx\n", - size/1024/1024, size, ((dcmd&0x8) == 0)?"non-":"", - PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK ); - - /* - * Turn on PCI memory and I/O bus access just for kicks - */ - pci_write_config_word( dev, PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_IO ); + if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { + return -ENODEV; + } /* - * Config DRAM + * Precharge Dram */ pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 ); pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf ); @@ -431,11 +486,16 @@ static u32 fixup_pmc551 (struct pci_dev *dev) * Wait untill command has gone through * FIXME: register spinning issue */ - do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd ); + do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd ); + if(counter++ > 100)break; } while ( (PCI_COMMAND_IO) & cmd ); /* - * Must be held high for some duration of time to take effect?? + * Turn on auto refresh + * The loop is taken directly from Ramix's example code. I assume that + * this must be held high for some duration of time, but I can find no + * documentation refrencing the reasons why. + * */ for ( i = 1; i<=8 ; i++) { pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df); @@ -444,7 +504,9 @@ static u32 fixup_pmc551 (struct pci_dev *dev) * Make certain command has gone through * FIXME: register spinning issue */ - do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd); + counter=0; + do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd); + if(counter++ > 100)break; } while ( (PCI_COMMAND_IO) & cmd ); } @@ -455,7 +517,9 @@ static u32 fixup_pmc551 (struct pci_dev *dev) * Wait until command completes * FIXME: register spinning issue */ - do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd); + counter=0; + do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd); + if(counter++ > 100)break; } while ( (PCI_COMMAND_IO) & cmd ); pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd); @@ -481,54 +545,97 @@ static u32 fixup_pmc551 (struct pci_dev *dev) cmd &= ~PCI_STATUS_DEVSEL_MASK; pci_write_config_word( dev, PCI_STATUS, cmd ); } + /* + * Set to be prefetchable and put everything back based on old cfg. + * it's possible that the reset of the V370PDC nuked the original + * settup + */ + cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH; + pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg ); + + /* + * Turn PCI memory and I/O bus access back on + */ + pci_write_config_word( dev, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_IO ); +#ifdef CONFIG_MTD_PMC551_DEBUG + /* + * Some screen fun + */ + printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n", + (size<1024)?size:(size<1048576)?size/1024:size/1024/1024, + (size<1024)?'B':(size<1048576)?'K':'M', + size, ((dcmd&(0x1<<3)) == 0)?"non-":"", + PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK ); /* * Check to see the state of the memory - * FIXME: perhaps hide some of this around an #ifdef DEBUG as - * it doesn't effect or enhance cards functionality */ - pci_read_config_dword( dev, 0x74, &dcmd ); - printk(KERN_NOTICE "pmc551: DRAM_BLK3 Flags: %s,%s\n", - ((0x2&dcmd) == 0)?"RW":"RO", - ((0x1&dcmd) == 0)?"Off":"On" ); - - pci_read_config_dword( dev, 0x70, &dcmd ); - printk(KERN_NOTICE "pmc551: DRAM_BLK2 Flags: %s,%s\n", - ((0x2&dcmd) == 0)?"RW":"RO", - ((0x1&dcmd) == 0)?"Off":"On" ); - - pci_read_config_dword( dev, 0x6C, &dcmd ); - printk(KERN_NOTICE "pmc551: DRAM_BLK1 Flags: %s,%s\n", - ((0x2&dcmd) == 0)?"RW":"RO", - ((0x1&dcmd) == 0)?"Off":"On" ); - - pci_read_config_dword( dev, 0x68, &dcmd ); - printk(KERN_NOTICE "pmc551: DRAM_BLK0 Flags: %s,%s\n", - ((0x2&dcmd) == 0)?"RW":"RO", - ((0x1&dcmd) == 0)?"Off":"On" ); - - pci_read_config_word( dev, 0x4, &cmd ); - printk( KERN_NOTICE "pmc551: Memory Access %s\n", - ((0x2&cmd) == 0)?"off":"on" ); - printk( KERN_NOTICE "pmc551: I/O Access %s\n", - ((0x1&cmd) == 0)?"off":"on" ); - - pci_read_config_word( dev, 0x6, &cmd ); - printk( KERN_NOTICE "pmc551: Devsel %s\n", + pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd ); + printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n" + "pmc551: DRAM_BLK0 Size: %d at %d\n" + "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n", + (((0x1<<1)&dcmd) == 0)?"RW":"RO", + (((0x1<<0)&dcmd) == 0)?"Off":"On", + PMC551_DRAM_BLK_GET_SIZE(dcmd), + ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) ); + + pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd ); + printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n" + "pmc551: DRAM_BLK1 Size: %d at %d\n" + "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n", + (((0x1<<1)&dcmd) == 0)?"RW":"RO", + (((0x1<<0)&dcmd) == 0)?"Off":"On", + PMC551_DRAM_BLK_GET_SIZE(dcmd), + ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) ); + + pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd ); + printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n" + "pmc551: DRAM_BLK2 Size: %d at %d\n" + "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n", + (((0x1<<1)&dcmd) == 0)?"RW":"RO", + (((0x1<<0)&dcmd) == 0)?"Off":"On", + PMC551_DRAM_BLK_GET_SIZE(dcmd), + ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) ); + + pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd ); + printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n" + "pmc551: DRAM_BLK3 Size: %d at %d\n" + "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n", + (((0x1<<1)&dcmd) == 0)?"RW":"RO", + (((0x1<<0)&dcmd) == 0)?"Off":"On", + PMC551_DRAM_BLK_GET_SIZE(dcmd), + ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) ); + + pci_read_config_word( dev, PCI_COMMAND, &cmd ); + printk( KERN_DEBUG "pmc551: Memory Access %s\n", + (((0x1<<1)&cmd) == 0)?"off":"on" ); + printk( KERN_DEBUG "pmc551: I/O Access %s\n", + (((0x1<<0)&cmd) == 0)?"off":"on" ); + + pci_read_config_word( dev, PCI_STATUS, &cmd ); + printk( KERN_DEBUG "pmc551: Devsel %s\n", ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast": ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium": ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" ); - printk( KERN_NOTICE "pmc551: %sFast Back-to-Back\n", + printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n", ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" ); + pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); + printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n" + "pmc551: System Control Register is %slocked to PCI access\n" + "pmc551: System Control Register is %slocked to EEPROM access\n", + (bcmd&0x1)?"software":"hardware", + (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un"); +#endif return size; } /* * Kernel version specific module stuffages */ -#if LINUX_VERSION_CODE < 0x20300 +#if LINUX_VERSION_CODE < 0x20211 #ifdef MODULE #define init_pmc551 init_module #define cleanup_pmc551 cleanup_module @@ -536,11 +643,27 @@ static u32 fixup_pmc551 (struct pci_dev *dev) #define __exit #endif +#if defined(MODULE) +MODULE_AUTHOR("Mark Ferrell "); +MODULE_DESCRIPTION(PMC551_VERSION); +MODULE_PARM(msize, "i"); +MODULE_PARM_DESC(msize, "memory size, 6=32M, 7=64M, 8=128M, ect.. [32M-1024M]"); +MODULE_PARM(asize, "i"); +MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1M-1024M]"); +#endif +/* + * Stuff these outside the ifdef so as to not bust compiled in driver support + */ +static int msize=0; +#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE) +static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE +#else +static int asize=0; +#endif /* * PMC551 Card Initialization */ -//static int __init init_pmc551(void) int __init init_pmc551(void) { struct pci_dev *PCI_Device = NULL; @@ -549,9 +672,23 @@ int __init init_pmc551(void) struct mtd_info *mtd; u32 length = 0; + if(msize) { + if (msize < 6 || msize > 11 ) { + printk(KERN_NOTICE "pmc551: Invalid memory size\n"); + return -ENODEV; + } + msize = (512*1024)< 11 ) { + printk(KERN_NOTICE "pmc551: Invalid aperture size\n"); + return -ENODEV; + } + asize = (512*1024)<priv = priv; priv->dev = PCI_Device; - priv->aperture_size = PMC551_APERTURE_SIZE; + if(asize) { + if(asize > length) { + asize=length; + printk(KERN_NOTICE "pmc551: reducing aperture size to fit memory [0x%x]\n",asize); + } else { + printk(KERN_NOTICE "pmc551: Using specified aperture size 0x%x\n", asize); + } + priv->aperture_size = asize; + } else { + priv->aperture_size = length; + } priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device) & PCI_BASE_ADDRESS_MEM_MASK), priv->aperture_size); - priv->mem_map0_base_val = (PMC551_APERTURE_VAL - | PMC551_PCI_MEM_MAP_REG_EN - | PMC551_PCI_MEM_MAP_ENABLE); + + /* + * Due to the dynamic nature of the code, we need to figure + * this out in order to stuff the register to set the proper + * aperture size. If you know of an easier way to do this then + * PLEASE help yourself. + * + * Not with bloody floating point, you don't. Consider yourself + * duly LARTed. dwmw2. + */ + { + u32 size; + u16 bits; + size = priv->aperture_size>>20; + for(bits=0;!(size&0x01)&&size>0;bits++,size=size>>1); + //size=((u32)((log10(priv->aperture_size)/.30103)-19)<<4); + priv->mem_map0_base_val = (PMC551_PCI_MEM_MAP_REG_EN + | PMC551_PCI_MEM_MAP_ENABLE + | size); +#ifdef CONFIG_MTD_PMC551_DEBUG + printk(KERN_NOTICE "pmc551: aperture set to %d[%d]\n", + size, size>>4); +#endif + } priv->curr_mem_map0_val = priv->mem_map0_base_val; pci_write_config_dword ( priv->dev, @@ -641,7 +813,10 @@ int __init init_pmc551(void) priv->aperture_size/1024/1024, priv->start, priv->start + priv->aperture_size); - printk(KERN_NOTICE "Total memory is %dM\n", length/1024/1024); + printk(KERN_NOTICE "Total memory is %d%c\n", + (length<1024)?length: + (length<1048576)?length/1024:length/1024/1024, + (length<1024)?'B':(length<1048576)?'K':'M'); priv->nextpmc551 = pmc551list; pmc551list = mtd; found++; @@ -651,8 +826,8 @@ int __init init_pmc551(void) printk(KERN_NOTICE "pmc551: not detected,\n"); return -ENODEV; } else { - return 0; printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found); + return 0; } } @@ -669,7 +844,7 @@ static void __exit cleanup_pmc551(void) priv = (struct mypriv *)mtd->priv; pmc551list = priv->nextpmc551; - if(priv->start) + if(priv->start) iounmap(((struct mypriv *)mtd->priv)->start); kfree (mtd->priv); @@ -681,10 +856,7 @@ static void __exit cleanup_pmc551(void) printk(KERN_NOTICE "pmc551: %d pmc551 devices unloaded\n", found); } -#if LINUX_VERSION_CODE > 0x20300 +#if LINUX_VERSION_CODE >= 0x20211 module_init(init_pmc551); module_exit(cleanup_pmc551); #endif - - - diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index b26b0630217d..b66edcc44b3f 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -134,6 +134,7 @@ an MMIO register read. */ +#include #include #include #include @@ -141,18 +142,21 @@ an MMIO register read. #include #include #include +#include #include #include -#define RTL8139_VERSION "0.9.11" -#define RTL8139_MODULE_NAME "8139too" -#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION -#define PFX RTL8139_MODULE_NAME ": " +#define RTL8139_VERSION "0.9.12" +#define MODNAME "8139too" +#define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION +#define PFX MODNAME ": " -/* define to 1 to enable PIO instead of MMIO */ -#undef USE_IO_OPS +/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */ +#ifdef CONFIG_8139TOO_PIO +#define USE_IO_OPS 1 +#endif /* define to 1 to enable copious debugging info */ #undef RTL8139_DEBUG @@ -502,12 +506,11 @@ struct rtl8139_private { int drv_flags; struct pci_dev *pci_dev; struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int tx_flag; - atomic_t cur_tx; - atomic_t dirty_tx; + unsigned int cur_tx; + unsigned int dirty_tx; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ @@ -524,6 +527,9 @@ struct rtl8139_private { unsigned int mediasense:1; /* Media sensing in progress. */ spinlock_t lock; chip_t chipset; + pid_t thr_pid; + wait_queue_head_t thr_wait; + struct semaphore thr_exited; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -538,7 +544,7 @@ static int rtl8139_open (struct net_device *dev); static int mdio_read (struct net_device *dev, int phy_id, int location); static void mdio_write (struct net_device *dev, int phy_id, int location, int val); -static void rtl8139_timer (unsigned long data); +static int rtl8139_thread (void *data); static void rtl8139_tx_timeout (struct net_device *dev); static void rtl8139_init_ring (struct net_device *dev); static int rtl8139_start_xmit (struct sk_buff *skb, @@ -552,7 +558,6 @@ static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); - #ifdef USE_IO_OPS #define RTL_R8(reg) inb (((unsigned long)ioaddr) + (reg)) @@ -648,6 +653,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } + SET_MODULE_OWNER(dev); tp = dev->priv; pio_start = pci_resource_start (pdev, 0); @@ -867,7 +873,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, tp->pci_dev = pdev; tp->board = ent->driver_data; tp->mmio_addr = ioaddr; - tp->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init (&tp->lock); + init_waitqueue_head (&tp->thr_wait); + init_MUTEX_LOCKED (&tp->thr_exited); pdev->driver_data = dev; @@ -897,7 +905,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ /* The lower four bits are the media type. */ - option = (board_idx > 7) ? 0 : media[board_idx]; + option = (board_idx >= ARRAY_SIZE(media)) ? 0 : media[board_idx]; if (option > 0) { tp->full_duplex = (option & 0x200) ? 1 : 0; tp->default_port = option & 15; @@ -1068,7 +1076,7 @@ static void mdio_sync (void *mdio_addr) static int mdio_read (struct net_device *dev, int phy_id, int location) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; @@ -1111,7 +1119,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location) static void mdio_write (struct net_device *dev, int phy_id, int location, int value) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; @@ -1154,7 +1162,7 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static int rtl8139_open (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; int retval; #ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; @@ -1162,12 +1170,9 @@ static int rtl8139_open (struct net_device *dev) DPRINTK ("ENTER\n"); - MOD_INC_USE_COUNT; - retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { DPRINTK ("EXIT, returning %d\n", retval); - MOD_DEC_USE_COUNT; return retval; } @@ -1186,13 +1191,13 @@ static int rtl8139_open (struct net_device *dev) tp->rx_ring, tp->rx_ring_dma); DPRINTK ("EXIT, returning -ENOMEM\n"); - MOD_DEC_USE_COUNT; return -ENOMEM; } tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; + tp->twistie = 1; rtl8139_init_ring (dev); rtl8139_hw_start (dev); @@ -1203,13 +1208,10 @@ static int rtl8139_open (struct net_device *dev) dev->irq, RTL_R8 (MediaStatus), tp->full_duplex ? "full" : "half"); - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer (&tp->timer); - tp->timer.expires = jiffies + 3 * HZ; - tp->timer.data = (unsigned long) dev; - tp->timer.function = &rtl8139_timer; - add_timer (&tp->timer); + tp->thr_pid = kernel_thread (rtl8139_thread, dev, CLONE_FS | CLONE_FILES); + if (tp->thr_pid < 0) + printk (KERN_WARNING "%s: unable to start kernel thread\n", + dev->name); DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1219,7 +1221,7 @@ static int rtl8139_open (struct net_device *dev) /* Start the hardware at open or resume. */ static void rtl8139_hw_start (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; u8 tmp; @@ -1311,14 +1313,14 @@ static void rtl8139_hw_start (struct net_device *dev) /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void rtl8139_init_ring (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; int i; DPRINTK ("ENTER\n"); tp->cur_rx = 0; - atomic_set (&tp->cur_tx, 0); - atomic_set (&tp->dirty_tx, 0); + tp->cur_tx = 0; + tp->dirty_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { tp->tx_info[i].skb = NULL; @@ -1330,7 +1332,10 @@ static void rtl8139_init_ring (struct net_device *dev) } -#ifndef RTL_TUNE_TWISTER +/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */ +static int next_tick = 3 * HZ; + +#ifndef CONFIG_8139TOO_TUNE_TWISTER static inline void rtl8139_tune_twister (struct net_device *dev, struct rtl8139_private *tp) {} #else @@ -1338,6 +1343,7 @@ static void rtl8139_tune_twister (struct net_device *dev, struct rtl8139_private *tp) { int linkcase; + void *ioaddr = tp->mmio_addr; DPRINTK ("ENTER\n"); @@ -1421,15 +1427,13 @@ static void rtl8139_tune_twister (struct net_device *dev, DPRINTK ("EXIT\n"); } -#endif /* RTL_TUNE_TWISTER */ +#endif /* CONFIG_8139TOO_TUNE_TWISTER */ -static void rtl8139_timer (unsigned long data) +static inline void rtl8139_thread_iter (struct net_device *dev, + struct rtl8139_private *tp, + void *ioaddr) { - struct net_device *dev = (struct net_device *) data; - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; - void *ioaddr = tp->mmio_addr; - int next_tick = 60 * HZ; int mii_reg5; mii_reg5 = mdio_read (dev, tp->phys[0], 5); @@ -1450,6 +1454,8 @@ static void rtl8139_timer (unsigned long data) } } + next_tick = HZ * 60; + rtl8139_tune_twister (dev, tp); DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", @@ -1462,9 +1468,33 @@ static void rtl8139_timer (unsigned long data) DPRINTK ("%s: Chip config %2.2x %2.2x.\n", dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); +} + + +static int rtl8139_thread (void *data) +{ + struct net_device *dev = data; + struct rtl8139_private *tp = dev->priv; + unsigned long timeout; - tp->timer.expires = jiffies + next_tick; - add_timer (&tp->timer); + daemonize (); + sprintf (current->comm, "k8139d-%s", dev->name); + + while (1) { + timeout = next_tick; + do { + timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); + } while (!signal_pending (current) && (timeout > 0)); + + if (signal_pending (current)) + break; + + rtnl_lock (); + rtl8139_thread_iter (dev, tp, tp->mmio_addr); + rtnl_unlock (); + } + + up_and_exit (&tp->thr_exited, 0); } @@ -1472,8 +1502,8 @@ static void rtl8139_tx_clear (struct rtl8139_private *tp) { int i; - atomic_set (&tp->cur_tx, 0); - atomic_set (&tp->dirty_tx, 0); + tp->cur_tx = 0; + tp->dirty_tx = 0; /* Dump the unsent Tx packets. */ for (i = 0; i < NUM_TX_DESC; i++) { @@ -1494,11 +1524,10 @@ static void rtl8139_tx_clear (struct rtl8139_private *tp) static void rtl8139_tx_timeout (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int i; u8 tmp8; - unsigned long flags; DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1516,20 +1545,17 @@ static void rtl8139_tx_timeout (struct net_device *dev) /* Emit info to figure out what went wrong. */ printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", - dev->name, atomic_read (&tp->cur_tx), - atomic_read (&tp->dirty_tx)); + dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), - i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? + i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); /* Stop a shared interrupt from scavenging while we are. */ - spin_lock_irqsave (&tp->lock, flags); - + spin_lock_irq (&tp->lock); rtl8139_tx_clear (tp); - - spin_unlock_irqrestore (&tp->lock, flags); + spin_unlock_irq (&tp->lock); /* ...and finally, reset everything */ rtl8139_hw_start (dev); @@ -1539,27 +1565,37 @@ static void rtl8139_tx_timeout (struct net_device *dev) static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry; /* Calculate the next Tx descriptor entry. */ - entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC; + entry = tp->cur_tx % NUM_TX_DESC; assert (tp->tx_info[entry].skb == NULL); assert (tp->tx_info[entry].mapping == 0); tp->tx_info[entry].skb = skb; - /* tp->tx_info[entry].mapping = 0; */ - memcpy (tp->tx_buf[entry], skb->data, skb->len); + if ((long) skb->data & 3) { /* Must use alignment buffer. */ + /* tp->tx_info[entry].mapping = 0; */ + memcpy (tp->tx_buf[entry], skb->data, skb->len); + RTL_W32 (TxAddr0 + (entry * 4), + tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); + } else { + tp->tx_info[entry].mapping = + pci_map_single (tp->pci_dev, skb->data, skb->len, + PCI_DMA_TODEVICE); + RTL_W32 (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping); + } /* Note: the chip doesn't have auto-pad! */ - RTL_W32 (TxStatus0 + (entry * sizeof(u32)), + RTL_W32 (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; - atomic_inc (&tp->cur_tx); - if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC) + tp->cur_tx++; + mb(); + if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", @@ -1573,16 +1609,14 @@ static void rtl8139_tx_interrupt (struct net_device *dev, struct rtl8139_private *tp, void *ioaddr) { - int cur_tx, dirty_tx, tx_left; + unsigned int dirty_tx, tx_left; assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - dirty_tx = atomic_read (&tp->dirty_tx); - - cur_tx = atomic_read (&tp->cur_tx); - tx_left = cur_tx - dirty_tx; + dirty_tx = tp->dirty_tx; + tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus; @@ -1632,29 +1666,27 @@ static void rtl8139_tx_interrupt (struct net_device *dev, } dev_kfree_skb_irq (tp->tx_info[entry].skb); tp->tx_info[entry].skb = NULL; - dirty_tx++; - if (dirty_tx < 0) { /* handle signed int overflow */ - atomic_sub (cur_tx, &tp->cur_tx); /* XXX racy? */ - dirty_tx = cur_tx - tx_left + 1; - } - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); - - cur_tx = atomic_read (&tp->cur_tx); - tx_left = cur_tx - dirty_tx; + dirty_tx++; + tx_left--; } #ifndef RTL8139_NDEBUG - if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) { + if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { printk (KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n", - dev->name, dirty_tx, atomic_read (&tp->cur_tx)); + dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } #endif /* RTL8139_NDEBUG */ - atomic_set (&tp->dirty_tx, dirty_tx); + /* only wake the queue if we did work, and the queue is stopped */ + if (tp->dirty_tx != dirty_tx) { + tp->dirty_tx = dirty_tx; + mb(); + if (netif_queue_stopped (dev)) + netif_wake_queue (dev); + } } @@ -1879,7 +1911,7 @@ static void rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ @@ -1962,20 +1994,27 @@ static void rtl8139_interrupt (int irq, void *dev_instance, static int rtl8139_close (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; - unsigned long flags; + int ret = 0; DPRINTK ("ENTER\n"); netif_stop_queue (dev); + if (tp->thr_pid >= 0) { + ret = kill_proc (tp->thr_pid, SIGTERM, 1); + if (ret) { + printk (KERN_ERR "%s: unable to signal thread\n", dev->name); + return ret; + } + down (&tp->thr_exited); + } + DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); - del_timer_sync (&tp->timer); - - spin_lock_irqsave (&tp->lock, flags); + spin_lock_irq (&tp->lock); /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear)); @@ -1987,7 +2026,7 @@ static int rtl8139_close (struct net_device *dev) tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); - spin_unlock_irqrestore (&tp->lock, flags); + spin_unlock_irq (&tp->lock); synchronize_irq (); free_irq (dev->irq, dev); @@ -2006,8 +2045,6 @@ static int rtl8139_close (struct net_device *dev) RTL_W8 (Config1, 0x03); RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - MOD_DEC_USE_COUNT; - DPRINTK ("EXIT\n"); return 0; } @@ -2015,9 +2052,8 @@ static int rtl8139_close (struct net_device *dev) static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; u16 *data = (u16 *) & rq->ifr_data; - unsigned long flags; int rc = 0; DPRINTK ("ENTER\n"); @@ -2028,9 +2064,7 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) /* Fall Through */ case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ - spin_lock_irqsave (&tp->lock, flags); data[3] = mdio_read (dev, data[0], data[1] & 0x1f); - spin_unlock_irqrestore (&tp->lock, flags); break; case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ @@ -2039,9 +2073,7 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) break; } - spin_lock_irqsave (&tp->lock, flags); mdio_write (dev, data[0], data[1] & 0x1f, data[2]); - spin_unlock_irqrestore (&tp->lock, flags); break; default: @@ -2056,22 +2088,14 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; DPRINTK ("ENTER\n"); - assert (tp != NULL); - if (netif_running(dev)) { - unsigned long flags; - - spin_lock_irqsave (&tp->lock, flags); - tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); - - spin_unlock_irqrestore (&tp->lock, flags); } DPRINTK ("EXIT\n"); @@ -2104,7 +2128,7 @@ static inline u32 ether_crc (int length, unsigned char *data) static void rtl8139_set_rx_mode (struct net_device *dev) { - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; @@ -2160,7 +2184,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) static void rtl8139_suspend (struct pci_dev *pdev) { struct net_device *dev = pdev->driver_data; - struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -2190,7 +2214,7 @@ static void rtl8139_resume (struct pci_dev *pdev) static struct pci_driver rtl8139_pci_driver = { - name: RTL8139_MODULE_NAME, + name: MODNAME, id_table: rtl8139_pci_tbl, probe: rtl8139_init_one, remove: rtl8139_remove_one, diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 9bbaf963128d..a4ec3fb54b64 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -38,6 +38,7 @@ Paul Gortmaker : add kmod support for auto-loading of the 8390 module by all drivers that require it. Alan Cox : Spinlocking work, added 'BUG_83C690' + Paul Gortmaker : Separate out Tx timeout code from Tx path. Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. @@ -105,6 +106,7 @@ int ei_debug = 1; /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); +static void ei_tx_timeout(struct net_device *dev); static void ei_receive(struct net_device *dev); static void ei_rx_overrun(struct net_device *dev); @@ -161,6 +163,13 @@ int ei_open(struct net_device *dev) printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name); return -ENXIO; } + + /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout + wrapper that does e.g. media check & then calls ei_tx_timeout. */ + if (dev->tx_timeout == NULL) + dev->tx_timeout = ei_tx_timeout; + if (dev->watchdog_timeo <= 0) + dev->watchdog_timeo = TX_TIMEOUT; /* * Grab the page lock so we own the register set, then call @@ -200,89 +209,66 @@ int ei_close(struct net_device *dev) } /** - * ei_start_xmit - begin packet transmission - * @skb: packet to be sent - * @dev: network device to which packet is sent + * ei_tx_timeout - handle transmit time out condition + * @dev: network device which has apparently fallen asleep * - * Sends a packet to an 8390 network device. + * Called by kernel when device never acknowledges a transmit has + * completed (or failed) - i.e. never posted a Tx related interrupt. */ - -static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) + +void ei_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; - int length, send_length, output_page; + int txsr, isr, tickssofar = jiffies - dev->trans_start; unsigned long flags; - /* - * If it has been too long since the last Tx, we assume the - * board has died and kick it. - */ - - if (netif_queue_stopped(dev)) { - /* Do timeouts, just like the 8003 driver. */ - int txsr; - int isr; - int tickssofar = jiffies - dev->trans_start; - - /* - * Need the page lock. Now see what went wrong. This bit is - * fast. - */ - - spin_lock_irqsave(&ei_local->page_lock, flags); - txsr = inb(e8390_base+EN0_TSR); - if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX))) - { - spin_unlock_irqrestore(&ei_local->page_lock, flags); - return 1; - } - - ei_local->stat.tx_errors++; - isr = inb(e8390_base+EN0_ISR); - if (!netif_running(dev)) { - spin_unlock_irqrestore(&ei_local->page_lock, flags); - printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name); - return 1; - } - - /* - * Note that if the Tx posted a TX_ERR interrupt, then the - * error will have been handled from the interrupt handler - * and not here. Error statistics are handled there as well. - */ + ei_local->stat.tx_errors++; - printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", - dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : - (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); + spin_lock_irqsave(&ei_local->page_lock, flags); + txsr = inb(e8390_base+EN0_TSR); + isr = inb(e8390_base+EN0_ISR); + spin_unlock_irqrestore(&ei_local->page_lock, flags); - if (!isr && !ei_local->stat.tx_packets) - { - /* The 8390 probably hasn't gotten on the cable yet. */ - ei_local->interface_num ^= 1; /* Try a different xcvr. */ - } + printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n", + dev->name, (txsr & ENTSR_ABT) ? "excess collisions." : + (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar); - /* - * Play shuffle the locks, a reset on some chips takes a few - * mS. We very rarely hit this point. - */ - - spin_unlock_irqrestore(&ei_local->page_lock, flags); + if (!isr && !ei_local->stat.tx_packets) + { + /* The 8390 probably hasn't gotten on the cable yet. */ + ei_local->interface_num ^= 1; /* Try a different xcvr. */ + } - /* Ugly but a reset can be slow, yet must be protected */ + /* Ugly but a reset can be slow, yet must be protected */ - disable_irq_nosync(dev->irq); - spin_lock(&ei_local->page_lock); + disable_irq_nosync(dev->irq); + spin_lock(&ei_local->page_lock); - /* Try to restart the card. Perhaps the user has fixed something. */ - ei_reset_8390(dev); - NS8390_init(dev, 1); + /* Try to restart the card. Perhaps the user has fixed something. */ + ei_reset_8390(dev); + NS8390_init(dev, 1); - spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); - dev->trans_start = jiffies; - } + spin_unlock(&ei_local->page_lock); + enable_irq(dev->irq); + netif_wake_queue(dev); +} +/** + * ei_start_xmit - begin packet transmission + * @skb: packet to be sent + * @dev: network device to which packet is sent + * + * Sends a packet to an 8390 network device. + */ + +static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + long e8390_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *) dev->priv; + int length, send_length, output_page; + unsigned long flags; + length = skb->len; /* Mask interrupts from the ethercard. @@ -1147,6 +1133,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); +EXPORT_SYMBOL(ei_tx_timeout); EXPORT_SYMBOL(ethdev_init); EXPORT_SYMBOL(NS8390_init); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 5c00406b4881..7a4c1a1d6e49 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -50,7 +50,6 @@ static const char *version = #include #include -#include #include #include @@ -220,8 +219,10 @@ static struct net_device_stats *cops_get_stats (struct net_device *dev); int __init cops_probe(struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; - + int base_addr = dev->base_addr; + + SET_MODULE_OWNER(dev); + if(base_addr == 0 && io) base_addr=io; @@ -235,13 +236,9 @@ int __init cops_probe(struct net_device *dev) * Dayna cards don't autoprobe well at all, but if your card is * at IRQ 5 & IO 0x240 we find it every time. ;) JS */ - for(i=0; cops_portlist[i]; i++) { - int ioaddr = cops_portlist[i]; - if(check_region(ioaddr, COPS_IO_EXTENT)) - continue; - if(cops_probe1(dev, ioaddr) == 0) + for(i=0; cops_portlist[i]; i++) + if(cops_probe1(dev, cops_portlist[i]) == 0) return 0; - } return -ENODEV; } @@ -254,13 +251,17 @@ int __init cops_probe(struct net_device *dev) static int __init cops_probe1(struct net_device *dev, int ioaddr) { struct cops_local *lp; - static unsigned version_printed = 0; - + static unsigned version_printed; int board = board_type; + int retval; if(cops_debug && version_printed++ == 0) printk("%s", version); + /* Grab the region so no one else tries to probe our ioports. */ + if (!request_region(ioaddr, COPS_IO_EXTENT, dev->name)) + return -EBUSY; + /* * Since this board has jumpered interrupts, allocate the interrupt * vector now. There is no point in waiting since no other device @@ -273,13 +274,14 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) case 0: /* COPS AutoIRQ routine */ dev->irq = cops_irq(ioaddr, board); - if(!dev->irq) - return -EINVAL; /* No IRQ found on this port */ - break; + if(!dev->irq) { + retval = -EINVAL; /* No IRQ found on this port */ + goto err_out; + } case 1: - return -EINVAL; - break; + retval = -EINVAL; + goto err_out; /* Fixup for users that don't know that IRQ 2 is really * IRQ 9, or don't know which one to set. @@ -301,17 +303,22 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) } /* Reserve any actual interrupt. */ - if(dev->irq && request_irq(dev->irq, &cops_interrupt, 0, cardname, dev)) - return -EINVAL; + if(dev->irq) { + retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); + if (retval) + goto err_out; + } - /* Grab the region so no one else tries to probe our ioports. */ - request_region(ioaddr, COPS_IO_EXTENT, cardname); - dev->base_addr = ioaddr; + dev->base_addr = ioaddr; /* Initialize the private device structure. */ dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL); - if(dev->priv == NULL) - return -ENOMEM; + if(dev->priv == NULL) { + if (dev->irq) + free_irq(dev->irq, dev); + retval = -ENOMEM; + goto err_out; + } lp = (struct cops_local *)dev->priv; memset(lp, 0, sizeof(struct cops_local)); @@ -347,6 +354,10 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) } return 0; + +err_out: + release_region(ioaddr, COPS_IO_EXTENT); + return retval; } static int __init cops_irq (int ioaddr, int board) @@ -426,10 +437,6 @@ static int cops_open(struct net_device *dev) cops_jumpstart(dev); /* Start the card up. */ netif_start_queue(dev); -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return 0; } @@ -990,10 +997,6 @@ static int cops_close(struct net_device *dev) del_timer(&cops_timer); netif_stop_queue(dev); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; } @@ -1039,8 +1042,7 @@ void cleanup_module(void) { /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ unregister_netdev(&cops0_dev); - if(cops0_dev.priv) - kfree(cops0_dev.priv); + kfree(cops0_dev.priv); if(cops0_dev.irq) free_irq(cops0_dev.irq, &cops0_dev); release_region(cops0_dev.base_addr, COPS_IO_EXTENT); diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 503c66167b8d..b7bca28da2c5 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -62,22 +62,12 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int ipddp_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int ipddp_close(struct net_device *dev) -{ - MOD_DEC_USE_COUNT; - return 0; -} - static int __init ipddp_init(struct net_device *dev) { static unsigned version_printed = 0; + SET_MODULE_OWNER(dev); + if (ipddp_debug && version_printed++ == 0) printk("%s", version); @@ -100,8 +90,6 @@ static int __init ipddp_init(struct net_device *dev) return -ENOMEM; memset(dev->priv,0,sizeof(struct net_device_stats)); - dev->open = ipddp_open; - dev->stop = ipddp_close; dev->get_stats = ipddp_get_stats; dev->do_ioctl = ipddp_ioctl; @@ -298,7 +286,7 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } -static struct net_device dev_ipddp = { init: ipddp_init }; +static struct net_device dev_ipddp; MODULE_PARM(ipddp_mode, "i"); @@ -306,6 +294,7 @@ static int __init ipddp_init_module(void) { int err; + dev_ipddp.init = ipddp_init; err=dev_alloc_name(&dev_ipddp, "ipddp%d"); if(err < 0) return err; diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index d9b81882412c..b55a37f28b97 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -206,11 +206,7 @@ static int io=0; static int irq=0; static int dma=0; -#ifdef MODULE #include -#include -#endif - #include #include #include @@ -710,22 +706,6 @@ static struct timer_list ltpc_timer; static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *ltpc_get_stats(struct net_device *dev); -static int ltpc_open(struct net_device *dev) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - return 0; -} - -static int ltpc_close(struct net_device *dev) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - return 0; -} - static int read_30 ( struct net_device *dev) { lt_command c; @@ -921,9 +901,6 @@ static int ltpc_init(struct net_device *dev) memset(dev->priv, 0, sizeof(struct ltpc_private)); dev->get_stats = ltpc_get_stats; - dev->open = ltpc_open; - dev->stop = ltpc_close; - /* add the ltpc-specific things */ dev->do_ioctl = <pc_ioctl; @@ -1008,7 +985,7 @@ static struct net_device_stats *ltpc_get_stats(struct net_device *dev) /* initialization stuff */ -int __init ltpc_probe_dma(int base) +static int __init ltpc_probe_dma(int base) { int dma = 0; int timeout; @@ -1087,6 +1064,8 @@ int __init ltpc_probe(struct net_device *dev) unsigned long flags; unsigned long f; + SET_MODULE_OWNER(dev); + save_flags(flags); /* probe for the I/O port address */ @@ -1273,11 +1252,7 @@ static int __init ltpc_setup(char *str) __setup("ltpc=", ltpc_setup); #endif /* MODULE */ -static struct net_device dev_ltpc = { - "", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, ltpc_probe }; +static struct net_device dev_ltpc; #ifdef MODULE MODULE_PARM(debug, "i"); @@ -1295,6 +1270,7 @@ int __init init_module(void) "ltpc: Autoprobing is not recommended for modules\n"); /* Find a name for this unit */ + dev_ltpc.init = ltpc_probe; err=dev_alloc_name(&dev_ltpc,"lt%d"); if(err<0) diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c index b7718aba5ffa..ee4ba5876a4c 100644 --- a/drivers/net/daynaport.c +++ b/drivers/net/daynaport.c @@ -44,8 +44,6 @@ static int version_printed; #include #include "8390.h" -extern int console_loglevel; - int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, int prom, struct nubus_dev *ndev); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index bf3a376a2d8a..1d974350cc77 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -39,18 +39,6 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *dummy_get_stats(struct net_device *dev); -static int dummy_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int dummy_close(struct net_device *dev) -{ - MOD_DEC_USE_COUNT; - return 0; -} - /* fake multicast ability */ static void set_multicast_list(struct net_device *dev) { @@ -74,8 +62,6 @@ static int __init dummy_init(struct net_device *dev) memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = dummy_get_stats; - dev->open = dummy_open; - dev->stop = dummy_close; dev->set_multicast_list = set_multicast_list; /* Fill in the fields of the device structure with ethernet-generic values. */ @@ -107,12 +93,17 @@ static struct net_device_stats *dummy_get_stats(struct net_device *dev) return dev->priv; } -static struct net_device dev_dummy = { init: dummy_init }; +static struct net_device dev_dummy; static int __init dummy_init_module(void) { + int err; + + dev_dummy.init = dummy_init; + SET_MODULE_OWNER(&dev_dummy); + /* Find a name for this unit */ - int err=dev_alloc_name(&dev_dummy,"dummy%d"); + err=dev_alloc_name(&dev_dummy,"dummy%d"); if(err<0) return err; if (register_netdev(&dev_dummy) != 0) diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 112e0afbab4c..e281511dcb5a 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -201,6 +201,8 @@ static int __init eql_init(struct net_device *dev) /* static unsigned num_masters = 0; */ equalizer_t *eql = 0; + SET_MODULE_OWNER(dev); + if ( version_printed++ == 0 && eql_debug > 0) printk(version); /* @@ -259,8 +261,6 @@ static int eql_open(struct net_device *dev) equalizer_t *eql = (equalizer_t *) dev->priv; slave_queue_t *new_queue; - MOD_INC_USE_COUNT; - #ifdef EQL_DEBUG if (eql_debug >= 5) printk ("%s: open\n", dev->name); @@ -284,7 +284,6 @@ static int eql_open(struct net_device *dev) return 0; } - MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -310,7 +309,6 @@ static int eql_close(struct net_device *dev) eql_delete_slave_queue (eql->queue); - MOD_DEC_USE_COUNT; return 0; } @@ -985,14 +983,12 @@ static void eql_timer(unsigned long param) } } -static struct net_device dev_eql = -{ - name: "eql", - init: eql_init, -}; +static struct net_device dev_eql; static int __init eql_init_module(void) { + strcpy(dev_eql.name, "eql"); + dev_eql.init = eql_init; if (register_netdev(&dev_eql) != 0) { printk("eql: register_netdev() returned non-zero.\n"); return -EIO; diff --git a/drivers/net/hamradio/6pack.h b/drivers/net/hamradio/6pack.h index b929c83a64e8..08cee0485699 100644 --- a/drivers/net/hamradio/6pack.h +++ b/drivers/net/hamradio/6pack.h @@ -101,7 +101,8 @@ struct sixpack { int mtu; /* Our mtu (to spot changes!) */ int buffsize; /* Max buffers sizes */ - unsigned char flags; /* Flag values/ mode etc */ + unsigned long flags; /* Flag values/ mode etc */ + /* long req'd for set_bit --RR */ unsigned char mode; /* 6pack mode */ /* 6pack stuff */ diff --git a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h index c24c278192c3..4a3d700cb18d 100644 --- a/drivers/net/hamradio/mkiss.h +++ b/drivers/net/hamradio/mkiss.h @@ -42,7 +42,8 @@ struct ax_disp { int buffsize; /* Max buffers sizes */ - unsigned char flags; /* Flag values/ mode etc */ + unsigned long flags; /* Flag values/ mode etc */ + /* long req'd: used by set_bit --RR */ #define AXF_INUSE 0 /* Channel in use */ #define AXF_ESCAPE 1 /* ESC received */ #define AXF_ERROR 2 /* Parity, etc. error */ diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index b476e290c6cb..1be9f6561fef 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -406,7 +406,6 @@ static int shaper_open(struct net_device *dev) return -ENODEV; if(shaper->bitspersec==0) return -EINVAL; - MOD_INC_USE_COUNT; return 0; } @@ -419,7 +418,6 @@ static int shaper_close(struct net_device *dev) struct shaper *shaper=dev->priv; shaper_flush(shaper); del_timer_sync(&shaper->timer); - MOD_DEC_USE_COUNT; return 0; } @@ -618,34 +616,31 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } -static struct shaper *shaper_alloc(struct net_device *dev) +static void shaper_init_priv(struct net_device *dev) { - struct shaper *sh=kmalloc(sizeof(struct shaper), GFP_KERNEL); - if(sh==NULL) - return NULL; - memset(sh,0,sizeof(*sh)); + struct shaper *sh = dev->priv; + skb_queue_head_init(&sh->sendq); init_timer(&sh->timer); sh->timer.function=shaper_timer; sh->timer.data=(unsigned long)sh; init_waitqueue_head(&sh->wait_queue); - return sh; } /* * Add a shaper device to the system */ -int __init shaper_probe(struct net_device *dev) +static int __init shaper_probe(struct net_device *dev) { /* * Set up the shaper. */ - - dev->priv = shaper_alloc(dev); - if(dev->priv==NULL) - return -ENOMEM; - + + SET_MODULE_OWNER(dev); + + shaper_init_priv(dev); + dev->open = shaper_open; dev->stop = shaper_close; dev->hard_start_xmit = shaper_start_xmit; @@ -685,89 +680,68 @@ int __init shaper_probe(struct net_device *dev) return 0; } +static int shapers = 1; #ifdef MODULE -static struct net_device dev_shape = -{ - "", - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, shaper_probe -}; +MODULE_PARM(shapers, "i"); -int init_module(void) -{ - int err=dev_alloc_name(&dev_shape,"shaper%d"); - if(err<0) - return err; - printk(SHAPER_BANNER); - if (register_netdev(&dev_shape) != 0) - return -EIO; - printk("Traffic shaper initialised.\n"); - return 0; -} +#else /* MODULE */ -void cleanup_module(void) +static int __init set_num_shapers(char *str) { - struct shaper *sh=dev_shape.priv; + shapers = simple_strtol(str, NULL, 0); + return 1; +} - /* - * No need to check MOD_IN_USE, as sys_delete_module() checks. - * To be unloadable we must be closed and detached so we don't - * need to flush things. - */ - - unregister_netdev(&dev_shape); +__setup("shapers=", set_num_shapers); - /* - * Free up the private structure, or leak memory :-) - */ - kfree(sh); - dev_shape.priv = NULL; -} +#endif /* MODULE */ -#else +static struct net_device *devs; -static struct net_device dev_sh0 = +static int __init shaper_init(void) { - "shaper0", - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, shaper_probe -}; + int i, err; + size_t alloc_size; + struct shaper *sp; + unsigned int shapers_registered = 0; + if (shapers < 1) + return -ENODEV; -static struct net_device dev_sh1 = -{ - "shaper1", - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, shaper_probe -}; + alloc_size = (sizeof(*devs) * shapers) + + (sizeof(struct shaper) * shapers); + devs = kmalloc(alloc_size, GFP_KERNEL); + if (!devs) + return -ENOMEM; + memset(devs, 0, alloc_size); + sp = (struct shaper *) &devs[shapers]; + for (i = 0; i < shapers; i++) { + err = dev_alloc_name(&devs[i], "shaper%d"); + if (err < 0) + break; + devs[i].init = shaper_probe; + devs[i].priv = &sp[i]; + if (register_netdev(&devs[i])) + break; + shapers_registered++; + } -static struct net_device dev_sh2 = -{ - "shaper2", - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, shaper_probe -}; + if (!shapers_registered) { + kfree(devs); + devs = NULL; + } -static struct net_device dev_sh3 = -{ - "shaper3", - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, shaper_probe -}; + return (shapers_registered ? 0 : -ENODEV); +} -void shaper_init(void) +static void __exit shaper_exit (void) { - register_netdev(&dev_sh0); - register_netdev(&dev_sh1); - register_netdev(&dev_sh2); - register_netdev(&dev_sh3); + kfree(devs); + devs = NULL; } -#endif /* MODULE */ +module_init(shaper_init); +module_exit(shaper_exit); + diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 7420e569191f..6e8427a3b367 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -549,7 +549,6 @@ sl_close(struct net_device *dev) sl->xleft = 0; spin_unlock_bh(&sl->lock); - MOD_DEC_USE_COUNT; return 0; } @@ -564,7 +563,6 @@ static int sl_open(struct net_device *dev) sl->flags &= (1 << SLF_INUSE); netif_start_queue(dev); - MOD_INC_USE_COUNT; return 0; } @@ -647,6 +645,8 @@ static int sl_init(struct net_device *dev) dev->type = ARPHRD_SLIP + sl->mode; dev->tx_queue_len = 10; + SET_MODULE_OWNER(dev); + dev_init_buffers(dev); /* New-style flags. */ diff --git a/drivers/net/slip.h b/drivers/net/slip.h index c9f064b1d5e2..bbd82fda55c8 100644 --- a/drivers/net/slip.h +++ b/drivers/net/slip.h @@ -91,7 +91,7 @@ struct slip { int xdata, xbits; /* 6 bit slip controls */ #endif - unsigned int flags; /* Flag values/ mode etc */ + unsigned long flags; /* Flag values/ mode etc */ #define SLF_INUSE 0 /* Channel in use */ #define SLF_ESCAPE 1 /* ESC received */ #define SLF_ERROR 2 /* Parity, etc. error */ diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 17d81a534565..e23ad7a6ec60 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -237,6 +237,7 @@ subsequent_board: printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " "by a %s (%d) block.\n", dev->name, i, medianame[leaf->media], leaf->media, + leaf->type >= ARRAY_SIZE(block_name) ? "UNKNOWN" : block_name[leaf->type], leaf->type); } if (new_advertise) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8a80813aaabd..0a44dcf9f225 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -130,6 +130,7 @@ int tun_net_init(struct net_device *dev) DBG(KERN_INFO "%s: tun_net_init\n", tun->name); + SET_MODULE_OWNER(dev); dev->open = tun_net_open; dev->hard_start_xmit = tun_net_xmit; dev->stop = tun_net_close; @@ -454,8 +455,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) tun->dev.init = tun_net_init; tun->dev.priv = tun; - MOD_INC_USE_COUNT; - return 0; } @@ -479,7 +478,6 @@ static int tun_chr_close(struct inode *inode, struct file *file) kfree(tun); file->private_data = NULL; - MOD_DEC_USE_COUNT; return 0; } diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index 47b3d88fefcf..b07d83358d98 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -27,8 +27,6 @@ extern void via_nubus_init(void); extern void oss_nubus_init(void); -extern int console_loglevel; - /* Constants */ /* This is, of course, the size in bytelanes, rather than the size in @@ -967,8 +965,9 @@ static int nubus_read_proc(char *buf, char **start, off_t off, int count, int *eof, void *data) { int nprinted, len, begin = 0; - int slot; - + int slot,size; + struct nubus_board* board; + len = sprintf(buf, "Nubus devices found:\n"); /* Walk the list of NuBus boards */ for (board = nubus_boards; board != NULL; board = board->next) @@ -987,7 +986,7 @@ static int nubus_read_proc(char *buf, char **start, off_t off, if (slot==16 || len+begin < off) *eof = 1; off -= begin; - *strat = buf + off; + *start = buf + off; len -= off; if (len>count) len = count; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ed9fd9bffa9c..99ed14b8fbd5 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -540,15 +540,9 @@ static u32 pci_size(u32 base, unsigned long mask) static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; - u32 l, sz, tmp; - u16 cmd; + u32 l, sz; struct resource *res; - /* Disable IO and memory while we fiddle */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(dev, PCI_COMMAND, tmp); - for(pos=0; posresource[pos]; @@ -611,7 +605,6 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } res->name = dev->name; } - pci_write_config_word(dev, PCI_COMMAND, cmd); } void __init pci_read_bridge_bases(struct pci_bus *child) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index d9d8ae97d4ab..bf9c82c5a742 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -45,24 +45,28 @@ pbus_assign_resources_sorted(struct pci_bus *bus, head_io.next = head_mem.next = NULL; for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { struct pci_dev *dev = pci_dev_b(ln); + u16 class = dev->class >> 8; u16 cmd; /* First, disable the device to avoid side effects of possibly overlapping I/O and memory ranges. - Except the VGA - for obvious reason. :-) */ - if (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) + Leave VGA enabled - for obvious reason. :-) + Same with all sorts of bridges - they may + have VGA behind them. */ + if (class == PCI_CLASS_DISPLAY_VGA + || class == PCI_CLASS_NOT_DEFINED_VGA) found_vga = 1; - else { + else if (class >> 8 != PCI_BASE_CLASS_BRIDGE) { pci_read_config_word(dev, PCI_COMMAND, &cmd); cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); pci_write_config_word(dev, PCI_COMMAND, cmd); } - + /* Reserve some resources for CardBus. Are these values reasonable? */ - if (dev->class >> 8 == PCI_CLASS_BRIDGE_CARDBUS) { + if (class == PCI_CLASS_BRIDGE_CARDBUS) { io_reserved += 8*1024; mem_reserved += 32*1024*1024; continue; diff --git a/drivers/sound/maestro.c b/drivers/sound/maestro.c index 6013b2ec23c5..7529c1db3dba 100644 --- a/drivers/sound/maestro.c +++ b/drivers/sound/maestro.c @@ -115,6 +115,8 @@ * themselves, but we'll see. * * History + * (still kind of v0.14) Nov 23 - Alan Cox + * Add clocking= for people with seriously warped hardware * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz * add __init to maestro_ac97_init() and maestro_install() * (still based on v0.14) Mar 29 2000 - Zach Brown @@ -262,6 +264,10 @@ static int debug=0; static int dsps_order=0; /* wether or not we mess around with power management */ static int use_pm=2; /* set to 1 for force */ +/* clocking for broken hardware - a few laptops seem to use a 50Khz clock + ie insmod with clocking=50000 or so */ + +static int clocking=48000; /* --------------------------------------------------------------------- */ #define DRIVER_VERSION "0.14" @@ -1200,7 +1206,10 @@ static u32 compute_rate(struct ess_state *s, u32 freq) { u32 clock = clock_freq[s->card->card_type]; - if (freq == 48000) return 0x10000; + freq = (freq * clocking)/48000; + + if (freq == 48000) + return 0x10000; return ((freq / clock) <<16 )+ (((freq % clock) << 16) / clock); @@ -3578,6 +3587,7 @@ MODULE_PARM(debug,"i"); #endif MODULE_PARM(dsps_order,"i"); MODULE_PARM(use_pm,"i"); +MODULE_PARM(clocking, "i"); void cleanup_module(void) { M_printk("maestro: unloading\n"); diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c index 50a045c1c4ad..d266b1353576 100644 --- a/drivers/sound/sound_core.c +++ b/drivers/sound/sound_core.c @@ -454,11 +454,8 @@ static int soundcore_open(struct inode *, struct file *); static struct file_operations soundcore_fops= { -/* owner: THIS_MODULE, * this is a bug: if we have an owner, the kernel - generates a MOD_INC_USE_COUNT - thus - the module cannot be unloaded since the device - is never released here ! - solution: owner - has to be NULL. Patch by Peter Wahl */ + /* We must have an owner or the module locking fails */ + owner: THIS_MODULE, open: soundcore_open, }; diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c index 0509f23471ac..616058acc0af 100644 --- a/drivers/usb/bluetooth.c +++ b/drivers/usb/bluetooth.c @@ -1,11 +1,15 @@ /* - * bluetooth.c Version 0.6 + * bluetooth.c Version 0.7 * * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * + * (11/29/2000) Version 0.7 gkh + * Fixed problem with overrunning the tty flip buffer. + * Removed unneeded NULL pointer initialization. + * * (10/05/2000) Version 0.6 gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. @@ -211,8 +215,7 @@ static struct tty_driver bluetooth_tty_driver; static struct tty_struct * bluetooth_tty[BLUETOOTH_TTY_MINORS]; static struct termios * bluetooth_termios[BLUETOOTH_TTY_MINORS]; static struct termios * bluetooth_termios_locked[BLUETOOTH_TTY_MINORS]; -static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, }; - +static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS]; static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function) @@ -327,6 +330,11 @@ static int bluetooth_open (struct tty_struct *tty, struct file * filp) tty->driver_data = bluetooth; bluetooth->tty = tty; + /* force low_latency on so that our tty_push actually forces the data through, + * otherwise it is scheduled, and with high data rates (like with OHCI) data + * can get lost. */ + bluetooth->tty->low_latency = 1; + bluetooth->active = 1; /* Reset the packet position counters */ @@ -786,9 +794,14 @@ static void bluetooth_int_callback (struct urb *urb) return; } - if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){ - for (i = 0; i < bluetooth->int_packet_pos; ++i) + if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) { + for (i = 0; i < bluetooth->int_packet_pos; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */ + if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(bluetooth->tty); + } tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0); + } tty_flip_buffer_push(bluetooth->tty); bluetooth->int_packet_pos = 0; @@ -900,8 +913,13 @@ static void bluetooth_read_bulk_callback (struct urb *urb) } if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) { - for (i = 0; i < bluetooth->bulk_packet_pos; ++i) + for (i = 0; i < bluetooth->bulk_packet_pos; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ + if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(bluetooth->tty); + } tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0); + } tty_flip_buffer_push(bluetooth->tty); bluetooth->bulk_packet_pos = 0; } diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index c77ba35e275c..58061ec90074 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -82,6 +82,7 @@ struct usblp { int readcount; /* Counter for reads */ int ifnum; /* Interface number */ int minor; /* minor number of device */ + unsigned int quirks; /* quirks flags */ unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ @@ -90,6 +91,26 @@ struct usblp { static struct usblp *usblp_table[USBLP_MINORS]; +/* Quirks: various printer quirks are handled by this table & its flags. */ + +struct quirk_printer_struct { + __u16 vendorId; + __u16 productId; + unsigned int quirks; +}; + +#define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ +#define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ + +static struct quirk_printer_struct quirk_printers[] = { + { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ + { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */ + { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ + { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ + { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ + { 0, 0 } +}; + /* * Functions for usblp control messages. */ @@ -325,8 +346,17 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, return -ENODEV; if (usblp->writeurb.status) { - err = usblp_check_status(usblp, err); - continue; + if (usblp->quirks & USBLP_QUIRK_BIDIR) { + if (usblp->writeurb.status != -EINPROGRESS) + err("usblp%d: error %d writing to printer", + usblp->minor, usblp->writeurb.status); + err = usblp->writeurb.status; + continue; + } + else { + err = usblp_check_status(usblp, err); + continue; + } } writecount += usblp->writeurb.transfer_buffer_length; @@ -393,13 +423,42 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t return count; } +/* + * Checks for printers that have quirks, such as requiring unidirectional + * communication but reporting bidirectional; currently some HP printers + * have this flaw (HP 810, 880, 895, etc.), or needing an init string + * sent at each open (like some Epsons). + * Returns 1 if found, 0 if not found. + * + * HP recommended that we use the bidirectional interface but + * don't attempt any bulk IN transfers from the IN endpoint. + * Here's some more detail on the problem: + * The problem is not that it isn't bidirectional though. The problem + * is that if you request a device ID, or status information, while + * the buffers are full, the return data will end up in the print data + * buffer. For example if you make sure you never request the device ID + * while you are sending print data, and you don't try to query the + * printer status every couple of milliseconds, you will probably be OK. + */ +static unsigned int usblp_quirks (__u16 vendor, __u16 product) +{ + int i; + + for (i = 0; quirk_printers[i].vendorId; i++) { + if (vendor == quirk_printers[i].vendorId && + product == quirk_printers[i].productId) + return quirk_printers[i].quirks; + } + return 0; +} + static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *epread, *epwrite; struct usblp *usblp; - int minor, i, bidir = 0; + int minor, i, bidir = 0, quirks; int alts = dev->actconfig->interface[ifnum].act_altsetting; int length, err; char *buf; @@ -453,10 +512,21 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, } memset(usblp, 0, sizeof(struct usblp)); + /* lookup quirks for this printer */ + quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct); + + if (bidir && (quirks & USBLP_QUIRK_BIDIR)) { + bidir = 0; + epread = NULL; + info ("Disabling reads from problem bidirectional printer on usblp%d", + minor); + } + usblp->dev = dev; usblp->ifnum = ifnum; usblp->minor = minor; usblp->bidir = bidir; + usblp->quirks = quirks; init_waitqueue_head(&usblp->wait); diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index 6b5d6e7f0bd2..1a07a03d5f6e 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -15,6 +15,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (12/29/2000) gkh + * Small NULL pointer initialization cleanup which saves a bit of disk image + * * (11/01/2000) Adam J. Richter * instead of using idVendor/idProduct pairs, usb serial drivers * now identify their hardware interest with usb_device_id tables, @@ -346,7 +349,7 @@ static struct tty_driver serial_tty_driver; static struct tty_struct * serial_tty[SERIAL_TTY_MINORS]; static struct termios * serial_termios[SERIAL_TTY_MINORS]; static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; -static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, }; +static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ LIST_HEAD(usb_serial_driver_list); diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index e671ee3e491e..ec039aaa24db 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -2,7 +2,7 @@ * Universal Host Controller Interface driver for USB. * * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@sventech.com + * (C) Copyright 1999-2000 Johannes Erdfelt, johannes@erdfelt.com * (C) Copyright 1999 Randy Dunlap * (C) Copyright 1999 Georg Acher, acher@in.tum.de * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de @@ -2357,6 +2357,8 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) { uhci->irq = irq; + pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); + if (!uhci_start_root_hub(uhci)) return 0; } @@ -2370,13 +2372,12 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign return retval; } -static int __devinit -uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int i; /* disable legacy emulation */ - pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT); + pci_write_config_word(dev, USBLEGSUP, 0); if (pci_enable_device(dev) < 0) return -ENODEV; @@ -2405,8 +2406,7 @@ uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } -static void __devexit -uhci_pci_remove (struct pci_dev *dev) +static void __devexit uhci_pci_remove(struct pci_dev *dev) { struct uhci *uhci = dev->driver_data; @@ -2423,14 +2423,12 @@ uhci_pci_remove (struct pci_dev *dev) release_uhci(uhci); } -static void -uhci_pci_suspend (struct pci_dev *dev) +static void uhci_pci_suspend(struct pci_dev *dev) { reset_hc((struct uhci *) dev->driver_data); } -static void -uhci_pci_resume (struct pci_dev *dev) +static void uhci_pci_resume(struct pci_dev *dev) { reset_hc((struct uhci *) dev->driver_data); start_hc((struct uhci *) dev->driver_data); diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index 2cb333118617..85b39cc1be21 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -16,7 +16,7 @@ * (C) Copyright 1999 Randy Dunlap * (C) Copyright 1999 Gregory P. Smith * - * $Id: usb-uhci.c,v 1.249 2000/11/21 12:03:34 acher Exp $ + * $Id: usb-uhci.c,v 1.251 2000/11/30 09:47:54 acher Exp $ */ #include @@ -52,7 +52,7 @@ /* This enables an extra UHCI slab for memory debugging */ #define DEBUG_SLAB -#define VERSTR "$Revision: 1.249 $ time " __TIME__ " " __DATE__ +#define VERSTR "$Revision: 1.251 $ time " __TIME__ " " __DATE__ #include #include "usb-uhci.h" @@ -582,6 +582,7 @@ _static int init_skel (uhci_t *s) fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand) insert_td (s, qh, td, 0); + qh->hw.qh.element &= ~UHCI_PTR_TERM; // remove TERM bit s->td1ms=td; dbg("allocating qh: bulk_chain"); @@ -2916,6 +2917,9 @@ _static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_ return -1; } + /* Enable PIRQ */ + pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT); + s->irq = irq; if(uhci_start_usb (s) < 0) { @@ -2944,14 +2948,14 @@ uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) unsigned int io_addr = dev->resource[i].start; unsigned int io_size = dev->resource[i].end - dev->resource[i].start + 1; - if (!(dev->resource[i].flags & 1)) + if (!(dev->resource[i].flags & IORESOURCE_IO)) continue; /* Is it already in use? */ if (check_region (io_addr, io_size)) break; /* disable legacy emulation */ - pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT); + pci_write_config_word (dev, USBLEGSUP, 0); return alloc_uhci(dev, dev->irq, io_addr, io_size); } diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index 05fcfcbe152d..626bf3cad35f 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -283,7 +283,6 @@ struct fb_info_aty128 { const struct aty128_meminfo *mem; /* onboard mem info */ struct aty128fb_par default_par, current_par; struct display disp; - struct display_switch dispsw; /* for cursor and font */ struct { u8 red, green, blue, pad; } palette[256]; union { #ifdef FBCON_HAS_CFB16 @@ -347,7 +346,7 @@ static void aty128fbcon_blank(int blank, struct fb_info *fb); static void aty128_encode_fix(struct fb_fix_screeninfo *fix, struct aty128fb_par *par, const struct fb_info_aty128 *info); -static void aty128_set_disp(struct display *disp, +static void aty128_set_dispsw(struct display *disp, struct fb_info_aty128 *info, int bpp, int accel); static int aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); @@ -1392,7 +1391,7 @@ aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb) display->inverse = 0; accel = var->accel_flags & FB_ACCELF_TEXT; - aty128_set_disp(display, info, par.crtc.bpp, accel); + aty128_set_dispsw(display, info, par.crtc.bpp, accel); if (accel) display->scrollmode = SCROLL_YNOMOVE; @@ -1417,35 +1416,31 @@ aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb) static void -aty128_set_disp(struct display *disp, +aty128_set_dispsw(struct display *disp, struct fb_info_aty128 *info, int bpp, int accel) { switch (bpp) { #ifdef FBCON_HAS_CFB8 case 8: - info->dispsw = accel ? fbcon_aty128_8 : fbcon_cfb8; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 case 15: case 16: - info->dispsw = accel ? fbcon_aty128_16 : fbcon_cfb16; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->dispsw = accel ? fbcon_aty128_24 : fbcon_cfb24; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24; disp->dispsw_data = info->fbcon_cmap.cfb24; break; #endif #ifdef FBCON_HAS_CFB32 case 32: - info->dispsw = accel ? fbcon_aty128_32 : fbcon_cfb32; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32; disp->dispsw_data = info->fbcon_cmap.cfb32; break; #endif @@ -2135,7 +2130,7 @@ aty128fbcon_switch(int con, struct fb_info *fb) aty128_decode_var(&fb_display[con].var, &par, info); aty128_set_par(&par, info); - aty128_set_disp(&fb_display[con], info, par.crtc.bpp, + aty128_set_dispsw(&fb_display[con], info, par.crtc.bpp, par.accel_flags & FB_ACCELF_TEXT); do_install_cmap(con, fb); diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 48b3b4ca28ff..fb3b09bc95c9 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -466,8 +466,8 @@ static void set_off_pitch(struct atyfb_par *par, static int encode_fix(struct fb_fix_screeninfo *fix, const struct atyfb_par *par, const struct fb_info_aty *info); -static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info, - int bpp, int accel); +static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, + int bpp, int accel); static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -2826,8 +2826,8 @@ static int atyfb_get_var(struct fb_var_screeninfo *var, int con, } -static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info, - int bpp, int accel) +static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, + int bpp, int accel) { switch (bpp) { #ifdef FBCON_HAS_CFB8 @@ -2898,6 +2898,7 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, oldbpp = display->var.bits_per_pixel; oldaccel = display->var.accel_flags; display->var = *var; + accel = var->accel_flags & FB_ACCELF_TEXT; if (oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { @@ -2913,8 +2914,6 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, display->line_length = fix.line_length; display->can_soft_blank = 1; display->inverse = 0; - accel = var->accel_flags & FB_ACCELF_TEXT; - atyfb_set_disp(display, info, par.crtc.bpp, accel); if (accel) display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; else @@ -2923,8 +2922,10 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, (*info->fb_info.changevar)(con); } if (!info->fb_info.display_fg || - info->fb_info.display_fg->vc_num == con) + info->fb_info.display_fg->vc_num == con) { atyfb_set_par(&par, info); + atyfb_set_dispsw(display, info, par.crtc.bpp, accel); + } if (oldbpp != var->bits_per_pixel) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; @@ -4241,8 +4242,8 @@ static int atyfbcon_switch(int con, struct fb_info *fb) atyfb_decode_var(&fb_display[con].var, &par, info); atyfb_set_par(&par, info); - atyfb_set_disp(&fb_display[con], info, par.crtc.bpp, - par.accel_flags & FB_ACCELF_TEXT); + atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp, + par.accel_flags & FB_ACCELF_TEXT); /* Install new colormap */ do_install_cmap(con, fb); diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 558b6f44e0e5..20ab5c4e59e8 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -65,7 +65,6 @@ struct fb_par_platinum { struct fb_info_platinum { struct fb_info fb_info; struct display disp; - struct display_switch dispsw; struct fb_par_platinum default_par; struct fb_par_platinum current_par; @@ -140,8 +139,9 @@ static int platinum_var_to_par(const struct fb_var_screeninfo *var, static int platinum_encode_fix(struct fb_fix_screeninfo *fix, const struct fb_par_platinum *par, const struct fb_info_platinum *info); -static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info, - int cmode, int accel); +static void platinum_set_dispsw(struct display *disp, + struct fb_info_platinum *info, int cmode, + int accel); static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -193,27 +193,25 @@ static int platinum_get_var(struct fb_var_screeninfo *var, int con, return 0; } -static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info, - int cmode, int accel) +static void platinum_set_dispsw(struct display *disp, + struct fb_info_platinum *info, int cmode, + int accel) { switch(cmode) { #ifdef FBCON_HAS_CFB8 case CMODE_8: - info->dispsw = fbcon_cfb8; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 case CMODE_16: - info->dispsw = fbcon_cfb16; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; break; #endif #ifdef FBCON_HAS_CFB32 case CMODE_32: - info->dispsw = fbcon_cfb32; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_cfb32; disp->dispsw_data = info->fbcon_cmap.cfb32; break; #endif @@ -271,7 +269,7 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con, display->line_length = fix.line_length; display->can_soft_blank = 1; display->inverse = 0; - platinum_set_disp(display, info, par.cmode, 0); + platinum_set_dispsw(display, info, par.cmode, 0); display->scrollmode = SCROLL_YREDRAW; if (info->fb_info.changevar) (*info->fb_info.changevar)(con); @@ -341,7 +339,7 @@ static int platinum_switch(int con, struct fb_info *fb) platinum_var_to_par(&fb_display[con].var, &par, info); platinum_set_par(&par, info); - platinum_set_disp(&fb_display[con], info, par.cmode, 0); + platinum_set_dispsw(&fb_display[con], info, par.cmode, 0); do_install_cmap(con, fb); return 1; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 4128c313ec9c..d954dc02e85c 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -327,7 +327,6 @@ struct fb_info_tdfx { struct tdfxfb_par default_par; struct tdfxfb_par current_par; struct display disp; - struct display_switch dispsw; #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) union { #ifdef FBCON_HAS_CFB16 @@ -412,10 +411,10 @@ static int tdfxfb_encode_var(struct fb_var_screeninfo* var, static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix, const struct tdfxfb_par* par, const struct fb_info_tdfx* info); -static void tdfxfb_set_disp(struct display* disp, - struct fb_info_tdfx* info, - int bpp, - int accel); +static void tdfxfb_set_dispsw(struct display* disp, + struct fb_info_tdfx* info, + int bpp, + int accel); static int tdfxfb_getcolreg(u_int regno, u_int* red, u_int* green, @@ -1640,48 +1639,43 @@ static int tdfxfb_get_var(struct fb_var_screeninfo *var, return 0; } -static void tdfxfb_set_disp(struct display *disp, - struct fb_info_tdfx *info, - int bpp, - int accel) { +static void tdfxfb_set_dispsw(struct display *disp, + struct fb_info_tdfx *info, + int bpp, + int accel) { if (disp->dispsw && disp->conp) fb_con.con_cursor(disp->conp, CM_ERASE); switch(bpp) { #ifdef FBCON_HAS_CFB8 case 8: - info->dispsw = noaccel ? fbcon_cfb8 : fbcon_banshee8; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8; if (nohwcursor) fbcon_banshee8.cursor = NULL; break; #endif #ifdef FBCON_HAS_CFB16 case 16: - info->dispsw = noaccel ? fbcon_cfb16 : fbcon_banshee16; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16; disp->dispsw_data = info->fbcon_cmap.cfb16; if (nohwcursor) fbcon_banshee16.cursor = NULL; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->dispsw = noaccel ? fbcon_cfb24 : fbcon_banshee24; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24; disp->dispsw_data = info->fbcon_cmap.cfb24; if (nohwcursor) fbcon_banshee24.cursor = NULL; break; #endif #ifdef FBCON_HAS_CFB32 case 32: - info->dispsw = noaccel ? fbcon_cfb32 : fbcon_banshee32; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32; disp->dispsw_data = info->fbcon_cmap.cfb32; if (nohwcursor) fbcon_banshee32.cursor = NULL; break; #endif default: - info->dispsw = fbcon_dummy; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_dummy; } } @@ -1735,7 +1729,7 @@ static int tdfxfb_set_var(struct fb_var_screeninfo *var, display->can_soft_blank = 1; display->inverse = inverse; accel = var->accel_flags & FB_ACCELF_TEXT; - tdfxfb_set_disp(display, info, par.bpp, accel); + tdfxfb_set_dispsw(display, info, par.bpp, accel); if(nopan) display->scrollmode = SCROLL_YREDRAW; @@ -2083,10 +2077,10 @@ static int tdfxfb_switch_con(int con, info->cursor.redraw=1; - tdfxfb_set_disp(&fb_display[con], - info, - par.bpp, - par.accel_flags & FB_ACCELF_TEXT); + tdfxfb_set_dispsw(&fb_display[con], + info, + par.bpp, + par.accel_flags & FB_ACCELF_TEXT); tdfxfb_install_cmap(&fb_display[con], fb); tdfxfb_updatevar(con, fb); diff --git a/fs/buffer.c b/fs/buffer.c index fff4bb9a2904..d8328e1b8b23 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -871,10 +871,11 @@ int fsync_inode_buffers(struct inode *inode) else { bh->b_inode = &tmp; list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers); - atomic_inc(&bh->b_count); if (buffer_dirty(bh)) { + atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); ll_rw_block(WRITE, 1, &bh); + brelse(bh); spin_lock(&lru_list_lock); } } @@ -883,6 +884,7 @@ int fsync_inode_buffers(struct inode *inode) while (!list_empty(&tmp.i_dirty_buffers)) { bh = BH_ENTRY(tmp.i_dirty_buffers.prev); remove_inode_queue(bh); + atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); wait_on_buffer(bh); if (!buffer_uptodate(bh)) @@ -929,9 +931,9 @@ int osync_inode_buffers(struct inode *inode) atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); wait_on_buffer(bh); - brelse(bh); if (!buffer_uptodate(bh)) err = -EIO; + brelse(bh); spin_lock(&lru_list_lock); goto repeat; } @@ -947,7 +949,6 @@ int osync_inode_buffers(struct inode *inode) * probably unmounting the fs, but that doesn't mean we have already * done a sync(). Just drop the buffers from the inode list. */ - void invalidate_inode_buffers(struct inode *inode) { struct list_head *list, *next; diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index cf8fa51543b0..9e4a9b6b0211 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -256,7 +256,7 @@ error_return: * For other inodes, search forward from the parent directory\'s block * group to find a free inode. */ -struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err) +struct inode * ext2_new_inode (const struct inode * dir, int mode) { struct super_block * sb; struct buffer_head * bh; @@ -267,26 +267,22 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err) struct ext2_group_desc * gdp; struct ext2_group_desc * tmp; struct ext2_super_block * es; + int err; /* Cannot create files in a deleted directory */ - if (!dir || !dir->i_nlink) { - *err = -EPERM; - return NULL; - } + if (!dir || !dir->i_nlink) + return ERR_PTR(-EPERM); sb = dir->i_sb; inode = new_inode(sb); - if (!inode) { - *err = -ENOMEM; - return NULL; - } + if (!inode) + return ERR_PTR(-ENOMEM); lock_super (sb); es = sb->u.ext2_sb.s_es; repeat: gdp = NULL; i=0; - *err = -ENOSPC; if (S_ISDIR(mode)) { avefreei = le32_to_cpu(es->s_free_inodes_count) / sb->u.ext2_sb.s_groups_count; @@ -365,18 +361,14 @@ repeat: } } - if (!gdp) { - unlock_super (sb); - iput(inode); - return NULL; - } + err = -ENOSPC; + if (!gdp) + goto fail; + + err = -EIO; bitmap_nr = load_inode_bitmap (sb, i); - if (bitmap_nr < 0) { - unlock_super (sb); - iput(inode); - *err = -EIO; - return NULL; - } + if (bitmap_nr < 0) + goto fail; bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data, @@ -397,11 +389,11 @@ repeat: ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", i); - if (sb->s_flags & MS_RDONLY) { - unlock_super (sb); - iput (inode); - return NULL; - } + /* Is it really ENOSPC? */ + err = -ENOSPC; + if (sb->s_flags & MS_RDONLY) + goto fail; + gdp->bg_free_inodes_count = 0; mark_buffer_dirty(bh2); } @@ -412,10 +404,8 @@ repeat: ext2_error (sb, "ext2_new_inode", "reserved inode or inode > inodes count - " "block_group = %d,inode=%d", i, j); - unlock_super (sb); - iput (inode); - *err = -EIO; - return NULL; + err = -EIO; + goto fail; } gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); @@ -464,13 +454,15 @@ repeat: sb->dq_op->drop(inode); inode->i_nlink = 0; iput(inode); - *err = -EDQUOT; - return NULL; + return ERR_PTR(-EDQUOT); } ext2_debug ("allocating inode %lu\n", inode->i_ino); - - *err = 0; return inode; + +fail: + unlock_super(sb); + iput(inode); + return ERR_PTR(err); } unsigned long ext2_count_free_inodes (struct super_block * sb) diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 1eaaac407273..59d3ef492a2f 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -361,11 +361,9 @@ static int ext2_delete_entry (struct inode * dir, */ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode) { - struct inode * inode; - int err; - - inode = ext2_new_inode (dir, mode, &err); - if (!inode) + struct inode * inode = ext2_new_inode (dir, mode); + int err = PTR_ERR(inode); + if (IS_ERR(inode)) return err; inode->i_op = &ext2_file_inode_operations; @@ -387,11 +385,10 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode) static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) { - struct inode * inode; - int err; + struct inode * inode = ext2_new_inode (dir, mode); + int err = PTR_ERR(inode); - inode = ext2_new_inode (dir, mode, &err); - if (!inode) + if (IS_ERR(inode)) return err; inode->i_uid = current->fsuid; @@ -421,8 +418,9 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) if (dir->i_nlink >= EXT2_LINK_MAX) return -EMLINK; - inode = ext2_new_inode (dir, S_IFDIR, &err); - if (!inode) + inode = ext2_new_inode (dir, S_IFDIR); + err = PTR_ERR(inode); + if (IS_ERR(inode)) return err; inode->i_op = &ext2_dir_inode_operations; @@ -628,7 +626,9 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * if (l > dir->i_sb->s_blocksize) return -ENAMETOOLONG; - if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) + inode = ext2_new_inode (dir, S_IFLNK); + err = PTR_ERR(inode); + if (IS_ERR(inode)) return err; inode->i_mode = S_IFLNK | S_IRWXUGO; diff --git a/fs/inode.c b/fs/inode.c index 24016206dfec..abbc04f1c58e 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -77,7 +77,13 @@ static kmem_cache_t * inode_cachep; #define alloc_inode() \ ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL)) -#define destroy_inode(inode) kmem_cache_free(inode_cachep, (inode)) +static void destroy_inode(struct inode *inode) +{ + if (!list_empty(&inode->i_dirty_buffers)) + BUG(); + kmem_cache_free(inode_cachep, (inode)); +} + /* * These are initializations that only need to be done @@ -348,6 +354,9 @@ int generic_osync_inode(struct inode *inode, int datasync) void clear_inode(struct inode *inode) { + if (!list_empty(&inode->i_dirty_buffers)) + invalidate_inode_buffers(inode); + if (inode->i_data.nrpages) BUG(); if (!(inode->i_state & I_FREEING)) @@ -407,6 +416,7 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru inode = list_entry(tmp, struct inode, i_list); if (inode->i_sb != sb) continue; + invalidate_inode_buffers(inode); if (!atomic_read(&inode->i_count)) { list_del(&inode->i_hash); INIT_LIST_HEAD(&inode->i_hash); diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 6423b0eb7a10..6f0957dce489 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -163,7 +163,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, return 0; memcpy((void *) tmpde + slop, bh->b_data, offset); } - de = tmpde; + de = tmpde; } if (de->flags[-high_sierra] & 0x80) { diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index d75edccf67f8..5d50c37a687e 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -754,8 +754,9 @@ root_found: s->u.isofs_sb.s_gid = opt.gid; s->u.isofs_sb.s_utf8 = opt.utf8; /* - * It would be incredibly stupid to allow people to mark every file on the disk - * as suid, so we merely allow them to set the default permissions. + * It would be incredibly stupid to allow people to mark every file + * on the disk as suid, so we merely allow them to set the default + * permissions. */ s->u.isofs_sb.s_mode = opt.mode & 0777; @@ -1017,10 +1018,7 @@ static int isofs_read_level3_size(struct inode * inode) unsigned long block, offset; int i = 0; int more_entries = 0; - struct iso_directory_record * tmpde = kmalloc(256, GFP_KERNEL); - - if (!tmpde) - return -ENOMEM; + struct iso_directory_record * tmpde = NULL; inode->i_size = 0; inode->u.isofs_i.i_next_section_ino = 0; @@ -1054,6 +1052,11 @@ static int isofs_read_level3_size(struct inode * inode) /* Make sure we have a full directory entry */ if (offset >= bufsize) { int slop = bufsize - offset + de_len; + if (!tmpde) { + tmpde = kmalloc(256, GFP_KERNEL); + if (!tmpde) + goto out_nomem; + } memcpy(tmpde, de, slop); offset &= bufsize - 1; block++; @@ -1080,14 +1083,23 @@ static int isofs_read_level3_size(struct inode * inode) goto out_toomany; } while(more_entries); out: - kfree(tmpde); - if (bh) brelse(bh); + if (tmpde) + kfree(tmpde); + if (bh) + brelse(bh); return 0; +out_nomem: + if (bh) + brelse(bh); + return -ENOMEM; + out_noread: printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block); - kfree(tmpde); - return 1; + if (tmpde) + kfree(tmpde); + return -EIO; + out_toomany: printk(KERN_INFO "isofs_read_level3_size: " "More than 100 file sections ?!?, aborting...\n" @@ -1102,22 +1114,39 @@ static void isofs_read_inode(struct inode * inode) unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); int high_sierra = sb->u.isofs_sb.s_high_sierra; - struct buffer_head * bh; - struct iso_directory_record * raw_inode; - unsigned char *pnt; + struct buffer_head * bh = NULL; + struct iso_directory_record * de; + struct iso_directory_record * tmpde = NULL; + unsigned int de_len; + unsigned long offset; int volume_seq_no, i; bh = bread(inode->i_dev, block, bufsize); - if (!bh) { - printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); - goto fail; - } + if (!bh) + goto out_badread; + + offset = (inode->i_ino & (bufsize - 1)); + de = (struct iso_directory_record *) (bh->b_data + offset); + de_len = *(unsigned char *) de; - pnt = ((unsigned char *) bh->b_data - + (inode->i_ino & (bufsize - 1))); - raw_inode = ((struct iso_directory_record *) pnt); + if (offset + de_len > bufsize) { + int frag1 = bufsize - offset; - if (raw_inode->flags[-high_sierra] & 2) { + tmpde = kmalloc(de_len, GFP_KERNEL); + if (tmpde == NULL) { + printk(KERN_INFO "isofs_read_inode: out of memory\n"); + goto fail; + } + memcpy(tmpde, bh->b_data + offset, frag1); + brelse(bh); + bh = bread(inode->i_dev, ++block, bufsize); + if (!bh) + goto out_badread; + memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1); + de = tmpde; + } + + if (de->flags[-high_sierra] & 2) { inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; inode->i_nlink = 1; /* Set to 1. We know there are 2, but the find utility tries to optimize @@ -1132,10 +1161,10 @@ static void isofs_read_inode(struct inode * inode) /* If there are no periods in the name, * then set the execute permission bit */ - for(i=0; i< raw_inode->name_len[0]; i++) - if(raw_inode->name[i]=='.' || raw_inode->name[i]==';') + for(i=0; i< de->name_len[0]; i++) + if(de->name[i]=='.' || de->name[i]==';') break; - if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';') + if(i == de->name_len[0] || de->name[i] == ';') inode->i_mode |= S_IXUGO; /* execute permission */ } inode->i_uid = inode->i_sb->u.isofs_sb.s_uid; @@ -1143,84 +1172,77 @@ static void isofs_read_inode(struct inode * inode) inode->i_blocks = inode->i_blksize = 0; - inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size); - if(raw_inode->flags[-high_sierra] & 0x80) { + inode->u.isofs_i.i_section_size = isonum_733 (de->size); + if(de->flags[-high_sierra] & 0x80) { if(isofs_read_level3_size(inode)) goto fail; } else { - inode->i_size = isonum_733 (raw_inode->size); + inode->i_size = isonum_733 (de->size); } /* There are defective discs out there - we do this to protect ourselves. A cdrom will never contain more than 800Mb .. but a DVD may be up to 1Gig (Ulrich Habel) */ - if((inode->i_size < 0 || inode->i_size > 1073741824) && + + if ((inode->i_size < 0 || inode->i_size > 1073741824) && inode->i_sb->u.isofs_sb.s_cruft == 'n') { - printk(KERN_WARNING "Warning: defective CD-ROM. Enabling \"cruft\" mount option.\n"); - inode->i_sb->u.isofs_sb.s_cruft = 'y'; + printk(KERN_WARNING "Warning: defective CD-ROM. " + "Enabling \"cruft\" mount option.\n"); + inode->i_sb->u.isofs_sb.s_cruft = 'y'; } -/* Some dipshit decided to store some other bit of information in the high - byte of the file length. Catch this and holler. WARNING: this will make - it impossible for a file to be > 16Mb on the CDROM!!!*/ + /* + * Some dipshit decided to store some other bit of information + * in the high byte of the file length. Catch this and holler. + * WARNING: this will make it impossible for a file to be > 16MB + * on the CDROM. + */ - if(inode->i_sb->u.isofs_sb.s_cruft == 'y' && - inode->i_size & 0xff000000){ -/* printk("Illegal format on cdrom. Pester manufacturer.\n"); */ - inode->i_size &= 0x00ffffff; + if (inode->i_sb->u.isofs_sb.s_cruft == 'y' && + inode->i_size & 0xff000000) { + inode->i_size &= 0x00ffffff; } - if (raw_inode->interleave[0]) { + if (de->interleave[0]) { printk("Interleaved files not (yet) supported.\n"); inode->i_size = 0; } /* I have no idea what file_unit_size is used for, so we will flag it for now */ - if(raw_inode->file_unit_size[0] != 0){ - printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino); + if (de->file_unit_size[0] != 0) { + printk("File unit size != 0 for ISO file (%ld).\n", + inode->i_ino); } /* I have no idea what other flag bits are used for, so we will flag it for now */ #ifdef DEBUG - if((raw_inode->flags[-high_sierra] & ~2)!= 0){ + if((de->flags[-high_sierra] & ~2)!= 0){ printk("Unusual flag settings for ISO file (%ld %x).\n", - inode->i_ino, raw_inode->flags[-high_sierra]); + inode->i_ino, de->flags[-high_sierra]); } #endif -#ifdef DEBUG - printk("Get inode %x: %d %d: %d\n",inode->i_ino, block, - ((int)pnt) & 0x3ff, inode->i_size); -#endif - inode->i_mtime = inode->i_atime = inode->i_ctime = - iso_date(raw_inode->date, high_sierra); + iso_date(de->date, high_sierra); - inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) + - isonum_711 (raw_inode->ext_attr_length)); + inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) + + isonum_711 (de->ext_attr_length)); -/* Now test for possible Rock Ridge extensions which will override some of - these numbers in the inode structure. */ + /* + * Now test for possible Rock Ridge extensions which will override + * some of these numbers in the inode structure. + */ if (!high_sierra) { - parse_rock_ridge_inode(raw_inode, inode); - /* hmm..if we want uid or gid set, override the rock ridge setting */ - test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid); - test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid); + parse_rock_ridge_inode(de, inode); + /* if we want uid/gid set, override the rock ridge setting */ + test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid); + test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid); } -#ifdef DEBUG - printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent); -#endif - /* get the volume sequence number */ - volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ; - - /* - * All done with buffer ... no more references to buffer memory! - */ - brelse(bh); + volume_seq_no = isonum_723 (de->volume_sequence_number) ; /* * Disable checking if we see any volume number other than 0 or 1. @@ -1230,8 +1252,10 @@ static void isofs_read_inode(struct inode * inode) */ if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && (volume_seq_no != 0) && (volume_seq_no != 1)) { - printk(KERN_WARNING "Warning: defective CD-ROM (volume sequence number). Enabling \"cruft\" mount option.\n"); - inode->i_sb->u.isofs_sb.s_cruft = 'y'; + printk(KERN_WARNING "Warning: defective CD-ROM " + "(volume sequence number %d). " + "Enabling \"cruft\" mount option.\n", volume_seq_no); + inode->i_sb->u.isofs_sb.s_cruft = 'y'; } /* Install the inode operations vector */ @@ -1242,25 +1266,32 @@ static void isofs_read_inode(struct inode * inode) } else #endif IGNORE_WRONG_MULTI_VOLUME_SPECS { - if (S_ISREG(inode->i_mode)) { - inode->i_fop = &generic_ro_fops; - inode->i_data.a_ops = &isofs_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &isofs_dir_inode_operations; - inode->i_fop = &isofs_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; - inode->i_data.a_ops = &isofs_symlink_aops; - } else - /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ - init_special_inode(inode, inode->i_mode, kdev_t_to_nr(inode->i_rdev)); + if (S_ISREG(inode->i_mode)) { + inode->i_fop = &generic_ro_fops; + inode->i_data.a_ops = &isofs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &isofs_dir_inode_operations; + inode->i_fop = &isofs_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &page_symlink_inode_operations; + inode->i_data.a_ops = &isofs_symlink_aops; + } else + /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); } + out: + if (tmpde) + kfree(tmpde); + if (bh) + brelse(bh); return; - fail: - /* With a data error we return this information */ + out_badread: + printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); + fail: make_bad_inode(inode); - return; + goto out; } #ifdef LEAK_CHECK diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 24872970aed2..3f44d90335fa 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -161,13 +161,14 @@ struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry) struct inode *inode; struct page *page; -#ifdef DEBUG - printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name); -#endif dentry->d_op = dir->i_sb->s_root->d_op; page = alloc_page(GFP_USER); - ino = isofs_find_entry(dir, dentry, page_address(page), 1024 + page_address(page)); + if (!page) + return ERR_PTR(-ENOMEM); + + ino = isofs_find_entry(dir, dentry, page_address(page), + 1024 + page_address(page)); __free_page(page); inode = NULL; diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index a2511444d669..4ac4bc0ced43 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -72,7 +72,7 @@ cont_size = 0; \ cont_offset = 0; \ goto LABEL; \ - }; \ + } \ printk("Unable to read rock-ridge attributes\n"); \ }} @@ -120,22 +120,16 @@ int find_rock_ridge_relocation(struct iso_directory_record * de, CHECK_SP(goto out); break; case SIG('C','L'): -#ifdef DEBUG - printk("RR: CL\n"); -#endif if (flag == 0) { retval = isonum_733(rr->u.CL.location); goto out; - }; + } break; case SIG('P','L'): -#ifdef DEBUG - printk("RR: PL\n"); -#endif if (flag != 0) { retval = isonum_733(rr->u.PL.location); goto out; - }; + } break; case SIG('C','E'): CHECK_CE; /* This tells is if there is a continuation record */ @@ -143,8 +137,8 @@ int find_rock_ridge_relocation(struct iso_directory_record * de, default: break; } - }; - }; + } + } MAYBE_CONTINUE(repeat, inode); return retval; out: @@ -203,24 +197,21 @@ int get_rock_ridge_filename(struct iso_directory_record * de, if (rr->u.NM.flags & ~1) { printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags); break; - }; + } if((strlen(retname) + rr->len - 5) >= 254) { truncate = 1; break; - }; + } strncat(retname, rr->u.NM.name, rr->len - 5); retnamlen += rr->len - 5; break; case SIG('R','E'): -#ifdef DEBUG - printk("RR: RE (%x)\n", inode->i_ino); -#endif if (buffer) kfree(buffer); return -1; default: break; } - }; + } } MAYBE_CONTINUE(repeat,inode); return retnamlen; /* If 0, this file did not have a NM field */ @@ -266,10 +257,10 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, break; case SIG('E','R'): inode->i_sb->u.isofs_sb.s_rock = 1; - printk(KERN_DEBUG"ISO 9660 Extensions: "); + printk(KERN_DEBUG "ISO 9660 Extensions: "); { int p; for(p=0;pu.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); - }; + } printk("\n"); break; case SIG('P','X'): @@ -294,7 +285,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, } else { inode->i_rdev = MKDEV(high, low); } - }; + } break; case SIG('T','F'): /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. @@ -334,7 +325,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, break; default: printk("Symlink component flag not implemented\n"); - }; + } slen -= slp->len + 2; oldslp = slp; slp = (struct SL_component *) (((char *) slp) + slp->len + 2); @@ -348,19 +339,16 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, /* * If this component record isn't continued, then append a '/'. */ - if( (!rootflag) - && ((oldslp->flags & 1) == 0) ) inode->i_size += 1; + if (!rootflag && (oldslp->flags & 1) == 0) + inode->i_size += 1; } } symlink_len = inode->i_size; break; case SIG('R','E'): - printk("Attempt to read inode for relocated directory\n"); + printk(KERN_WARNING "Attempt to read inode for relocated directory\n"); goto out; case SIG('C','L'): -#ifdef DEBUG - printk("RR CL (%x)\n",inode->i_ino); -#endif inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location); reloc = iget(inode->i_sb, (inode->u.isofs_i.i_first_extent << @@ -381,7 +369,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, default: break; } - }; + } } MAYBE_CONTINUE(repeat,inode); return 0; diff --git a/fs/isofs/util.c b/fs/isofs/util.c index 12cd2d30493d..b966c512bc49 100644 --- a/fs/isofs/util.c +++ b/fs/isofs/util.c @@ -98,7 +98,7 @@ isonum_733 (char * p) int iso_date(char * p, int flag) { - int year, month, day, hour ,minute, second, tz; + int year, month, day, hour, minute, second, tz; int crtime, days, i; year = p[0] - 70; diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 211b01530295..592851be615d 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -50,7 +50,7 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) nlmclnt_next_cookie(&argp->cookie); argp->state = nsm_local_state; - memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry), sizeof(struct nfs_fh)); + memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); lock->caller = system_utsname.nodename; lock->oh.data = req->a_owner; lock->oh.len = sprintf(req->a_owner, "%d@%s", diff --git a/fs/locks.c b/fs/locks.c index 7a6d868e253c..e65b593946c6 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1623,7 +1623,7 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) if (error < 0) goto out_putf; } - error = posix_lock_file(filp, file_lock, cmd == F_SETLKW); + error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64); out_putf: fput(filp); diff --git a/fs/namei.c b/fs/namei.c index c0d1abc36e57..37644f4a1015 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -152,18 +152,10 @@ char * getname(const char * filename) * for filesystem access without changing the "normal" uids which * are used for other things.. */ -int permission(struct inode * inode,int mask) +int vfs_permission(struct inode * inode,int mask) { int mode = inode->i_mode; - if (inode->i_op && inode->i_op->permission) { - int retval; - lock_kernel(); - retval = inode->i_op->permission(inode, mask); - unlock_kernel(); - return retval; - } - if ((mask & S_IWOTH) && IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; /* Nobody gets write access to a read-only fs */ @@ -188,6 +180,18 @@ int permission(struct inode * inode,int mask) return -EACCES; } +int permission(struct inode * inode,int mask) +{ + if (inode->i_op && inode->i_op->permission) { + int retval; + lock_kernel(); + retval = inode->i_op->permission(inode, mask); + unlock_kernel(); + return retval; + } + return vfs_permission(inode, mask); +} + /* * get_write_access() gets write permission for a file. * put_write_access() releases this write permission. diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c66d870d9f22..4821de8d346a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -63,6 +63,7 @@ struct inode_operations nfs_dir_inode_operations = { rmdir: nfs_rmdir, mknod: nfs_mknod, rename: nfs_rename, + permission: nfs_permission, revalidate: nfs_revalidate, setattr: nfs_notify_change, }; @@ -97,6 +98,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) { struct file *file = desc->file; struct inode *inode = file->f_dentry->d_inode; + struct rpc_cred *cred = nfs_file_cred(file); void *buffer = kmap(page); int plus = NFS_USE_READDIRPLUS(inode); int error; @@ -104,7 +106,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); again: - error = NFS_PROTO(inode)->readdir(file, desc->entry->cookie, buffer, + error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer, NFS_SERVER(inode)->dtsize, plus); /* We requested READDIRPLUS, but the server doesn't grok it */ if (desc->plus && error == -ENOTSUPP) { @@ -308,6 +310,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, { struct file *file = desc->file; struct inode *inode = file->f_dentry->d_inode; + struct rpc_cred *cred = nfs_file_cred(file); struct page *page = NULL; u32 *p; int status = -EIO; @@ -324,7 +327,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, goto out; } p = kmap(page); - status = NFS_PROTO(inode)->readdir(file, desc->target, p, + status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p, NFS_SERVER(inode)->dtsize, 0); if (status >= 0) { p = desc->decode(p, desc->entry, 0); @@ -483,16 +486,15 @@ static inline int nfs_neg_need_reval(struct dentry *dentry) */ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) { - struct dentry *dir = dentry->d_parent; - struct inode *dir_i = dir->d_inode; - struct inode * inode = dentry->d_inode; + struct inode *dir; + struct inode *inode; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; lock_kernel(); - dir = dentry->d_parent; - dir_i = dir->d_inode; + dir = dentry->d_parent->d_inode; + inode = dentry->d_inode; /* * If we don't have an inode, let's look at the parent * directory mtime to get a hint about how often we @@ -506,7 +508,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) if (is_bad_inode(inode)) { dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", - dir->d_name.name, dentry->d_name.name); + dentry->d_parent->d_name.name, dentry->d_name.name); goto out_bad; } @@ -514,15 +516,14 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) goto out_valid; if (IS_ROOT(dentry)) { - __nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); + __nfs_revalidate_inode(NFS_SERVER(inode), inode); goto out_valid_renew; } /* * Do a new lookup and check the dentry attributes. */ - error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle, - &fattr); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error) goto out_bad; @@ -533,10 +534,10 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) goto out_bad; /* Filehandle matches? */ - if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) + if (memcmp(NFS_FH(inode), fhandle.data, sizeof(struct nfs_fh))) goto out_bad; - /* Ok, remeber that we successfully checked it.. */ + /* Ok, remember that we successfully checked it.. */ nfs_refresh_inode(inode, &fattr); out_valid_renew: @@ -551,7 +552,7 @@ out_bad: goto out_valid; d_drop(dentry); /* Purge readdir caches. */ - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); if (inode && S_ISDIR(inode->i_mode)) nfs_zap_caches(inode); unlock_kernel(); @@ -575,30 +576,6 @@ static int nfs_dentry_delete(struct dentry *dentry) } -static kmem_cache_t *nfs_fh_cachep; - -__inline__ struct nfs_fh *nfs_fh_alloc(void) -{ - return kmem_cache_alloc(nfs_fh_cachep, SLAB_KERNEL); -} - -__inline__ void nfs_fh_free(struct nfs_fh *p) -{ - kmem_cache_free(nfs_fh_cachep, p); -} - -/* - * Called when the dentry is being freed to release private memory. - */ -static void nfs_dentry_release(struct dentry *dentry) -{ - if (dentry->d_fsdata) { - lock_kernel(); - nfs_fh_free(dentry->d_fsdata); - unlock_kernel(); - } -} - /* * Called when the dentry loses inode. * We use it to clean up silly-renamed files. @@ -616,35 +593,27 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) struct dentry_operations nfs_dentry_operations = { d_revalidate: nfs_lookup_revalidate, d_delete: nfs_dentry_delete, - d_release: nfs_dentry_release, d_iput: nfs_dentry_iput, }; -static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry) +static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry) { - struct dentry *dir = dentry->d_parent; struct inode *inode; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; dfprintk(VFS, "NFS: lookup(%s/%s)\n", - dir->d_name.name, dentry->d_name.name); + dentry->d_parent->d_name.name, dentry->d_name.name); error = -ENAMETOOLONG; - if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen) + if (dentry->d_name.len > NFS_SERVER(dir)->namelen) goto out; error = -ENOMEM; - if (!dentry->d_fsdata) { - dentry->d_fsdata = nfs_fh_alloc(); - if (!dentry->d_fsdata) - goto out; - } dentry->d_op = &nfs_dentry_operations; - error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle, - &fattr); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); inode = NULL; if (error == -ENOENT) goto no_entry; @@ -686,16 +655,15 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */ -static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode) +static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) { - struct dentry *dir = dentry->d_parent; struct iattr attr; struct nfs_fattr fattr; struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: create(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; @@ -706,8 +674,8 @@ static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode) * select the appropriate create strategy. Currently open_namei * does not pass the create flags. */ - nfs_zap_caches(dir_i); - error = NFS_PROTO(dir_i)->create(dir, &dentry->d_name, + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, 0, &fhandle, &fattr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); @@ -719,22 +687,21 @@ static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode) /* * See comments for nfs_proc_create regarding failed operations. */ -static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev) +static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) { - struct dentry *dir = dentry->d_parent; struct iattr attr; struct nfs_fattr fattr; struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - nfs_zap_caches(dir_i); - error = NFS_PROTO(dir_i)->mknod(dir, &dentry->d_name, &attr, rdev, + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev, &fhandle, &fattr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); @@ -746,16 +713,15 @@ static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int r /* * See comments for nfs_proc_create regarding failed operations. */ -static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode) +static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct dentry *dir = dentry->d_parent; struct iattr attr; struct nfs_fattr fattr; struct nfs_fh fhandle; int error; dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); attr.ia_valid = ATTR_MODE; attr.ia_mode = mode | S_IFDIR; @@ -769,8 +735,8 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode) */ d_drop(dentry); #endif - nfs_zap_caches(dir_i); - error = NFS_PROTO(dir_i)->mkdir(dir, &dentry->d_name, &attr, &fhandle, + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, &fattr); if (!error && fhandle.size != 0) error = nfs_instantiate(dentry, &fhandle, &fattr); @@ -779,25 +745,23 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode) return error; } -static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry) +static int nfs_rmdir(struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; int error; dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name); + dir->i_dev, dir->i_ino, dentry->d_name.name); - nfs_zap_caches(dir_i); - error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name); + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); return error; } -static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry) +static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; static unsigned int sillycounter; - const int i_inosize = sizeof(dir_i->i_ino)*2; + const int i_inosize = sizeof(dir->i_ino)*2; const int countersize = sizeof(sillycounter)*2; const int slen = strlen(".nfs") + i_inosize + countersize; char silly[slen+1]; @@ -848,10 +812,10 @@ dentry->d_parent->d_name.name, dentry->d_name.name); goto out; } while(sdentry->d_inode != NULL); /* need negative lookup */ - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); qsilly.name = silly; qsilly.len = strlen(silly); - error = NFS_PROTO(dir_i)->rename(dir, &dentry->d_name, dir, &qsilly); + error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); if (!error) { nfs_renew_times(dentry); d_move(dentry, sdentry); @@ -872,8 +836,7 @@ out: */ static int nfs_safe_remove(struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; - struct inode *dir_i = dir->d_inode; + struct inode *dir = dentry->d_parent->d_inode; struct inode *inode = dentry->d_inode; int error = -EBUSY, rehash = 0; @@ -902,10 +865,10 @@ static int nfs_safe_remove(struct dentry *dentry) goto out_delete; } - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); if (inode) NFS_CACHEINV(inode); - error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); if (error < 0) goto out; @@ -943,9 +906,8 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) } static int -nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname) +nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct dentry *dir = dentry->d_parent; struct iattr attr; struct nfs_fattr sym_attr; struct nfs_fh sym_fh; @@ -954,10 +916,10 @@ nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname) int error; dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n", - dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname); + dir->i_dev, dir->i_ino, dentry->d_name.name, symname); error = -ENAMETOOLONG; - maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN; + maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN; if (strlen(symname) > maxlen) goto out; @@ -976,15 +938,15 @@ dentry->d_parent->d_name.name, dentry->d_name.name); qsymname.name = symname; qsymname.len = strlen(symname); - nfs_zap_caches(dir_i); - error = NFS_PROTO(dir_i)->symlink(dir, &dentry->d_name, &qsymname, + nfs_zap_caches(dir); + error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, &attr, &sym_fh, &sym_attr); if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) { error = nfs_instantiate(dentry, &sym_fh, &sym_attr); } else { if (error == -EEXIST) printk("nfs_proc_symlink: %s/%s already exists??\n", - dir->d_name.name, dentry->d_name.name); + dentry->d_parent->d_name.name, dentry->d_name.name); d_drop(dentry); } @@ -993,9 +955,8 @@ out: } static int -nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) +nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct dentry *dir = dentry->d_parent; struct inode *inode = old_dentry->d_inode; int error; @@ -1009,9 +970,9 @@ nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) * we can't use the existing dentry. */ d_drop(dentry); - nfs_zap_caches(dir_i); + nfs_zap_caches(dir); NFS_CACHEINV(inode); - error = NFS_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name); + error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); return error; } @@ -1116,10 +1077,8 @@ go_ahead: nfs_zap_caches(new_dir); nfs_zap_caches(old_dir); - error = NFS_PROTO(old_dir)->rename(old_dentry->d_parent, - &old_dentry->d_name, - new_dentry->d_parent, - &new_dentry->d_name); + error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, + new_dir, &new_dentry->d_name); out: if (rehash) d_rehash(rehash); @@ -1132,22 +1091,33 @@ out: return error; } -int nfs_init_fhcache(void) +int +nfs_permission(struct inode *inode, int mask) { - nfs_fh_cachep = kmem_cache_create("nfs_fh", - sizeof(struct nfs_fh), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (nfs_fh_cachep == NULL) - return -ENOMEM; + int error = vfs_permission(inode, mask); - return 0; -} + if (!NFS_PROTO(inode)->access) + goto out; + /* + * Trust UNIX mode bits except: + * + * 1) When override capabilities may have been invoked + * 2) When root squashing may be involved + * 3) When ACLs may overturn a negative answer */ + if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH) + && (current->fsuid != 0) && (current->fsgid != 0) + && error != -EACCES) + goto out; -void nfs_destroy_fhcache(void) -{ - if (kmem_cache_destroy(nfs_fh_cachep)) - printk(KERN_INFO "nfs_fh: not all structures were freed\n"); + error = NFS_PROTO(inode)->access(inode, mask, 0); + + if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv && + current->uid != 0 && current->gid != 0 && + (current->fsuid != current->uid || current->fsgid != current->gid)) + error = NFS_PROTO(inode)->access(inode, mask, 1); + + out: + return error; } /* diff --git a/fs/nfs/file.c b/fs/nfs/file.c index c30fc5062f20..d5c92ba3be85 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -52,6 +52,7 @@ struct file_operations nfs_file_operations = { }; struct inode_operations nfs_file_inode_operations = { + permission: nfs_permission, revalidate: nfs_revalidate, setattr: nfs_notify_change, }; @@ -90,13 +91,14 @@ static ssize_t nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) { struct dentry * dentry = file->f_dentry; + struct inode * inode = dentry->d_inode; ssize_t result; dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (unsigned long) count, (unsigned long) *ppos); - result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); + result = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (!result) result = generic_file_read(file, buf, count, ppos); return result; @@ -106,12 +108,13 @@ static int nfs_file_mmap(struct file * file, struct vm_area_struct * vma) { struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; int status; dfprintk(VFS, "nfs: mmap(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); - status = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); + status = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (!status) status = generic_file_mmap(file, vma); return status; @@ -179,7 +182,7 @@ static int nfs_sync_page(struct page *page) struct address_space *mapping; struct inode *inode; unsigned long index = page_index(page); - unsigned int rpages, wpages; + unsigned int rpages; int result; mapping = page->mapping; @@ -192,14 +195,8 @@ static int nfs_sync_page(struct page *page) rpages = NFS_SERVER(inode)->rpages; result = nfs_pagein_inode(inode, index, rpages); if (result < 0) - goto out_bad; - wpages = NFS_SERVER(inode)->wpages; - result = nfs_sync_file(inode, NULL, index, wpages, FLUSH_STABLE); - if (result < 0) - goto out_bad; + return result; return 0; - out_bad: - return result; } struct address_space_operations nfs_file_aops = { @@ -227,7 +224,7 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) result = -EBUSY; if (IS_SWAPFILE(inode)) goto out_swapfile; - result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); + result = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (result) goto out; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 5b582024ef94..a205c3ad4a28 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -39,7 +39,7 @@ #define NFSDBG_FACILITY NFSDBG_VFS #define NFS_PARANOIA 1 -static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *); +static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); void nfs_zap_caches(struct inode *); static void nfs_invalidate_inode(struct inode *); @@ -222,13 +222,10 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh) return NULL; } - inode = __nfs_fhget(sb, &fattr); + inode = __nfs_fhget(sb, rootfh, &fattr); return inode; } -extern struct nfs_fh *nfs_fh_alloc(void); -extern void nfs_fh_free(struct nfs_fh *p); - /* * The way this works is that the mount process passes a structure * in the data argument which contains the server's IP address @@ -242,7 +239,7 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) struct nfs_server *server; struct rpc_xprt *xprt = NULL; struct rpc_clnt *clnt = NULL; - struct nfs_fh *root = &data->root, *root_fh, fh; + struct nfs_fh *root = &data->root, fh; struct inode *root_inode = NULL; unsigned int authflavor; struct sockaddr_in srvaddr; @@ -365,16 +362,10 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) * Keep the super block locked while we try to get * the root fh attributes. */ - root_fh = nfs_fh_alloc(); - if (!root_fh) - goto out_no_fh; - memcpy((u8*)root_fh, (u8*)root, sizeof(*root)); - /* Did getting the root inode fail? */ if (!(root_inode = nfs_get_root(sb, root)) && (data->flags & NFS_MOUNT_VER3)) { data->flags &= ~NFS_MOUNT_VER3; - nfs_fh_free(root_fh); rpciod_down(); rpc_shutdown_client(server->client); goto nfsv3_try_again; @@ -387,7 +378,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) goto out_no_root; sb->s_root->d_op = &nfs_dentry_operations; - sb->s_root->d_fsdata = root_fh; /* Get some general file system info */ if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) { @@ -462,8 +452,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) out_no_root: printk("nfs_read_super: get root inode failed\n"); iput(root_inode); - nfs_fh_free(root_fh); -out_no_fh: rpciod_down(); goto out_shutdown; @@ -507,7 +495,7 @@ nfs_statfs(struct super_block *sb, struct statfs *buf) struct nfs_fsinfo res; int error; - error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res); + error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res); buf->f_type = NFS_SUPER_MAGIC; if (error < 0) goto out_err; @@ -531,43 +519,6 @@ nfs_statfs(struct super_block *sb, struct statfs *buf) return 0; } -/* - * Free all unused dentries in an inode's alias list. - * - * Subtle note: we have to be very careful not to cause - * any IO operations with the stale dentries, as this - * could cause file corruption. But since the dentry - * count is 0 and all pending IO for a dentry has been - * flushed when the count went to 0, we're safe here. - * Also returns the number of unhashed dentries - */ -static int -nfs_free_dentries(struct inode *inode) -{ - struct list_head *tmp, *head; - int unhashed; - - if (S_ISDIR(inode->i_mode)) { - struct dentry *dentry = d_find_alias(inode); - if (dentry) { - shrink_dcache_parent(dentry); - dput(dentry); - } - } - d_prune_aliases(inode); - spin_lock(&dcache_lock); - head = &inode->i_dentry; - tmp = head; - unhashed = 0; - while ((tmp = tmp->next) != head) { - struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); - if (list_empty(&dentry->d_hash)) - unhashed++; - } - spin_unlock(&dcache_lock); - return unhashed; -} - /* * Invalidate the local caches */ @@ -600,7 +551,7 @@ nfs_invalidate_inode(struct inode *inode) * Fill in inode information from the fattr. */ static void -nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr) +nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr) { /* * Check whether the mode has been set, as we only want to @@ -638,6 +589,7 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr) NFS_CACHE_ISIZE(inode) = fattr->size; NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; + memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)); } nfs_refresh_inode(inode, fattr); } @@ -652,42 +604,34 @@ static int nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque) { struct nfs_fattr *fattr = (struct nfs_fattr *)opaque; + if (NFS_FSID(inode) != fattr->fsid) return 0; if (NFS_FILEID(inode) != fattr->fileid) return 0; + return 1; } static int -nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr) +nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr) { - int unhashed; - int is_stale = 0; + /* Empty inodes are not stale */ + if (!inode->i_mode) + return 0; - if (inode->i_mode && - (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) - is_stale = 1; + if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) + return 1; if (is_bad_inode(inode)) - is_stale = 1; + return 1; - /* - * If the inode seems stale, free up cached dentries. - */ - unhashed = nfs_free_dentries(inode); - - /* Assume we're holding an i_count - * - * NB: sockets sometimes have volatile file handles - * don't invalidate their inodes even if all dentries are - * unhashed. - */ - if (unhashed && atomic_read(&inode->i_count) == unhashed + 1 - && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode)) - is_stale = 1; + /* Has the filehandle changed? If so is the old one stale? */ + if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 && + __nfs_revalidate_inode(NFS_SERVER(inode),inode) < 0) + return 1; - return is_stale; + return 0; } /* @@ -709,9 +653,6 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle, dentry->d_parent->d_name.name, dentry->d_name.name, (long long)fattr->fileid); - /* Install the file handle in the dentry */ - memcpy(dentry->d_fsdata, fhandle, sizeof(struct nfs_fh)); - #ifdef CONFIG_NFS_SNAPSHOT /* * Check for NetApp snapshot dentries, and get an @@ -725,14 +666,14 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle, goto out; inode->i_ino = nfs_fattr_to_ino_t(fattr); nfs_read_inode(inode); - nfs_fill_inode(inode, fattr); + nfs_fill_inode(inode, fhandle, fattr); inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT; dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino); out: return inode; } #endif - return __nfs_fhget(sb, fattr); + return __nfs_fhget(sb, fhandle, fattr); } /* @@ -744,7 +685,7 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle, * server has reused a fileid (i_ino) and we have a stale inode. */ static struct inode * -__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr) +__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) { struct inode *inode = NULL; unsigned long ino; @@ -770,11 +711,12 @@ __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr) * as the inode may have become a different object. * (We can probably handle modes changes here, too.) */ - if (!nfs_inode_is_stale(inode,fattr)) + if (!nfs_inode_is_stale(inode, fh, fattr)) break; - dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n", - inode->i_ino, atomic_read(&inode->i_count)); + dprintk("__nfs_fhget: inode (%x/%Ld) still busy, i_count=%d\n", + inode->i_dev, (long long)NFS_FILEID(inode), + atomic_read(&inode->i_count)); nfs_zap_caches(inode); remove_inode_hash(inode); iput(inode); @@ -783,9 +725,10 @@ __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr) if (!inode) goto out_no_inode; - nfs_fill_inode(inode, fattr); - dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n", - inode->i_dev, inode->i_ino, atomic_read(&inode->i_count)); + nfs_fill_inode(inode, fh, fattr); + dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n", + inode->i_dev, (long long)NFS_FILEID(inode), + atomic_read(&inode->i_count)); out: return inode; @@ -820,7 +763,7 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error); if (error) goto out; - error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); + error = NFS_PROTO(inode)->setattr(inode, &fattr, attr); if (error) goto out; /* @@ -872,7 +815,8 @@ nfs_wait_on_inode(struct inode *inode, int flag) int nfs_revalidate(struct dentry *dentry) { - return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); + struct inode *inode = dentry->d_inode; + return nfs_revalidate_inode(NFS_SERVER(inode), inode); } /* @@ -913,15 +857,13 @@ int nfs_release(struct inode *inode, struct file *filp) * the cached attributes have to be refreshed. */ int -__nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) +__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { - struct inode *inode = dentry->d_inode; int status = 0; struct nfs_fattr fattr; - dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - inode->i_ino); + dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n", + inode->i_dev, (long long)NFS_FILEID(inode)); lock_kernel(); if (!inode || is_bad_inode(inode)) { @@ -942,46 +884,21 @@ __nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) } NFS_FLAGS(inode) |= NFS_INO_REVALIDATING; - status = NFS_PROTO(inode)->getattr(dentry, &fattr); + status = NFS_PROTO(inode)->getattr(inode, &fattr); if (status) { - struct dentry *dir = dentry->d_parent; - struct inode *dir_i = dir->d_inode; - int error; - u32 *fh; - struct nfs_fh fhandle; - dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n", - dir->d_name.name, dentry->d_name.name, - inode->i_ino, status); - if (status != -ESTALE) - goto out; - /* - * A "stale filehandle" error ... show the current fh - * and find out what the filehandle should be. - */ - fh = (u32 *) NFS_FH(dentry)->data; - dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n", - fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); - error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, - &fhandle, &fattr); - if (error) { - dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error); - goto out; - } - fh = (u32 *) fhandle.data; - dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n", - fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n", + inode->i_dev, (long long)NFS_FILEID(inode), status); goto out; } status = nfs_refresh_inode(inode, &fattr); if (status) { - dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n", - dentry->d_parent->d_name.name, - dentry->d_name.name, inode->i_ino, status); + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n", + inode->i_dev, (long long)NFS_FILEID(inode), status); goto out; } - dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n", + inode->i_dev, (long long)NFS_FILEID(inode)); out: NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; wake_up(&inode->i_wait); @@ -1165,8 +1082,6 @@ out_changed: */ static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME); -extern int nfs_init_fhcache(void); -extern void nfs_destroy_fhcache(void); extern int nfs_init_nfspagecache(void); extern void nfs_destroy_nfspagecache(void); extern int nfs_init_readpagecache(void); @@ -1180,10 +1095,6 @@ init_nfs_fs(void) { int err; - err = nfs_init_fhcache(); - if (err) - return err; - err = nfs_init_nfspagecache(); if (err) return err; @@ -1218,7 +1129,6 @@ cleanup_module(void) { nfs_destroy_readpagecache(); nfs_destroy_nfspagecache(); - nfs_destroy_fhcache(); #ifdef CONFIG_PROC_FS rpc_proc_unregister("nfs"); #endif diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index d75e9eda00ec..86cfd1b811ef 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -37,34 +37,34 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, * One function for each procedure in the NFS protocol. */ static int -nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr) +nfs3_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) { int status; dprintk("NFS call getattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR, - NFS_FH(dentry), fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_GETATTR, + NFS_FH(inode), fattr, 0); dprintk("NFS reply getattr\n"); return status; } static int -nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, +nfs3_proc_setattr(struct inode *inode, struct nfs_fattr *fattr, struct iattr *sattr) { - struct nfs3_sattrargs arg = { NFS_FH(dentry), sattr, 0, 0 }; + struct nfs3_sattrargs arg = { NFS_FH(inode), sattr, 0, 0 }; int status; dprintk("NFS call setattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr\n"); return status; } static int -nfs3_proc_lookup(struct dentry *dir, struct qstr *name, +nfs3_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; @@ -75,20 +75,20 @@ nfs3_proc_lookup(struct dentry *dir, struct qstr *name, dprintk("NFS call lookup %s\n", name->name); dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR, + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply lookup: %d\n", status); - nfs_refresh_inode(dir->d_inode, &dir_attr); + nfs_refresh_inode(dir, &dir_attr); return status; } static int -nfs3_proc_access(struct dentry *dentry, int mode, int ruid) +nfs3_proc_access(struct inode *inode, int mode, int ruid) { struct nfs_fattr fattr; - struct nfs3_accessargs arg = { NFS_FH(dentry), 0 }; + struct nfs3_accessargs arg = { NFS_FH(inode), 0 }; struct nfs3_accessres res = { &fattr, 0 }; int status, flags; @@ -97,7 +97,7 @@ nfs3_proc_access(struct dentry *dentry, int mode, int ruid) if (mode & MAY_READ) arg.access |= NFS3_ACCESS_READ; - if (S_ISDIR(dentry->d_inode->i_mode)) { + if (S_ISDIR(inode->i_mode)) { if (mode & MAY_WRITE) arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE; if (mode & MAY_EXEC) @@ -109,8 +109,8 @@ nfs3_proc_access(struct dentry *dentry, int mode, int ruid) arg.access |= NFS3_ACCESS_EXECUTE; } flags = (ruid) ? RPC_CALL_REALUID : 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags); - nfs_refresh_inode(dentry->d_inode, &fattr); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags); + nfs_refresh_inode(inode, &fattr); dprintk("NFS reply access\n"); if (status == 0 && (arg.access & res.access) != arg.access) @@ -119,29 +119,28 @@ nfs3_proc_access(struct dentry *dentry, int mode, int ruid) } static int -nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen) +nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen) { struct nfs_fattr fattr; - struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen }; + struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen }; struct nfs3_readlinkres res = { &fattr, buffer, buflen }; int status; dprintk("NFS call readlink\n"); fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK, + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, &args, &res, 0); - nfs_refresh_inode(dentry->d_inode, &fattr); + nfs_refresh_inode(inode, &fattr); dprintk("NFS reply readlink: %d\n", status); return status; } static int -nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, +nfs3_proc_read(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, int flags, loff_t offset, unsigned int count, void *buffer, int *eofp) { - struct dentry *dentry = file->f_dentry; - struct rpc_cred *cred = nfs_file_cred(file); - struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1, + struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count, 0 }; @@ -150,20 +149,19 @@ nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, dprintk("NFS call read %d @ %Ld\n", count, (long long)offset); fattr->valid = 0; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); dprintk("NFS reply read: %d\n", status); *eofp = res.eof; return status; } static int -nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags, +nfs3_proc_write(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, int flags, loff_t offset, unsigned int count, void *buffer, struct nfs_writeverf *verf) { - struct dentry *dentry = file->f_dentry; - struct rpc_cred *cred = nfs_file_cred(file); - struct nfs_writeargs arg = { NFS_FH(dentry), offset, count, + struct nfs_writeargs arg = { NFS_FH(inode), offset, count, NFS_FILE_SYNC, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; @@ -177,7 +175,7 @@ nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags, rpcflags |= NFS_RPC_SWAPFLAGS; arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); dprintk("NFS reply read: %d\n", status); return status < 0? status : res.count; @@ -188,7 +186,7 @@ nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags, * For now, we don't implement O_EXCL. */ static int -nfs3_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr, +nfs3_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; @@ -208,8 +206,8 @@ nfs3_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr, again: dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); /* If the server doesn't support the exclusive creation semantics, * try again with simple 'guarded' mode. */ @@ -242,7 +240,7 @@ exit: * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR, + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr (post-create): %d\n", status); } @@ -251,7 +249,7 @@ exit: } static int -nfs3_proc_remove(struct dentry *dir, struct qstr *name) +nfs3_proc_remove(struct inode *dir, struct qstr *name) { struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; @@ -260,8 +258,8 @@ nfs3_proc_remove(struct dentry *dir, struct qstr *name) dprintk("NFS call remove %s\n", name->name); dir_attr.valid = 0; - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status; } @@ -276,7 +274,7 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr if (!arg) return -ENOMEM; res = (struct nfs_fattr*)(arg + 1); - arg->fh = NFS_FH(dir); + arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; res->valid = 0; @@ -299,8 +297,8 @@ nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) } static int -nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name, - struct dentry *new_dir, struct qstr *new_name) +nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, + struct inode *new_dir, struct qstr *new_name) { struct nfs_fattr old_dir_attr, new_dir_attr; struct nfs3_renameargs arg = { NFS_FH(old_dir), @@ -313,18 +311,18 @@ nfs3_proc_rename(struct dentry *old_dir, struct qstr *old_name, dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); old_dir_attr.valid = 0; new_dir_attr.valid = 0; - status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0); - nfs_refresh_inode(old_dir->d_inode, &old_dir_attr); - nfs_refresh_inode(new_dir->d_inode, &new_dir_attr); + status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); + nfs_refresh_inode(old_dir, &old_dir_attr); + nfs_refresh_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); return status; } static int -nfs3_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name) +nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { struct nfs_fattr dir_attr, fattr; - struct nfs3_linkargs arg = { NFS_FH(dentry), NFS_FH(dir), + struct nfs3_linkargs arg = { NFS_FH(inode), NFS_FH(dir), name->name, name->len }; struct nfs3_linkres res = { &dir_attr, &fattr }; int status; @@ -332,15 +330,15 @@ nfs3_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name) dprintk("NFS call link %s\n", name->name); dir_attr.valid = 0; fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); - nfs_refresh_inode(dentry->d_inode, &fattr); + status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); + nfs_refresh_inode(inode, &fattr); dprintk("NFS reply link: %d\n", status); return status; } static int -nfs3_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path, +nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { @@ -353,14 +351,14 @@ nfs3_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path, dprintk("NFS call symlink %s -> %s\n", name->name, path->name); dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply symlink: %d\n", status); return status; } static int -nfs3_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr, +nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; @@ -372,14 +370,14 @@ nfs3_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr, dprintk("NFS call mkdir %s\n", name->name); dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply mkdir: %d\n", status); return status; } static int -nfs3_proc_rmdir(struct dentry *dir, struct qstr *name) +nfs3_proc_rmdir(struct inode *dir, struct qstr *name) { struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { NFS_FH(dir), name->name, name->len }; @@ -387,8 +385,8 @@ nfs3_proc_rmdir(struct dentry *dir, struct qstr *name) dprintk("NFS call rmdir %s\n", name->name); dir_attr.valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, &dir_attr, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -403,16 +401,15 @@ nfs3_proc_rmdir(struct dentry *dir, struct qstr *name) * readdirplus. */ static int -nfs3_proc_readdir(struct file *file, u64 cookie, void *entry, +nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred, + u64 cookie, void *entry, unsigned int size, int plus) { - struct dentry *dir = file->f_dentry; - struct rpc_cred *cred = nfs_file_cred(file); struct nfs_fattr dir_attr; struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 }; struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 }; struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred }; - u32 *verf = NFS_COOKIEVERF(dir->d_inode); + u32 *verf = NFS_COOKIEVERF(dir); int status; arg.buffer = entry; @@ -432,14 +429,14 @@ nfs3_proc_readdir(struct file *file, u64 cookie, void *entry, plus? "plus" : "", (unsigned int) cookie); dir_attr.valid = 0; - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply readdir: %d\n", status); return status; } static int -nfs3_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr, +nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr) { struct nfs_fattr dir_attr; @@ -459,8 +456,8 @@ nfs3_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr, dprintk("NFS call mknod %s %x\n", name->name, rdev); dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0); - nfs_refresh_inode(dir->d_inode, &dir_attr); + status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); + nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply mknod: %d\n", status); return status; } diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index be935c0838aa..17bb39f36ca8 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -64,34 +64,34 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, * One function for each procedure in the NFS protocol. */ static int -nfs_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr) +nfs_proc_getattr(struct inode *inode, struct nfs_fattr *fattr) { int status; dprintk("NFS call getattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR, - NFS_FH(dentry), fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_GETATTR, + NFS_FH(inode), fattr, 0); dprintk("NFS reply getattr\n"); return status; } static int -nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, +nfs_proc_setattr(struct inode *inode, struct nfs_fattr *fattr, struct iattr *sattr) { - struct nfs_sattrargs arg = { NFS_FH(dentry), sattr }; + struct nfs_sattrargs arg = { NFS_FH(inode), sattr }; int status; dprintk("NFS call setattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr\n"); return status; } static int -nfs_proc_lookup(struct dentry *dir, struct qstr *name, +nfs_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len }; @@ -100,32 +100,31 @@ nfs_proc_lookup(struct dentry *dir, struct qstr *name, dprintk("NFS call lookup %s\n", name->name); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0); dprintk("NFS reply lookup: %d\n", status); return status; } static int -nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz) +nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz) { - struct nfs_readlinkargs args = { NFS_FH(dentry), buffer, bufsiz }; + struct nfs_readlinkargs args = { NFS_FH(inode), buffer, bufsiz }; struct nfs_readlinkres res = { buffer, bufsiz }; int status; dprintk("NFS call readlink\n"); - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK, + status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, &res, 0); dprintk("NFS reply readlink: %d\n", status); return status; } static int -nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, +nfs_proc_read(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, int flags, loff_t offset, unsigned int count, void *buffer, int *eofp) { - struct dentry *dentry = file->f_dentry; - struct rpc_cred *cred = nfs_file_cred(file); - struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1, + struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1, {{ buffer, count }, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count, 0}; @@ -134,7 +133,7 @@ nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, dprintk("NFS call read %d @ %Ld\n", count, (long long)offset); fattr->valid = 0; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); dprintk("NFS reply read: %d\n", status); *eofp = res.eof; @@ -142,13 +141,12 @@ nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, } static int -nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how, +nfs_proc_write(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, int how, loff_t offset, unsigned int count, void *buffer, struct nfs_writeverf *verf) { - struct dentry *dentry = file->f_dentry; - struct rpc_cred *cred = nfs_file_cred(file); - struct nfs_writeargs arg = {NFS_FH(dentry), offset, count, + struct nfs_writeargs arg = {NFS_FH(inode), offset, count, NFS_FILE_SYNC, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}}; @@ -160,7 +158,7 @@ nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how, fattr->valid = 0; if (how & NFS_RW_SWAP) flags |= NFS_RPC_SWAPFLAGS; - status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags); + status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); dprintk("NFS reply write: %d\n", status); verf->committed = NFS_FILE_SYNC; /* NFSv2 always syncs data */ @@ -168,7 +166,7 @@ nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how, } static int -nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr, +nfs_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_createargs arg = { NFS_FH(dir), name->name, @@ -178,7 +176,7 @@ nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr, fattr->valid = 0; dprintk("NFS call create %s\n", name->name); - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); dprintk("NFS reply create: %d\n", status); return status; } @@ -187,7 +185,7 @@ nfs_proc_create(struct dentry *dir, struct qstr *name, struct iattr *sattr, * In NFSv2, mknod is grafted onto the create call. */ static int -nfs_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr, +nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_createargs arg = { NFS_FH(dir), name->name, @@ -207,26 +205,26 @@ nfs_proc_mknod(struct dentry *dir, struct qstr *name, struct iattr *sattr, } fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); } dprintk("NFS reply mknod: %d\n", status); return status; } static int -nfs_proc_remove(struct dentry *dir, struct qstr *name) +nfs_proc_remove(struct inode *dir, struct qstr *name) { struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len }; struct rpc_message msg = { NFSPROC_REMOVE, &arg, NULL, NULL }; int status; dprintk("NFS call remove %s\n", name->name); - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply remove: %d\n", status); return status; @@ -240,7 +238,7 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr * arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL); if (!arg) return -ENOMEM; - arg->fh = NFS_FH(dir); + arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; msg->rpc_proc = NFSPROC_REMOVE; @@ -258,8 +256,8 @@ nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) } static int -nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name, - struct dentry *new_dir, struct qstr *new_name) +nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, + struct inode *new_dir, struct qstr *new_name) { struct nfs_renameargs arg = { NFS_FH(old_dir), old_name->name, old_name->len, @@ -268,26 +266,26 @@ nfs_proc_rename(struct dentry *old_dir, struct qstr *old_name, int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0); dprintk("NFS reply rename: %d\n", status); return status; } static int -nfs_proc_link(struct dentry *dentry, struct dentry *dir, struct qstr *name) +nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { - struct nfs_linkargs arg = { NFS_FH(dentry), NFS_FH(dir), + struct nfs_linkargs arg = { NFS_FH(inode), NFS_FH(dir), name->name, name->len }; int status; dprintk("NFS call link %s\n", name->name); - status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); dprintk("NFS reply link: %d\n", status); return status; } static int -nfs_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path, +nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { @@ -297,13 +295,13 @@ nfs_proc_symlink(struct dentry *dir, struct qstr *name, struct qstr *path, dprintk("NFS call symlink %s -> %s\n", name->name, path->name); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); dprintk("NFS reply symlink: %d\n", status); return status; } static int -nfs_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr, +nfs_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_createargs arg = { NFS_FH(dir), name->name, name->len, @@ -313,19 +311,19 @@ nfs_proc_mkdir(struct dentry *dir, struct qstr *name, struct iattr *sattr, dprintk("NFS call mkdir %s\n", name->name); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); dprintk("NFS reply mkdir: %d\n", status); return status; } static int -nfs_proc_rmdir(struct dentry *dir, struct qstr *name) +nfs_proc_rmdir(struct inode *dir, struct qstr *name) { struct nfs_diropargs arg = { NFS_FH(dir), name->name, name->len }; int status; dprintk("NFS call rmdir %s\n", name->name); - status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0); + status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -338,11 +336,10 @@ nfs_proc_rmdir(struct dentry *dir, struct qstr *name) * from nfs_readdir by calling the decode_entry function directly. */ static int -nfs_proc_readdir(struct file *file, __u64 cookie, void *entry, +nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred, + __u64 cookie, void *entry, unsigned int size, int plus) { - struct dentry *dir = file->f_dentry; - struct rpc_cred *cred = nfs_file_cred(file); struct nfs_readdirargs arg; struct nfs_readdirres res; struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred }; @@ -356,7 +353,7 @@ nfs_proc_readdir(struct file *file, __u64 cookie, void *entry, res.bufsiz = size; dprintk("NFS call readdir %d\n", (unsigned int)cookie); - status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); dprintk("NFS reply readdir: %d\n", status); return status; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 76fc2f437bb1..219f4c207a88 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -36,7 +36,7 @@ struct nfs_read_data { struct rpc_task task; - struct dentry *dentry; + struct inode *inode; struct rpc_cred *cred; struct nfs_readargs args; /* XDR argument struct */ struct nfs_readres res; /* ... and result struct */ @@ -82,10 +82,10 @@ static void nfs_readdata_release(struct rpc_task *task) * Read a page synchronously. */ static int -nfs_readpage_sync(struct file *file, struct page *page) +nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page) { struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; + struct rpc_cred *cred = nfs_file_cred(file); struct nfs_fattr fattr; loff_t offset = page_offset(page); char *buffer; @@ -112,8 +112,8 @@ nfs_readpage_sync(struct file *file, struct page *page) (long long)offset, rsize, buffer); lock_kernel(); - result = NFS_PROTO(inode)->read(file, &fattr, flags, offset, - rsize, buffer, &eof); + result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags, + offset, rsize, buffer, &eof); unlock_kernel(); nfs_refresh_inode(inode, &fattr); @@ -180,7 +180,7 @@ nfs_find_read(struct inode *inode, struct page *page) static inline void nfs_mark_request_read(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; spin_lock(&nfs_wreq_lock); if (list_empty(&req->wb_list)) { @@ -196,9 +196,8 @@ nfs_mark_request_read(struct nfs_page *req) } static int -nfs_readpage_async(struct file *file, struct page *page) +nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) { - struct inode *inode = file->f_dentry->d_inode; struct nfs_page *req, *new = NULL; int result; @@ -228,7 +227,7 @@ nfs_readpage_async(struct file *file, struct page *page) } result = -ENOMEM; - new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE); + new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE); if (!new) break; } @@ -264,9 +263,9 @@ nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data) data->args.nriov++; } req = nfs_list_entry(data->pages.next); - data->dentry = req->wb_dentry; + data->inode = req->wb_inode; data->cred = req->wb_cred; - data->args.fh = NFS_FH(req->wb_dentry); + data->args.fh = NFS_FH(req->wb_inode); data->args.offset = page_offset(req->wb_page) + req->wb_offset; data->args.count = count; data->res.fattr = &data->fattr; @@ -292,9 +291,8 @@ nfs_async_read_error(struct list_head *head) } static int -nfs_pagein_one(struct list_head *head, struct dentry *dentry) +nfs_pagein_one(struct list_head *head, struct inode *inode) { - struct inode *inode = dentry->d_inode; struct rpc_task *task; struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_read_data *data; @@ -328,9 +326,9 @@ nfs_pagein_one(struct list_head *head, struct dentry *dentry) msg.rpc_cred = data->cred; /* Start the async call */ - dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n", + dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n", task->tk_pid, - dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_dev, (long long)NFS_FILEID(inode), data->args.count, data->args.nriov); rpc_clnt_sigmask(clnt, &oldset); @@ -355,7 +353,7 @@ nfs_pagein_list(struct inode *inode, struct list_head *head) while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, rpages); req = nfs_list_entry(one_request.next); - error = nfs_pagein_one(&one_request, req->wb_dentry); + error = nfs_pagein_one(&one_request, req->wb_inode); if (error < 0) break; } @@ -429,8 +427,7 @@ static void nfs_readpage_result(struct rpc_task *task) { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; - struct dentry *dentry = data->dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = data->inode; int count = data->res.count; dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", @@ -451,9 +448,9 @@ nfs_readpage_result(struct rpc_task *task) kunmap(page); UnlockPage(page); - dprintk("NFS: read (%s/%s %d@%Ld)\n", - req->wb_dentry->d_parent->d_name.name, - req->wb_dentry->d_name.name, + dprintk("NFS: read (%x/%Ld %d@%Ld)\n", + req->wb_inode->i_dev, + (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(page) + req->wb_offset)); nfs_unlock_request(req); @@ -473,9 +470,19 @@ nfs_readpage_result(struct rpc_task *task) int nfs_readpage(struct file *file, struct page *page) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode; int error; + if (!file) { + struct address_space *mapping = page->mapping; + if (!mapping) + BUG(); + inode = (struct inode *)mapping->host; + } else + inode = file->f_dentry->d_inode; + if (!inode) + BUG(); + dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", page, PAGE_CACHE_SIZE, page->index); /* @@ -491,11 +498,11 @@ nfs_readpage(struct file *file, struct page *page) error = -1; if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) - error = nfs_readpage_async(file, page); + error = nfs_readpage_async(file, inode, page); if (error >= 0) goto out; - error = nfs_readpage_sync(file, page); + error = nfs_readpage_sync(file, inode, page); if (error < 0 && IS_SWAPFILE(inode)) printk("Aiee.. nfs swap-in of page failed!\n"); out: diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 4960526b4705..eba7a859a750 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -27,9 +27,8 @@ /* Symlink caching in the page cache is even more simplistic * and straight-forward than readdir caching. */ -static int nfs_symlink_filler(struct dentry *dentry, struct page *page) +static int nfs_symlink_filler(struct inode *inode, struct page *page) { - struct inode *inode = dentry->d_inode; void *buffer = kmap(page); int error; @@ -38,7 +37,7 @@ static int nfs_symlink_filler(struct dentry *dentry, struct page *page) * XDR response verification will NULL terminate it. */ lock_kernel(); - error = NFS_PROTO(inode)->readlink(dentry, buffer, + error = NFS_PROTO(inode)->readlink(inode, buffer, PAGE_CACHE_SIZE - sizeof(u32)-4); unlock_kernel(); if (error < 0) @@ -55,15 +54,14 @@ error: return -EIO; } -static char *nfs_getlink(struct dentry *dentry, struct page **ppage) +static char *nfs_getlink(struct inode *inode, struct page **ppage) { - struct inode *inode = dentry->d_inode; struct page *page; u32 *p; /* Caller revalidated the directory inode already. */ page = read_cache_page(&inode->i_data, 0, - (filler_t *)nfs_symlink_filler, dentry); + (filler_t *)nfs_symlink_filler, inode); if (IS_ERR(page)) goto read_failed; if (!Page_Uptodate(page)) @@ -81,8 +79,9 @@ read_failed: static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen) { + struct inode *inode = dentry->d_inode; struct page *page = NULL; - int res = vfs_readlink(dentry,buffer,buflen,nfs_getlink(dentry,&page)); + int res = vfs_readlink(dentry,buffer,buflen,nfs_getlink(inode,&page)); if (page) { kunmap(page); page_cache_release(page); @@ -92,8 +91,9 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen) static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd) { + struct inode *inode = dentry->d_inode; struct page *page = NULL; - int res = vfs_follow_link(nd, nfs_getlink(dentry,&page)); + int res = vfs_follow_link(nd, nfs_getlink(inode,&page)); if (page) { kunmap(page); page_cache_release(page); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 2309549931ab..b634bc0f55b4 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -77,7 +77,7 @@ static atomic_t nfs_nr_requests = ATOMIC_INIT(0); */ struct nfs_write_data { struct rpc_task task; - struct dentry *dentry; + struct inode *inode; struct rpc_cred *cred; struct nfs_writeargs args; /* argument struct */ struct nfs_writeres res; /* result struct */ @@ -89,7 +89,8 @@ struct nfs_write_data { /* * Local function declarations */ -static struct nfs_page * nfs_update_request(struct file*, struct page *page, +static struct nfs_page * nfs_update_request(struct file*, struct inode *, + struct page *, unsigned int, unsigned int); static void nfs_strategy(struct inode *inode); static void nfs_writeback_done(struct rpc_task *); @@ -167,11 +168,11 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) * Offset is the data offset within the page. */ static int -nfs_writepage_sync(struct file *file, struct page *page, +nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page, unsigned int offset, unsigned int count) { struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; + struct rpc_cred *cred = nfs_file_cred(file); loff_t base; unsigned int wsize = NFS_SERVER(inode)->wsize; int result, refresh = 0, written = 0, flags; @@ -193,7 +194,7 @@ nfs_writepage_sync(struct file *file, struct page *page, if (count < wsize && !IS_SWAPFILE(inode)) wsize = count; - result = NFS_PROTO(inode)->write(file, &fattr, flags, + result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags, base, wsize, buffer, &verf); nfs_write_attributes(inode, &fattr); @@ -229,18 +230,18 @@ io_error: } static int -nfs_writepage_async(struct file *file, struct page *page, +nfs_writepage_async(struct file *file, struct inode *inode, struct page *page, unsigned int offset, unsigned int count) { struct nfs_page *req; int status; - req = nfs_update_request(file, page, offset, count); + req = nfs_update_request(file, inode, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status < 0) goto out; nfs_release_request(req); - nfs_strategy(file->f_dentry->d_inode); + nfs_strategy(inode); out: return status; } @@ -251,11 +252,25 @@ nfs_writepage_async(struct file *file, struct page *page, int nfs_writepage(struct file *file, struct page *page) { - struct inode *inode = file->f_dentry->d_inode; - unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; + struct inode *inode; + unsigned long end_index; unsigned offset = PAGE_CACHE_SIZE; int err; + if (!file) { + struct address_space *mapping = page->mapping; + if (!mapping) + BUG(); + inode = (struct inode *)mapping->host; + } else + inode = file->f_dentry->d_inode; + if (!inode) + BUG(); + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + + /* Ensure we've flushed out any previous writes */ + nfs_wb_page(inode,page); + /* easy case */ if (page->index < end_index) goto do_it; @@ -266,11 +281,11 @@ nfs_writepage(struct file *file, struct page *page) return -EIO; do_it: if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { - err = nfs_writepage_async(file, page, 0, offset); + err = nfs_writepage_async(file, inode, page, 0, offset); if (err >= 0) goto out_ok; } - err = nfs_writepage_sync(file, page, 0, offset); + err = nfs_writepage_sync(file, inode, page, 0, offset); if ( err == offset) goto out_ok; return err; @@ -315,6 +330,8 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req) return; if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted hashed!\n"); + if (list_empty(&inode->u.nfs_i.writeback)) + atomic_inc(&inode->i_count); inode->u.nfs_i.npages++; list_add(&req->wb_hash, &inode->u.nfs_i.writeback); req->wb_count++; @@ -334,12 +351,14 @@ nfs_inode_remove_request(struct nfs_page *req) } if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n"); - inode = req->wb_dentry->d_inode; + inode = req->wb_inode; list_del(&req->wb_hash); INIT_LIST_HEAD(&req->wb_hash); inode->u.nfs_i.npages--; if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n"); + if (list_empty(&inode->u.nfs_i.writeback)) + iput(inode); if (!nfs_have_writebacks(inode) && !nfs_have_read(inode)) inode_remove_flushd(inode); spin_unlock(&nfs_wreq_lock); @@ -422,7 +441,7 @@ void nfs_list_remove_request(struct nfs_page *req) static inline void nfs_mark_request_dirty(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; spin_lock(&nfs_wreq_lock); if (list_empty(&req->wb_list)) { @@ -443,7 +462,7 @@ nfs_mark_request_dirty(struct nfs_page *req) static inline int nfs_dirty_request(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty; } @@ -454,7 +473,7 @@ nfs_dirty_request(struct nfs_page *req) static inline void nfs_mark_request_commit(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; spin_lock(&nfs_wreq_lock); if (list_empty(&req->wb_list)) { @@ -477,11 +496,10 @@ nfs_mark_request_commit(struct nfs_page *req) * when we reach the hard limit on the number of dirty pages. * It should be safe to sleep here. */ -struct nfs_page *nfs_create_request(struct file *file, struct page *page, +struct nfs_page *nfs_create_request(struct file *file, struct inode *inode, + struct page *page, unsigned int offset, unsigned int count) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct nfs_page *req = NULL; long timeout; @@ -533,9 +551,15 @@ struct nfs_page *nfs_create_request(struct file *file, struct page *page, req->wb_offset = offset; req->wb_bytes = count; req->wb_file = file; - get_file(file); - req->wb_dentry = dentry; - req->wb_cred = nfs_file_cred(file); + + /* If we have a struct file, use its cached credentials + * else cache the current process' credentials. */ + if (file) { + get_file(file); + req->wb_cred = nfs_file_cred(file); + } else + req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + req->wb_inode = inode; req->wb_count = 1; /* register request's existence */ @@ -554,7 +578,7 @@ struct nfs_page *nfs_create_request(struct file *file, struct page *page, void nfs_release_request(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct page *page = req->wb_page; @@ -576,7 +600,11 @@ nfs_release_request(struct nfs_page *req) if (NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: Request released while still locked!\n"); - fput(req->wb_file); + /* Release struct file or cached credential */ + if (req->wb_file) + fput(req->wb_file); + else + rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred); page_cache_release(page); nfs_page_free(req); /* wake up anyone waiting to allocate a request */ @@ -599,7 +627,7 @@ nfs_release_request(struct nfs_page *req) static int nfs_wait_on_request(struct nfs_page *req) { - struct inode *inode = req->wb_dentry->d_inode; + struct inode *inode = req->wb_inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); if (!NFS_WBACK_BUSY(req)) @@ -814,10 +842,9 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned * Note: Should always be called with the Page Lock held! */ static struct nfs_page * -nfs_update_request(struct file* file, struct page *page, +nfs_update_request(struct file* file, struct inode *inode, struct page *page, unsigned int offset, unsigned int bytes) { - struct inode *inode = file->f_dentry->d_inode; struct nfs_page *req, *new = NULL; unsigned long rqend, end; @@ -857,7 +884,7 @@ nfs_update_request(struct file* file, struct page *page, */ if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT) nfs_wb_file(inode, file); - new = nfs_create_request(file, page, offset, bytes); + new = nfs_create_request(file, inode, page, offset, bytes); if (!new) return ERR_PTR(-ENOMEM); /* If the region is locked, adjust the timeout */ @@ -995,7 +1022,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign * page synchronously. */ if (NFS_SERVER(inode)->wsize < PAGE_SIZE) - return nfs_writepage_sync(file, page, offset, count); + return nfs_writepage_sync(file, inode, page, offset, count); /* * Try to find an NFS request corresponding to this page @@ -1004,7 +1031,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign * it out now. */ do { - req = nfs_update_request(file, page, offset, count); + req = nfs_update_request(file, inode, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status != -EBUSY) break; @@ -1068,9 +1095,9 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) data->args.nriov++; } req = nfs_list_entry(data->pages.next); - data->dentry = req->wb_dentry; + data->inode = req->wb_inode; data->cred = req->wb_cred; - data->args.fh = NFS_FH(req->wb_dentry); + data->args.fh = NFS_FH(req->wb_inode); data->args.offset = page_offset(req->wb_page) + req->wb_offset; data->args.count = count; data->res.fattr = &data->fattr; @@ -1088,9 +1115,8 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data) * that has been written but not committed. */ static int -nfs_flush_one(struct list_head *head, struct dentry *dentry, int how) +nfs_flush_one(struct list_head *head, struct inode *inode, int how) { - struct inode *inode = dentry->d_inode; struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_write_data *data; struct rpc_task *task; @@ -1134,10 +1160,10 @@ nfs_flush_one(struct list_head *head, struct dentry *dentry, int how) msg.rpc_resp = &data->res; msg.rpc_cred = data->cred; - dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n", + dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n", task->tk_pid, - dentry->d_parent->d_name.name, - dentry->d_name.name, + inode->i_dev, + (long long)NFS_FILEID(inode), data->args.count, data->args.nriov); rpc_clnt_sigmask(clnt, &oldset); @@ -1167,7 +1193,7 @@ nfs_flush_list(struct inode *inode, struct list_head *head, int how) while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, wpages); req = nfs_list_entry(one_request.next); - error = nfs_flush_one(&one_request, req->wb_dentry, how); + error = nfs_flush_one(&one_request, req->wb_inode, how); if (error < 0) break; } @@ -1193,8 +1219,7 @@ nfs_writeback_done(struct rpc_task *task) struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; struct nfs_writeargs *argp = &data->args; struct nfs_writeres *resp = &data->res; - struct dentry *dentry = data->dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = data->inode; struct nfs_page *req; struct page *page; @@ -1249,9 +1274,9 @@ nfs_writeback_done(struct rpc_task *task) kunmap(page); - dprintk("NFS: write (%s/%s %d@%Ld)", - req->wb_dentry->d_parent->d_name.name, - req->wb_dentry->d_name.name, + dprintk("NFS: write (%x/%Ld %d@%Ld)", + req->wb_inode->i_dev, + (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(page) + req->wb_offset)); @@ -1292,7 +1317,6 @@ static void nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) { struct nfs_page *first, *last; - struct dentry *dentry; struct inode *inode; loff_t start, end, len; @@ -1303,8 +1327,7 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) INIT_LIST_HEAD(head); first = nfs_list_entry(data->pages.next); last = nfs_list_entry(data->pages.prev); - dentry = first->wb_dentry; - inode = dentry->d_inode; + inode = first->wb_inode; /* * Determine the offset range of requests in the COMMIT call. @@ -1317,9 +1340,9 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data) if (end >= inode->i_size || len < 0 || len > (~((u32)0) >> 1)) len = 0; - data->dentry = dentry; + data->inode = inode; data->cred = first->wb_cred; - data->args.fh = NFS_FH(dentry); + data->args.fh = NFS_FH(inode); data->args.offset = start; data->res.count = data->args.count = (u32)len; data->res.fattr = &data->fattr; @@ -1352,7 +1375,7 @@ nfs_commit_list(struct list_head *head, int how) /* Set up the argument struct */ nfs_commit_rpcsetup(head, data); req = nfs_list_entry(data->pages.next); - clnt = NFS_CLIENT(req->wb_dentry->d_inode); + clnt = NFS_CLIENT(req->wb_inode); rpc_init_task(task, clnt, nfs_commit_done, flags); task->tk_calldata = data; @@ -1389,8 +1412,7 @@ nfs_commit_done(struct rpc_task *task) struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; struct nfs_writeres *resp = &data->res; struct nfs_page *req; - struct dentry *dentry = data->dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = data->inode; dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); @@ -1400,9 +1422,9 @@ nfs_commit_done(struct rpc_task *task) req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); - dprintk("NFS: commit (%s/%s %d@%Ld)", - req->wb_dentry->d_parent->d_name.name, - req->wb_dentry->d_name.name, + dprintk("NFS: commit (%x/%Ld %d@%Ld)", + req->wb_inode->i_dev, + (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(req->wb_page) + req->wb_offset)); if (task->tk_status < 0) { diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index 49d2160a62c2..c18a5f01c1de 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -557,7 +557,8 @@ ntfs_bmap(struct inode *ino,int block) #endif /* It's fscking broken. */ - +/* FIXME: [bm]map code is disabled until ntfs_get_block gets sorted! */ +/* static int ntfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create) { BUG(); @@ -573,6 +574,7 @@ static struct file_operations ntfs_file_operations = { }; static struct inode_operations ntfs_inode_operations; +*/ static struct file_operations ntfs_dir_operations = { read: generic_read_dir, @@ -587,6 +589,7 @@ static struct inode_operations ntfs_dir_inode_operations = { #endif }; +/* static int ntfs_writepage(struct file *file, struct page *page) { return block_write_full_page(page,ntfs_get_block); @@ -612,6 +615,8 @@ struct address_space_operations ntfs_aops = { commit_write: generic_commit_write, bmap: _ntfs_bmap }; +*/ + /* ntfs_read_inode is called by the Virtual File System (the kernel layer that * deals with filesystems) when iget is called requesting an inode not already * present in the inode table. Typically filesystems have separate @@ -664,7 +669,10 @@ static void ntfs_read_inode(struct inode* inode) else { inode->i_size=data->size; - can_mmap=!data->resident && !data->compressed; + /* FIXME: once ntfs_get_block is implemented, uncomment the + * next line and remove the can_mmap = 0; */ + /* can_mmap=!data->resident && !data->compressed;*/ + can_mmap = 0; } /* get the file modification times from the standard information */ si=ntfs_find_attr(ino,vol->at_standard_information,NULL); @@ -687,12 +695,17 @@ static void ntfs_read_inode(struct inode* inode) } else { - if (can_mmap) { + /* As long as ntfs_get_block() is just a call to BUG() do not + * define any [bm]map ops or we get the BUG() whenever someone + * runs mc or mpg123 on an ntfs partition! + * FIXME: Uncomment the below code when ntfs_get_block is + * implemented. */ + /* if (can_mmap) { inode->i_op = &ntfs_inode_operations; inode->i_fop = &ntfs_file_operations; inode->i_mapping->a_ops = &ntfs_aops; inode->u.ntfs_i.mmu_private = inode->i_size; - } else { + } else */ { inode->i_op=&ntfs_inode_operations_nobmap; inode->i_fop=&ntfs_file_operations_nommap; } @@ -931,8 +944,7 @@ static int __init init_ntfs_fs(void) /* Comment this if you trust klogd. There are reasons not to trust it */ #if defined(DEBUG) && !defined(MODULE) - extern int console_loglevel; - console_loglevel=15; + console_verbose(); #endif printk(KERN_NOTICE "NTFS version " NTFS_VERSION "\n"); SYSCTL(1); diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h index 649abd02d351..78e0f58c39b2 100644 --- a/include/asm-alpha/bitops.h +++ b/include/asm-alpha/bitops.h @@ -20,31 +20,12 @@ * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1). */ -#define BITOPS_NO_BRANCH - -extern __inline__ void set_bit(unsigned long nr, volatile void * addr) +extern __inline__ void +set_bit(unsigned long nr, volatile void * addr) { -#ifndef BITOPS_NO_BRANCH - unsigned long oldbit; -#endif unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + int *m = ((int *) addr) + (nr >> 5); -#ifndef BITOPS_NO_BRANCH - __asm__ __volatile__( - "1: ldl_l %0,%4\n" - " and %0,%3,%2\n" - " bne %2,2f\n" - " xor %0,%3,%0\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - "2:\n" - ".subsection 2\n" - "3: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (*m), "=&r" (oldbit) - :"Ir" (1UL << (nr & 31)), "m" (*m)); -#else __asm__ __volatile__( "1: ldl_l %0,%3\n" " bis %0,%2,%0\n" @@ -55,58 +36,28 @@ extern __inline__ void set_bit(unsigned long nr, volatile void * addr) ".previous" :"=&r" (temp), "=m" (*m) :"Ir" (1UL << (nr & 31)), "m" (*m)); -#endif } /* * WARNING: non atomic version. */ -extern __inline__ void __set_bit(unsigned long nr, volatile void * addr) +extern __inline__ void +__set_bit(unsigned long nr, volatile void * addr) { - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); - /* - * Asm and C produces the same thing so let - * the compiler to do its good work. - */ -#if 0 - int tmp; + int *m = ((int *) addr) + (nr >> 5); - __asm__ __volatile__( - "ldl %0,%3\n\t" - "bis %0,%2,%0\n\t" - "stl %0,%1" - : "=&r" (tmp), "=m" (*m) - : "Ir" (1UL << (nr & 31)), "m" (*m)); -#else *m |= 1UL << (nr & 31); -#endif } #define smp_mb__before_clear_bit() smp_mb() #define smp_mb__after_clear_bit() smp_mb() -extern __inline__ void clear_bit(unsigned long nr, volatile void * addr) + +extern __inline__ void +clear_bit(unsigned long nr, volatile void * addr) { -#ifndef BITOPS_NO_BRANCH - unsigned long oldbit; -#endif unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + int *m = ((int *) addr) + (nr >> 5); -#ifndef BITOPS_NO_BRANCH - __asm__ __volatile__( - "1: ldl_l %0,%4\n" - " and %0,%3,%2\n" - " beq %2,2f\n" - " xor %0,%3,%0\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - "2:\n" - ".subsection 2\n" - "3: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (*m), "=&r" (oldbit) - :"Ir" (1UL << (nr & 31)), "m" (*m)); -#else __asm__ __volatile__( "1: ldl_l %0,%3\n" " and %0,%2,%0\n" @@ -117,13 +68,13 @@ extern __inline__ void clear_bit(unsigned long nr, volatile void * addr) ".previous" :"=&r" (temp), "=m" (*m) :"Ir" (~(1UL << (nr & 31))), "m" (*m)); -#endif } -extern __inline__ void change_bit(unsigned long nr, volatile void * addr) +extern __inline__ void +change_bit(unsigned long nr, volatile void * addr) { unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + int *m = ((int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%3\n" @@ -137,12 +88,12 @@ extern __inline__ void change_bit(unsigned long nr, volatile void * addr) :"Ir" (1UL << (nr & 31)), "m" (*m)); } -extern __inline__ int test_and_set_bit(unsigned long nr, - volatile void * addr) +extern __inline__ int +test_and_set_bit(unsigned long nr, volatile void *addr) { unsigned long oldbit; unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + int *m = ((int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%4\n" @@ -151,10 +102,10 @@ extern __inline__ int test_and_set_bit(unsigned long nr, " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" + "2:\n" #ifdef CONFIG_SMP " mb\n" #endif - "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" @@ -167,32 +118,23 @@ extern __inline__ int test_and_set_bit(unsigned long nr, /* * WARNING: non atomic version. */ -extern __inline__ int __test_and_set_bit(unsigned long nr, - volatile void * addr) +extern __inline__ int +__test_and_set_bit(unsigned long nr, volatile void * addr) { - unsigned long oldbit; - unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); - - __asm__ __volatile__( - " ldl %0,%4\n" - " and %0,%3,%2\n" - " bne %2,1f\n" - " xor %0,%3,%0\n" - " stl %0,%1\n" - "1:\n" - :"=&r" (temp), "=m" (*m), "=&r" (oldbit) - :"Ir" (1UL << (nr & 31)), "m" (*m)); + unsigned long mask = 1 << (nr & 0x1f); + int *m = ((int *) addr) + (nr >> 5); + int old = *m; - return oldbit != 0; + *m = old | mask; + return (old & mask) != 0; } -extern __inline__ int test_and_clear_bit(unsigned long nr, - volatile void * addr) +extern __inline__ int +test_and_clear_bit(unsigned long nr, volatile void * addr) { unsigned long oldbit; unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + int *m = ((int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%4\n" @@ -201,10 +143,10 @@ extern __inline__ int test_and_clear_bit(unsigned long nr, " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" + "2:\n" #ifdef CONFIG_SMP " mb\n" #endif - "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" @@ -217,32 +159,23 @@ extern __inline__ int test_and_clear_bit(unsigned long nr, /* * WARNING: non atomic version. */ -extern __inline__ int __test_and_clear_bit(unsigned long nr, - volatile void * addr) +extern __inline__ int +__test_and_clear_bit(unsigned long nr, volatile void * addr) { - unsigned long oldbit; - unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + unsigned long mask = 1 << (nr & 0x1f); + int *m = ((int *) addr) + (nr >> 5); + int old = *m; - __asm__ __volatile__( - " ldl %0,%4\n" - " and %0,%3,%2\n" - " beq %2,1f\n" - " xor %0,%3,%0\n" - " stl %0,%1\n" - "1:\n" - :"=&r" (temp), "=m" (*m), "=&r" (oldbit) - :"Ir" (1UL << (nr & 31)), "m" (*m)); - - return oldbit != 0; + *m = old & ~mask; + return (old & mask) != 0; } -extern __inline__ int test_and_change_bit(unsigned long nr, - volatile void * addr) +extern __inline__ int +test_and_change_bit(unsigned long nr, volatile void * addr) { unsigned long oldbit; unsigned long temp; - unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + int *m = ((int *) addr) + (nr >> 5); __asm__ __volatile__( "1: ldl_l %0,%4\n" @@ -262,7 +195,8 @@ extern __inline__ int test_and_change_bit(unsigned long nr, return oldbit != 0; } -extern __inline__ int test_bit(int nr, volatile void * addr) +extern __inline__ int +test_bit(int nr, volatile void * addr) { return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; } @@ -289,7 +223,7 @@ extern inline unsigned long ffz_b(unsigned long x) extern inline unsigned long ffz(unsigned long word) { #if defined(__alpha_cix__) && defined(__alpha_fix__) - /* Whee. EV6 can calculate it directly. */ + /* Whee. EV67 can calculate it directly. */ unsigned long result; __asm__("cttz %1,%0" : "=r"(result) : "r"(~word)); return result; @@ -325,7 +259,7 @@ extern inline int ffs(int word) */ #if defined(__alpha_cix__) && defined(__alpha_fix__) -/* Whee. EV6 can calculate it directly. */ +/* Whee. EV67 can calculate it directly. */ extern __inline__ unsigned long hweight64(unsigned long w) { unsigned long result; @@ -347,7 +281,8 @@ extern __inline__ unsigned long hweight64(unsigned long w) /* * Find next zero bit in a bitmap reasonably efficiently.. */ -extern inline unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset) +extern inline unsigned long +find_next_zero_bit(void * addr, unsigned long size, unsigned long offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 6); unsigned long result = offset & ~63UL; diff --git a/include/asm-alpha/byteorder.h b/include/asm-alpha/byteorder.h index edc376a049b7..91b55ea3e754 100644 --- a/include/asm-alpha/byteorder.h +++ b/include/asm-alpha/byteorder.h @@ -3,6 +3,44 @@ #include +#ifdef __GNUC__ + +static __inline __u32 __attribute__((__const)) __arch__swab32(__u32 x) +{ + /* + * Unfortunately, we can't use the 6 instruction sequence + * on ev6 since the latency of the UNPKBW is 3, which is + * pretty hard to hide. Just in case a future implementation + * has a lower latency, here's the sequence (also by Mike Burrows) + * + * UNPKBW a0, v0 v0: 00AA00BB00CC00DD + * SLL v0, 24, a0 a0: BB00CC00DD000000 + * BIS v0, a0, a0 a0: BBAACCBBDDCC00DD + * EXTWL a0, 6, v0 v0: 000000000000BBAA + * ZAP a0, 0xf3, a0 a0: 00000000DDCC0000 + * ADDL a0, v0, v0 v0: ssssssssDDCCBBAA + */ + + __u64 t0, t1, t2, t3; + + __asm__("inslh %1, 7, %0" /* t0 : 0000000000AABBCC */ + : "=r"(t0) : "r"(x)); + __asm__("inswl %1, 3, %0" /* t1 : 000000CCDD000000 */ + : "=r"(t1) : "r"(x)); + + t1 |= t0; /* t1 : 000000CCDDAABBCC */ + t2 = t1 >> 16; /* t2 : 0000000000CCDDAA */ + t0 = t1 & 0xFF00FF00; /* t0 : 00000000DD00BB00 */ + t3 = t2 & 0x00FF00FF; /* t3 : 0000000000CC00AA */ + t1 = t0 + t3; /* t1 : ssssssssDDCCBBAA */ + + return t1; +} + +#define __arch__swab32 __arch__swab32 + +#endif /* __GNUC__ */ + #define __BYTEORDER_HAS_U64__ #include diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h index b02a78594624..acd1b9a03bdf 100644 --- a/include/asm-alpha/fpu.h +++ b/include/asm-alpha/fpu.h @@ -131,17 +131,19 @@ rdfpcr(void) unsigned long tmp, ret; #if defined(__alpha_cix__) || defined(__alpha_fix__) - __asm__ ("ftoit $f0,%0\n\t" - "mf_fpcr $f0\n\t" - "ftoit $f0,%1\n\t" - "itoft %0,$f0" - : "=r"(tmp), "=r"(ret)); + __asm__ __volatile__ ( + "ftoit $f0,%0\n\t" + "mf_fpcr $f0\n\t" + "ftoit $f0,%1\n\t" + "itoft %0,$f0" + : "=r"(tmp), "=r"(ret)); #else - __asm__ ("stt $f0,%0\n\t" - "mf_fpcr $f0\n\t" - "stt $f0,%1\n\t" - "ldt $f0,%0" - : "=m"(tmp), "=m"(ret)); + __asm__ __volatile__ ( + "stt $f0,%0\n\t" + "mf_fpcr $f0\n\t" + "stt $f0,%1\n\t" + "ldt $f0,%0" + : "=m"(tmp), "=m"(ret)); #endif return ret; @@ -153,11 +155,12 @@ wrfpcr(unsigned long val) unsigned long tmp; #if defined(__alpha_cix__) || defined(__alpha_fix__) - __asm__ __volatile__ ("ftoit $f0,%0\n\t" - "itoft %1,$f0\n\t" - "mt_fpcr $f0\n\t" - "itoft %0,$f0" - : "=&r"(tmp) : "r"(val)); + __asm__ __volatile__ ( + "ftoit $f0,%0\n\t" + "itoft %1,$f0\n\t" + "mt_fpcr $f0\n\t" + "itoft %0,$f0" + : "=&r"(tmp) : "r"(val)); #else __asm__ __volatile__ ( "stt $f0,%0\n\t" diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h index 54341fff11e9..b3f6e81412f1 100644 --- a/include/asm-alpha/pgtable.h +++ b/include/asm-alpha/pgtable.h @@ -59,6 +59,11 @@ #define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */ #define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */ #define _PAGE_ASM 0x0010 +#if defined(CONFIG_ALPHA_EV6) && !defined(CONFIG_SMP) +#define _PAGE_MBE 0x0080 /* MB disable bit for EV6. */ +#else +#define _PAGE_MBE 0x0000 +#endif #define _PAGE_KRE 0x0100 /* xxx - see below on the "accessed" bit */ #define _PAGE_URE 0x0200 /* xxx */ #define _PAGE_KWE 0x1000 /* used to do the dirty bit in software */ @@ -85,19 +90,20 @@ #define _PFN_MASK 0xFFFFFFFF00000000 #define _PAGE_TABLE (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS) -#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS) +#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_MBE) /* - * All the normal masks have the "page accessed" bits on, as any time they are used, - * the page is accessed. They are cleared only by the page-out routines + * All the normal masks have the "page accessed" bits on, as any time they + * are used, the page is accessed. They are cleared only by the page-out + * routines. */ #define PAGE_NONE __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE) #define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS) #define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) #define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) -#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE) +#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE | _PAGE_MBE) -#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x)) +#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_MBE | (x)) #define _PAGE_P(x) _PAGE_NORMAL((x) | (((x) & _PAGE_FOW)?0:_PAGE_FOW)) #define _PAGE_S(x) _PAGE_NORMAL(x) @@ -189,6 +195,7 @@ extern unsigned long __zero_page(void); * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ + #define mk_pte(page, pgprot) \ ({ \ pte_t pte; \ @@ -199,7 +206,7 @@ extern unsigned long __zero_page(void); }) extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) -{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; } +{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | (pgprot_val(pgprot) & ~_PAGE_MBE); return pte; } extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h index 3860288ad10d..9ccc2821c5d7 100644 --- a/include/asm-i386/hardirq.h +++ b/include/asm-i386/hardirq.h @@ -42,7 +42,7 @@ typedef struct { #include extern unsigned char global_irq_holder; -extern unsigned volatile int global_irq_lock; +extern unsigned volatile long global_irq_lock; /* long for set_bit -RR */ static inline int irqs_running (void) { diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index 8272b8f29a54..8bf9bd75c53a 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -82,8 +82,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; #ifndef __ASSEMBLY__ -extern int console_loglevel; - /* * Tell the user there is some problem. Beep too, so we can * see^H^H^Hhear bugs in early bootup as well! diff --git a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h index 7c1a4d1096f8..1dabc1bdfeab 100644 --- a/include/asm-ia64/hardirq.h +++ b/include/asm-ia64/hardirq.h @@ -49,7 +49,7 @@ typedef struct { #include extern unsigned int global_irq_holder; -extern volatile unsigned int global_irq_lock; +extern volatile unsigned long global_irq_lock; static inline int irqs_running (void) { diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index aa406533f2b6..53d486ef13a2 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -76,8 +76,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; #ifndef __ASSEMBLY__ -extern int console_loglevel; - /* * Tell the user there is some problem. */ diff --git a/include/linux/agpgart.h b/include/linux/agpgart.h index 7457cd114baf..d18b71dc7357 100644 --- a/include/linux/agpgart.h +++ b/include/linux/agpgart.h @@ -207,7 +207,7 @@ typedef struct _agp_file_private { struct _agp_file_private *next; struct _agp_file_private *prev; pid_t my_pid; - u32 access_flags; + long access_flags; /* long req'd for set_bit --RR */ } agp_file_private; struct agp_front_data { diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 847ae567ed1e..dd9fdcfaf910 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -552,7 +552,7 @@ extern int ext2_sync_file (struct file *, struct dentry *, int); extern int ext2_fsync_inode (struct inode *, int); /* ialloc.c */ -extern struct inode * ext2_new_inode (const struct inode *, int, int *); +extern struct inode * ext2_new_inode (const struct inode *, int); extern void ext2_free_inode (struct inode *); extern unsigned long ext2_count_free_inodes (struct super_block *); extern void ext2_check_inodes_bitmap (struct super_block *); diff --git a/include/linux/fs.h b/include/linux/fs.h index ff0098c64d08..869716d7bf9d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1065,6 +1065,7 @@ extern void sync_supers(kdev_t); extern int bmap(struct inode *, int); extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode *, int); +extern int vfs_permission(struct inode *, int); extern int get_write_access(struct inode *); extern int deny_write_access(struct file *); static inline void put_write_access(struct inode * inode) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 4e1b281be11e..ee3e8906c5d6 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -69,6 +69,19 @@ extern int session_of_pgrp(int pgrp); asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); +extern int console_loglevel; + +static inline void console_silent(void) +{ + console_loglevel = 0; +} + +static inline void console_verbose(void) +{ + if (console_loglevel) + console_loglevel = 15; +} + #if DEBUG #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index c8bdd1cd7e30..4ce69eee899a 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -91,8 +91,9 @@ struct cfi_private { must be of the same type. */ int numchips; unsigned long chipshift; /* Because they're of the same type */ - struct flchip chips[0]; /* per-chip data structure for each chip */ const char *im_name; /* inter_module name for cmdset_setup */ + struct flchip chips[0]; /* per-chip data structure for each chip */ + /* do not add extra fields after "chips" */ }; #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */ diff --git a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h index 05c506516953..144eb922a76e 100644 --- a/include/linux/mtd/pmc551.h +++ b/include/linux/mtd/pmc551.h @@ -1,5 +1,5 @@ /* - * $Id: pmc551.h,v 1.2 2000/03/31 14:40:42 dwmw2 Exp $ + * $Id: pmc551.h,v 1.3 2000/10/30 20:03:23 major Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -17,6 +17,9 @@ #include +#define PMC551_VERSION "$Id: pmc551.h,v 1.3 2000/10/30 20:03:23 major Exp $\n"\ + "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" + /* * Our personal and private information */ @@ -54,68 +57,25 @@ static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_cha #define PMC551_PCI_MEM_MAP1 0x54 #define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000 #define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0 -#define PMC551_PCI_MEM_MAP_1MB_APERTURE 0x00000000 -#define PMC551_PCI_MEM_MAP_2MB_APERTURE 0x00000010 -#define PMC551_PCI_MEM_MAP_REG_EN 0x00000002 -#define PMC551_PCI_MEM_MAP_ENABLE 0x00000001 - -#define PMC551_SDRAM_MA 0x60 -#define PMC551_SDRAM_CMD 0x62 -#define PMC551_DRAM_CFG 0x64 - -#define PMC551_DRAM_BLK0 0x68 -#define PMC551_DRAM_BLK1 0x6c -#define PMC551_DRAM_BLK2 0x70 -#define PMC551_DRAM_BLK3 0x74 -#define PMC551_DRAM_BLK_GET_SIZE(x) ((512 * 1024) << ((x >> 4) & 0xf)) -#define PMC551_DRAM_BLK_SET_COL_MUX(x,v) (((x) & ~0x00007000) | (((v) & 0x7) << 12)) -#define PMC551_DRAM_BLK_SET_ROW_MUX(x,v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8)) - - -/* Use a 1MB apeture into the card. */ -#define PMC551_APERTURE_SIZE 0x00100000 -#define PMC551_ADDR_HIGH_MASK 0x3ff00000 -#define PMC551_ADDR_LOW_MASK 0x000fffff -#define PMC551_APERTURE_VAL PMC551_PCI_MEM_MAP_1MB_APERTURE -/* - * Define the PCI ID's if the kernel doesn't define them for us - */ -#ifndef PCI_VENDOR_ID_V3_SEMI -#define PCI_VENDOR_ID_V3_SEMI 0x11b0 -#endif - -#ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC -#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 -#endif - - -#define PMC551_PCI_MEM_MAP0 0x50 -#define PMC551_PCI_MEM_MAP1 0x54 -#define PMC551_PCI_MEM_MAP_MAP_ADDR_MASK 0x3ff00000 -#define PMC551_PCI_MEM_MAP_APERTURE_MASK 0x000000f0 -#define PMC551_PCI_MEM_MAP_1MB_APERTURE 0x00000000 -#define PMC551_PCI_MEM_MAP_2MB_APERTURE 0x00000010 #define PMC551_PCI_MEM_MAP_REG_EN 0x00000002 #define PMC551_PCI_MEM_MAP_ENABLE 0x00000001 #define PMC551_SDRAM_MA 0x60 #define PMC551_SDRAM_CMD 0x62 #define PMC551_DRAM_CFG 0x64 +#define PMC551_SYS_CTRL_REG 0x78 #define PMC551_DRAM_BLK0 0x68 #define PMC551_DRAM_BLK1 0x6c #define PMC551_DRAM_BLK2 0x70 #define PMC551_DRAM_BLK3 0x74 -#define PMC551_DRAM_BLK_GET_SIZE(x) ((512 * 1024) << ((x >> 4) & 0xf)) +#define PMC551_DRAM_BLK_GET_SIZE(x) (524288<<((x>>4)&0x0f)) #define PMC551_DRAM_BLK_SET_COL_MUX(x,v) (((x) & ~0x00007000) | (((v) & 0x7) << 12)) #define PMC551_DRAM_BLK_SET_ROW_MUX(x,v) (((x) & ~0x00000f00) | (((v) & 0xf) << 8)) -/* Use a 1MB apeture into the card. */ -#define PMC551_APERTURE_SIZE 0x00100000 #define PMC551_ADDR_HIGH_MASK 0x3ff00000 #define PMC551_ADDR_LOW_MASK 0x000fffff -#define PMC551_APERTURE_VAL PMC551_PCI_MEM_MAP_1MB_APERTURE #endif /* __MTD_PMC551_H__ */ diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b61722b1527f..26734dce1f75 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -63,8 +63,7 @@ */ #define NFS_SUPER_MAGIC 0x6969 -#define NFS_FH(dentry) ((struct nfs_fh *) ((dentry)->d_fsdata)) -#define NFS_DSERVER(dentry) (&(dentry)->d_sb->u.nfs_sb.s_server) +#define NFS_FH(inode) (&(inode)->u.nfs_i.fh) #define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server) #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) #define NFS_PROTO(inode) (NFS_SERVER(inode)->rpc_ops) @@ -143,9 +142,10 @@ extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *, struct nfs_fattr *); extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_revalidate(struct dentry *); +extern int nfs_permission(struct inode *, int); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); -extern int __nfs_revalidate_inode(struct nfs_server *, struct dentry *); +extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int nfs_notify_change(struct dentry *, struct iattr *); /* @@ -264,12 +264,11 @@ extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *); * inline functions */ static inline int -nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) +nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { - struct inode *inode = dentry->d_inode; if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) return 0; - return __nfs_revalidate_inode(server, dentry); + return __nfs_revalidate_inode(server, inode); } static inline loff_t diff --git a/include/linux/nfs_fs_i.h b/include/linux/nfs_fs_i.h index 2e10b196346a..f14f3d8d9c8e 100644 --- a/include/linux/nfs_fs_i.h +++ b/include/linux/nfs_fs_i.h @@ -3,6 +3,7 @@ #include #include +#include /* * nfs fs inode data in memory @@ -14,6 +15,11 @@ struct nfs_inode_info { __u64 fsid; __u64 fileid; + /* + * NFS file handle + */ + struct nfs_fh fh; + /* * Various flags */ @@ -72,6 +78,7 @@ struct nfs_inode_info { /* * Legal inode flag values */ +#define NFS_INO_STALE 0x0001 /* possible stale inode */ #define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */ #define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */ #define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */ diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index f6c35dc01d2f..2f37a4b19491 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -26,7 +26,7 @@ struct nfs_page { wb_list, /* Defines state of page: */ *wb_list_head; /* read/write/commit */ struct file *wb_file; - struct dentry *wb_dentry; + struct inode *wb_inode; struct rpc_cred *wb_cred; struct page *wb_page; /* page to read in/write out */ wait_queue_head_t wb_wait; /* wait queue */ @@ -41,6 +41,7 @@ struct nfs_page { #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) extern struct nfs_page *nfs_create_request(struct file *file, + struct inode *inode, struct page *page, unsigned int offset, unsigned int count); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 9863c06af0b9..1ee4dd6167e1 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -316,39 +316,41 @@ struct nfs_rpc_ops { int (*getroot) (struct nfs_server *, struct nfs_fh *, struct nfs_fattr *); - int (*getattr) (struct dentry *, struct nfs_fattr *); - int (*setattr) (struct dentry *, struct nfs_fattr *, + int (*getattr) (struct inode *, struct nfs_fattr *); + int (*setattr) (struct inode *, struct nfs_fattr *, struct iattr *); - int (*lookup) (struct dentry *, struct qstr *, + int (*lookup) (struct inode *, struct qstr *, struct nfs_fh *, struct nfs_fattr *); - int (*access) (struct dentry *, int , int); - int (*readlink)(struct dentry *, void *, unsigned int); - int (*read) (struct file *, struct nfs_fattr *, + int (*access) (struct inode *, int , int); + int (*readlink)(struct inode *, void *, unsigned int); + int (*read) (struct inode *, struct rpc_cred *, + struct nfs_fattr *, int, loff_t, unsigned int, void *buffer, int *eofp); - int (*write) (struct file *, struct nfs_fattr *, + int (*write) (struct inode *, struct rpc_cred *, + struct nfs_fattr *, int, loff_t, unsigned int, void *buffer, struct nfs_writeverf *verfp); - int (*commit) (struct dentry *, struct nfs_fattr *, + int (*commit) (struct inode *, struct nfs_fattr *, unsigned long, unsigned int); - int (*create) (struct dentry *, struct qstr *, struct iattr *, + int (*create) (struct inode *, struct qstr *, struct iattr *, int, struct nfs_fh *, struct nfs_fattr *); - int (*remove) (struct dentry *, struct qstr *); + int (*remove) (struct inode *, struct qstr *); int (*unlink_setup) (struct rpc_message *, struct dentry *, struct qstr *); void (*unlink_done) (struct dentry *, struct rpc_message *); - int (*rename) (struct dentry *, struct qstr *, - struct dentry *, struct qstr *); - int (*link) (struct dentry *, struct dentry *, struct qstr *); - int (*symlink) (struct dentry *, struct qstr *, struct qstr *, + int (*rename) (struct inode *, struct qstr *, + struct inode *, struct qstr *); + int (*link) (struct inode *, struct inode *, struct qstr *); + int (*symlink) (struct inode *, struct qstr *, struct qstr *, struct iattr *, struct nfs_fh *, struct nfs_fattr *); - int (*mkdir) (struct dentry *, struct qstr *, struct iattr *, + int (*mkdir) (struct inode *, struct qstr *, struct iattr *, struct nfs_fh *, struct nfs_fattr *); - int (*rmdir) (struct dentry *, struct qstr *); - int (*readdir) (struct file *, u64 cookie, void *, unsigned int, - int); - int (*mknod) (struct dentry *, struct qstr *, struct iattr *, + int (*rmdir) (struct inode *, struct qstr *); + int (*readdir) (struct inode *, struct rpc_cred *, + u64, void *, unsigned int, int); + int (*mknod) (struct inode *, struct qstr *, struct iattr *, dev_t, struct nfs_fh *, struct nfs_fattr *); int (*statfs) (struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 64aeef389123..6c82d1d77fa0 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -406,10 +406,6 @@ #define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 #define PCI_DEVICE_ID_ELSA_QS3000 0x3000 -#define PCI_VENDOR_ID_ELSA 0x1048 -#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 -#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 - #define PCI_VENDOR_ID_SGS 0x104a #define PCI_DEVICE_ID_SGS_2000 0x0008 #define PCI_DEVICE_ID_SGS_1764 0x0009 diff --git a/include/linux/signal.h b/include/linux/signal.h index f2d0766ef7c8..c4e6eb3bd2ca 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -193,7 +193,7 @@ static inline void siginitset(sigset_t *set, unsigned long mask) memset(&set->sig[1], 0, sizeof(long)*(_NSIG_WORDS-1)); break; case 2: set->sig[1] = 0; - case 1: + case 1: ; } } @@ -205,7 +205,7 @@ static inline void siginitsetinv(sigset_t *set, unsigned long mask) memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1)); break; case 2: set->sig[1] = -1; - case 1: + case 1: ; } } diff --git a/init/main.c b/init/main.c index f933d2923ccc..d7d56607515e 100644 --- a/init/main.c +++ b/init/main.c @@ -51,8 +51,8 @@ extern int con3215_activate(void); #endif -#ifdef CONFIG_MAC -extern void nubus_init(void); +#ifdef CONFIG_NUBUS +#include #endif #ifdef CONFIG_ISAPNP @@ -80,8 +80,6 @@ extern void nubus_init(void); extern char _stext, _etext; extern char *linux_banner; -extern int console_loglevel; - static int init(void *); extern void init_IRQ(void); @@ -682,7 +680,7 @@ static void __init do_basic_setup(void) #ifdef CONFIG_DIO dio_init(); #endif -#ifdef CONFIG_MAC +#ifdef CONFIG_NUBUS nubus_init(); #endif #ifdef CONFIG_ISAPNP diff --git a/ipc/shm.c b/ipc/shm.c index f1e18e3e8856..195e9116c3f3 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1406,7 +1406,7 @@ static int shm_swapout(struct page * page, struct file *file) */ page_cache_free(page); - return 1; /* We might have slept */ + return 0; } /* diff --git a/kernel/exit.c b/kernel/exit.c index 3045d7ac60c9..c60bafe8cdd6 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -22,7 +22,7 @@ extern struct task_struct *child_reaper; int getrusage(struct task_struct *, int, struct rusage *); -static void release(struct task_struct * p) +static void release_task(struct task_struct * p) { if (p != current) { #ifdef CONFIG_SMP @@ -31,15 +31,15 @@ static void release(struct task_struct * p) * runqueue (active on some other CPU still) */ for (;;) { - spin_lock_irq(&runqueue_lock); + task_lock(p); if (!p->has_cpu) break; - spin_unlock_irq(&runqueue_lock); + task_unlock(p); do { barrier(); } while (p->has_cpu); } - spin_unlock_irq(&runqueue_lock); + task_unlock(p); #endif atomic_dec(&p->user->processes); free_uid(p->user); @@ -550,7 +550,7 @@ repeat: do_notify_parent(p, SIGCHLD); write_unlock_irq(&tasklist_lock); } else - release(p); + release_task(p); goto end_wait4; default: continue; diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 100adaeb3687..9a41f0ecb49f 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -53,7 +53,6 @@ #include #endif -extern int console_loglevel; extern void set_device_ro(kdev_t dev,int flag); extern void *sys_call_table; @@ -175,6 +174,7 @@ EXPORT_SYMBOL(invalidate_inode_pages); EXPORT_SYMBOL(truncate_inode_pages); EXPORT_SYMBOL(fsync_dev); EXPORT_SYMBOL(permission); +EXPORT_SYMBOL(vfs_permission); EXPORT_SYMBOL(inode_setattr); EXPORT_SYMBOL(inode_change_ok); EXPORT_SYMBOL(write_inode_now); diff --git a/kernel/sched.c b/kernel/sched.c index 119edeb8134b..faf9a80e1002 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -197,7 +197,7 @@ static inline int preemption_goodness(struct task_struct * prev, struct task_str /* * This is ugly, but reschedule_idle() is very timing-critical. - * We `are called with the runqueue spinlock held and we must + * We are called with the runqueue spinlock held and we must * not claim the tasklist_lock. */ static FASTCALL(void reschedule_idle(struct task_struct * p)); @@ -272,8 +272,10 @@ send_now_idle: } tsk = target_tsk; if (tsk) { - if (oldest_idle != -1ULL) + if (oldest_idle != -1ULL) { + best_cpu = tsk->processor; goto send_now_idle; + } tsk->need_resched = 1; if (tsk->processor != this_cpu) smp_send_reschedule(tsk->processor); @@ -452,7 +454,7 @@ static inline void __schedule_tail(struct task_struct *prev) goto needs_resched; out_unlock: - task_unlock(prev); + task_unlock(prev); /* Synchronise here with release_task() if prev is TASK_ZOMBIE */ return; /* diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5591ee2bcf4a..3fdf03c342c4 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -41,7 +41,7 @@ /* External variables not in a header file. */ extern int panic_timeout; -extern int console_loglevel, C_A_D; +extern int C_A_D; extern int bdf_prm[], bdflush_min[], bdflush_max[]; extern int sysctl_overcommit_memory; extern int max_threads; diff --git a/mm/filemap.c b/mm/filemap.c index 5d205c3c8d49..e7f05ffd3fa6 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1490,9 +1490,11 @@ static int filemap_write_page(struct file *file, extern void wakeup_bdflush(int); int filemap_swapout(struct page * page, struct file *file) { - filemap_write_page(file, page, 0); + int error; + + error = filemap_write_page(file, page, 0); wakeup_bdflush(0); - return 1; /* We might have slept */ + return error; } /* Called with mm->page_table_lock held to protect against other diff --git a/mm/vmscan.c b/mm/vmscan.c index 014d76ed89c1..a3a2de242be4 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -176,7 +176,7 @@ out_failed: UnlockPage(page); deactivate_page(page); page_cache_release(page); - return error; + return 1; /* We released page_table_lock */ } /* @@ -620,6 +620,7 @@ dirty_page_rescan: spin_unlock(&pagemap_lru_lock); writepage(NULL, page); + UnlockPage(page); page_cache_release(page); /* And re-start the thing.. */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 173506c3d449..ca7433f9bf9b 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -417,7 +417,7 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask) } /** - * skb_copy - copy and expand sk_buff + * skb_copy_expand - copy and expand sk_buff * @skb: buffer to copy * @newheadroom: new free bytes at head * @newtailroom: new free bytes at tail diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 7b73fb6426ca..26cc633483e2 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -135,7 +135,7 @@ static spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED; static ipx_interface *ipx_primary_net; static ipx_interface *ipx_internal_net; -#define IPX_REFCNT_DEBUG +#undef IPX_REFCNT_DEBUG #ifdef IPX_REFCNT_DEBUG atomic_t ipx_sock_nr; #endif diff --git a/scripts/kernel-doc b/scripts/kernel-doc index d5aac6238bf2..eb4c33cc144f 100644 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -85,7 +85,7 @@ $type_constant = "\\\%([-_\\w]+)"; $type_func = "(\\w+)\\(\\)"; $type_param = "\\\@(\\w+)"; -$type_struct = "\\\&((struct\\s*)?\\w+)"; +$type_struct = "\\\&((struct\\s*)?[_\\w]+)"; $type_env = "(\\\$\\w+)"; @@ -326,7 +326,8 @@ sub output_sgml { print "\n"; print " ".$args{'function'}."\n"; print " \n"; - print " ".$args{'purpose'}."\n"; + print " "; + output_highlight ($args{'purpose'}); print " \n"; print "\n"; -- 2.39.5