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
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
-----------------------------------------
---------
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
--- /dev/null
+
+ 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 <tigran@veritas.com>
+
+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"
+
+
+
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!
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
Using the initial RAM disk (initrd)
===================================
-Written 1996 by Werner Almesberger <almesber@lrc.epfl.ch> and
- Hans Lermen <lermen@elserv.ffm.fgan.de>
+Written 1996,2000 by Werner Almesberger <werner.almesberger@epfl.ch> and
+ Hans Lermen <lermen@fgan.de>
-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
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
initrd adds the following new options:
- initrd=<path> (LOADLIN only)
+ initrd=<path> (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
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
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 <rescue.gz >/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 <kernel> initrd=<disk_image>
-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=<path> 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 >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
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
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/
------------------------------------------
Stefan Laudat <Stefan.Laudat@asit.ro>
-[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
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 \
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
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
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
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
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" \
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
}
}
-void __init
+void
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
#
.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:
--- /dev/null
+/*
+ * arch/alpha/lib/ev6-clear_user.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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
+
--- /dev/null
+/*
+ * arch/alpha/lib/ev6-copy_user.S
+ *
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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
+
--- /dev/null
+/*
+ * arch/alpha/lib/ev6-csum_ipv6_magic.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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 <proto> (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 <len> (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 : <sign bits>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 : <sign bits>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
--- /dev/null
+/*
+ * arch/alpha/lib/ev6-divide.S
+ *
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * arch/alpha/lib/ev6-strncpy_from_user.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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 <asm/errno.h>
+#include <alpha/regdef.h>
+
+
+/* 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
--- /dev/null
+/*
+ * arch/alpha/lib/ev67-strcat.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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
--- /dev/null
+/*
+ * arch/alpha/lib/ev67-strchr.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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 <alpha/regdef.h>
+
+ .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
--- /dev/null
+/*
+ * arch/alpha/lib/ev67-strlen.S
+ * 21264 version by Rick Gorton <rick.gorton@alpha-processor.com>
+ *
+ * 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
--- /dev/null
+/*
+ * arch/alpha/lib/ev67-strlen_user.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
+ *
+ * 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 <alpha/regdef.h>
+
+
+/* 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
--- /dev/null
+/*
+ * arch/alpha/lib/ev67-strncat.S
+ * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
+ *
+ * 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
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
#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);
"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",
/*
* 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;
goto smp_done;
}
+ verify_local_APIC();
+
/*
* If SMP should be disabled, then really disable it!
*/
*/
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);
#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);
void baboon_irq(int, void *, struct pt_regs *);
-extern int console_loglevel;
-
extern int macide_ack_intr(ide_hwif_t *);
/*
via_init_clock(vector);
}
-extern int console_loglevel;
-
#if 0
void mac_waitbut (void)
{
* 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 *);
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
void psc_irq(int, void *, struct pt_regs *);
-extern int console_loglevel;
-
/*
* Debugging dump, used in various places to see what's going on.
*/
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;
/*
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
-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
*/
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
-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);
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) \
{ \
#include <asm/atomic.h>
#include <asm/processor.h>
-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, \
*/
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);
}
}
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
* 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);
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 ...
#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",
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,
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;
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);
}
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 ?
#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;
#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;
#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;
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;
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
#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
*/
/* 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;
* 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;
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;
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;
/* 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;
*
*/
-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
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;
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;
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;
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;
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;
*/
/* 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;
}
/* 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;
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;
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;
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;
* addresses in this case.
*
*/
-void __init riscom8_setup(char *str, int * ints)
+static void __init riscom8_setup(char *str, int * ints)
{
int i;
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;
}
#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) {
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;
rc_release_io_range(&rc_board[i]);
}
-#endif /* MODULE */
+
+module_init(riscom8_init_module);
+module_exit(riscom8_exit_module);
+
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;
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 */
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);
}
-/* $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
#include <linux/interrupt.h>
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
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)
-/* $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
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
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)
-/* $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
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[] =
{
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 */
-/* $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
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
#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");
-/* $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
*
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)
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)
-/* $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
*
#include <linux/pci.h>
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
return (0);
}
-static struct pci_dev *dev_tel __initdata;
+static struct pci_dev *dev_tel __initdata = NULL;
static int
setup_gazelpci(struct IsdnCardState *cs)
-/* $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)
#include <linux/pci.h>
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)
return(0);
}
-static struct pci_dev *niccy_dev __initdata;
+static struct pci_dev *niccy_dev __initdata = NULL;
int __init
setup_niccy(struct IsdnCard *card)
-// $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
//
#include <linux/ppp_defs.h>
#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)
{
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)
-/* $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
*
#include <linux/ppp_defs.h>
#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)
{
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)
-/* $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),
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+",
return(0);
}
-static struct pci_dev *dev_sedl __devinitdata;
+static struct pci_dev *dev_sedl __devinitdata = NULL;
int __devinit
setup_sedlbauer(struct IsdnCard *card)
-/* $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
*
#include <linux/pci.h>
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
return(0);
}
-static struct pci_dev *dev_tel __initdata;
+static struct pci_dev *dev_tel __initdata = NULL;
int __init
setup_telespci(struct IsdnCard *card)
-/* $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
*
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
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)
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;
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)
}
}
+#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
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
msp->thread = NULL;
if(msp->notify != NULL)
- up(msp->notify);
+ up_and_exit(msp->notify, 0);
return 0;
}
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;
}
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
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);
/*======================================================================
- $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
-
======================================================================*/
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)
{
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;
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)
{
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;
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)
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))
{
}
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;
}
}
-#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
kfree(mymtd);
}
+#if LINUX_VERSION_CODE >= 0x20211
+module_init(init_doc1000);
+module_exit(cleanup_doc1000);
+#endif
/* 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:
*/
/*======================================================================
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 = (0x100000<part->mtd->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,
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;
}
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
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) {
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");
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");
/*
- * $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 <mferrell@mvista.com>
* 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
* 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 <saeed@ramix.com> of Ramix INC. for the initial
* 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
* <dhinds@allegro.stanford.edu> 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
* * 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
#include <stdarg.h>
#include <linux/pci.h>
+#ifndef CONFIG_PCI
+#error Enable PCI in your kernel config
+#endif
+
#include <linux/mtd/mtd.h>
#include <linux/mtd/pmc551.h>
#include <linux/mtd/compatmac.h>
#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.
* 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);
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
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 );
* 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);
* 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 );
}
* 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);
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
#define __exit
#endif
+#if defined(MODULE)
+MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
+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;
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)<<msize;
+ }
- printk(KERN_NOTICE "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n");
- printk(KERN_INFO "$Id: pmc551.c,v 1.8 2000/07/14 07:53:31 dwmw2 Exp $\n");
+ if(asize) {
+ if (asize < 1 || asize > 11 ) {
+ printk(KERN_NOTICE "pmc551: Invalid aperture size\n");
+ return -ENODEV;
+ }
+ asize = (512*1024)<<asize;
+ }
+
+ printk(KERN_INFO PMC551_VERSION);
if(!pci_present()) {
printk(KERN_NOTICE "pmc551: PCI not enabled.\n");
printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
break;
}
+ if(msize) {
+ length = msize;
+ printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
+ }
mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd) {
mtd->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,
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++;
printk(KERN_NOTICE "pmc551: not detected,\n");
return -ENODEV;
} else {
- return 0;
printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
+ return 0;
}
}
priv = (struct mypriv *)mtd->priv;
pmc551list = priv->nextpmc551;
- if(priv->start)
+ if(priv->start)
iounmap(((struct mypriv *)mtd->priv)->start);
kfree (mtd->priv);
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
-
-
-
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include <linux/delay.h>
#include <asm/io.h>
-#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
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 */
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 <jgarzik@mandrakesoft.com>");
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,
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))
DPRINTK ("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
+ SET_MODULE_OWNER(dev);
tp = dev->priv;
pio_start = pci_resource_start (pdev, 0);
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;
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;
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;
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;
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;
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;
}
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);
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;
/* 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;
/* 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;
}
-#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
struct rtl8139_private *tp)
{
int linkcase;
+ void *ioaddr = tp->mmio_addr;
DPRINTK ("ENTER\n");
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);
}
}
+ next_tick = HZ * 60;
+
rtl8139_tune_twister (dev, tp);
DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
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);
}
{
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++) {
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,
/* 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);
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",
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;
}
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);
+ }
}
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 */
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));
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);
RTL_W8 (Config1, 0x03);
RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
- MOD_DEC_USE_COUNT;
-
DPRINTK ("EXIT\n");
return 0;
}
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");
/* 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 */
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:
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");
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;
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;
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,
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.
/* 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);
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
}
/**
- * 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.
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);
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
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;
* 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;
}
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
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.
}
/* 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));
}
return 0;
+
+err_out:
+ release_region(ioaddr, COPS_IO_EXTENT);
+ return retval;
}
static int __init cops_irq (int ioaddr, int board)
cops_jumpstart(dev); /* Start the card up. */
netif_start_queue(dev);
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-
return 0;
}
del_timer(&cops_timer);
netif_stop_queue(dev);
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-
return 0;
}
{
/* 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);
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);
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;
}
}
-static struct net_device dev_ipddp = { init: ipddp_init };
+static struct net_device dev_ipddp;
MODULE_PARM(ipddp_mode, "i");
{
int err;
+ dev_ipddp.init = ipddp_init;
err=dev_alloc_name(&dev_ipddp, "ipddp%d");
if(err < 0)
return err;
static int irq=0;
static int dma=0;
-#ifdef MODULE
#include <linux/module.h>
-#include <linux/version.h>
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
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;
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;
/* initialization stuff */
-int __init ltpc_probe_dma(int base)
+static int __init ltpc_probe_dma(int base)
{
int dma = 0;
int timeout;
unsigned long flags;
unsigned long f;
+ SET_MODULE_OWNER(dev);
+
save_flags(flags);
/* probe for the I/O port address */
__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");
"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)
#include <linux/etherdevice.h>
#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);
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)
{
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. */
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)
/* static unsigned num_masters = 0; */
equalizer_t *eql = 0;
+ SET_MODULE_OWNER(dev);
+
if ( version_printed++ == 0 && eql_debug > 0)
printk(version);
/*
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);
return 0;
}
- MOD_DEC_USE_COUNT;
return -ENOMEM;
}
eql_delete_slave_queue (eql->queue);
- MOD_DEC_USE_COUNT;
return 0;
}
}
}
-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;
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 */
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 */
return -ENODEV;
if(shaper->bitspersec==0)
return -EINVAL;
- MOD_INC_USE_COUNT;
return 0;
}
struct shaper *shaper=dev->priv;
shaper_flush(shaper);
del_timer_sync(&shaper->timer);
- MOD_DEC_USE_COUNT;
return 0;
}
}
}
-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;
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);
+
sl->xleft = 0;
spin_unlock_bh(&sl->lock);
- MOD_DEC_USE_COUNT;
return 0;
}
sl->flags &= (1 << SLF_INUSE);
netif_start_queue(dev);
- MOD_INC_USE_COUNT;
return 0;
}
dev->type = ARPHRD_SLIP + sl->mode;
dev->tx_queue_len = 10;
+ SET_MODULE_OWNER(dev);
+
dev_init_buffers(dev);
/* New-style flags. */
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 */
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)
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;
tun->dev.init = tun_net_init;
tun->dev.priv = tun;
- MOD_INC_USE_COUNT;
-
return 0;
}
kfree(tun);
file->private_data = NULL;
- MOD_DEC_USE_COUNT;
return 0;
}
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
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)
if (slot==16 || len+begin < off)
*eof = 1;
off -= begin;
- *strat = buf + off;
+ *start = buf + off;
len -= off;
if (len>count)
len = count;
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; pos<howmany; pos = next) {
next = pos+1;
res = &dev->resource[pos];
}
res->name = dev->name;
}
- pci_write_config_word(dev, PCI_COMMAND, cmd);
}
void __init pci_read_bridge_bases(struct pci_bus *child)
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;
* themselves, but we'll see.
*
* History
+ * (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com>
+ * Add clocking= for people with seriously warped hardware
* (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
* add __init to maestro_ac97_init() and maestro_install()
* (still based on v0.14) Mar 29 2000 - Zach Brown <zab@redhat.com>
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"
{
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);
#endif
MODULE_PARM(dsps_order,"i");
MODULE_PARM(use_pm,"i");
+MODULE_PARM(clocking, "i");
void cleanup_module(void) {
M_printk("maestro: unloading\n");
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 <Peter.Wahl@epost.de> */
+ /* We must have an owner or the module locking fails */
+ owner: THIS_MODULE,
open: soundcore_open,
};
/*
- * bluetooth.c Version 0.6
+ * bluetooth.c Version 0.7
*
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
*
* 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.
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)
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 */
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;
}
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;
}
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) */
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.
*/
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;
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;
}
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);
*
* 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,
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);
* 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
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;
}
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;
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;
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);
* (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 <linux/config.h>
/* 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 <linux/usb.h>
#include "usb-uhci.h"
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");
return -1;
}
+ /* Enable PIRQ */
+ pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
s->irq = irq;
if(uhci_start_usb (s) < 0) {
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);
}
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
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);
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;
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
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);
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,
}
-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
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) {
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
(*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;
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);
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;
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,
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
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);
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;
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
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,
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;
}
}
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;
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);
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);
}
}
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))
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;
}
* 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;
* 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;
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;
}
}
- 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,
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);
}
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);
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)
*/
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;
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;
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;
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;
#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
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))
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);
return 0;
memcpy((void *) tmpde + slop, bh->b_data, offset);
}
- de = tmpde;
+ de = tmpde;
}
if (de->flags[-high_sierra] & 0x80) {
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;
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;
/* 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++;
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"
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
/* 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;
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.
*/
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 */
} 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
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;
cont_size = 0; \
cont_offset = 0; \
goto LABEL; \
- }; \
+ } \
printk("Unable to read rock-ridge attributes\n"); \
}}
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 */
default:
break;
}
- };
- };
+ }
+ }
MAYBE_CONTINUE(repeat, inode);
return retval;
out:
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 */
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;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
- };
+ }
printk("\n");
break;
case SIG('P','X'):
} else {
inode->i_rdev = MKDEV(high, low);
}
- };
+ }
break;
case SIG('T','F'):
/* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
break;
default:
printk("Symlink component flag not implemented\n");
- };
+ }
slen -= slp->len + 2;
oldslp = slp;
slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
/*
* 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 <<
default:
break;
}
- };
+ }
}
MAYBE_CONTINUE(repeat,inode);
return 0;
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;
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",
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);
* 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 */
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.
rmdir: nfs_rmdir,
mknod: nfs_mknod,
rename: nfs_rename,
+ permission: nfs_permission,
revalidate: nfs_revalidate,
setattr: nfs_notify_change,
};
{
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;
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) {
{
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;
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);
*/
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
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;
}
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;
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:
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();
}
-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.
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;
* 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;
* 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);
/*
* 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);
/*
* 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;
*/
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);
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];
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);
*/
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;
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;
}
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;
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;
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);
}
}
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;
* 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;
}
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);
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;
}
/*
};
struct inode_operations nfs_file_inode_operations = {
+ permission: nfs_permission,
revalidate: nfs_revalidate,
setattr: nfs_notify_change,
};
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;
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;
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;
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 = {
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;
#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 *);
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
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;
* 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;
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) {
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;
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;
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
*/
* 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
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);
}
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;
}
/*
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
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);
}
/*
* 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;
* 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);
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;
if (error)
goto out;
- error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
+ error = NFS_PROTO(inode)->setattr(inode, &fattr, attr);
if (error)
goto out;
/*
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);
}
/*
* 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)) {
}
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);
*/
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);
{
int err;
- err = nfs_init_fhcache();
- if (err)
- return err;
-
err = nfs_init_nfspagecache();
if (err)
return err;
{
nfs_destroy_readpagecache();
nfs_destroy_nfspagecache();
- nfs_destroy_fhcache();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
* 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;
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;
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)
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)
}
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 };
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}} };
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;
* 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;
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. */
* 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);
}
}
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 };
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;
}
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;
}
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),
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;
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)
{
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;
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 };
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;
}
* 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;
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;
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;
}
* 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 };
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};
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;
}
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}}};
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 */
}
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,
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;
}
* 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,
}
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;
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;
}
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,
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)
{
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,
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;
}
* 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 };
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;
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 */
* 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;
(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);
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)) {
}
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;
}
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;
}
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;
}
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;
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);
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;
}
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",
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);
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);
/*
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:
/* 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;
* 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)
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))
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);
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);
*/
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 */
/*
* 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 *);
* 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;
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);
}
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;
}
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;
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;
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++;
}
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);
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)) {
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;
}
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)) {
* 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;
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 */
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;
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 */
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))
* 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;
*/
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 */
* 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
* 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;
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;
* 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;
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);
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;
}
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;
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));
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;
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.
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;
/* 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;
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);
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) {
#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();
};
static struct inode_operations ntfs_inode_operations;
+*/
static struct file_operations ntfs_dir_operations = {
read: generic_read_dir,
#endif
};
+/*
static int ntfs_writepage(struct file *file, struct page *page)
{
return block_write_full_page(page,ntfs_get_block);
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
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);
}
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;
}
/* 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);
* 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"
".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"
".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"
:"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"
" 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"
/*
* 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"
" 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"
/*
* 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"
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;
}
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;
*/
#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;
/*
* 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;
#include <asm/types.h>
+#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 <linux/byteorder/little_endian.h>
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;
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"
#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 */
#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)
* 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; \
})
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; }
#include <asm/smp.h>
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)
{
#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!
#include <asm/smp.h>
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)
{
#ifndef __ASSEMBLY__
-extern int console_loglevel;
-
/*
* Tell the user there is some problem.
*/
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 {
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 *);
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)
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)
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() */
/*
- * $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
*
#include <linux/mtd/mtd.h>
+#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
*/
#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__ */
*/
#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)
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 *);
/*
* 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
#include <asm/types.h>
#include <linux/list.h>
+#include <linux/nfs.h>
/*
* nfs fs inode data in memory
__u64 fsid;
__u64 fileid;
+ /*
+ * NFS file handle
+ */
+ struct nfs_fh fh;
+
/*
* Various flags
*/
/*
* 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 */
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 */
#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);
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 *);
#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
memset(&set->sig[1], 0, sizeof(long)*(_NSIG_WORDS-1));
break;
case 2: set->sig[1] = 0;
- case 1:
+ case 1: ;
}
}
memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1));
break;
case 2: set->sig[1] = -1;
- case 1:
+ case 1: ;
}
}
extern int con3215_activate(void);
#endif
-#ifdef CONFIG_MAC
-extern void nubus_init(void);
+#ifdef CONFIG_NUBUS
+#include <linux/nubus.h>
#endif
#ifdef CONFIG_ISAPNP
extern char _stext, _etext;
extern char *linux_banner;
-extern int console_loglevel;
-
static int init(void *);
extern void init_IRQ(void);
#ifdef CONFIG_DIO
dio_init();
#endif
-#ifdef CONFIG_MAC
+#ifdef CONFIG_NUBUS
nubus_init();
#endif
#ifdef CONFIG_ISAPNP
*/
page_cache_free(page);
- return 1; /* We might have slept */
+ return 0;
}
/*
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
* 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);
do_notify_parent(p, SIGCHLD);
write_unlock_irq(&tasklist_lock);
} else
- release(p);
+ release_task(p);
goto end_wait4;
default:
continue;
#include <linux/kmod.h>
#endif
-extern int console_loglevel;
extern void set_device_ro(kdev_t dev,int flag);
extern void *sys_call_table;
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);
/*
* 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));
}
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);
goto needs_resched;
out_unlock:
- task_unlock(prev);
+ task_unlock(prev); /* Synchronise here with release_task() if prev is TASK_ZOMBIE */
return;
/*
/* 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;
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
UnlockPage(page);
deactivate_page(page);
page_cache_release(page);
- return error;
+ return 1; /* We released page_table_lock */
}
/*
spin_unlock(&pagemap_lru_lock);
writepage(NULL, page);
+ UnlockPage(page);
page_cache_release(page);
/* And re-start the thing.. */
}
/**
- * 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
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
$type_constant = "\\\%([-_\\w]+)";
$type_func = "(\\w+)\\(\\)";
$type_param = "\\\@(\\w+)";
-$type_struct = "\\\&((struct\\s*)?\\w+)";
+$type_struct = "\\\&((struct\\s*)?[_\\w]+)";
$type_env = "(\\\$\\w+)";
print "<refnamediv>\n";
print " <refname>".$args{'function'}."</refname>\n";
print " <refpurpose>\n";
- print " ".$args{'purpose'}."\n";
+ print " ";
+ output_highlight ($args{'purpose'});
print " </refpurpose>\n";
print "</refnamediv>\n";