PCI_DMA_TODEVICE means "from main memory to the PCI device"
PCI_DMA_FROMDEVICE means "from the PCI device to main memory"
-Cou are _strongly_ encouraged to specify this as precisely
+You are _strongly_ encouraged to specify this as precisely
as you possibly can.
If you absolutely cannot know the direction of the DMA transfer,
To unmap a scatterlist, just call:
- pci_unmap_sg(dev, sglist, nents);
+ pci_unmap_sg(dev, sglist, nents, direction);
Again, make sure DMA activity finished.
system 64-bit serial number
+ mem_fclk_21285
+
+ The speed of the external oscillator to the 21285 (footbridge),
+ which control's the speed of the memory bus, timer & serial port.
+ Depending upon the speed of the cpu its value can be between
+ 0-66 MHz. If no params are passed or a value of zero is passed,
+ then a value of 50 Mhz is the default on 21285 architectures.
+
paths[8][128]
These are now obsolete, and should not be used.
These notes are for the drivers which have already been integrated into the
kernel and have been tested on Linux kernels 2.0, 2.2, and 2.3.
-Version: 1.2.4
-Date: 12/15/99
+Version: 1.2.9
+Date: 04/12/2000
Author: Andrew Manison <amanison@america.net>
Testing: larryg@computone.com
Support: support@computone.com
-Fixes and Updates: Doug McNash <dmcnash@computone.com>
+Fixes and Updates: Doug McNash <dougm@computone.com>
Proc Filesystem and Kernel Integration: Mike Warfield <mhw@wittsend.com>
products previous to the Intelliport II.
This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.2.13; it will probably not work with earlier v1.X kernels,.
+to v2.2.14; it will probably not work with earlier v1.X kernels,.
2. QUICK INSTALLATION
Note the hardware address from the Computone ISA cards installed into
the system. These are required for editing ip2.h or editing
- /etc/config.modules, or for specification on the modprobe
+ /etc/modules.conf, or for specification on the modprobe
command line.
+ Note that the /etc/modules.conf file is named /etc/conf.modules
+ with older versions of the module utilities.
+
Software -
Module installation:
-a) Obtain driver-kernel patch file
-b) Copy to the linux source tree root, Run ip2build (if not patch)
-c) Determine free irq/address to use if any (configure BIOS if need be)
-d) Run "make config" or "make menuconfig" or "make xconfig"
+a) Determine free irq/address to use if any (configure BIOS if need be)
+b) Run "make config" or "make menuconfig" or "make xconfig"
Select (m) module for CONFIG_COMPUTONE under character
devices. CONFIG_PCI and CONFIG_MODULES also may need to be set.
-e) Set address on ISA cards then:
+c) Set address on ISA cards then:
edit /usr/src/linux/drivers/char/ip2/ip2.h if needed
or
edit /etc/modules.conf if needed (module).
or both to match this setting.
-f) Run "make dep"
-g) Run "make modules"
-h) Run "make modules_install"
-i) Run "/sbin/depmod -a"
-j) install driver using `modprobe ip2 <options>` (options listed below)
-k) run ip2mkdev (either the script below or the binary version)
+d) Run "make dep"
+e) Run "make modules"
+f) Run "make modules_install"
+g) Run "/sbin/depmod -a"
+h) install driver using `modprobe ip2 <options>` (options listed below)
+i) run ip2mkdev (either the script below or the binary version)
Kernel installation:
-a) Obtain driver-kernel patch file
-b) Copy to the linux source tree root, Run ip2build (if not patch)
-c) Determine free irq/address to use if any (configure BIOS if need be)
-d) Run "make config" or "make menuconfig" or "make xconfig"
+a) Determine free irq/address to use if any (configure BIOS if need be)
+b) Run "make config" or "make menuconfig" or "make xconfig"
Select (y) kernel for CONFIG_COMPUTONE under character
devices. CONFIG_PCI may need to be set if you have PCI bus.
-e) Set address on ISA cards then:
+c) Set address on ISA cards then:
edit /usr/src/linux/drivers/char/ip2/ip2.h
-f) Run "make dep"
-g) Run "make zImage" or whatever target you prefer.
-h) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
-i) Add new config for this kernel into /etc/lilo.conf, run "lilo"
+d) Run "make dep"
+e) Run "make zImage" or whatever target you prefer.
+f) mv /usr/src/linux/arch/i386/boot/zImage to /boot.
+g) Add new config for this kernel into /etc/lilo.conf, run "lilo"
or copy to a floppy disk and boot from that floppy disk.
-j) Reboot using this kernel
-k) run ip2mkdev (either the script below or the binary version)
+h) Reboot using this kernel
+i) run ip2mkdev (either the script below or the binary version)
3. INSTALLATION
Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
cuf0 - cuf255 for callout devices.
+If you are using devfs, existing devices are automatically created within
+the devfs name space. Normal devices will be ttf/0 - ttf/255 and callout
+devices will be cuf/0 - cuf/255. With devfs installed, ip2mkdev will
+create symbolic links in /dev from the old conventional names to the newer
+devfs names as follows:
+
+ /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3
+ /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3
+ /dev/ttyF[n] -> /dev/ttf/[n] n = 0 - 255
+ /dev/cuf[n] -> /dev/cuf/[n] n = 0 - 255
+
+Only devices for existing ports and boards will be created.
+
+You do not need to run ip2mkdev if you are using devfs and only want to
+use the devfs native device names.
+
4. USING THE DRIVERS
use the ip2mkdev script, you must have procfs enabled and the proc file
system mounted on /proc.
-6. NOTES
+You do not need to run ip2mkdev if you are using devfs and only want to
+use the devfs native device names.
+
+
+6. DEVFS
+
+DEVFS is the DEVice File System available as an add on package for the
+2.2.x kernels and available as a configuration option in 2.3.46 and higher.
+Devfs allows for the automatic creation and management of device names
+under control of the device drivers themselves. The Devfs namespace is
+hierarchial and reduces the clutter present in the normal flat /dev
+namespace. Devfs names and conventional device names may be intermixed.
+A userspace daemon, devfsd, exists to allow for automatic creation and
+management of symbolic links from the devfs name space to the conventional
+names. More details on devfs can be found on the DEVFS home site at
+<http://www.atnf.csiro.au/~rgooch/linux/> or in the file kernel
+documenation files, .../linux/Documenation/filesystems/devfs/REAME.
+
+If you are using devfs, existing devices are automatically created within
+the devfs name space. Normal devices will be ttf/0 - ttf/255 and callout
+devices will be cuf/0 - cuf/255. With devfs installed, ip2mkdev will
+create symbolic links in /dev from the old conventional names to the newer
+devfs names as follows:
+
+ /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3
+ /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3
+ /dev/ttyF[n] -> /dev/ttf/[n] n = 0 - 255
+ /dev/cuf[n] -> /dev/cuf/[n] n = 0 - 255
+
+Only devices for existing ports and boards will be created.
+
+You do not need to run ip2mkdev if you are using devfs and only want to
+use the devfs native device names.
+
+
+7. NOTES
This is a release version of the driver, but it is impossible to test it
in all configurations of Linux. If there is any anomalous behaviour that
does not match the standard serial port's behaviour please let us know.
-7. ip2mkdev shell script
+8. ip2mkdev shell script
Previously, this script was simply attached here. It is now attached as a
shar archive to make it easier to extract the script from the documentation.
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
-# Made on 1999-12-17 16:06 EST by <root@alcove.wittsend.com>.
-# Source directory was `/mnt2/src/linux-2.3.33/Documentation'.
+# Made on 2000-03-10 11:55 EST by <root@wittsend.wittsend.com>.
+# Source directory was `/mnt1/src/linux-2.3.50c/Documentation'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
-# 3300 -rwxr-xr-x ip2mkdev
+# 4061 -rwxr-xr-x ip2mkdev
#
save_IFS="${IFS}"
IFS="${IFS}:"
fi
rm -f 1231235999 $$.touch
#
-if mkdir _sh06360; then
+if mkdir _sh17088; then
$echo 'x -' 'creating lock directory'
else
$echo 'failed to create lock directory'
$echo 'x -' extracting 'ip2mkdev' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' &&
#!/bin/sh -
-X
+#
# ip2mkdev
#
# Make or remove devices as needed for Computone Intelliport drivers
# with it. That prevents us from screwing up open ttys, ownership
# and permissions on a running system!
#
-# This script will NOT remove devices that no longer exist because
-# their board or interface box has been removed. If you want to get
-# rid of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
-# before running this script, which will then recreate all the valid
-# devices
+# This script will NOT remove devices that no longer exist if their
+# board or interface box has been removed. If you want to get rid
+# of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
+# before running this script. Running this script will then recreate
+# all the valid devices.
#
# =mhw=
# Michael H. Warfield
# mhw@wittsend.com
#
+# Updated 03/09/2000 for devfs support in ip2 drivers. =mhw=
+#
+X
+if test -d /dev/ip2 ; then
+# This is devfs mode... We don't do anything except create symlinks
+# from the real devices to the old names!
+X cd /dev
+X echo "Creating symbolic links to devfs devices"
+X for i in `ls ip2` ; do
+X if test ! -L ip2$i ; then
+X # Remove it incase it wasn't a symlink (old device)
+X rm -f ip2$i
+X ln -s ip2/$i ip2$i
+X fi
+X done
+X for i in `ls ttf` ; do
+X if test ! -L ttyF$i ; then
+X # Remove it incase it wasn't a symlink (old device)
+X rm -f ttyF$i
+X ln -s ttyf/$i ttyF$i
+X fi
+X done
+X for i in `ls cuf` ; do
+X if test ! -L cuf$i ; then
+X # Remove it incase it wasn't a symlink (old device)
+X rm -f cuf$i
+X ln -s cuf/$i cuf$i
+X fi
+X done
+X exit 0
+fi
+X
if test ! -f /proc/tty/drivers
then
X echo "\
# Ok... So we got the driver loaded and we can locate the procfs files.
# Next we need our major numbers.
X
-TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tty/!d' -e 's/.*tty.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
-CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu.[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
+TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
+CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2`
X
echo "\
X
Xexit 0
SHAR_EOF
- $shar_touch -am 1217160599 'ip2mkdev' &&
+ $shar_touch -am 03101153100 'ip2mkdev' &&
chmod 0755 'ip2mkdev' ||
$echo 'restore of' 'ip2mkdev' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'ip2mkdev:' 'MD5 check failed'
-eccd181f4a2005e47a969fc83885df61 ip2mkdev
+b0671abeba07b0a9266b70aaf24509b3 ip2mkdev
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`"
- test 3300 -eq "$shar_count" ||
- $echo 'ip2mkdev:' 'original size' '3300,' 'current size' "$shar_count!"
+ test 4061 -eq "$shar_count" ||
+ $echo 'ip2mkdev:' 'original size' '4061,' 'current size' "$shar_count!"
fi
fi
-rm -fr _sh06360
+rm -fr _sh17088
exit 0
different situations. We also investigate the complex topic of
DMA".
+ * Title: "Device Drivers Concluded"
+ Author: Georg v. Zezschwitz.
+ URL: http://www2.linuxjournal.com/lj-issues/issue28/1287.html
+ Keywords: address spaces, pages, pagination, page management,
+ demand loading, swapping, memory protection, memory mapping, mmap,
+ virtual memory areas (VMAs), vremap, PCI.
+ Description: Finally, the above turned out into a five articles
+ series. This latest one's introduction reads: "This is the last of
+ five articles about character device drivers. In this final
+ section, Georg deals with memory mapping devices, beginning with
+ an overall description of the Linux memory management concepts".
+
* Title: "Network Buffers And Memory Management"
Author: Alan Cox.
URL: http://www.ssc.com/lj/issue30/kk30.html
Description: 68 pages paper on writing character drivers. A little
bit old (1.993, 1.994) although still useful.
+ * Title: "Design and Implementation of the Second Extended
+ Filesystem"
+ Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
+ URL: http://web.mit.edu/tytso/www/linux/ext2intro.html
+ Keywords: ext2, linux fs history, inode, directory, link, devices,
+ VFS, physical structure, performance, benchmarks, ext2fs library,
+ ext2fs tools, e2fsck.
+ Description: Paper written by three of the top ext2 hackers.
+ Covers Linux filesystems history, ext2 motivation, ext2 features,
+ design, physical structure on disk, performance, benchmarks,
+ e2fsck's passes description... A must read!
+ Notes: This paper was first published in the Proceedings of the
+ First Dutch International Symposium on Linux, ISBN 90-367-0385-9.
+
* Title: "The Second Extended Filesystem"
Author: Matthew Wilcox.
URL: http://pocket.fluff.org/~mrw/linux/ext2.txt
Keywords: ext2, filesystem.
- Description: Description of ext2's blocks, directories, inodes ...
+ Description: Description of ext2's blocks, directories, inodes...
+ Notes: Seems to be DOWN. Anyone knows another link for it?
* Title: "Analysis of the Ext2fs structure"
Author: Louis-Dominique Dubeau.
Description: Description of ext2's blocks, directories, inodes,
bitmaps, invariants ...
+ * Title: "Journaling the Linux ext2fs Filesystem"
+ Author: Stephen C. Tweedie.
+ URL:
+ ftp://ftp.uk.linux.org:/pub/linux/sct/fs/jfs/journal-design.ps.gz
+ Keywords: ext3, journalist.
+ Description: Excellent 8-pages paper explaining the journaling
+ capabilities added to ext2 by the author, showing different
+ problems faced and the alternatives chosen.
+
* Title: "Kernel API changes from 2.0 to 2.2"
Author: Richard Gooch.
URL:
* Title: "Kernel API changes from 2.2 to 2.3"
Author: Richard Gooch.
URL:
- http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.2.html
+ http://www.atnf.csiro.au/~rgooch/linux/docs/porting-to-2.3.html
Keywords: 2.3, changes.
Description: Kernel functions/structures/variables which changed
from 2.2.x to 2.3.x.
want a mechanism that is scalable. This means a large number of
inactive FDs cost very little in memory and CPU time to manage".
+ * Title: "The Kernel Hacking HOWTO"
+ Author: Various Talented People, and Rusty.
+ URL: http://www.samba.org/~netfilter/kernel-hacking-HOWTO.html
+ Keywords: HOWTO, kernel contexts, deadlock, locking, modules,
+ symbols, return conventions.
+ Description: From the Introduction: "Please understand that I
+ never wanted to write this document, being grossly underqualified,
+ but I always wanted to read it, and this was the only way. I
+ simply explain some best practices, and give reading entry-points
+ into the kernel sources. I avoid implementation details: that's
+ what the code is for, and I ignore whole tracts of useful
+ routines. This document assumes familiarity with C, and an
+ understanding of what the kernel is, and how it is used. It was
+ originally written for the 2.3 kernels, but nearly all of it
+ applies to 2.2 too; 2.0 is slightly different. ".
+
+ * Title: "ALSA 0.5.0 Developer documentation"
+ Author: Stephan 'Jumpy' Bartels .
+ URL: http://www.math.TU-Berlin.de/~sbartels/alsa/
+ Keywords: ALSA, sound, soundcard, driver, lowlevel, hardware.
+ Description: Advanced Linux Sound Architecture for developers,
+ both at kernel and user-level sides. Work in progress. ALSA is
+ supposed to be Linux's next generation sound architecture.
+
+ * Title: "Programming Guide for Linux USB Device Drivers"
+ Author: Detlef Fliegl.
+ URL: http://usb.in.tum.de/usbdoc/
+ Keywords: USB, universal serial bus.
+ Description: A must-read. From the Preface: "This document should
+ give detailed information about the current state of the USB
+ subsystem and its API for USB device drivers. The first section
+ will deal with the basics of USB devices. You will learn about
+ different types of devices and their properties. Going into detail
+ you will see how USB devices communicate on the bus. The second
+ section gives an overview of the Linux USB subsystem [2] and the
+ device driver framework. Then the API and its data structures will
+ be explained step by step. The last section of this document
+ contains a reference of all API calls and their return codes".
+ Notes: Beware: the main page states: "This document may not be
+ published, printed or used in excerpts without explicit permission
+ of the author". Fortunately, it may still be read...
+
+ * Title: "Tour Of the Linux Kernel Source"
+ Author: Vijo Cherian.
+ URL: http://www.geocities.com/vijoc/tolks/tolks.html
+ Keywords: .
+ Description: A classic of this page! Was lost for a while and is
+ back again. Thanks Vijo! TOLKS: the name says it all. A tour of
+ the sources, describing directories, files, variables, data
+ structures... It covers general stuff, device drivers,
+ filesystems, IPC and Networking Code.
+
+ * Title: "Linux Kernel Mailing List Glossary"
+ Author: John Levon.
+ URL: http://www.movement.uklinux.net/glossary.html
+ Keywords: glossary, terms, linux-kernel.
+ Description: From the introduction: "This glossary is intended as
+ a brief description of some of the acronyms and terms you may hear
+ during discussion of the Linux kernel".
+
+ * Title: "Linux Kernel Locking HOWTO"
+ Author: Various Talented People, and Rusty.
+ URL:
+ http://netfilter.kernelnotes.org/unreliable-guides/kernel-locking-
+ HOWTO.html
+ Keywords: locks, locking, spinlock, semaphore, atomic, race
+ condition, bottom halves, tasklets, softirqs.
+ Description: The title says it all: document describing the
+ locking system in the Linux Kernel either in uniprocessor or SMP
+ systems.
+ Notes: "It was originally written for the later (>2.3.47) 2.3
+ kernels, but most of it applies to 2.2 too; 2.0 is slightly
+ different". Freely redistributable under the conditions of the GNU
+ General Public License.
+
BOOKS: (Not on-line)
* Title: "Linux Device Drivers"
* Title: "Linux Core Kernel Commentary. Guide to Insider's Knowledge
on the Core Kernel od the Linux Code"
Author: Scott Maxwell.
- Publisher: ???.
+ Publisher: Coriolis.
Date: 1999.
Pages: 592.
ISBN: 1-57610-469-9
- Notes: CD-ROM included.
+ Notes: CD-ROM included. Line by line commentary of the kernel
+ code.
+
+ * Title: "Linux IP Stacks Commentary"
+ Author: Stephen Satchell and HBJ Clifford.
+ Publisher: Coriolis.
+ Date: 2000.
+ Pages: ???.
+ ISBN: 1-57610-470-2
+ Notes: Line by line source code commentary book.
+
+ * Title: "Programming for the real world - POSIX.4"
+ Author: Bill O. Gallmeister.
+ Publisher: O'Reilly & Associates, Inc..
+ Date: 1995.
+ Pages: ???.
+ ISBN: I-56592-074-0
+ Notes: Though not being directly about Linux, Linux aims to be
+ POSIX. Good reference.
MISCELLANEOUS:
- * Name: Linux Source Driver.
+ * Name: "Linux Source Driver"
URL: http://lsd.linux.cz
Keywords: Browsing source code.
Description: "Linux Source Driver (LSD) is an application, which
and variables) and LSD can generate patches for you on the fly
(files, directories or kernel)".
- * Name: Cross-Referencing Linux.
+ * Name: "Cross-Referencing Linux"
URL: http://lxr.linux.no/source/
Keywords: Browsing source code.
Description: Another web-based Linux kernel source code browser.
Lots of cross references to variables and functions. You can see
where they are defined and where they are used.
- * Name: Linux Weekly News.
+ * Name: "Linux Weekly News"
URL: http://lwn.net
Keywords: latest kernel news.
Description: The title says it all. There's a fixed kernel section
summarizing developers' work, bug fixes, new features and versions
produced during the week. Published every Thursday.
- * Name: Kernel Traffic.
+ * Name: "Kernel Traffic"
URL: http://kt.linuxcare.com
Keywords: linux-kernel mailing list, weekly kernel news.
Description: Weekly newsletter covering the most relevant
discussions of the linux-kernel mailing list.
- * Name: CuTTiNG.eDGe.LiNuX.
+ * Name: "CuTTiNG.eDGe.LiNuX"
URL: http://edge.kernelnotes.org
Keywords: changelist.
Description: Site which provides the changelist for every kernel
the patches and describes them. Pointers to the patches are there,
too.
- * Name: New linux-kernel Mailing List FAQ.
+ * Name: "New linux-kernel Mailing List FAQ"
URL: Original site:
http://www.altern.org/andrebalsa/doc/lkml-faq.html
URL: U.S. mirror site:
Description: Set of slides, presumably from a presentation on the
Linux VFS layer. Covers version 2.1.x, with dentries and the
dcache.
+
+ * Name: "Gary's Enciclopedia - The Linux Kernel"
+ Author: Gary (I suppose...).
+ URL: http://members.aa.net/~swear/pedia/kernel.html
+ Keywords: links, not found here?.
+ Description: Gary's Enciclopedia exists to allow the rapid finding
+ of documentation and other information of interest to GNU/Linux
+ users. It has about 4000 links to external pages in 150 major
+ categories. This link is for kernel-specific links, documents,
+ sites... Look there if you could not find here whar you were
+ looking for.
+
+ * Name: "The home page of Linux-MM"
+ Author: The Linux-MM team.
+ URL: http://www.linux.eu.org/Linux-MM/
+ Keywords: memory management, Linux-MM, mm patches, TODO, docs,
+ mailing list.
+ Description: Site devoted to Linux Memory Mangement development.
+ Memory related patches, HOWTOs, links, mm developers... Don't miss
+ it if you are interested in memory management development!
+
+ * Name: "Kernel Newbies IRC Channel"
+ URL: http://www.surriel.com/kernelnewbies.shtml
+ Keywords: IRC, newbies, channel, asking doubts.
+ Description: #kernelnewbies on irc.openprojects.net. From the web
+ page: "#kernelnewbies is an IRC network dedicated to the 'newbie'
+ kernel hacker. The audience mostly consists of people who are
+ learning about the kernel, working on kernel projects or
+ professional kernel hackers that want to help less seasoned kernel
+ people. [...] #kernelnewbies is on the Open Projects IRC Network,
+ try irc.openprojects.net or irc.<country>.openprojects.net as your
+ server and then /join #kernelnewbies".
+
+ * Name: "linux-kernel mailing list archives and search engines"
+ URL: http://www.uwsg.indiana.edu/hypermail/linux/kernel/index.html
+ URL: http://www.kernelnotes.org/lnxlists/linux-kernel/
+ Keywords: linux-kernel, archives, search.
+ Description: Some of the linux-kernel mailing list archivers. If
+ you have a better/another one, please let me know.
_________________________________________________________________
- Document last updated on Tue Nov 30 11:20:00 CET 1999
+ Document last updated on Mon Apr 17 18:07:07 CEST 2000
ARM PORT
P: Russell King
M: linux@arm.linux.org.uk
-L: linux-arm@vger.rutgers.edu
+L: linux-arm-kernel@lists.arm.linux.org.uk
W: http://www.arm.linux.org.uk/
S: Maintained
pcibios_align_resource(void *data, struct resource *res, unsigned long size)
{
struct pci_dev *dev = data;
+ struct pci_controler *hose = dev->sysdata;
unsigned long alignto;
unsigned long start = res->start;
if (res->flags & IORESOURCE_IO) {
+ /* Make sure we start at our min on all hoses */
+ if (start - hose->io_space->start < PCIBIOS_MIN_IO)
+ start = PCIBIOS_MIN_IO + hose->io_space->start;
+
/*
* Aligning to 0x800 rather than the minimum base of
* 0x400 is an attempt to avoid having devices in
* probes for EISA cards.
*
* Adaptecs, especially, resent such intrusions.
+ *
+ * The de4x5 driver has the eisa probe conditionalized
+ * out for Alpha, so lower the minimum base back to 0x400.
*/
- alignto = MAX(0x800, size);
+ alignto = MAX(0x400, size);
start = ALIGN(start, alignto);
}
else if (res->flags & IORESOURCE_MEM) {
+ /* Make sure we start at our min on all hoses */
+ if (start - hose->mem_space->start < PCIBIOS_MIN_MEM)
+ start = PCIBIOS_MIN_MEM + hose->io_space->start;
+
/*
* The following holds at least for the Low Cost
* Alpha implementation of the PCI interface:
pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
{
/* Update device resources. */
-
+ struct pci_controler *hose = (struct pci_controler *)bus->sysdata;
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
continue;
if (dev->resource[i].flags & IORESOURCE_IO)
pcibios_fixup_resource(&dev->resource[i],
- bus->resource[0]);
+ hose->io_space);
else if (dev->resource[i].flags & IORESOURCE_MEM)
pcibios_fixup_resource(&dev->resource[i],
- bus->resource[1]);
+ hose->mem_space);
}
pcibios_assign_special(dev);
}
bus->resource[0] = hose->io_space;
bus->resource[1] = hose->mem_space;
+ /* If this is a bridge, get the current bases */
+ if (bus->self) {
+ pci_read_bridge_bases(bus);
+ pcibios_fixup_device_resources(bus->self, bus->parent);
+ }
+
for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
struct pci_dev *dev = pci_dev_b(ln);
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
+ struct pci_controler *hose = dev->sysdata;
int where;
u32 reg;
+ if (resource < PCI_ROM_RESOURCE)
where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ else if (resource == PCI_ROM_RESOURCE)
+ where = dev->rom_base_reg;
+ else {
+ /* Don't update non-standard resources here */
+ return;
+ }
+
+ /* Point root at the hose root */
+ if (res->flags & IORESOURCE_IO)
+ root = hose->io_space;
+ if (res->flags & IORESOURCE_MEM)
+ root = hose->mem_space;
+
reg = (res->start - root->start) | (res->flags & 0xf);
pci_write_config_dword(dev, where, reg);
if ((res->flags & (PCI_BASE_ADDRESS_SPACE
pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges)
{
- ranges->io_start -= bus->resource[0]->start;
- ranges->io_end -= bus->resource[0]->start;
- ranges->mem_start -= bus->resource[1]->start;
- ranges->mem_end -= bus->resource[1]->start;
+ struct pci_controler *hose = (struct pci_controler *)bus->sysdata;
+
+ ranges->io_start -= hose->io_space->start;
+ ranges->io_end -= hose->io_space->start;
+ ranges->mem_start -= hose->mem_space->start;
+ ranges->mem_end -= hose->mem_space->start;
}
int
return 0;
}
+#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
+
+static void __init
+pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+{
+ struct pbus_set_ranges_data inner;
+ struct pci_dev *dev;
+ struct pci_dev *bridge = bus->self;
+ struct pci_controler *hose = bus->sysdata;
+ struct list_head *ln;
+
+ if (!bridge)
+ return; /* host bridge, nothing to do */
+
+ /* set reasonable default locations for pcibios_align_resource */
+ inner.io_start = hose->io_space->start + PCIBIOS_MIN_IO;
+ inner.mem_start = hose->mem_space->start + PCIBIOS_MIN_MEM;
+ inner.io_end = inner.io_start;
+ inner.mem_end = inner.mem_start;
+
+ /* Collect information about how our direct children are layed out. */
+ for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+ int i;
+ dev = pci_dev_b(ln);
+
+ /* Skip bridges for now */
+ if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
+ continue;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource res;
+ unsigned long size;
+
+ memcpy(&res, &dev->resource[i], sizeof(res));
+ size = res.end - res.start + 1;
+
+ if (res.flags & IORESOURCE_IO) {
+ res.start = inner.io_end;
+ pcibios_align_resource(dev, &res, size);
+ inner.io_end = res.start + size;
+ } else if (res.flags & IORESOURCE_MEM) {
+ res.start = inner.mem_end;
+ pcibios_align_resource(dev, &res, size);
+ inner.mem_end = res.start + size;
+ }
+ }
+ }
+
+ /* And for all of the subordinate busses. */
+ for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+ pcibios_size_bridge(pci_bus_b(ln), &inner);
+
+ /* turn the ending locations into sizes (subtract start) */
+ inner.io_end -= inner.io_start;
+ inner.mem_end -= inner.mem_start;
+
+ /* Align the sizes up by bridge rules */
+ inner.io_end = ROUND_UP(inner.io_end, 4*1024);
+ inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
+
+ /* Adjust the bridge's allocation requirements */
+ bridge->resource[0].end = bridge->resource[0].start + inner.io_end;
+ bridge->resource[1].end = bridge->resource[1].start + inner.mem_end;
+
+ /* adjust parent's resource requirements */
+ if (outer) {
+ outer->io_end = ROUND_UP(outer->io_end, 4*1024);
+ outer->io_end += inner.io_end;
+
+ outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
+ outer->mem_end += inner.mem_end;
+ }
+}
+
+#undef ROUND_UP
+
+static void __init
+pcibios_size_bridges(void)
+{
+ struct list_head *ln1, *ln2;
+
+ for(ln1=pci_root_buses.next; ln1 != &pci_root_buses; ln1=ln1->next)
+ for(ln2 = pci_bus_b(ln1)->children.next;
+ ln2 != &pci_bus_b(ln1)->children;
+ ln2 = ln2->next)
+ pcibios_size_bridge(pci_bus_b(ln2), NULL);
+}
+
void __init
common_init_pci(void)
{
next_busno += 1;
}
+ pcibios_size_bridges();
pci_assign_unassigned_resources();
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
pci_set_bus_ranges();
#include <linux/linkage.h>
.section ".start", #alloc, #execinstr
+
+/*
+ * Debugging stuff
+ */
+ .macro kputc,val
+ mov r0, \val
+ bl putc
+ .endm
+
+ .macro kphex,val,len
+ mov r0, \val
+ mov r1, #\len
+ bl phex
+ .endm
+
+ .macro debug_reloc_start
+#ifdef DEBUG
+ kputc #'\n'
+ kphex r6, 8
+ kputc #':'
+ kphex r5, 8
+ kputc #'-'
+ kphex r8, 8
+ kputc #'>'
+ kphex r4, 8
+ kputc #'\n'
+#endif
+ .endm
+
+ .macro debug_reloc_end
+#ifdef DEBUG
+ mov r8, r0
+ kphex r5, 8
+ kputc #'-'
+ kphex r8, 8
+ kputc #'\n'
+ mov r0, r4
+ bl memdump
+#endif
+ .endm
+
+#if 0
+ .macro loadsp, rb
+ mov \rb, #0x7c000000
+ .endm
+
+ .macro writeb, rb
+ strb \rb, [r3, #0x3f8]
+ .endm
+#else
+ .macro loadsp, rb
+ mov \rb, #0x03000000
+ orr \rb, \rb, #0x00010000
+ .endm
+
+ .macro writeb, rb
+ strb \rb, [r3, #0x3f8 << 2]
+ .endm
+#endif
+
/*
* sort out different calling conventions
*/
cmp r2, r3
blt 1b
+ bl cache_on
+
mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max
cmp r2, r3
blt 1b
- eor r1, r6, #0x44 << 24 @ SA-110 or SA-1100?
- eor r1, r1, #0x01 << 16
- eor r1, r1, #0xa1 << 8
- movs r1, r1, lsr #5
- mcreq p15, 0, r1, c7, c7, 0 @ flush I & D-cache
- mcreq p15, 0, r1, c7, c10, 4 @ drain WB
+ bl cache_clean_flush
add pc, r5, r0 @ call relocation code
+/*
+ * Page table physical address list
+ */
+ .align 5
+ .type pgtable,#object
+pgtable: .word 0x00004000 @ 0x00
+ .word 0x10004000 @ 0x01
+ .word 0x00000000 @ 0x02
+ .word 0x40004000 @ 0x03
+ .word 0x00004000 @ 0x04
+ .word 0x00004000 @ 0x05
+ .word 0x00004000 @ 0x06
+ .word 0x80004000 @ 0x07
+ .word 0x00004000 @ 0x08
+ .word 0x00000000 @ 0x09
+ .word 0x00000000 @ 0x0a
+ .word 0x00000000 @ 0x0b
+ .word 0x00000000 @ 0x0c
+ .word 0x00000000 @ 0x0d
+ .word 0x10004000 @ 0x0e
+ .word 0x08004000 @ 0x0f
+ .word 0xc0004000 @ 0x10
+ .size pgtable,. - pgtable
+1:
+
+ .type LC0, #object
+LC0: .word __bss_start
+ .word _end
+ .word _load_addr
+ .word _start
+ .word user_stack+4096
+ .size LC0, . - LC0
+
+ .align 5
+cache_on: ldr r1, proc_sa110_type
+ eor r1, r1, r6
+ movs r1, r1, lsr #5
+ movne pc, lr
+ cmp r7, #(1b - pgtable) >> 2
+ movge pc, lr
+ adr r3, pgtable
+ ldr r3, [r3, r7, lsl #2]
+ teq r3, #0
+ moveq pc, lr
+/*
+ * Initialise the page tables
+ */
+ mov r0, r3
+ mov r8, r0, lsr #18
+ mov r8, r8, lsl #18 @ start of RAM
+ add r9, r8, #0x20000000 @ the maximum RAM size
+ mov r1, #0x12
+ orr r1, r1, #3 << 10
+ add r2, r3, #16384
+1: cmp r1, r8 @ if virt > start of RAM
+ orrge r1, r1, #0x0c @ set cacheable, bufferable
+ cmp r1, r9 @ if virt > end of RAM
+ bicge r1, r1, #0x0c @ clear cacheable, bufferable
+ str r1, [r0], #4 @ 1:1 mapping
+ add r1, r1, #1048576
+ teq r0, r2
+ bne 1b
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
+ mcr p15, 0, r0, c8, c7 @ flush I,D TLBs
+ mcr p15, 0, r3, c2, c0 @ load page table pointer
+ mov r0, #-1
+ mcr p15, 0, r0, c3, c0 @ load domain access register
+ mrc p15, 0, r0, c1, c0
+ orr r0, r0, #0x1000 @ I-cache enable
+#ifndef DEBUG
+ orr r0, r0, #0x003d @ Write buffer, mmu
+#endif
+ mcr p15, 0, r0, c1, c0
+ mov pc, lr
+
/*
* r0 = decompressed kernel length
* r1-r3 = unused
* r7 = architecture ID
* r8-r14 = unused
*/
+ .align 5
reloc_start: add r8, r5, r0
-#if 0
- mov r0, #'\n'
- bl putc
- mov r0, r6
- mov r1, #8
- bl phex
- mov r0, #':'
- bl putc
- mov r0, r5
- mov r1, #8
- bl phex
- mov r0, #'-'
- bl putc
- mov r0, r8
- mov r1, #8
- bl phex
- mov r0, #'>'
- bl putc
- mov r0, r4
- mov r1, #8
- bl phex
- mov r0, #'\n'
- bl putc
-#endif
- mov r0, r8
+ debug_reloc_start
mov r1, r4
1:
.rept 4
- ldmia r5!, {r2, r3, r8 - r13} @ relocate kernel
- stmia r1!, {r2, r3, r8 - r13}
+ ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel
+ stmia r1!, {r0, r2, r3, r9 - r13}
.endr
- cmp r5, r0
+ cmp r5, r8
blt 1b
-#if 0
- mov r8, r0
- mov r0, r5
- mov r1, #8
- bl phex
- mov r0, #'-'
- bl putc
- mov r0, r8
- mov r1, #8
- bl phex
- mov r0, #'\n'
- bl putc
- mov r0, r4
- bl memdump
-#endif
- eor r0, r6, #0x44 << 24 @ SA-110 or SA-1100?
- eor r0, r0, #0x01 << 16
- eor r0, r0, #0xa1 << 8
- movs r0, r0, lsr #5
- mcreq p15, 0, r0, c7, c7, 0 @ flush I cache
- mcreq p15, 0, r1, c7, c10, 4 @ drain WB
-
-call_kernel: mov r0, #0
+ debug_reloc_end
+
+call_kernel: bl cache_clean_flush
+ bl cache_off
+ mov r0, #0
mov r1, r7 @ restore architecture number
mov pc, r4 @ call kernel
-phexbuf: .space 12
+ .type proc_sa110_type,#object
+proc_sa110_type:
+ .word 0x4401a100
+ .size proc_sa110_type, . - proc_sa110_type
-#if 0
- .macro loadsp, rb
- mov \rb, #0x7c000000
- .endm
+/*
+ * Turn off StrongARM cache and MMU
+ */
+ .align 5
+cache_off: ldr r1, proc_sa110_type
+ eor r1, r1, r6
+ movs r1, r1, lsr #5
+ movne pc, lr
+ mrc p15, 0, r0, c1, c0
+ bic r0, r0, #0x000d
+ mcr p15, 0, r0, c1, c0
+ mov pc, lr
- .macro writeb, rb
- strb \rb, [r3, #0x3f8]
- .endm
-#else
- .macro loadsp, rb
- mov \rb, #0x03000000
- orr \rb, \rb, #0x00010000
- .endm
+/*
+ * Clean and flush the cache to maintain consistency.
+ */
+ .align 5
+cache_clean_flush:
+ ldr r1, proc_sa110_type @ SA-110 or SA-1100?
+ eor r1, r1, r6
+ movs r1, r1, lsr #5
+ movne pc, lr
- .macro writeb, rb
- strb \rb, [r3, #0x3f8 << 2]
- .endm
-#endif
+ bic r1, pc, #31
+ add r2, r1, #32768
+1: ldr r12, [r1], #32
+ teq r1, r2
+ bne 1b
+
+ mcr p15, 0, r1, c7, c7, 0 @ flush I cache
+ mcr p15, 0, r1, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+#ifdef DEBUG
+ .type phexbuf,#object
+phexbuf: .space 12
+ .size phexbuf, . - phexbuf
phex: adr r3, phexbuf
mov r2, #0
cmp r11, #64
blt 2b
mov pc, r10
+#endif
+
reloc_end:
-LC0: .word __bss_start
- .word _end
- .word _load_addr
- .word _start
- .word user_stack+4096
.align
-
.section ".stack"
user_stack: .space 4096
define_bool CONFIG_ISA_DMA n
fi
-define_bool CONFIG_SBUS n
-define_bool CONFIG_PCMCIA n
-
if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
bool 'Kernel-mode alignment trap handler' CONFIG_ALIGNMENT_TRAP
fi
fi
fi
-
#source drivers/misc/Config.in
if [ "$CONFIG_VT" = "y" ]; then
# Automatically generated make config: don't edit
#
CONFIG_ARM=y
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
#
# System and processor type
CONFIG_ARCH_EBSA110=y
# CONFIG_FOOTBRIDGE is not set
# CONFIG_ARCH_ACORN is not set
-# CONFIG_ISA_DMA is not set
CONFIG_CPU_32=y
# CONFIG_CPU_26 is not set
-# CONFIG_CPU_ARM2 is not set
-# CONFIG_CPU_ARM3 is not set
-# CONFIG_CPU_ARM6 is not set
-# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_32v4=y
CONFIG_CPU_SA110=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_TEXT_SECTIONS is not set
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
#
# Loadable module support
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_NWFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=m
+CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Parallel port support
+#
CONFIG_PARPORT=y
CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_PC_SUPERIO=y
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8"
CONFIG_LEDS=y
#
-# Plug and Play support
+# I2O device support
#
-# CONFIG_PNP is not set
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
#
-# Block devices
+# Plug and Play configuration
#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
#
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Block devices
#
-# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
#
# Additional Block Devices
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_HD is not set
#
# Character devices
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
CONFIG_PRINTER=m
-CONFIG_PRINTER_READBACK=y
-CONFIG_MOUSE=y
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
#
# Mice
#
-# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
+CONFIG_MOUSE=y
# CONFIG_PSMOUSE is not set
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
# CONFIG_QIC02_TAPE is not set
-CONFIG_WATCHDOG=y
#
# Watchdog Cards
#
+CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
# CONFIG_WDT is not set
CONFIG_SOFT_WATCHDOG=y
# CONFIG_PCWATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_MIXCOMWD is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
# Video For Linux
#
# CONFIG_VIDEO_DEV is not set
-
-#
-# Joystick support
-#
-# CONFIG_JOYSTICK is not set
# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
# Networking options
#
CONFIG_PACKET=m
-# CONFIG_NETLINK is not set
-CONFIG_FIREWALL=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_TOS is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_ROUTE_LARGE_TABLES is not set
CONFIG_IP_PNP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
-CONFIG_IP_FIREWALL=y
-CONFIG_IP_ALWAYS_DEFRAG=y
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-CONFIG_IP_MASQUERADE_ICMP=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_MOD is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_ARPD is not set
CONFIG_SYN_COOKIES=y
#
# (it is safe to leave these untouched)
#
-# CONFIG_INET_RARP is not set
# CONFIG_SKB_LARGE is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_FTP=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_LIMIT=y
+# CONFIG_IP_NF_MATCH_MAC is not set
+CONFIG_IP_NF_MATCH_MARK=y
+CONFIG_IP_NF_MATCH_MULTIPORT=y
+CONFIG_IP_NF_MATCH_TOS=y
+CONFIG_IP_NF_MATCH_STATE=y
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=y
+CONFIG_IP_NF_TARGET_MARK=y
+CONFIG_IP_NF_TARGET_LOG=y
# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
#
#
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
#
# QoS and/or fair queueing
# CONFIG_HAMRADIO is not set
#
-# IrDA subsystem support
+# IrDA (infrared) support
#
# CONFIG_IRDA is not set
# Network device support
#
CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
CONFIG_NET_ETHERNET=y
CONFIG_ARM_AM79C961A=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
# CONFIG_PLIP is not set
CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_SLIP is not set
#
-# CCP compressors for PPP are only built as modules.
+# Wireless LAN (non-hamradio)
#
-# CONFIG_SLIP is not set
# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
# CONFIG_TR is not set
-# CONFIG_SHAPER is not set
-# CONFIG_HOSTESS_SV11 is not set
-# CONFIG_COSA is not set
+# CONFIG_NET_FC is not set
# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
# CONFIG_SCSI is not set
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
CONFIG_MINIX_FS=y
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_EXT2_FS is not set
# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
#
#
# Partition Types
#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
# CONFIG_MSDOS_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ACORN_PARTITION is not set
# CONFIG_NLS is not set
+#
+# USB support
+#
+# CONFIG_USB is not set
+
#
# Kernel hacking
#
-CONFIG_FRAME_POINTER=y
+# CONFIG_FRAME_POINTER is not set
CONFIG_DEBUG_ERRORS=y
# CONFIG_DEBUG_USER is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_ARTHUR is not set
# CONFIG_DEBUG_LL is not set
/*
* linux/arch/arm/kernel/arch.c
*
- * Architecture specifics
+ * Architecture specific fixups. This is where any
+ * parameters in the params struct are fixed up, or
+ * any additional architecture specific information
+ * is pulled from the params struct.
*/
#include <linux/config.h>
#include <linux/tty.h>
#include <linux/init.h>
+#include <asm/dec21285.h>
#include <asm/elf.h>
#include <asm/setup.h>
#include <asm/system.h>
#include "arch.h"
-extern unsigned int system_rev;
-extern unsigned int system_serial_low;
-extern unsigned int system_serial_high;
-
unsigned int vram_size;
-#ifdef CONFIG_ARCH_ACORN
-unsigned int memc_ctrl_reg;
-unsigned int number_mfm_drives;
-#endif
extern void setup_initrd(unsigned int start, unsigned int size);
extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz);
-/*
- * Architecture specific fixups. This is where any
- * parameters in the params struct are fixed up, or
- * any additional architecture specific information
- * is pulled from the params struct.
- */
+#ifdef CONFIG_ARCH_ACORN
+
+unsigned int memc_ctrl_reg;
+unsigned int number_mfm_drives;
+
static void __init
fixup_acorn(struct machine_desc *desc, struct param_struct *params,
char **cmdline, struct meminfo *mi)
{
-#ifdef CONFIG_ARCH_ACORN
- int i;
-
if (machine_is_riscpc()) {
+ int i;
+
/*
* RiscPC can't handle half-word loads and stores
*/
}
memc_ctrl_reg = params->u1.s.memc_control_reg;
number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
-#endif
}
+#ifdef CONFIG_ARCH_RPC
+MACHINE_START(RISCPC, "Acorn-RiscPC")
+ MAINTAINER("Russell King")
+ BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
+ BOOT_PARAMS(0x10000100)
+ DISABLE_PARPORT(0)
+ DISABLE_PARPORT(1)
+ FIXUP(fixup_acorn)
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_ARC
+MACHINE_START(ARCHIMEDES, "Acorn-Archimedes")
+ MAINTAINER("Dave Gilbert")
+ BOOT_PARAMS(0x0207c000)
+ FIXUP(fixup_acorn)
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_A5K
+MACHINE_START(A5K, "Acorn-A5000")
+ MAINTAINER("Russell King")
+ BOOT_PARAMS(0x0207c000)
+ FIXUP(fixup_acorn)
+MACHINE_END
+#endif
+#endif
+
+#ifdef CONFIG_ARCH_EBSA285
+
static void __init
fixup_ebsa285(struct machine_desc *desc, struct param_struct *params,
char **cmdline, struct meminfo *mi)
ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
}
+MACHINE_START(EBSA285, "EBSA285")
+ MAINTAINER("Russell King")
+ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+ BOOT_PARAMS(0x00000100)
+ VIDEO(0x000a0000, 0x000bffff)
+ FIXUP(fixup_ebsa285)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_NETWINDER
/*
* Older NeTTroms either do not provide a parameters
* page, or they don't supply correct information in
}
}
+MACHINE_START(NETWINDER, "Rebel-NetWinder")
+ MAINTAINER("Russell King/Rebel.com")
+ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+ BOOT_PARAMS(0x00000100)
+ VIDEO(0x000a0000, 0x000bffff)
+ DISABLE_PARPORT(0)
+ DISABLE_PARPORT(2)
+ FIXUP(fixup_netwinder)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_CATS
/*
* CATS uses soft-reboot by default, since
* hard reboots fail on early boards.
ORIG_Y = 24;
}
+MACHINE_START(CATS, "Chalice-CATS")
+ MAINTAINER("Philip Blundell")
+ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+ SOFT_REBOOT
+ FIXUP(fixup_cats)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_CO285
+
static void __init
fixup_coebsa285(struct machine_desc *desc, struct param_struct *params,
char **cmdline, struct meminfo *mi)
{
-#if 0
extern unsigned long boot_memory_end;
extern char boot_command_line[];
mi->bank[0].size = boot_memory_end;
*cmdline = boot_command_line;
-#endif
}
+MACHINE_START(CO285, "co-EBSA285")
+ MAINTAINER("Mark van Doesburg")
+ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000)
+ FIXUP(fixup_coebsa285)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_SA1100
+
+extern void select_sa1100_io_desc(void);
+#define SET_BANK(__nr,__start,__size) \
+ mi->bank[__nr].start = (__start), \
+ mi->bank[__nr].size = (__size)
static void __init
fixup_sa1100(struct machine_desc *desc, struct param_struct *params,
char **cmdline, struct meminfo *mi)
{
-#ifdef CONFIG_ARCH_SA1100
- int i;
- extern struct mem_desc {
- unsigned long phys_start;
- unsigned long length;
- } mem_desc[];
- extern unsigned int mem_desc_size;
-
- for( i = 0; i < mem_desc_size; i++ ) {
- if( i >= NR_BANKS ) {
- printk( __FUNCTION__
- ": mem_desc too large for meminfo structure\n");
- break;
- }
- mi->bank[i].start = mem_desc[i].phys_start;
- mi->bank[i].size = mem_desc[i].length;
+ select_sa1100_io_desc();
+
+ if (machine_is_assabet()) {
+ SET_BANK( 0, 0xc0000000, 32*1024*1024 );
+ mi->nr_banks = 1;
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk( 1, 0, 0, 8192 );
+ setup_initrd( 0xc0800000, 3*1024*1024 );
}
- mi->nr_banks = i;
-
-#if defined(CONFIG_SA1100_BRUTUS)
- ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
- setup_ramdisk( 1, 0, 0, 8192 );
- setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
-#elif defined(CONFIG_SA1100_EMPEG)
- ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */
- setup_ramdisk( 1, 0, 0, 4096 );
- setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) );
-#elif defined(CONFIG_SA1100_THINCLIENT)
- ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
- setup_ramdisk( 1, 0, 0, 8192 );
- setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
-#elif defined(CONFIG_SA1100_TIFON)
- ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
- setup_ramdisk(1, 0, 0, 4096);
- setup_initrd( 0xd0000000 + 0x1100004, 0x140000 );
-#elif defined(CONFIG_SA1100_VICTOR)
- ROOT_DEV = MKDEV( 60, 2 );
-
- /* Get command line parameters passed from the loader (if any) */
- if( *((char*)0xc0000000) )
- strcpy( default_command_line, ((char *)0xc0000000) );
-
- /* power off if any problem */
- strcat( default_command_line, " panic=1" );
-#elif defined(CONFIG_SA1100_LART)
- ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
- setup_ramdisk(1, 0, 0, 8192);
- setup_initrd(0xc0400000, 0x00400000);
-#endif
-#endif
-}
-#define NO_PARAMS 0
-#define NO_VIDEO 0, 0
+ else if (machine_is_brutus()) {
+ SET_BANK( 0, 0xc0000000, 4*1024*1024 );
+ SET_BANK( 1, 0xc8000000, 4*1024*1024 );
+ SET_BANK( 2, 0xd0000000, 4*1024*1024 );
+ SET_BANK( 3, 0xd8000000, 4*1024*1024 );
+ mi->nr_banks = 4;
-/*
- * This is the list of all architectures supported by
- * this kernel. This should be integrated with the list
- * in head-armv.S.
- */
-static struct machine_desc machine_desc[] __attribute__ ((__section__ (".arch.info"))) = {
-#ifdef CONFIG_ARCH_EBSA110
- {
- MACH_TYPE_EBSA110,
- "EBSA110", /* RMK */
- 0x00000400,
- NO_VIDEO,
- 1, 0, 1, 0, 1,
- NULL
- },
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk( 1, 0, 0, 8192 );
+ setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
+ }
+
+ else if (machine_is_empeg()) {
+ SET_BANK( 0, 0xc0000000, 4*1024*1024 );
+ SET_BANK( 1, 0xc8000000, 4*1024*1024 );
+ mi->nr_banks = 2;
+
+ ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */
+ setup_ramdisk( 1, 0, 0, 4096 );
+ setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) );
+ }
+
+ else if (machine_is_lart()) {
+ /*
+ * Note that LART is a special case - it doesn't use physical
+ * address line A23 on the DRAM, so we effectively have 4 * 8MB
+ * in two SA1100 banks.
+ */
+ SET_BANK( 0, 0xc0000000, 8*1024*1024 );
+ SET_BANK( 1, 0xc1000000, 8*1024*1024 );
+ SET_BANK( 2, 0xc8000000, 8*1024*1024 );
+ SET_BANK( 3, 0xc9000000, 8*1024*1024 );
+ mi->nr_banks = 4;
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk(1, 0, 0, 8192);
+ setup_initrd(0xc0400000, 4*1024*1024);
+ }
+
+ else if (machine_is_thinclient()) {
+ SET_BANK( 0, 0xc0000000, 16*1024*1024 );
+ mi->nr_banks = 1;
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk( 1, 0, 0, 8192 );
+ setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
+ }
+
+ else if (machine_is_tifon()) {
+ SET_BANK( 0, 0xc0000000, 16*1024*1024 );
+ SET_BANK( 1, 0xc8000000, 16*1024*1024 );
+ mi->nr_banks = 2;
+
+ ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0);
+ setup_ramdisk(1, 0, 0, 4096);
+ setup_initrd( 0xd0000000 + 0x1100004, 0x140000 );
+ }
+
+ else if (machine_is_victor()) {
+ SET_BANK( 0, 0xc0000000, 4*1024*1024 );
+ mi->nr_banks = 1;
+
+ ROOT_DEV = MKDEV( 60, 2 );
+
+ /* Get command line parameters passed from the loader (if any) */
+ if( *((char*)0xc0000000) )
+ strcpy( *cmdline, ((char *)0xc0000000) );
+
+ /* power off if any problem */
+ strcat( *cmdline, " panic=1" );
+ }
+
+}
+
+#ifdef CONFIG_SA1100_ASSABET
+MACHINE_START(ASSABET, "Intel-Assabet")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_RPC
- {
- MACH_TYPE_RISCPC,
- "Acorn-RiscPC", /* RMK */
- 0x10000100,
- NO_VIDEO,
- 1, 1, 0, 0, 0,
- fixup_acorn
- },
+#ifdef CONFIG_SA1100_BITSY
+MACHINE_START(BITSY, "Compaq Bitsy")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ BOOT_PARAMS(0xc0000100)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_NEXUSPCI
- {
- MACH_TYPE_NEXUSPCI,
- "FTV/PCI", /* Philip Blundell */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- },
+#ifdef CONFIG_SA1100_BRUTUS
+MACHINE_START(BRUTUS, "Intel Brutus (SA1100 eval board)")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_EBSA285
- {
- MACH_TYPE_EBSA285,
- "EBSA285", /* RMK */
- 0x00000100,
- 0x000a0000, 0x000bffff,
- 0, 0, 0, 0, 0,
- fixup_ebsa285
- },
+#ifdef CONFIG_SA1100_EMPEG
+MACHINE_START(EMPEG, "empeg MP3 Car Audio Player")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_NETWINDER
- {
- MACH_TYPE_NETWINDER,
- "Rebel-NetWinder", /* RMK */
- 0x00000100,
- 0x000a0000, 0x000bffff,
- 1, 0, 1, 0, 0,
- fixup_netwinder
- },
+#ifdef CONFIG_SA1100_ITSY
+MACHINE_START(ITSY, "Compaq Itsy")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ BOOT_PARAMS(0xc0000100
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_CATS
- {
- MACH_TYPE_CATS,
- "Chalice-CATS", /* Philip Blundell */
- NO_PARAMS,
- 0x000a0000, 0x000bffff,
- 0, 0, 0, 0, 1,
- fixup_cats
- },
+#ifdef CONFIG_SA1100_LART
+MACHINE_START(LART, "LART")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_TBOX
- {
- MACH_TYPE_TBOX,
- "unknown-TBOX", /* Philip Blundell */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- },
+#ifdef CONFIG_SA1100_PLEB
+MACHINE_START(PLEB, "PLEB")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_CO285
- {
- MACH_TYPE_CO285,
- "co-EBSA285", /* Mark van Doesburg */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- fixup_coebsa285
- },
+#ifdef CONFIG_SA1100_THINCLIENT
+MACHINE_START(THINCLIENT, "ADS ThinClient")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_CLPS7110
- {
- MACH_TYPE_CLPS7110,
- "CL-PS7110", /* Werner Almesberger */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- },
+#ifdef CONFIG_SA1100_TIFON
+MACHINE_START(TIFON, "Tifon")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_ARC
- {
- MACH_TYPE_ARCHIMEDES,
- "Acorn-Archimedes",/* RMK/DAG */
- 0x0207c000,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- fixup_acorn
- },
+#ifdef CONFIG_SA1100_VICTOR
+MACHINE_START(VICTOR, "VisuAide Victor")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
#endif
-#ifdef CONFIG_ARCH_A5K
- {
- MACH_TYPE_A5K,
- "Acorn-A5000", /* RMK/PB */
- 0x0207c000,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- fixup_acorn
- },
+#endif
+
+#ifdef CONFIG_ARCH_EBSA110
+MACHINE_START(EBSA110, "EBSA110")
+ MAINTAINER("Russell King")
+ BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
+ BOOT_PARAMS(0x00000400)
+ DISABLE_PARPORT(0)
+ DISABLE_PARPORT(2)
+ SOFT_REBOOT
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_NEXUSPCI
+MACHINE_START(NEXUSPCI, "FTV/PCI")
+ MAINTAINER("Philip Blundell")
+ BOOT_MEM(0x40000000, 0x10000000, 0xe0000000)
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_TBOX
+MACHINE_START(TBOX, "unknown-TBOX")
+ MAINTAINER("Philip Blundell")
+ BOOT_MEM(0x80000000, 0x00400000, 0xe0000000)
+MACHINE_END
+#endif
+#ifdef CONFIG_ARCH_CLPS7110
+MACHINE_START(CLPS7110, "CL-PS7110")
+ MAINTAINER("Werner Almesberger")
+MACHINE_END
#endif
#ifdef CONFIG_ARCH_ETOILE
- {
- MACH_TYPE_ETOILE,
- "Etoile", /* Alex de Vries */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- },
+MACHINE_START(ETOILE, "Etoile")
+ MAINTAINER("Alex de Vries")
+MACHINE_END
#endif
#ifdef CONFIG_ARCH_LACIE_NAS
- {
- MACH_TYPE_LACIE_NAS,
- "LaCie_NAS", /* Benjamin Herrenschmidt */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- },
+MACHINE_START(LACIE_NAS, "LaCie_NAS")
+ MAINTAINER("Benjamin Herrenschmidt")
+MACHINE_END
#endif
#ifdef CONFIG_ARCH_CLPS7500
- {
- MACH_TYPE_CLPS7500,
- "CL-PS7500", /* Philip Blundell */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- },
+MACHINE_START(CLPS7500, "CL-PS7500")
+ MAINTAINER("Philip Blundell")
+ BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
+MACHINE_END
#endif
#ifdef CONFIG_ARCH_SHARK
- {
- MACH_TYPE_SHARK,
- "Shark", /* Alexander Schulz */
- NO_PARAMS,
- 0x06000000, 0x06000000+0x001fffff,
- 0, 0, 0, 0, 0,
- NULL
- },
-#endif
-#ifdef CONFIG_ARCH_SA1100
- {
- MACH_TYPE_SA1100,
- "SA1100-based", /* Nicolas Pitre */
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- fixup_sa1100
- },
+MACHINE_START(SHARK, "Shark")
+ MAINTAINER("Alexander Schulz")
+ BOOT_MEM(0x08000000, 0x40000000, 0xe0000000)
+ VIDEO(0x06000000, 0x061fffff)
+MACHINE_END
#endif
#ifdef CONFIG_ARCH_PERSONAL_SERVER
- {
- MACH_TYPE_PERSONAL_SERVER,
- "Compaq Personal Server",
- NO_PARAMS,
- NO_VIDEO,
- 0, 0, 0, 0, 0,
- NULL
- }
+MACHINE_START(PERSONAL_SERVER, "Compaq Personal Server")
+ MAINTAINER("Jamey Hicks / George France")
+ BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+ BOOT_PARAMS(0x00000100)
+MACHINE_END
#endif
-};
+/*
+ * The size of struct machine_desc
+ * (for assembler code)
+ */
+#define SIZEOF_MACHINE_DESC 40
+
+#ifndef __ASSEMBLY__
+
struct machine_desc {
+ /*
+ * Note! The first four elements are used
+ * by assembler code in head-armv.S
+ */
unsigned int nr; /* architecture number */
+ unsigned int phys_ram; /* start of physical ram */
+ unsigned int phys_io; /* start of physical io */
+ unsigned int virt_io; /* start of virtual io */
+
const char *name; /* architecture name */
unsigned int param_offset; /* parameter page */
+
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
+
unsigned int reserve_lp0 :1; /* never has lp0 */
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
struct param_struct *, char **,
struct meminfo *);
};
+
+/*
+ * Set of macros to define architecture features
+ */
+#define MACHINE_START(_type,_name) \
+const struct machine_desc __mach_desc_##_type \
+ __attribute__((__section__(".arch.info"))) = { \
+ nr: MACH_TYPE_##_type##, \
+ name: _name,
+
+#define MAINTAINER(n)
+
+#define BOOT_MEM(_pram,_pio,_vio) \
+ phys_ram: _pram, \
+ phys_io: _pio, \
+ virt_io: _vio,
+
+#define BOOT_PARAMS(_params) \
+ param_offset: _params,
+
+#define VIDEO(_start,_end) \
+ video_start: _start, \
+ video_end: _end,
+
+#define DISABLE_PARPORT(_n) \
+ reserve_lp##_n##: 1,
+
+#define BROKEN_HLT \
+ broken_hlt: 1,
+
+#define SOFT_REBOOT \
+ soft_reboot: 1,
+
+#define FIXUP(_func) \
+ fixup: _func,
+
+#define MACHINE_END \
+};
+
+#endif
EXPORT_SYMBOL(system_rev);
EXPORT_SYMBOL(system_serial_low);
EXPORT_SYMBOL(system_serial_high);
+EXPORT_SYMBOL(mem_fclk_21285);
EXPORT_SYMBOL(__bug);
EXPORT_SYMBOL(__readwrite_bug);
EXPORT_SYMBOL(enable_irq);
extern void hw_init(void);
-void pcibios_report_device_errors(void)
+void pcibios_report_device_errors(int warn)
{
struct pci_dev *dev;
continue;
pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
- printk(KERN_DEBUG "PCI: %02X:%02X: status %04X on %s\n",
- dev->bus->number, dev->devfn, status, dev->name);
+
+ if (warn)
+ printk(KERN_DEBUG "PCI: %02X:%02X: status %04X "
+ "on %s\n", dev->bus->number, dev->devfn,
+ status, dev->name);
}
}
* - (0x48) enable all memory requests from ISA to be channeled to PCI
* - (0x42) disable ping-pong (as per errata)
* - (0x40) enable PCI packet retry
- * - (0x44) Route INTA to IRQ11
- * - (0x83) don't use CPU park enable, park on last master, disable GAT bit
- * - (0x80) default rotating priorities
- * - (0x81) rotate bank 4
*/
static void __init pci_fixup_83c553(struct pci_dev *dev)
{
pci_write_config_byte(dev, 0x48, 0xff);
pci_write_config_byte(dev, 0x42, 0x00);
pci_write_config_byte(dev, 0x40, 0x22);
- pci_write_config_word(dev, 0x44, 0xb000);
- pci_write_config_byte(dev, 0x83, 0x02);
+
+ /*
+ * We used to set the arbiter to "park on last master"
+ * (bit 1 set), but unfortunately the CyberPro does not
+ * park the bus. We must therefore park on CPU.
+ */
+ pci_write_config_byte(dev, 0x83, 0x00);
+
+ /*
+ * Rotate priorities of each PCI request
+ */
pci_write_config_byte(dev, 0x80, 0xe0);
pci_write_config_byte(dev, 0x81, 0x01);
+
+ /*
+ * Route INTA input to IRQ 11, and set
+ * IRQ11 to be level sensitive.
+ */
+ pci_write_config_word(dev, 0x44, 0xb000);
+ outb(0x08, 0x4d1);
}
static void __init pci_fixup_unassign(struct pci_dev *dev)
dev->resource[0].start = 0;
}
+/*
+ * Prevent the PCI layer from seeing the resources
+ * allocated to this device. These resources are
+ * of no consequence to the PCI layer (they are
+ * handled elsewhere).
+ */
+static void __init pci_fixup_disable(struct pci_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ }
+}
+
/*
* PCI IDE controllers use non-standard I/O port
* decoding, respect it.
struct pci_fixup pcibios_fixups[] = {
{
+ PCI_FIXUP_HEADER,
+ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285,
+ pci_fixup_disable
+ }, {
PCI_FIXUP_HEADER,
PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553,
pci_fixup_83c553
case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000):
case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010):
+ case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000):
return IRQ_NETWINDER_VGA;
default:
#ifndef CONFIG_DEBUG_DC21285_PORT
/* For NetWinder debugging */
.macro addruart,rx
- mov \rx, #0xff000000
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ moveq \rx, #0x7c000000 @ physical
+ movne \rx, #0xff000000 @ virtual
orr \rx, \rx, #0x000003f8
.endm
#elif defined(CONFIG_ARCH_SA1100)
.macro addruart,rx
- mov \rx, #0xf8000000
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ moveq \rx, #0x80000000 @ physical base address
+ movne \rx, #0xf8000000 @ virtual address
add \rx, \rx, #0x00050000 @ Ser3
@add \rx, \rx, #0x00010000 @ Ser1
.endm
ENTRY(printhex2)
mov r1, #2
-printhex: ldr r2, =hexbuf
+printhex: adr r2, hexbuf
add r3, r2, r1
mov r1, #0
strb r1, [r3]
mov r0, #0
b 1b
- .bss
hexbuf: .space 16
#define MAX_SLOTS 21
extern int setup_arm_irq(int, struct irqaction *);
-extern void pcibios_report_device_errors(void);
+extern void pcibios_report_device_errors(int warn);
static unsigned long
-dc21285_base_address(struct pci_dev *dev, int where)
+dc21285_base_address(struct pci_dev *dev)
{
unsigned long addr = 0;
unsigned int devfn = dev->devfn;
- if (dev->bus->number != 0)
+ if (dev->bus->number == 0) {
+ if (PCI_SLOT(devfn) == 0)
+ /*
+ * For devfn 0, point at the 21285
+ */
+ addr = ARMCSR_BASE;
+ else {
+ devfn -= 1 << 3;
+
+ if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
+ addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
+ }
+ } else
addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8);
- else if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
- addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
return addr;
}
static int
dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
- unsigned long addr = dc21285_base_address(dev, where);
+ unsigned long addr = dc21285_base_address(dev);
u8 v;
if (addr)
static int
dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
- unsigned long addr = dc21285_base_address(dev, where);
+ unsigned long addr = dc21285_base_address(dev);
u16 v;
if (addr)
static int
dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
- unsigned long addr = dc21285_base_address(dev, where);
+ unsigned long addr = dc21285_base_address(dev);
u32 v;
if (addr)
static int
dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
- unsigned long addr = dc21285_base_address(dev, where);
+ unsigned long addr = dc21285_base_address(dev);
if (addr)
asm("str%?b %0, [%1, %2]"
static int
dc21285_write_config_word(struct pci_dev *dev, int where, u16 value)
{
- unsigned long addr = dc21285_base_address(dev, where);
+ unsigned long addr = dc21285_base_address(dev);
if (addr)
asm("str%?h %0, [%1, %2]"
static int
dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
- unsigned long addr = dc21285_base_address(dev, where);
+ unsigned long addr = dc21285_base_address(dev);
if (addr)
asm("str%? %0, [%1, %2]"
unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
int warn = time_after_eq(jiffies, next_warn);
+ if (machine_is_netwinder())
+ warn = 0;
+
ctrl |= SA110_CNTL_DISCARDTIMER;
if (warn) {
if (warn)
printk("pc=[<%08lX>]\n", instruction_pointer(regs));
- pcibios_report_device_errors();
+ pcibios_report_device_errors(warn);
*CSR_PCICMD = cmd;
*CSR_SA110_CNTL = ctrl;
#define S_OFF 8
.macro get_softirq, rd
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#error SMP not supported
#else
ldr \rd, __softirq_state
#include <asm/hardware.h>
#include <asm/dec21285.h>
+#include "arch.h"
+
#if (TEXTADDR & 0xffff) != 0x8000
#error TEXTADDR must start at 0xXXXX8000
#endif
* Generally, only serious errors cause this.
*/
__error:
+#ifdef CONFIG_DEBUG_LL
+ mov r8, r0 @ preserve r0
+ adr r0, err_str
+ bl printascii
+ mov r0, r8
+ bl printch
+#endif
#ifdef CONFIG_ARCH_RPC
/*
* Turn the screen red on a error - RiscPC only.
1: mov r0, r0
b 1b
-
+#ifdef CONFIG_DEBUG_LL
+err_str: .asciz "\nError: "
+ .align
+#endif
/*
* Read processor ID register (CP#15, CR0), and determine
__lookup_processor_type:
adr r5, 2f
ldmia r5, {r7, r9, r10}
- sub r5, r5, r9
+ sub r5, r5, r10
add r7, r7, r5
- add r10, r10, r5
+ add r10, r9, r5
mrc p15, 0, r9, c0, c0 @ get processor id
1: ldmia r10, {r5, r6, r8} @ value, mask, mmuflags
eor r5, r5, r9
mov pc, lr
2: .long __proc_info_end
- .long 2b
.long __proc_info_begin
+ .long 2b
+ .long __arch_info_begin
+ .long __arch_info_end
/*
* Lookup machine architecture
* r7 = byte offset into page tables for IO
*/
__lookup_architecture_type:
- cmp r1, #(__arch_types_end - __arch_types_start) / 16
- bge 1f
- adr r4, __arch_types_start
- add r4, r4, r1, lsl #4
- ldmia r4, {r4, r5, r6, r7}
- mov r7, r7, lsr #18
+ adr r4, 2b
+ ldmia r4, {r2, r3, r5, r6, r7} @ throw away r2, r3
+ sub r5, r4, r5
+ add r4, r6, r5
+ add r7, r7, r5
+1: ldr r5, [r4]
+ teq r5, r1
+ beq 2f
+ add r4, r4, #SIZEOF_MACHINE_DESC
+ cmp r4, r7
+ blt 1b
+ mov r7, #0
mov pc, lr
-1: mov r7, #0
+2: ldmib r4, {r5, r6, r7}
mov pc, lr
-
-/*
- * Machine parameters. Each machine requires 4 words, which are:
- *
- * word0: unused
- * word1: physical start address of RAM
- * word2: physical start address of IO
- * word3: virtual start address of IO
- *
- * The IO mappings entered here are used to set up mappings
- * required for debugging information to be shown to the user.
- * paging_init() does the real page table initialisation.
- */
- .type __arch_types_start, #object
- @ 0x00 - DEC EBSA110
-__arch_types_start:
- .long 0
- .long 0
- .long 0xe0000000
- .long 0xe0000000
-
- @ 0x01 - Acorn RiscPC
- .long 0
- .long 0x10000000
- .long 0x03000000
- .long 0xe0000000
-
- @ 0x02 - Unused
- .long 0
- .long 0
- .long 0xe0000000
- .long 0xe0000000
-
- @ 0x03 - NexusPCI
- .long 0
- .long 0x40000000
- .long 0x10000000
- .long 0xe0000000
-
- @ 0x04 - DEC EBSA285
- .long 0
- .long 0
- .long DC21285_ARMCSR_BASE
- .long 0xfe000000
-
- @ 0x05 - Rebel.com NetWinder
- .long 0
- .long 0
- .long DC21285_ARMCSR_BASE
- .long 0xfe000000
-
- @ 0x06 - CATS
- .long 0
- .long 0
- .long DC21285_ARMCSR_BASE
- .long 0xfe000000
-
- @ 0x07 - tbox
- .long 0
- .long 0x80000000
- .long 0x00400000 @ Uart
- .long 0xe0000000
-
- @ 0x08 - DEC EBSA285 as co-processor
- .long 0
- .long 0
- .long DC21285_ARMCSR_BASE @ Physical I/O base address
- .long 0x7cf00000 @ Virtual I/O base address
-
- @ 0x09 - CL-PS7110
- .long 0
- .long 0
- .long 0
- .long 0
-
- @ 0x0a - Acorn Archimedes
- .long 0
- .long 0
- .long 0
- .long 0
-
- @ 0x0b - Acorn A5000
- .long 0
- .long 0
- .long 0
- .long 0
-
- @ 0x0c - Etoile
- .long 0
- .long 0
- .long 0
- .long 0
-
- @ 0x0d - LaCie_NAS
- .long 0
- .long 0
- .long 0
- .long 0
-
- @ 0x0e - CL-PS7500
- .long 0
- .long 0x10000000
- .long 0x03000000
- .long 0xe0000000
-
- @ 0x0f - Digital Shark (DNARD)
- .long 0
- .long 0x08000000
- .long 0x40000000
- .long 0xe0000000
-
- @ 0x10 - SA1100
- .long 0
- .long 0xc0000000
- .long 0x80000000
- .long 0xf8000000
-
- /*
- * Don't add anything here unless you have an
- * architecture number allocated - see
- * Documentation/arm/README
- */
-__arch_types_end:
cliIF();
irq_desc[irq].probing = 0;
irq_desc[irq].triggered = 0;
- if (!irq_desc[irq].noautoenable) {
- irq_desc[irq].enabled = 1;
- irq_desc[irq].unmask(irq);
- }
+ irq_desc[irq].enabled = 1;
+ irq_desc[irq].unmask(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
*/
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/utsname.h>
#include <linux/blk.h>
#include <linux/console.h>
-#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/init.h>
#include <asm/elf.h>
#include <asm/hardware.h>
#endif
extern void paging_init(struct meminfo *);
+extern void bootmem_init(struct meminfo *);
extern void reboot_setup(char *str);
extern void disable_hlt(void);
extern int root_mountflags;
unsigned int system_rev;
unsigned int system_serial_low;
unsigned int system_serial_high;
+unsigned int mem_fclk_21285 = 50000000;
unsigned int elf_hwcap;
#ifdef MULTI_CPU
if (to != command_line)
to -= 1;
- /* If the user specifies memory size, we
+ /*
+ * If the user specifies memory size, we
* blow away any automatically generated
* size.
*/
#endif
}
-#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT)
-#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x))
-
-#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT)
-#define V_PFN_UP(x) O_PFN_UP(__pa(x))
-
-#define PFN_SIZE(x) ((x) >> PAGE_SHIFT)
-#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
- (((unsigned long)(s)) & PAGE_MASK))
-
-/*
- * FIXME: These can be removed when Ingo's cleanup patch goes in
- */
-#define free_bootmem(s,sz) free_bootmem((s)<<PAGE_SHIFT, (sz)<<PAGE_SHIFT)
-#define reserve_bootmem(s,sz) reserve_bootmem((s)<<PAGE_SHIFT, (sz)<<PAGE_SHIFT)
-
-static unsigned int __init
-find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages)
-{
- unsigned int start_pfn, bank, bootmap_pfn;
-
- start_pfn = V_PFN_UP(&_end);
- bootmap_pfn = 0;
-
- /*
- * FIXME: We really want to avoid allocating the bootmap
- * over the top of the initrd.
- */
-#ifdef CONFIG_BLK_DEV_INITRD
- if (initrd_start) {
- if (__pa(initrd_end) > mi->end) {
- printk ("initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx) - disabling initrd\n",
- __pa(initrd_end), mi->end);
- initrd_start = 0;
- initrd_end = 0;
- }
- }
-#endif
-
- for (bank = 0; bank < mi->nr_banks; bank ++) {
- unsigned int start, end;
-
- if (mi->bank[bank].size == 0)
- continue;
-
- start = O_PFN_UP(mi->bank[bank].start);
- end = O_PFN_DOWN(mi->bank[bank].size +
- mi->bank[bank].start);
-
- if (end < start_pfn)
- continue;
-
- if (start < start_pfn)
- start = start_pfn;
-
- if (end <= start)
- continue;
-
- if (end - start >= bootmap_pages) {
- bootmap_pfn = start;
- break;
- }
- }
-
- if (bootmap_pfn == 0)
- BUG();
-
- return bootmap_pfn;
-}
-
-/*
- * Initialise the bootmem allocator.
- */
-static void __init setup_bootmem(struct meminfo *mi)
-{
- unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn;
- unsigned int i;
-
- /*
- * Calculate the physical address of the top of memory.
- */
- mi->end = 0;
- for (i = 0; i < mi->nr_banks; i++) {
- unsigned long end;
-
- if (mi->bank[i].size != 0) {
- end = mi->bank[i].start + mi->bank[i].size;
- if (mi->end < end)
- mi->end = end;
- }
- }
-
- start_pfn = O_PFN_UP(PHYS_OFFSET);
- end_pfn = O_PFN_DOWN(mi->end);
- bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
- bootmap_pfn = find_bootmap_pfn(mi, bootmap_pages);
-
- /*
- * Initialise the boot-time allocator
- */
- init_bootmem_start(bootmap_pfn, start_pfn, end_pfn);
-
- /*
- * Register all available RAM with the bootmem allocator.
- */
- for (i = 0; i < mi->nr_banks; i++)
- if (mi->bank[i].size)
- free_bootmem(O_PFN_UP(mi->bank[i].start),
- PFN_SIZE(mi->bank[i].size));
-
- /*
- * Register the reserved regions with bootmem
- */
- reserve_bootmem(bootmap_pfn, bootmap_pages);
- reserve_bootmem(V_PFN_DOWN(&_stext), PFN_RANGE(&_stext, &_end));
-
-#ifdef CONFIG_CPU_32
- /*
- * Reserve the page tables. These are already in use.
- */
- reserve_bootmem(V_PFN_DOWN(swapper_pg_dir),
- PFN_SIZE(PTRS_PER_PGD * sizeof(void *)));
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
- if (initrd_start)
- reserve_bootmem(V_PFN_DOWN(initrd_start),
- PFN_RANGE(initrd_start, initrd_end));
-#endif
-}
-
static void __init
request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
{
system_serial_low = params->u1.s.system_serial_low;
system_serial_high = params->u1.s.system_serial_high;
+ if (params->u1.s.mem_fclk_21285 > 0)
+ mem_fclk_21285 = params->u1.s.mem_fclk_21285;
+
setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0,
(params->u1.s.flags & FLAG_RDPROMPT) == 0,
params->u1.s.rd_start,
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(&meminfo, cmdline_p, from);
- setup_bootmem(&meminfo);
+ bootmem_init(&meminfo);
request_standard_resources(&meminfo, mdesc);
-
paging_init(&meminfo);
#ifdef CONFIG_VT
extern int setup_arm_irq(int, struct irqaction *);
extern void setup_timer(void);
+extern rwlock_t xtime_lock;
extern volatile unsigned long lost_ticks;
/* change this if you have some constant time drift */
}
/*
- * hook for getting the time offset
+ * hook for getting the time offset. Note that it is
+ * always called with interrupts disabled.
*/
unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset;
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
+ unsigned long usec, sec;
- save_flags_cli (flags);
- *tv = xtime;
- tv->tv_usec += gettimeoffset();
+ read_lock_irqsave(&xtime_lock, flags);
+ usec = gettimeoffset();
+ {
+ unsigned long lost = lost_ticks;
- /*
- * xtime is atomically updated in timer_bh. lost_ticks is
- * nonzero if the timer bottom half hasnt executed yet.
- */
- if (lost_ticks)
- tv->tv_usec += USECS_PER_JIFFY;
-
- restore_flags(flags);
-
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
+ if (lost)
+ usec += lost * USECS_PER_JIFFY;
}
+ sec = xtime.tv_sec;
+ usec += xtime.tv_usec;
+ read_unlock_irqrestore(&xtime_lock, flags);
+
+ /* usec may have gone up a lot: be safe */
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ sec++;
+ }
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
{
- cli ();
+ write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
* would have done, and then undo it!
*/
tv->tv_usec -= gettimeoffset();
+ tv->tv_usec -= lost_ticks * USECS_PER_JIFFY;
- if (tv->tv_usec < 0) {
+ while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+ write_unlock_irq(&xtime_lock);
}
static struct irqaction timer_irq = {
* Params : r0 = src, r1 = dst, r2 = len, r3 = checksum
* Returns : r0 = new checksum
*/
+
+ .macro save_regs
+ stmfd sp!, {r4 - r8, fp, ip, lr, pc}
+ .endm
+
+ .macro load_regs,flags
+ LOADREGS(\flags,fp,{r4 - r8, fp, sp, pc})
+ .endm
+
+ .macro load1b, reg1
+ ldrb \reg1, [r0], #1
+ .endm
+
+ .macro load2b, reg1, reg2
+ ldrb \reg1, [r0], #1
+ ldrb \reg2, [r0], #1
+ .endm
+
+ .macro load1l, reg1
+ ldr \reg1, [r0], #4
+ .endm
+
+ .macro load2l, reg1, reg2
+ ldr \reg1, [r0], #4
+ ldr \reg2, [r0], #4
+ .endm
+
+ .macro load4l, reg1, reg2, reg3, reg4
+ ldmia r0!, {\reg1, \reg2, \reg3, \reg4}
+ .endm
+
ENTRY(csum_partial_copy_nocheck)
mov ip, sp
- stmfd sp!, {r4 - r8, fp, ip, lr, pc}
+ save_regs
sub fp, ip, #4
cmp r2, #4
- blt Ltoo_small
+ blt .too_small
tst r1, #2 @ Test destination alignment
- beq Ldst_aligned
- ldrb ip, [r0], #1
- ldrb r8, [r0], #1
+ beq .dst_aligned
+ load2b ip, r8
subs r2, r2, #2 @ We do not know if SRC is aligned...
orr ip, ip, r8, lsl #8
adds r3, r3, ip
strb ip, [r1], #1
mov ip, ip, lsr #8
strb ip, [r1], #1 @ Destination now aligned
-Ldst_aligned: tst r0, #3
- bne Lsrc_not_aligned
+.dst_aligned: tst r0, #3
+ bne .src_not_aligned
adds r3, r3, #0
bics ip, r2, #15 @ Routine for src & dst aligned
- beq 3f
-1: ldmia r0!, {r4, r5, r6, r7}
+ beq 2f
+1: load4l r4, r5, r6, r7
stmia r1!, {r4, r5, r6, r7}
adcs r3, r3, r4
adcs r3, r3, r5
sub ip, ip, #16
teq ip, #0
bne 1b
-3: ands ip, r2, #12
- beq 5f
- tst ip, #8
+2: ands ip, r2, #12
beq 4f
- ldmia r0!, {r4, r5}
+ tst ip, #8
+ beq 3f
+ load2l r4, r5
stmia r1!, {r4, r5}
adcs r3, r3, r4
adcs r3, r3, r5
tst ip, #4
- beq 5f
-4: ldr r4, [r0], #4
+ beq 4f
+3: load1l r4
str r4, [r1], #4
adcs r3, r3, r4
-5: ands r2, r2, #3
+4: ands r2, r2, #3
adceq r0, r3, #0
- LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
- ldr r4, [r0], #4
+ load_regs eqea
+ load1l r4
tst r2, #2
- beq Lexit_r4
+ beq .exit
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
mov r4, r4, lsr #8
strb r4, [r1], #1
mov r4, r4, lsr #8
- b Lexit_r4
+.exit: tst r2, #1
+ strneb r4, [r1], #1
+ andne r4, r4, #255
+ adcnes r3, r3, r4
+ adcs r0, r3, #0
+ load_regs ea
-Ltoo_small: teq r2, #0
- LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+.too_small: teq r2, #0
+ load_regs eqea
cmp r2, #2
- blt Ltoo_small1
- ldrb ip, [r0], #1
- ldrb r8, [r0], #1
+ blt .too_small1
+ load2b ip, r8
orr ip, ip, r8, lsl #8
adds r3, r3, ip
strb ip, [r1], #1
strb r8, [r1], #1
tst r2, #1
-Ltoo_small1: ldrneb r4, [r0], #1
-Lexit_r4: tst r2, #1
- strneb r4, [r1], #1
- andne r4, r4, #255
- adcnes r3, r3, r4
- adcs r0, r3, #0
- LOADREGS(ea,fp,{r4 - r8, fp, sp, pc})
+.too_small1: @ C = 0
+ beq .csum_exit
+ load1b ip
+ strb ip, [r1], #1
+ adcs r3, r3, ip
+.csum_exit: adc r0, r3, #0
+ load_regs ea
-Lsrc_not_aligned:
+.src_not_aligned:
cmp r2, #4
- blt Ltoo_small
+ blt .too_small
and ip, r0, #3
bic r0, r0, #3
- ldr r4, [r0], #4
+ load1l r4
cmp ip, #2
- beq Lsrc2_aligned
- bhi Lsrc3_aligned
+ beq .src2_aligned
+ bhi .src3_aligned
mov r4, r4, lsr #8
adds r3, r3, #0
bics ip, r2, #15
beq 2f
-1: ldmia r0!, {r5, r6, r7, r8}
+1: load4l r5, r6, r7, r8
orr r4, r4, r5, lsl #24
mov r5, r5, lsr #8
orr r5, r5, r6, lsl #24
beq 4f
tst ip, #8
beq 3f
- ldmia r0!, {r5, r6}
+ load2l r5, r6
orr r4, r4, r5, lsl #24
mov r5, r5, lsr #8
orr r5, r5, r6, lsl #24
mov r4, r6, lsr #8
tst ip, #4
beq 4f
-3: ldr r5, [r0], #4
+3: load1l r5
orr r4, r4, r5, lsl #24
str r4, [r1], #4
adcs r3, r3, r4
mov r4, r5, lsr #8
4: ands r2, r2, #3
adceq r0, r3, #0
- LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ load_regs eqea
tst r2, #2
- beq Lexit_r4
+ beq .exit
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
mov r4, r4, lsr #8
strb r4, [r1], #1
mov r4, r4, lsr #8
- b Lexit_r4
+ b .exit
-Lsrc2_aligned: mov r4, r4, lsr #16
+.src2_aligned: mov r4, r4, lsr #16
adds r3, r3, #0
bics ip, r2, #15
beq 2f
-1: ldmia r0!, {r5, r6, r7, r8}
+1: load4l r5, r6, r7, r8
orr r4, r4, r5, lsl #16
mov r5, r5, lsr #16
orr r5, r5, r6, lsl #16
beq 4f
tst ip, #8
beq 3f
- ldmia r0!, {r5, r6}
+ load2l r5, r6
orr r4, r4, r5, lsl #16
mov r5, r5, lsr #16
orr r5, r5, r6, lsl #16
mov r4, r6, lsr #16
tst ip, #4
beq 4f
-3: ldr r5, [r0], #4
+3: load1l r5
orr r4, r4, r5, lsl #16
str r4, [r1], #4
adcs r3, r3, r4
mov r4, r5, lsr #16
4: ands r2, r2, #3
adceq r0, r3, #0
- LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ load_regs eqea
tst r2, #2
- beq Lexit_r4
+ beq .exit
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
mov r4, r4, lsr #8
strb r4, [r1], #1
- ldrb r4, [r0], #1
- b Lexit_r4
+ tst r2, #1
+ adceq r0, r3, #0
+ load_regs eqea
+ load1b r4
+ b .exit
-Lsrc3_aligned: mov r4, r4, lsr #24
+.src3_aligned: mov r4, r4, lsr #24
adds r3, r3, #0
bics ip, r2, #15
beq 2f
-1: ldmia r0!, {r5, r6, r7, r8}
+1: load4l r5, r6, r7, r8
orr r4, r4, r5, lsl #8
mov r5, r5, lsr #24
orr r5, r5, r6, lsl #8
beq 4f
tst ip, #8
beq 3f
- ldmia r0!, {r5, r6}
+ load2l r5, r6
orr r4, r4, r5, lsl #8
mov r5, r5, lsr #24
orr r5, r5, r6, lsl #8
mov r4, r6, lsr #24
tst ip, #4
beq 4f
-3: ldr r5, [r0], #4
+3: load1l r5
orr r4, r4, r5, lsl #8
str r4, [r1], #4
adcs r3, r3, r4
mov r4, r5, lsr #24
4: ands r2, r2, #3
adceq r0, r3, #0
- LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ load_regs eqea
tst r2, #2
- beq Lexit_r4
+ beq .exit
adcs r3, r3, r4, lsl #16
strb r4, [r1], #1
- ldr r4, [r0], #4
+ load1l r4
strb r4, [r1], #1
adcs r3, r3, r4, lsl #24
mov r4, r4, lsr #8
- b Lexit_r4
-
-
+ b .exit
save_regs
sub fp, ip, #4
cmp r2, #4
- blt .too_small_user
+ blt .too_small
tst r1, #2 @ Test destination alignment
- beq .dst_aligned_user
+ beq .dst_aligned
load2b ip, r8
subs r2, r2, #2 @ We do not know if SRC is aligned...
orr ip, ip, r8, lsl #8
strb ip, [r1], #1
mov ip, ip, lsr #8
strb ip, [r1], #1 @ Destination now aligned
-.dst_aligned_user:
- tst r0, #3
- bne .src_not_aligned_user
+.dst_aligned: tst r0, #3
+ bne .src_not_aligned
adds r3, r3, #0
bics ip, r2, #15 @ Routine for src & dst aligned
beq 2f
adcs r0, r3, #0
load_regs ea
-.too_small_user:
- teq r2, #0
+.too_small: teq r2, #0
load_regs eqea
cmp r2, #2
- blt .too_small_user1
+ blt .too_small1
load2b ip, r8
orr ip, ip, r8, lsl #8
adds r3, r3, ip
strb ip, [r1], #1
strb r8, [r1], #1
tst r2, #1
-.too_small_user1: @ C = 0
+.too_small1: @ C = 0
beq .csum_exit
load1b ip
strb ip, [r1], #1
.csum_exit: adc r0, r3, #0
load_regs ea
-.src_not_aligned_user:
+.src_not_aligned:
cmp r2, #4
- blt .too_small_user
+ blt .too_small
and ip, r0, #3
bic r0, r0, #3
load1l r4
cmp ip, #2
- beq .src2_aligned_user
- bhi .src3_aligned_user
+ beq .src2_aligned
+ bhi .src3_aligned
mov r4, r4, lsr #8
adds r3, r3, #0
bics ip, r2, #15
mov r4, r4, lsr #8
b .exit
-.src2_aligned_user:
- mov r4, r4, lsr #16
+.src2_aligned: mov r4, r4, lsr #16
adds r3, r3, #0
bics ip, r2, #15
beq 2f
load1b r4
b .exit
-.src3_aligned_user:
- mov r4, r4, lsr #24
+.src3_aligned: mov r4, r4, lsr #24
adds r3, r3, #0
bics ip, r2, #15
beq 2f
if (in_interrupt())
BUG();
+ size = PAGE_ALIGN(size);
order = get_order(size);
page = __get_free_pages(gfp, order);
if (!page)
goto no_page;
- memset((void *)page, 0, PAGE_SIZE << order);
- clean_cache_area(page, PAGE_SIZE << order);
+ memset((void *)page, 0, size);
+ clean_cache_area(page, size);
*dma_handle = virt_to_bus((void *)page);
- ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0);
- if (ret)
+ ret = __ioremap(virt_to_phys((void *)page), size, 0);
+ if (ret) {
+ /* free wasted pages */
+ unsigned long end = page + (PAGE_SIZE << order);
+ page += size;
+ while (page < end) {
+ free_page(page);
+ page += PAGE_SIZE;
+ }
return ret;
+ }
free_pages(page, order);
no_page:
/*
* make an area consistent.
*/
-void consistent_sync(void *vaddr, size_t size, int rw)
+void consistent_sync(void *vaddr, size_t size, int direction)
{
- switch (rw) {
- case 0:
+ switch (direction) {
+ case PCI_DMA_NONE:
BUG();
- case 1: /* invalidate only */
+ case PCI_DMA_FROMDEVICE: /* invalidate only */
dma_cache_inv(vaddr, size);
break;
- case 2: /* writeback only */
+ case PCI_DMA_TODEVICE: /* writeback only */
dma_cache_wback(vaddr, size);
break;
- case 3: /* writeback and invalidate */
+ case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */
dma_cache_wback_inv(vaddr, size);
break;
}
/*
* linux/arch/arm/mm/init.c
*
- * Copyright (C) 1995-1999 Russell King
+ * Copyright (C) 1995-2000 Russell King
*/
-
#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include "map.h"
+#ifdef CONFIG_CPU_32
+#define TABLE_OFFSET (PTRS_PER_PTE)
+#else
+#define TABLE_OFFSET 0
+#endif
+#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *))
+
static unsigned long totalram_pages;
-struct meminfo meminfo;
pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern int _stext, _text, _etext, _edata, _end;
+
+/*
+ * The sole use of this is to pass memory configuration
+ * data from paging_init to mem_init.
+ */
+static struct meminfo __initdata meminfo;
/*
* empty_bad_page is the page that is used for page faults when
void show_mem(void)
{
int free = 0, total = 0, reserved = 0;
- int shared = 0, cached = 0;
- struct page *page, *end;
+ int shared = 0, cached = 0, node;
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- page = mem_map;
- end = mem_map + max_mapnr;
+ for (node = 0; node < numnodes; node++) {
+ struct page *page, *end;
- do {
- if (PageSkip(page)) {
- page = page->next_hash;
- if (page == NULL)
- break;
- }
- total++;
- if (PageReserved(page))
- reserved++;
- else if (PageSwapCache(page))
- cached++;
- else if (!page_count(page))
- free++;
- else
- shared += atomic_read(&page->count) - 1;
- page++;
- } while (page < end);
+ page = NODE_MEM_MAP(node);
+ end = page + NODE_DATA(node)->node_size;
+
+ do {
+ if (PageSkip(page)) {
+ page = page->next_hash;
+ if (page == NULL)
+ break;
+ }
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (!page_count(page))
+ free++;
+ else
+ shared += atomic_read(&page->count) - 1;
+ page++;
+ } while (page < end);
+ }
printk("%d pages of RAM\n", total);
printk("%d free pages\n", free);
show_buffers();
}
+#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x))
+
+#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT)
+#define V_PFN_UP(x) O_PFN_UP(__pa(x))
+
+#define PFN_SIZE(x) ((x) >> PAGE_SHIFT)
+#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
+ (((unsigned long)(s)) & PAGE_MASK))
+
+static unsigned int __init
+find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages)
+{
+ unsigned int start_pfn, bank, bootmap_pfn;
+
+ start_pfn = V_PFN_UP(&_end);
+ bootmap_pfn = 0;
+
+ /*
+ * FIXME: We really want to avoid allocating the bootmap
+ * over the top of the initrd.
+ */
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start) {
+ if (__pa(initrd_end) > mi->end) {
+ printk ("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx) - disabling initrd\n",
+ __pa(initrd_end), mi->end);
+ initrd_start = 0;
+ initrd_end = 0;
+ }
+ }
+#endif
+
+ for (bank = 0; bank < mi->nr_banks; bank ++) {
+ unsigned int start, end;
+
+ if (mi->bank[bank].size == 0)
+ continue;
+
+ start = O_PFN_UP(mi->bank[bank].start);
+ end = O_PFN_DOWN(mi->bank[bank].size +
+ mi->bank[bank].start);
+
+ if (end < start_pfn)
+ continue;
+
+ if (start < start_pfn)
+ start = start_pfn;
+
+ if (end <= start)
+ continue;
+
+ if (end - start >= bootmap_pages) {
+ bootmap_pfn = start;
+ break;
+ }
+ }
+
+ if (bootmap_pfn == 0)
+ BUG();
+
+ return bootmap_pfn;
+}
+
+/*
+ * Initialise one node of the bootmem allocator. For now, we
+ * only initialise node 0. Notice that we have a bootmem
+ * bitmap per node.
+ */
+static void __init setup_bootmem_node(int node, struct meminfo *mi)
+{
+ unsigned int end_pfn, start_pfn, bootmap_pages, bootmap_pfn;
+ unsigned int i;
+
+ if (node != 0) /* only initialise node 0 for now */
+ return;
+
+ start_pfn = O_PFN_UP(PHYS_OFFSET);
+ end_pfn = O_PFN_DOWN(mi->end);
+ bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
+ bootmap_pfn = find_bootmap_pfn(mi, bootmap_pages);
+
+ /*
+ * Initialise the boot-time allocator
+ */
+ init_bootmem_node(node, bootmap_pfn, start_pfn, end_pfn);
+
+ /*
+ * Register all available RAM with the bootmem allocator.
+ */
+ for (i = 0; i < mi->nr_banks; i++)
+ if (mi->bank[i].size)
+ free_bootmem_node(node, mi->bank[i].start,
+ PFN_SIZE(mi->bank[i].size) << PAGE_SHIFT);
+
+ reserve_bootmem_node(node, bootmap_pfn << PAGE_SHIFT,
+ bootmap_pages << PAGE_SHIFT);
+}
+
+/*
+ * Initialise the bootmem allocator.
+ */
+void __init bootmem_init(struct meminfo *mi)
+{
+ unsigned int i, node;
+
+ /*
+ * Calculate the physical address of the top of memory.
+ * Note that there are no guarantees assumed about the
+ * ordering of the bank information.
+ */
+ mi->end = 0;
+ for (i = 0; i < mi->nr_banks; i++) {
+ unsigned long end;
+
+ if (mi->bank[i].size != 0) {
+ end = mi->bank[i].start + mi->bank[i].size;
+ if (mi->end < end)
+ mi->end = end;
+ }
+ }
+
+ max_low_pfn = O_PFN_DOWN(mi->end - PHYS_OFFSET);
+
+ /*
+ * Setup each node
+ */
+ for (node = 0; node < numnodes; node++)
+ setup_bootmem_node(node, mi);
+
+ /*
+ * Register the kernel text and data with bootmem.
+ * Note that this can only be in node 0.
+ */
+ reserve_bootmem_node(0, V_PFN_DOWN(&_stext) << PAGE_SHIFT,
+ PFN_RANGE(&_stext, &_end) << PAGE_SHIFT);
+
+#ifdef CONFIG_CPU_32
+ /*
+ * Reserve the page tables. These are already in use,
+ * and can only be in node 0.
+ */
+ reserve_bootmem_node(0, V_PFN_DOWN(swapper_pg_dir) << PAGE_SHIFT,
+ PFN_SIZE(PTRS_PER_PGD * sizeof(void *)) << PAGE_SHIFT);
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+ /*
+ * This may be in any bank. Currently, we assume that
+ * it is in bank 0.
+ */
+ if (initrd_start)
+ reserve_bootmem_node(0, V_PFN_DOWN(initrd_start) << PAGE_SHIFT,
+ PFN_RANGE(initrd_start, initrd_end) << PAGE_SHIFT);
+#endif
+}
+
/*
* paging_init() sets up the page tables...
*/
void __init paging_init(struct meminfo *mi)
{
void *zero_page, *bad_page, *bad_table;
- unsigned long zone_size[MAX_NR_ZONES];
- int i;
+ int node;
memcpy(&meminfo, mi, sizeof(meminfo));
-#ifdef CONFIG_CPU_32
-#define TABLE_OFFSET (PTRS_PER_PTE)
-#else
-#define TABLE_OFFSET 0
-#endif
-#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *))
-
/*
* allocate what we need for the bad pages
*/
/*
* initialise the page tables
*/
- pagetable_init();
+ pagetable_init(mi);
flush_tlb_all();
/*
- * Initialise the zones and mem_map
+ * initialise the zones within each node
*/
- for (i = 0; i < MAX_NR_ZONES; i++)
- zone_size[i] = 0;
+ for (node = 0; node < numnodes; node++) {
+ unsigned long zone_size[MAX_NR_ZONES];
+ unsigned long zhole_size[MAX_NR_ZONES];
+ struct bootmem_data *bdata;
+ pg_data_t *pgdat;
+ int i;
- /*
- * Calculate the size of the zones. On ARM, we don't have
- * any problems with DMA or highmem, so all memory is
- * allocated to the DMA zone.
- */
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].size) {
- unsigned int end;
-
- end = (mi->bank[i].start - PHYS_OFFSET +
- mi->bank[i].size) >> PAGE_SHIFT;
- if (zone_size[0] < end)
- zone_size[0] = end;
+ /*
+ * Initialise the zone size information.
+ */
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ zone_size[i] = 0;
+ zhole_size[i] = 0;
}
+
+ pgdat = NODE_DATA(node);
+ bdata = pgdat->bdata;
+
+ /*
+ * The size of this node has already been determined.
+ * If we need to do anything fancy with the allocation
+ * of this memory to the zones, now is the time to do
+ * it. For now, we don't touch zhole_size.
+ */
+ zone_size[0] = bdata->node_low_pfn -
+ (bdata->node_boot_start >> PAGE_SHIFT);
+
+ free_area_init_node(node, pgdat, zone_size,
+ bdata->node_boot_start, zhole_size);
}
- free_area_init(zone_size);
/*
* finish off the bad pages once
*/
void __init mem_init(void)
{
- extern char __init_begin, __init_end, _text, _etext, _end;
+ extern char __init_begin, __init_end;
unsigned int codepages, datapages, initpages;
- int i;
+ int i, node;
codepages = &_etext - &_text;
datapages = &_end - &_etext;
initpages = &__init_end - &__init_begin;
- max_mapnr = max_low_pfn;
- high_memory = (void *)__va(PHYS_OFFSET + max_low_pfn * PAGE_SIZE);
+ high_memory = (void *)__va(meminfo.end);
+ max_mapnr = MAP_NR(high_memory);
/*
* We may have non-contiguous memory. Setup the PageSkip stuff,
* and mark the areas of mem_map which can be freed
*/
if (meminfo.nr_banks != 1)
- create_memmap_holes();
+ create_memmap_holes(&meminfo);
/* this will put all unused low memory onto the freelists */
- totalram_pages += free_all_bootmem();
+ for (node = 0; node < numnodes; node++)
+ totalram_pages += free_all_bootmem_node(node);
/*
* Since our memory may not be contiguous, calculate the
* real number of pages we have in this system
*/
- printk("Memory:");
+ printk(KERN_INFO "Memory:");
num_physpages = 0;
for (i = 0; i < meminfo.nr_banks; i++) {
}
printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
- printk("Memory: %luKB available (%dK code, %dK data, %dK init)\n",
+ printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
+ "%dK data, %dK init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
codepages >> 10, datapages >> 10, initpages >> 10);
extern struct map_desc io_desc[];
extern unsigned int io_desc_size;
-extern void zonesize_init(unsigned int *);
-extern void create_memmap_holes(void);
-extern void pagetable_init(void);
+struct meminfo;
+extern void create_memmap_holes(struct meminfo *);
+extern void pagetable_init(struct meminfo *);
* some more work to get it to fit into our separate processor and
* architecture structure.
*/
-void __init pagetable_init(void)
+void __init pagetable_init(struct meminfo *mi)
{
pte_t *pte;
int i;
/*
* We never have holes in the memmap
*/
-void __init create_memmap_holes(void)
+void __init create_memmap_holes(struct meminfo *mi)
{
}
}
}
-void __init pagetable_init(void)
+void __init pagetable_init(struct meminfo *mi)
{
struct map_desc *init_maps, *p, *q;
unsigned long address = 0;
p ++;
- for (i = 0; i < meminfo.nr_banks; i++) {
- if (meminfo.bank[i].size == 0)
+ for (i = 0; i < mi->nr_banks; i++) {
+ if (mi->bank[i].size == 0)
continue;
- p->physical = meminfo.bank[i].start;
+ p->physical = mi->bank[i].start;
p->virtual = __phys_to_virt(p->physical);
- p->length = meminfo.bank[i].size;
+ p->length = mi->bank[i].size;
p->domain = DOMAIN_KERNEL;
p->prot_read = 0;
p->prot_write = 1;
* The mem_map array can get very big. Mark the end of the valid mem_map
* banks with PG_skip, and setup the address validity bitmap.
*/
-void __init create_memmap_holes(void)
+void __init create_memmap_holes(struct meminfo *mi)
{
unsigned int start_pfn, end_pfn = -1;
struct page *pg = NULL;
#define PFN(x) (((x) - PHYS_OFFSET) >> PAGE_SHIFT)
#define free_bootmem(s,sz) free_bootmem(((s)<<PAGE_SHIFT)+PHYS_OFFSET, (sz)<<PAGE_SHIFT)
- for (i = 0; i < meminfo.nr_banks; i++) {
- if (meminfo.bank[i].size == 0)
+ for (i = 0; i < mi->nr_banks; i++) {
+ if (mi->bank[i].size == 0)
continue;
- start_pfn = PFN(meminfo.bank[i].start);
+ start_pfn = PFN(mi->bank[i].start);
/*
* subtle here - if we have a full bank, then
pg = NULL;
}
- end_pfn = PFN(meminfo.bank[i].start + meminfo.bank[i].size);
+ end_pfn = PFN(mi->bank[i].start + mi->bank[i].size);
- if (end_pfn != PFN(meminfo.end))
+ if (end_pfn != PFN(mi->end))
pg = mem_map + end_pfn;
}
#include <linux/mm.h>
#include <linux/init.h>
+#include <asm/hardware.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#define SIZE(x) (sizeof(x) / sizeof(x[0]))
-const struct map_desc io_desc[] __initdata = {
+struct map_desc io_desc[] __initdata = {
{ IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
{ IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }
};
struct map_desc io_desc[] __initdata = {
/* VRAM */
- { SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 },
+ { SCREEN_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 },
/* IO space */
{ IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
/* EASI space */
* 1999/12/04 Nicolas Pitre <nico@cam.org>
* Converted memory definition for struct meminfo initialisations.
* Memory is listed physically now.
+ *
+ * 2000/04/07 Nicolas Pitre <nico@cam.org>
+ * Reworked for real-time selection of memory definitions
+ *
*/
#include <linux/config.h>
#define SIZE(x) (sizeof(x) / sizeof(x[0]))
-/*
- * These are the RAM memory mappings for SA1100 implementations.
- * Note that LART is a special case - it doesn't use physical
- * address line A23 on the DRAM, so we effectively have 4 * 8MB
- * in two banks.
- */
-struct mem_desc {
- unsigned long phys_start;
- unsigned long length;
-} mem_desc[] __initdata = {
-#if defined(CONFIG_SA1100_BRUTUS)
- { 0xc0000000, 0x00400000 }, /* 4MB */
- { 0xc8000000, 0x00400000 }, /* 4MB */
- { 0xd0000000, 0x00400000 }, /* 4MB */
- { 0xd8000000, 0x00400000 } /* 4MB */
-#elif defined(CONFIG_SA1100_EMPEG)
- { 0xc0000000, 0x00400000 }, /* 4MB */
- { 0xc8000000, 0x00400000 } /* 4MB */
-#elif defined(CONFIG_SA1100_LART)
- { 0xc0000000, 0x00800000 }, /* 8MB */
- { 0xc1000000, 0x00800000 }, /* 8MB */
- { 0xc8000000, 0x00800000 }, /* 8MB */
- { 0xc9000000, 0x00800000 } /* 8MB */
-#elif defined(CONFIG_SA1100_VICTOR)
- { 0xc0000000, 0x00400000 } /* 4MB */
-#elif defined(CONFIG_SA1100_THINCLIENT)
- { 0xc0000000, 0x01000000 } /* 16MB */
-#elif defined(CONFIG_SA1100_TIFON)
- { 0xc0000000, 0x01000000 }, /* 16MB */
- { 0xc8000000, 0x01000000 } /* 16MB */
-#else
-#error missing memory configuration
+#define SA1100_STD_IO_MAPPING \
+ /* virtual physical length domain r w c b */ \
+ { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ \
+ { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ \
+ { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */ \
+ { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */ \
+ { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */ \
+ { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */ \
+ { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ \
+ { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ \
+ { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ \
+ { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 } /* LCD + DMA */
+
+
+static struct map_desc assabet_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_ASSABET
+ { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+ { 0xdc000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
+ SA1100_STD_IO_MAPPING
#endif
};
-unsigned int __initdata mem_desc_size = SIZE(mem_desc);
+static struct map_desc bitsy_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_BITSY
+ { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+ SA1100_STD_IO_MAPPING
+#endif
+};
+static struct map_desc empeg_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_EMPEG
+ { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+ SA1100_STD_IO_MAPPING
+#endif
+};
-struct map_desc io_desc[] __initdata = {
- /* virtual physical length domain r w c b */
-#if defined(CONFIG_SA1100_VICTOR)
- { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
-#elif defined(CONFIG_SA1100_EMPEG)
- { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
-#elif defined(CONFIG_SA1100_THINCLIENT)
+static struct map_desc thinclient_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_THINCLIENT
#if 1
- /* ThinClient: only one of those... */
-// { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
- { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
+ /* ThinClient: only one of those... */
+// { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */
+ { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */
#else
- /* GraphicsClient: */
- { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
- { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */
+ /* GraphicsClient: */
+ { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+ { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */
+#endif
+ { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
+ SA1100_STD_IO_MAPPING
#endif
-#elif defined(CONFIG_SA1100_TIFON)
- { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
- { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
+};
+
+static struct map_desc tifon_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_TIFON
+ { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */
+ { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */
+ SA1100_STD_IO_MAPPING
#endif
-#if defined( CONFIG_SA1101 )
- { 0xdc000000, SA1101_BASE, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA1101 */
-#elif defined( CONFIG_SA1100_THINCLIENT )
- { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
+};
+
+static struct map_desc victor_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_VICTOR
+ { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
+ SA1100_STD_IO_MAPPING
#endif
- { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
- { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
- { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 attr */
- { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 attr */
- { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 mem */
- { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 mem */
- { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
- { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
- { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
- { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 } /* LCD + DMA */
};
-unsigned int __initdata io_desc_size = SIZE(io_desc);
+
+static struct map_desc default_io_desc[] __initdata = {
+ SA1100_STD_IO_MAPPING
+};
+
+
+/*
+ * Here it would be wiser to simply assign a pointer to the appropriate
+ * list, but io_desc is already declared as an array in "map.h".
+ */
+struct map_desc io_desc[20] __initdata = { { 0, }, };
+unsigned int io_desc_size;
+
+void __init select_sa1100_io_desc(void)
+{
+ if( machine_is_assabet() ) {
+ memcpy( io_desc, assabet_io_desc, sizeof(assabet_io_desc) );
+ io_desc_size = SIZE(assabet_io_desc);
+ } else if( machine_is_bitsy() ) {
+ memcpy( io_desc, bitsy_io_desc, sizeof(bitsy_io_desc) );
+ io_desc_size = SIZE(bitsy_io_desc);
+ } else if( machine_is_empeg() ) {
+ memcpy( io_desc, empeg_io_desc, sizeof(empeg_io_desc) );
+ io_desc_size = SIZE(empeg_io_desc);
+ } else if( machine_is_thinclient() ) {
+ memcpy( io_desc, thinclient_io_desc, sizeof(thinclient_io_desc) );
+ io_desc_size = SIZE(thinclient_io_desc);
+ } else if( machine_is_tifon() ) {
+ memcpy( io_desc, tifon_io_desc, sizeof(tifon_io_desc) );
+ io_desc_size = SIZE(tifon_io_desc);
+ } else if( machine_is_victor() ) {
+ memcpy( io_desc, victor_io_desc, sizeof(victor_io_desc) );
+ io_desc_size = SIZE(victor_io_desc);
+ } else {
+ memcpy( io_desc, default_io_desc, sizeof(default_io_desc) );
+ io_desc_size = SIZE(default_io_desc);
+ }
+}
+
* (C) 1997-2000 Russell King
*
* These are the low level assembler for performing cache and TLB
- * functions on the StrongARM-110 and StrongARM-1100
+ * functions on the StrongARM-110, StrongARM-1100 and StrongARM-1110.
+ *
+ * Note that SA1100 and SA1110 share everything but their name and CPU ID.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
mov pc, lr
ENTRY(cpu_sa110_proc_fin)
-ENTRY(cpu_sa1100_proc_fin)
stmfd sp!, {r1, lr}
mrs r0, cpsr
orr r0, r0, #F_BIT | I_BIT
msr cpsr, r0
bl cpu_sa110_flush_cache_all @ clean caches
- mov r0, #0
+1: mov r0, #0
mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x1000 @ ...i............
mcr p15, 0, r0, c1, c0, 0 @ disable caches
ldmfd sp!, {r1, pc}
+ENTRY(cpu_sa1100_proc_fin)
+ stmfd sp!, {r1, lr}
+ mrs r0, cpsr
+ orr r0, r0, #F_BIT | I_BIT
+ msr cpsr, r0
+ bl cpu_sa1100_flush_cache_all @ clean caches
+ b 1b
+
+
.align 5
-idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt
+idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt, cache aligned
mov r0, r0 @ safety
mov pc, lr
/*
bic ip, ip, #0x1100 @ ...i...s........
mcr p15, 0, ip, c1, c0, 0 @ ctrl register
mov pc, r0
-/*
- * Purpose : Function pointers used to access above functions - all calls
- * come through these
- */
+
cpu_manu_name: .asciz "Intel"
-ENTRY(cpu_sa110_name)
- .asciz "StrongARM-110"
-ENTRY(cpu_sa1100_name)
+cpu_sa110_name: .asciz "StrongARM-110"
+cpu_sa1100_name:
.asciz "StrongARM-1100"
+cpu_sa1110_name:
+ .asciz "StrongARM-1110"
.align
.section ".text.init", #alloc, #execinstr
orr r0, r0, #0x1100 @ ...I...S........
mov pc, lr
+ .text
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+
.type sa110_processor_functions, #object
ENTRY(sa110_processor_functions)
.word cpu_sa110_data_abort
.size cpu_sa110_info, . - cpu_sa110_info
+/*
+ * SA1100 and SA1110 share the same function calls
+ */
.type sa1100_processor_functions, #object
ENTRY(sa1100_processor_functions)
.word cpu_sa1100_data_abort
.long cpu_sa1100_name
.size cpu_sa1100_info, . - cpu_sa1100_info
+cpu_sa1110_info:
+ .long cpu_manu_name
+ .long cpu_sa1110_name
+ .size cpu_sa1110_info, . - cpu_sa1110_info
+
+
.type cpu_arch_name, #object
cpu_arch_name: .asciz "armv4"
.size cpu_arch_name, . - cpu_arch_name
.long sa1100_processor_functions
.size __sa1100_proc_info, . - __sa1100_proc_info
+ .type __sa1110_proc_info,#object
+__sa1110_proc_info:
+ .long 0x6901b110
+ .long 0xfffffff0
+ .long 0x00000c02
+ b __sa110_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+ .long cpu_sa1110_info
+ .long sa1100_processor_functions
+ .size __sa1110_proc_info, . - __sa1110_proc_info
+
// finished sleeping, update system time
acpi_update_clock();
acpi_enter_dx(ACPI_D0);
+ acpi_sleep_state = ACPI_S0;
return 0;
}
* More important, however, is the fact that this allows us much
* more flexibility.
*/
-extern int cpus_initialized;
void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread,
return p - buffer;
}
-int cpus_initialized = 0;
-unsigned long cpu_initialized = 0;
+static unsigned long cpu_initialized __initdata = 0;
/*
* cpu_init() initializes state that is per-CPU. Some data is already
printk("CPU#%d already initialized!\n", nr);
for (;;) __sti();
}
- cpus_initialized++;
printk("Initializing CPU#%d\n", nr);
if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
int tmp, err = 0;
tmp = 0;
- __asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp));
+ __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int *)&sc->gs);
- __asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp));
+ __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
err |= __put_user(tmp, (unsigned int *)&sc->fs);
err |= __put_user(regs->xes, (unsigned int *)&sc->es);
((limit) & 0x0ffff); }
#define _set_tssldt_desc(n,addr,limit,type) \
-__asm__ __volatile__ ("movw %3,0(%2)\n\t" \
+__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
"movw %%ax,2(%2)\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,4(%2)\n\t" \
#ifdef CONFIG_HEARTBEAT
void (*mach_heartbeat) (int) __apusdata = NULL;
extern void apus_heartbeat (void);
-static int heartbeat_enabled = 1;
-
-void enable_heartbeat(void)
-{
- heartbeat_enabled = 1;
-}
-
-void disable_heartbeat(void)
-{
- heartbeat_enabled = 0;
- mach_heartbeat(0);
-}
#endif
extern unsigned long amiga_model;
-/* $Id: fault.c,v 1.114 2000/02/14 04:52:36 jj Exp $
+/* $Id: fault.c,v 1.115 2000/04/25 04:13:25 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-/* $Id: fault.c,v 1.46 2000/04/12 08:10:23 davem Exp $
+/* $Id: fault.c,v 1.47 2000/04/25 04:13:25 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
if (ether1_init_for_open(dev))
printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
+ else
+ priv->restart = 0;
}
/*
case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */
case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */
fas216_stoptransfer(info);
+ case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */
case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */
case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */
info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
tot_msglen = msgqueue_msglength(&info->scsi.msgs);
+#ifdef DEBUG_MESSAGES
+ {
+ struct message *msg;
+ int msgnr = 0, i;
+
+ printk("scsi%d.%c: message out: ",
+ info->host->host_no, '0' + SCpnt->target);
+ while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+ printk("{ ");
+ for (i = 0; i < msg->length; i++)
+ printk("%02x ", msg->msg[i]);
+ printk("} ");
+ }
+ printk("\n");
+ }
+#endif
+
if (tot_msglen == 1 || tot_msglen == 3) {
/*
* We have an easy message length to send...
static unsigned short virtual_dma_port=0x3f0;
void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int set_dor(int fdc, char mask, char data);
-static void register_devfs_entries (int drive);
+static void register_devfs_entries (int drive) __init;
static devfs_handle_t devfs_handle = NULL;
#define K_64 0x10000 /* 64KB */
#undef IN
}
-static void config_types(void)
+static void __init config_types(void)
{
int first=1;
int drive;
revalidate: floppy_revalidate,
};
-static void register_devfs_entries (int drive)
+static void __init register_devfs_entries (int drive)
{
int base_minor, i;
static char *table[] =
printk("\n");
} else
DPRINT("botched floppy option\n");
- DPRINT("Read linux/drivers/block/README.fd\n");
+ DPRINT("Read linux/Documentation/floppy.txt\n");
return 0;
}
/*
- * linux/drivers/char/mouse.c
+ * linux/drivers/char/busmouse.c
*
- * Copyright (C) 1995 - 1998 Russell King
- * Protocol taken from busmouse.c
+ * Copyright (C) 1995 - 1998 Russell King <linux@arm.linux.org.uk>
+ * Protocol taken from original busmouse.c
* read() waiting taken from psaux.c
*
* Medium-level interface for quadrature or bus mice.
- *
- * Currently, the majority of kernel busmice drivers in the
- * kernel common code to talk to userspace. This driver
- * attempts to rectify this situation by presenting a
- * simple and safe interface to the mice and user.
- *
- * This driver:
- * - is SMP safe
- * - handles multiple opens
- * - handles the wakeups and locking
- * - has optional blocking reads
*/
#include <linux/module.h>
/* Uncomment this if your mouse drivers expect the kernel to
* return with EAGAIN if the mouse does not have any events
* available, even if the mouse is opened in nonblocking mode.
- *
- * Should this be on a per-mouse basis? If so, add an entry to
- * the struct busmouse structure and add the relevent flag to
- * the drivers.
+ * Please report use of this "feature" to the author using the
+ * above address.
*/
/*#define BROKEN_MOUSE*/
struct fasync_struct *fasyncptr;
char active;
char buttons;
- char latch_buttons;
char ready;
int dxpos;
int dypos;
static struct busmouse_data *busmouse_data[NR_MICE];
static DECLARE_MUTEX(mouse_sem);
-/* a mouse driver just has to interface with these functions
- * These are !!!OLD!!! Do not use!!!
- */
-void add_mouse_movement(int dx, int dy)
-{
- struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
-
- mse->dxpos += dx;
- mse->dypos += dy;
- mse->ready = 1;
- wake_up(&mse->wait);
-}
-
-int add_mouse_buttonchange(int set, int value)
-{
- struct busmouse_data *mse = busmouse_data[MINOR_TO_MOUSE(6)];
-
- mse->buttons = (mse->buttons & ~set) ^ value;
- mse->ready = 1;
- wake_up(&mse->wait);
- return mse->buttons;
-}
-
-/* New interface. !!! Use this one !!!
- * These routines will most probably be called from interrupt.
+/**
+ * busmouse_add_movement - notification of a change of mouse position
+ * @mousedev: mouse number
+ * @dx: delta X movement
+ * @dy: delta Y movement
+ * @buttons: new button state
+ *
+ * Updates the mouse position and button information. The mousedev
+ * parameter is the value returned from register_busmouse. The
+ * movement information is updated, and the new button state is
+ * saved. A waiting user thread is woken.
*/
+
void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
{
struct busmouse_data *mse = busmouse_data[mousedev];
add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
mse->buttons = buttons;
-// mse->latch_buttons |= buttons;
mse->dxpos += dx;
mse->dypos += dy;
mse->ready = 1;
}
}
+/**
+ * busmouse_add_movement - notification of a change of mouse position
+ * @mousedev: mouse number
+ * @dx: delta X movement
+ * @dy: delta Y movement
+ *
+ * Updates the mouse position. The mousedev parameter is the value
+ * returned from register_busmouse. The movement information is
+ * updated, and a waiting user thread is woken.
+ */
+
void busmouse_add_movement(int mousedev, int dx, int dy)
{
struct busmouse_data *mse = busmouse_data[mousedev];
busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
}
+/**
+ * busmouse_add_buttons - notification of a change of button state
+ * @mousedev: mouse number
+ * @clear: mask of buttons to clear
+ * @eor: mask of buttons to change
+ *
+ * Updates the button state. The mousedev parameter is the value
+ * returned from register_busmouse. The buttons are updated by:
+ * new_state = (old_state & ~clear) ^ eor
+ * A waiting user thread is woken up.
+ */
+
void busmouse_add_buttons(int mousedev, int clear, int eor)
{
struct busmouse_data *mse = busmouse_data[mousedev];
static int busmouse_open(struct inode *inode, struct file *file)
{
struct busmouse_data *mse;
- unsigned long flags;
unsigned int mousedev;
int ret = -ENODEV;
MOD_INC_USE_COUNT;
- spin_lock_irqsave(&mse->lock, flags);
+ spin_lock_irq(&mse->lock);
mse->ready = 0;
mse->dxpos = 0;
else
mse->buttons = 7;
- spin_unlock_irqrestore(&mse->lock, flags);
+ spin_unlock_irq(&mse->lock);
end:
up(&mouse_sem);
return ret;
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
int dxpos, dypos, buttons;
if (count < 3)
return -EINVAL;
- spin_lock_irqsave(&mse->lock, flags);
+ spin_lock_irq(&mse->lock);
if (!mse->ready) {
#ifdef BROKEN_MOUSE
- spin_unlock_irqrestore(&mse->lock, flags);
+ spin_unlock_irq(&mse->lock);
return -EAGAIN;
#else
if (file->f_flags & O_NONBLOCK) {
- spin_unlock_irqrestore(&mse->lock, flags);
+ spin_unlock_irq(&mse->lock);
return -EAGAIN;
}
repeat:
set_current_state(TASK_INTERRUPTIBLE);
if (!mse->ready && !signal_pending(current)) {
- spin_unlock_irqrestore(&mse->lock, flags);
+ spin_unlock_irq(&mse->lock);
schedule();
- spin_lock_irqsave(&mse->lock, flags);
+ spin_lock_irq(&mse->lock);
goto repeat;
}
remove_wait_queue(&mse->wait, &wait);
if (signal_pending(current)) {
- spin_unlock_irqrestore(&mse->lock, flags);
+ spin_unlock_irq(&mse->lock);
return -ERESTARTSYS;
}
#endif
dxpos = mse->dxpos;
dypos = mse->dypos;
buttons = mse->buttons;
-// mse->latch_buttons = mse->buttons;
if (dxpos < -127)
dxpos =- 127;
*/
mse->ready = mse->dxpos || mse->dypos;
- spin_unlock_irqrestore(&mse->lock, flags);
+ spin_unlock_irq(&mse->lock);
/* Write out data to the user. Format is:
* byte 0 - identifer (0x80) and (inverted) mouse buttons
int unregister_busmouse(int mousedev)
{
int err = -EINVAL;
+
if (mousedev < 0)
return 0;
if (mousedev >= NR_MICE) {
goto fail;
}
- err=misc_deregister(&busmouse_data[mousedev]->miscdev);
+ err = misc_deregister(&busmouse_data[mousedev]->miscdev);
kfree(busmouse_data[mousedev]);
busmouse_data[mousedev] = NULL;
/*
- * linux/drivers/char/mouse.h
+ * linux/drivers/char/busmouse.h
*
* Copyright (C) 1995 - 1998 Russell King
*
* Prototypes for generic busmouse interface
*/
-#ifndef MOUSE_H
-#define MOUSE_H
+#ifndef BUSMOUSE_H
+#define BUSMOUSE_H
struct busmouse {
int minor;
cmd[7] = 0;
retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval)
+ if (retval) {
DBG("%x - failed, retval=%d\n", command, retval);
- else {
+ if (command == CPIA_COMMAND_GetColourParams ||
+ command == CPIA_COMMAND_GetColourBalance ||
+ command == CPIA_COMMAND_GetExposure)
+ up(&cam->param_lock);
+ } else {
switch(command) {
case CPIA_COMMAND_GetCPIAVersion:
cam->params.version.firmwareVersion = data[0];
// __initdata should work as advertized
//
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
ip2_loadmain(int *, int *, unsigned char *, int ); // ref into ip2main.c
#ifdef MODULE
-
-#include <linux/autoconf.h>
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
# define MODVERSIONS
#endif
//----------------------
// Mandatory Includes:
//----------------------
+#include <linux/config.h>
#include "ip2types.h"
#include "i2hw.h" // The hardware definitions
/************/
/* Includes */
/************/
+#include <linux/config.h>
// Uncomment the following if you want it compiled with modversions
#ifdef MODULE
-# include <linux/autoconf.h>
# if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
# define MODVERSIONS
# endif
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
-
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
memset(&pty_driver, 0, sizeof(struct tty_driver));
pty_driver.magic = TTY_DRIVER_MAGIC;
pty_driver.driver_name = "pty_master";
+#ifdef CONFIG_DEVFS_FS
pty_driver.name = "pty/m%d";
+#else
+ pty_driver.name = "pty";
+#endif
pty_driver.major = PTY_MASTER_MAJOR;
pty_driver.minor_start = 0;
pty_driver.num = NR_PTYS;
pty_slave_driver = pty_driver;
pty_slave_driver.driver_name = "pty_slave";
pty_slave_driver.proc_entry = 0;
+#ifdef CONFIG_DEVFS_FS
pty_slave_driver.name = "pty/s%d";
+#else
+ pty_slave_driver.name = "ttyp";
+#endif
pty_slave_driver.subtype = PTY_TYPE_SLAVE;
pty_slave_driver.major = PTY_SLAVE_MAJOR;
pty_slave_driver.minor_start = 0;
init_waitqueue_head(&ptm_state[i][j].open_wait);
pts_driver[i] = pty_slave_driver;
+#ifdef CONFIG_DEVFS_FS
pts_driver[i].name = "pts/%d";
+#else
+ pts_driver[i].name = "pts";
+#endif
pts_driver[i].proc_entry = 0;
pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i;
pts_driver[i].minor_start = 0;
#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
#endif
-#if (LINUX_VERSION_CODE > 0x2032D)
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS))
serial_driver.name = "tts/%d";
#else
serial_driver.name = "ttyS";
* major number and the subtype code.
*/
callout_driver = serial_driver;
-#if (LINUX_VERSION_CODE > 0x2032D)
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS))
callout_driver.name = "cua/%d";
#else
callout_driver.name = "cua";
dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
- dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+ dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
comment 'IDE chipset support/bugfixes'
if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
return cdrom_lockdoor(drive, lock, NULL);
}
-#undef __ACER50__
-
-#ifdef __ACER50__
-/*
- * the buffer struct used by ide_cdrom_get_capabilities()
- */
-struct get_capabilities_buf {
- char pad[8];
- struct atapi_capabilities_page cap; /* this is 4 bytes short of ATAPI standard */
- char extra_cap[4]; /* Acer 50X needs the regulation size buffer */
-};
-
-static
-int ide_cdrom_get_capabilities (struct cdrom_device_info *cdi, struct get_capabilities_buf *buf)
-{
- int stat, attempts = 3, buflen = sizeof(*buf);
- ide_drive_t *drive = (ide_drive_t*) cdi->handle;
- struct cdrom_generic_command cgc;
-
- /*
- * Most drives don't care about the buffer size;
- * they return as much info as there's room for.
- * But some older drives (?) had trouble with the
- * standard size, preferring 4 bytes less.
- * And the modern Acer 50X rejects anything smaller
- * than the standard size.
- */
- if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX")))
- buflen -= sizeof(buf->extra_cap); /* for all drives except Acer 50X */
-
- do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
- if (stat == 0) {
- /*
- * The ACER/AOpen 24X cdrom has the speed
- * fields byte-swapped from the standard.
- */
- if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) {
- buf->cap.curspeed = ntohs(buf->cap.curspeed);
- buf->cap.maxspeed = ntohs(buf->cap.maxspeed);
- }
- CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176;
- CDROM_CONFIG_FLAGS(drive)->max_speed = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176;
- return 0;
- }
- } while (--attempts);
- return stat;
-}
-#endif /* __ACER50__ */
-
static
int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
{
-#ifndef __ACER50__
- int attempts = 3;
- struct {
- char pad[8];
- struct atapi_capabilities_page cap;
- } buf;
-#else
- struct get_capabilities_buf buf;
-#endif /* __ACER50__ */
ide_drive_t *drive = (ide_drive_t*) cdi->handle;
- struct cdrom_generic_command cgc;
struct request_sense sense;
int stat;
if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
return stat;
- init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
-
-#ifndef __ACER50__
- /* Now with that done, update the speed fields */
- do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
- if (attempts-- <= 0)
- return 0;
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
- } while (stat);
-
- /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
- if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
- CDROM_STATE_FLAGS (drive)->current_speed =
- (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
- CDROM_CONFIG_FLAGS (drive)->max_speed =
- (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
- } else {
- CDROM_STATE_FLAGS (drive)->current_speed =
- (ntohs(buf.cap.curspeed) + (176/2)) / 176;
- CDROM_CONFIG_FLAGS (drive)->max_speed =
- (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
- }
-#else
- if (ide_cdrom_get_capabilities(cdi,&buf))
- return 0;
-#endif /* __ACER50__ */
-
cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
return 0;
}
if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
devinfo->mask |= CDC_CLOSE_TRAY;
- devinfo->de = devfs_register (drive->de, "cd", 2, DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
- S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
- ide_fops, NULL);
+ devinfo->de = devfs_register(drive->de, "cd", 2, DEVFS_FL_DEFAULT,
+ HWIF(drive)->major, minor,
+ S_IFBLK | S_IRUGO | S_IWUGO, 0, 0,
+ ide_fops, NULL);
- return register_cdrom (devinfo);
+ return register_cdrom(devinfo);
}
+/*
+ * the buffer struct used by ide_cdrom_get_capabilities()
+ */
+struct get_capabilities_buf {
+ char pad[8];
+ struct atapi_capabilities_page cap;
+ char extra_cap[4];
+};
static
-int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
{
struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *cdi = &info->devinfo;
-#ifndef __ACER50__
- int stat, nslots = 1, attempts = 3;
struct cdrom_generic_command cgc;
- struct {
- char pad[8];
- struct atapi_capabilities_page cap;
- } buf;
-#else
- int nslots = 1;
- struct cdrom_generic_command cgc;
- struct get_capabilities_buf buf;
-#endif /* __ACER50__ */
+ int stat, attempts = 3;
- if (CDROM_CONFIG_FLAGS (drive)->nec260) {
- CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
- CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
- return nslots;
- }
-
- init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN);
/* we have to cheat a little here. the packet will eventually
* be queued with ide_cdrom_packet(), which extracts the
* drive from cdi->handle. Since this device hasn't been
*/
cdi->handle = (ide_drive_t *) drive;
cdi->ops = &ide_cdrom_dops;
-#ifndef __ACER50__
- /* we seem to get stat=0x01,err=0x00 the first time (??) */
- do {
- if (attempts-- <= 0)
- return 0;
+ init_cdrom_command(&cgc, cap, sizeof(*cap), CGC_DATA_UNKNOWN);
+ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
- } while (stat);
-#else
- if (ide_cdrom_get_capabilities(cdi,&buf))
+ if (!stat)
+ break;
+ } while (--attempts);
+ return stat;
+}
+
+static
+int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ struct atapi_capabilities_page cap;
+ int nslots = 1;
+
+ if (CDROM_CONFIG_FLAGS (drive)->nec260) {
+ CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+ CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+ return nslots;
+ }
+
+ if (ide_cdrom_get_capabilities(drive, &cap))
return 0;
-#endif /* __ACER50__ */
- if (buf.cap.lock == 0)
+ if (cap.lock == 0)
CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
- if (buf.cap.eject)
+ if (cap.eject)
CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
- if (buf.cap.cd_r_write)
+ if (cap.cd_r_write)
CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
- if (buf.cap.cd_rw_write)
+ if (cap.cd_rw_write)
CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
- if (buf.cap.test_write)
+ if (cap.test_write)
CDROM_CONFIG_FLAGS (drive)->test_write = 1;
- if (buf.cap.dvd_ram_read || buf.cap.dvd_r_read || buf.cap.dvd_rom)
+ if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
CDROM_CONFIG_FLAGS (drive)->dvd = 1;
- if (buf.cap.dvd_ram_write)
+ if (cap.dvd_ram_write)
CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
- if (buf.cap.dvd_r_write)
+ if (cap.dvd_r_write)
CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
- if (buf.cap.audio_play)
+ if (cap.audio_play)
CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
- if (buf.cap.mechtype == 0)
+ if (cap.mechtype == 0)
CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
#if ! STANDARD_ATAPI
else
#endif /* not STANDARD_ATAPI */
- if (buf.cap.mechtype == mechtype_individual_changer ||
- buf.cap.mechtype == mechtype_cartridge_changer) {
+ if (cap.mechtype == mechtype_individual_changer ||
+ cap.mechtype == mechtype_cartridge_changer) {
if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
}
}
-#ifndef __ACER50__
/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
CDROM_STATE_FLAGS (drive)->current_speed =
- (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+ (((unsigned int)cap.curspeed) + (176/2)) / 176;
CDROM_CONFIG_FLAGS (drive)->max_speed =
- (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+ (((unsigned int)cap.maxspeed) + (176/2)) / 176;
} else {
CDROM_STATE_FLAGS (drive)->current_speed =
- (ntohs(buf.cap.curspeed) + (176/2)) / 176;
+ (ntohs(cap.curspeed) + (176/2)) / 176;
CDROM_CONFIG_FLAGS (drive)->max_speed =
- (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+ (ntohs(cap.maxspeed) + (176/2)) / 176;
}
-#endif /* __ACER50__ */
/* don't print speed if the drive reported 0.
*/
else
printk (" drive");
- printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
+ printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
#include <linux/cdrom.h>
#include <asm/byteorder.h>
+/*
+ * Apparently older drives have problems with filling out the entire
+ * mode_sense capability structure. Define this to 1 if your drive isn't
+ * probed correctly.
+ */
+#ifndef BROKEN_CAP_PAGE
+#define BROKEN_CAP_PAGE 0
+#endif
+
/* Turn this on to have the driver print out the meanings of the
ATAPI error codes. This will use up additional kernel-space
memory, though. */
* generic stuff now in the Mt. Fuji spec.
*/
struct atapi_capabilities_page {
+ struct mode_page_header header;
#if defined(__BIG_ENDIAN_BITFIELD)
__u8 parameters_saveable : 1;
__u8 reserved1 : 1;
unsigned short buffer_size;
/* Current speed (in kB/s). */
unsigned short curspeed;
-
- /* Truncate the structure here, so we don't have headaches reading
- from older drives. */
+#if !BROKEN_CAP_PAGE
+ char pad[4];
+#endif
};
reg2, reg3);
rc = pci_read_config_byte(bmide_dev, 0x4b, ®);
- p += sprintf(p, "Drvie 0: Postwrite %s \t \t Postwrite %s\n",
+ p += sprintf(p, "Drive 0: Postwrite %s \t \t Postwrite %s\n",
(reg & 0x10) ? "Enabled" : "Disabled",
(reg & 0x40) ? "Enabled" : "Disabled");
p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
rc = pci_read_config_byte(bmide_dev, 0x4b, ®);
- p += sprintf(p, "Drvie 1: Postwrite %s \t \t Postwrite %s\n",
+ p += sprintf(p, "Drive 1: Postwrite %s \t \t Postwrite %s\n",
(reg & 0x20) ? "Enabled" : "Disabled",
(reg & 0x80) ? "Enabled" : "Disabled");
p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
};
#endif
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
struct el3_isapnp_adapters_struct {
unsigned short vendor, function;
char *name;
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
};
#endif /* CONFIG_ISAPNP */
-#if defined(CONFIG_ISAPNP) || defined(MODULE)
+#if defined(__ISAPNP__) || defined(MODULE)
static int nopnp = 0;
#endif
u16 phys_addr[3];
static int current_tag = 0;
int mca_slot = -1;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
static int pnp_cards = 0;
#endif
}
#endif
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
if (nopnp == 1)
goto no_pnp;
phys_addr[i] = htons(id_read_eeprom(i));
}
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
if (nopnp == 0) {
/* The ISA PnP 3c509 cards respond to the ID sequence.
This check is needed in order not to register them twice. */
#define RX_RING_SIZE 16
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/isapnp.h>
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
struct corkscrew_isapnp_adapters_struct {
unsigned short vendor, function;
char *name;
static int ioaddr;
static int pnp_cards = 0;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
if(nopnp == 1)
goto no_pnp;
for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
}
}
no_pnp:
-#endif /* not CONFIG_ISAPNP */
+#endif /* not __ISAPNP__ */
/* Check all locations on the ISA bus -- evil! */
for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
int irq;
-#ifdef CONFIG_ISAPNP
+#ifdef __ISAPNP__
/* Make sure this was not already picked up by isapnp */
if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue;
if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue;
*/
-static const char *version = "82596.c:v1.0 15/07/98\n";
+static const char *version = "82596.c $Revision: 1.4 $\n";
#include <linux/config.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT 0x0001
+#define DEB_PROBE 0x0002
+#define DEB_SERIOUS 0x0004
+#define DEB_ERRORS 0x0008
+#define DEB_MULTI 0x0010
+#define DEB_TDR 0x0020
+#define DEB_OPEN 0x0040
+#define DEB_RESET 0x0080
+#define DEB_ADDCMD 0x0100
+#define DEB_STATUS 0x0200
+#define DEB_STARTTX 0x0400
+#define DEB_RXADDR 0x0800
+#define DEB_TXADDR 0x1000
+#define DEB_RXFRAME 0x2000
+#define DEB_INTS 0x4000
+#define DEB_STRUCT 0x8000
+#define DEB_ANY 0xffff
+
+
+#define DEB(x,y) if (i596_debug & (x)) y
+
#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
#define ENABLE_MVME16x_NET
#define ISCP_BUSY 0x00010000
#define MACH_IS_APRICOT 0
#else
-#define WSWAPrfd(x) x
-#define WSWAPrbd(x) ((struct i596_rbd *)(x))
-#define WSWAPiscp(x) ((struct i596_iscp *)(x))
-#define WSWAPscb(x) ((struct i596_scb *)(x))
-#define WSWAPcmd(x) x
-#define WSWAPtbd(x) x
-#define WSWAPchar(x) ((char *)(x))
+#define WSWAPrfd(x) ((struct i596_rfd *)(x))
+#define WSWAPrbd(x) ((struct i596_rbd *)(x))
+#define WSWAPiscp(x) ((struct i596_iscp *)(x))
+#define WSWAPscb(x) ((struct i596_scb *)(x))
+#define WSWAPcmd(x) ((struct i596_cmd *)(x))
+#define WSWAPtbd(x) ((struct i596_tbd *)(x))
+#define WSWAPchar(x) ((char *)(x))
#define ISCP_BUSY 0x0001
#define MACH_IS_APRICOT 1
#endif
#define PORT_ALTSCP 0x02 /* alternate SCB address */
#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
-#define I82596_DEBUG 1
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_PARM(i596_debug, "i");
-#ifdef I82596_DEBUG
-int i596_debug = I82596_DEBUG;
-#else
-int i596_debug = 1;
-#endif
/* Copy frames shorter than rx_copybreak, otherwise pass on up in
* a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
#define I596_TOTAL_SIZE 17
-#define I596_NULL -1
+#define I596_NULL ((void *)0xffffffff)
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
#define RX_SUSPEND 0x0030
#define RX_ABORT 0x0040
-#define TX_TIMEOUT 5
+#define TX_TIMEOUT 5
+
struct i596_reg {
unsigned short porthi;
unsigned long ca;
};
-struct i596_cmd {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *next;
-};
-
#define EOF 0x8000
#define SIZE_MASK 0x3fff
char *data;
};
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596. The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next. It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+ struct i596_cmd *v_next; /* Address from CPUs viewpoint */
+ unsigned short status;
+ unsigned short command;
+ struct i596_cmd *b_next; /* Address from i596 viewpoint */
+};
+
struct tx_cmd {
struct i596_cmd cmd;
struct i596_tbd *tbd;
struct sk_buff *skb; /* So we can free it after tx */
};
+struct tdr_cmd {
+ struct i596_cmd cmd;
+ unsigned short status;
+ unsigned short pad;
+};
+
+struct mc_cmd {
+ struct i596_cmd cmd;
+ short mc_cnt;
+ char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+ struct i596_cmd cmd;
+ char eth_addr[8];
+};
+
+struct cf_cmd {
+ struct i596_cmd cmd;
+ char i596_config[16];
+};
+
struct i596_rfd {
unsigned short stat;
unsigned short cmd;
- struct i596_rfd *next;
+ struct i596_rfd *b_next; /* Address from i596 viewpoint */
struct i596_rbd *rbd;
unsigned short count;
unsigned short size;
+ struct i596_rfd *v_next; /* Address from CPUs viewpoint */
+ struct i596_rfd *v_prev;
};
struct i596_rbd {
unsigned short count;
unsigned short zero1;
- struct i596_rbd *next;
- char *data;
+ struct i596_rbd *b_next;
+ unsigned char *b_data; /* Address from i596 viewpoint */
unsigned short size;
unsigned short zero2;
struct sk_buff *skb;
+ struct i596_rbd *v_next;
+ struct i596_rbd *b_addr; /* This rbd addr from i596 view */
+ unsigned char *v_data; /* Address from CPUs viewpoint */
};
-#define TX_RING_SIZE 16
+#define TX_RING_SIZE 64
#define RX_RING_SIZE 16
struct i596_scb {
volatile struct i596_scp scp;
volatile struct i596_iscp iscp;
volatile struct i596_scb scb;
- struct i596_cmd set_add;
- char eth_addr[8];
- struct i596_cmd set_conf;
- char i596_config[16];
- struct i596_cmd tdr;
- struct i596_cmd mc_cmd; /* Keep these three together!!! */
- short mc_cnt; /* Keep these three together!!! */
- char mc_addrs[MAX_MC_CNT*6]; /* Keep these three together!!! */
+ struct sa_cmd sa_cmd;
+ struct cf_cmd cf_cmd;
+ struct tdr_cmd tdr_cmd;
+ struct mc_cmd mc_cmd;
unsigned long stat;
int last_restart __attribute__((aligned(4)));
- struct i596_rfd *rx_tail;
+ struct i596_rfd *rfd_head;
+ struct i596_rbd *rbd_head;
struct i596_cmd *cmd_tail;
struct i596_cmd *cmd_head;
int cmd_backlog;
static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(char *);
+static void print_eth(unsigned char *buf, char *str);
static void set_multicast_list(struct net_device *dev);
static int rx_ring_size = RX_RING_SIZE;
static int ticks_limit = 25;
-static int max_cmd_backlog = 16;
-\f
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
static inline void CA(struct net_device *dev)
{
#endif
#ifdef ENABLE_BVME6000_NET
if (MACH_IS_BVME6000) {
- volatile u32 i = *(volatile u32 *) (dev->base_addr);
+ volatile u32 i;
+
+ i = *(volatile u32 *) (dev->base_addr);
}
#endif
#ifdef ENABLE_APRICOT
}
+static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+ while (--delcnt && lp->iscp.stat)
+ udelay(10);
+ if (!delcnt) {
+ printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str, lp->scb.status, lp->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
+{
+ while (--delcnt && lp->scb.command)
+ udelay(10);
+ if (!delcnt) {
+ printk("%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str, lp->scb.status, lp->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+ &lp->scp, lp->scp.sysbus, lp->scp.iscp);
+ printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+ &lp->iscp, lp->iscp.stat, lp->iscp.scb);
+ printk("scb at %p, scb.status = %04x, .command = %04x,"
+ " .cmd = %p, .rfd = %p\n",
+ &lp->scb, lp->scb.status, lp->scb.command,
+ lp->scb.cmd, lp->scb.rfd);
+ printk(" errors: crc %lx, align %lx, resource %lx,"
+ " over %lx, rcvdt %lx, short %lx\n",
+ lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
+ lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
+ cmd = lp->cmd_head;
+ while (cmd != I596_NULL) {
+ printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+ cmd, cmd->status, cmd->command, cmd->b_next);
+ cmd = cmd->v_next;
+ }
+ rfd = lp->rfd_head;
+ printk("rfd_head = %p\n", rfd);
+ do {
+ printk (" %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+ " count %04x\n",
+ rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
+ rfd->count);
+ rfd = rfd->v_next;
+ } while (rfd != lp->rfd_head);
+ rbd = lp->rbd_head;
+ printk("rbd_head = %p\n", rbd);
+ do {
+ printk(" %p .count %04x, b_next %p, b_data %p, size %04x\n",
+ rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
+ rbd = rbd->v_next;
+ } while (rbd != lp->rbd_head);
+}
+
+
#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
- struct i596_cmd *cmd;
+ volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
- struct i596_private *lp = (struct i596_private *) dev->priv;
- printk("i596_error: lp = 0x%08x\n", (u32) lp);
- printk("scp at %08x, .sysbus = %08x, .iscp = %08x\n",
- (u32) & lp->scp, (u32) lp->scp.sysbus, (u32) lp->scp.iscp);
- printk("iscp at %08x, .stat = %08x, .scb = %08x\n",
- (u32) & lp->iscp, (u32) lp->iscp.stat, (u32) lp->iscp.scb);
- printk("scb at %08x, .status = %04x, .command = %04x\n",
- (u32) & lp->scb, lp->scb.status, lp->scb.command);
- printk(" .cmd = %08x, .rfd = %08x\n", (u32) lp->scb.cmd,
- (u32) lp->scb.rfd);
- cmd = WSWAPcmd(lp->scb.cmd);
- while (cmd && (u32) cmd < 0x1000000) {
- printk("cmd at %08x, .status = %04x, .command = %04x, .next = %08x\n",
- (u32) cmd, cmd->status, cmd->command, (u32) cmd->next);
- cmd = WSWAPcmd(cmd->next);
- }
- while (1);
+ pcc2[0x28] = 1;
+ pcc2[0x2b] = 0x1d;
+ printk("%s: Error interrupt\n", dev->name);
+ i596_display_data(dev);
}
#endif
struct i596_rfd *rfd;
struct i596_rbd *rbd;
- if (i596_debug > 1)
- printk ("%s: init_rx_bufs %d.\n", dev->name, rx_ring_size);
-
/* First build the Receive Buffer Descriptor List */
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
if (skb == NULL)
panic("82596: alloc_skb() failed");
skb->dev = dev;
- rbd->next = WSWAPrbd(rbd+1);
+ rbd->v_next = rbd+1;
+ rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
+ rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
rbd->skb = skb;
- rbd->data = WSWAPchar(skb->tail);
+ rbd->v_data = skb->tail;
+ rbd->b_data = WSWAPchar(virt_to_bus(skb->tail));
rbd->size = PKT_BUF_SZ;
#ifdef __mc68000__
cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);
#endif
}
- lp->rbds[rx_ring_size-1].next = WSWAPrbd(lp->rbds);
+ lp->rbd_head = lp->rbds;
+ rbd = lp->rbds + rx_ring_size - 1;
+ rbd->v_next = lp->rbds;
+ rbd->b_next = WSWAPrbd(virt_to_bus(lp->rbds));
/* Now build the Receive Frame Descriptor List */
for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
- rfd->rbd = (struct i596_rbd *)I596_NULL;
- rfd->next = WSWAPrfd(rfd+1);
+ rfd->rbd = I596_NULL;
+ rfd->v_next = rfd+1;
+ rfd->v_prev = rfd-1;
+ rfd->b_next = WSWAPrfd(virt_to_bus(rfd+1));
rfd->cmd = CMD_FLEX;
}
- lp->scb.rfd = WSWAPrfd(lp->rfds);
- lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
+ lp->rfd_head = lp->rfds;
+ lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+ rfd = lp->rfds;
+ rfd->rbd = lp->rbd_head;
+ rfd->v_prev = lp->rfds + rx_ring_size - 1;
rfd = lp->rfds + rx_ring_size - 1;
- lp->rx_tail = rfd;
- rfd->next = WSWAPrfd(lp->rfds);
+ rfd->v_next = lp->rfds;
+ rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
rfd->cmd = CMD_EOL|CMD_FLEX;
}
}
}
-static inline void init_i596_mem(struct net_device *dev)
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = (struct i596_private *) dev->priv;
+ int i;
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+
+ for (i = 0; i < rx_ring_size; i++) {
+ lp->rfds[i].rbd = I596_NULL;
+ lp->rfds[i].cmd = CMD_FLEX;
+ }
+ lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+ lp->rfd_head = lp->rfds;
+ lp->scb.rfd = WSWAPrfd(virt_to_bus(lp->rfds));
+ lp->rbd_head = lp->rbds;
+ lp->rfds[0].rbd = WSWAPrbd(virt_to_bus(lp->rbds));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
short ioaddr = dev->base_addr;
#endif
- int boguscnt = 100000;
unsigned long flags;
- int i;
+
+ MPU_PORT(dev, PORT_RESET, 0);
+
+ udelay(100); /* Wait 100us - seems to help */
#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
#ifdef ENABLE_MVME16x_NET
/* Disable all ints for now */
pcc2[0x28] = 1;
- pcc2[0x2a] = 0x40;
+ pcc2[0x2a] = 0x48;
/* Following disables snooping. Snooping is not required
* as we make appropriate use of non-cached pages for
* shared data, and cache_push/cache_clear.
*/
- pcc2[0x2b] = 0x00;
+ pcc2[0x2b] = 0x08;
}
#endif
#ifdef ENABLE_BVME6000_NET
}
#endif
- MPU_PORT(dev, PORT_RESET, 0);
-
- udelay(100); /* Wait 100us - seems to help */
-
/* change the scp address */
- MPU_PORT(dev, PORT_ALTSCP, &lp->scp);
+ MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));
#elif defined(ENABLE_APRICOT)
- /* change the scp address */
- outw(0, ioaddr);
- outw(0, ioaddr);
- outb(4, ioaddr + 0xf);
- outw(((((int) &lp->scp) & 0xffff) | 2), ioaddr);
- outw((((int) &lp->scp) >> 16) & 0xffff, ioaddr);
+ {
+ u32 scp = virt_to_bus(&lp->scp);
+
+ /* change the scp address */
+ outw(0, ioaddr);
+ outw(0, ioaddr);
+ outb(4, ioaddr + 0xf);
+ outw(scp | 2, ioaddr);
+ outw(scp >> 16, ioaddr);
+ }
#endif
lp->last_cmd = jiffies;
lp->scp.sysbus = 0x00440000;
#endif
- lp->scp.iscp = WSWAPiscp(&(lp->iscp));
- lp->iscp.scb = WSWAPscb(&(lp->scb));
+ lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp)));
+ lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb)));
lp->iscp.stat = ISCP_BUSY;
lp->cmd_backlog = 0;
- lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+ lp->cmd_head = lp->scb.cmd = I596_NULL;
- if (i596_debug > 1)
- printk("%s: starting i82596.\n", dev->name);
+ DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
#if defined(ENABLE_APRICOT)
(void) inb(ioaddr + 0x10);
#endif
CA(dev);
- while (lp->iscp.stat)
- if (--boguscnt == 0) {
- printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ if (wait_istat(dev,lp,1000,"initialization timed out"))
+ goto failed;
+ DEB(DEB_INIT,printk("%s: i82596 initialization successful\n", dev->name));
/* Ensure rx frame/buffer descriptors are tidy */
- /* Bit naff doing this here as well as in init_rx_bufs() */
-
- for (i = 0; i < rx_ring_size; i++) {
- lp->rfds[i].rbd = (struct i596_rbd *)I596_NULL;
- lp->rfds[i].cmd = CMD_FLEX;
- }
- lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
- lp->scb.rfd = WSWAPrfd(lp->rfds);
- lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
- lp->rx_tail = lp->rfds + rx_ring_size - 1;
-
+ rebuild_rx_bufs(dev);
lp->scb.command = 0;
#ifdef ENABLE_MVME16x_NET
volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
/* Enable ints, etc. now */
- pcc2[0x2a] = 0x08;
pcc2[0x2a] = 0x55; /* Edge sensitive */
- pcc2[0x2b] = 0x55;
+ pcc2[0x2b] = 0x15;
}
#endif
#ifdef ENABLE_BVME6000_NET
}
#endif
- memcpy(lp->i596_config, init_setup, 14);
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, &lp->set_conf);
- memcpy(lp->eth_addr, dev->dev_addr, 6);
- lp->set_add.command = CmdSASetup;
- i596_add_cmd(dev, &lp->set_add);
+ DEB(DEB_INIT,printk("%s: queuing CmdConfigure\n", dev->name));
+ memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+ lp->cf_cmd.cmd.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->cf_cmd.cmd);
- lp->tdr.command = CmdTDR;
- i596_add_cmd(dev, &lp->tdr);
+ DEB(DEB_INIT,printk("%s: queuing CmdSASetup\n", dev->name));
+ memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
+ lp->sa_cmd.cmd.command = CmdSASetup;
+ i596_add_cmd(dev, &lp->sa_cmd.cmd);
- boguscnt = 200000;
+ DEB(DEB_INIT,printk("%s: queuing CmdTDR\n", dev->name));
+ lp->tdr_cmd.cmd.command = CmdTDR;
+ i596_add_cmd(dev, &lp->tdr_cmd.cmd);
spin_lock_irqsave (&lp->lock, flags);
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ if (wait_cmd(dev,lp,1000,"timed out waiting to issue RX_START"))
+ goto failed;
+ DEB(DEB_INIT,printk("%s: Issuing RX_START\n", dev->name));
lp->scb.command = RX_START;
CA(dev);
spin_unlock_irqrestore (&lp->lock, flags);
- boguscnt = 2000;
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
- return;
+ if (wait_cmd(dev,lp,1000,"RX_START not processed"))
+ goto failed;
+ DEB(DEB_INIT,printk("%s: Receive unit started OK\n", dev->name));
+ return 0;
+
+failed:
+ printk("%s: Failed to initialise 82596\n", dev->name);
+ MPU_PORT(dev, PORT_RESET, 0);
+ return -1;
}
static inline int i596_rx(struct net_device *dev)
struct i596_rbd *rbd;
int frames = 0;
- if (i596_debug > 3)
- printk ("i596_rx()\n");
+ DEB(DEB_RXFRAME,printk ("i596_rx(), rfd_head %p, rbd_head %p\n",
+ lp->rfd_head, lp->rbd_head));
- rfd = WSWAPrfd(lp->scb.rfd); /* Ref next frame to check */
+ rfd = lp->rfd_head; /* Ref next frame to check */
- while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
- rbd = WSWAPrbd(rfd->rbd); /* Ref associated buffer desc */
-
- if (i596_debug >2)
- print_eth(WSWAPchar(rbd->data));
-
- if ((rfd->stat) & STAT_OK) {
+ while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
+ if (rfd->rbd == I596_NULL)
+ rbd = I596_NULL;
+ else if (rfd->rbd == lp->rbd_head->b_addr)
+ rbd = lp->rbd_head;
+ else {
+ printk("%s: rbd chain broken!\n", dev->name);
+ /* XXX Now what? */
+ rbd = I596_NULL;
+ }
+ DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+
+ if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
/* a good frame */
int pkt_len = rbd->count & 0x3fff;
struct sk_buff *skb = rbd->skb;
int rx_in_place = 0;
+ DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
frames++;
/* Check if the packet is long enough to just accept
if (pkt_len > rx_copybreak) {
struct sk_buff *newskb;
- char *temp;
/* Get fresh skbuff to replace filled one. */
newskb = dev_alloc_skb(PKT_BUF_SZ);
goto memory_squeeze;
}
/* Pass up the skb already on the Rx ring. */
- temp = skb_put(skb, pkt_len);
- if (WSWAPchar(rbd->data) != temp)
- printk(KERN_ERR "%s: Internal consistency error "
- "-- the skbuff addresses do not match"
- " in i596_rx: %p vs. %p / %p.\n", dev->name,
- WSWAPchar(rbd->data),
- skb->head, temp);
+ skb_put(skb, pkt_len);
rx_in_place = 1;
rbd->skb = newskb;
newskb->dev = dev;
- rbd->data = WSWAPchar(newskb->tail);
+ rbd->v_data = newskb->tail;
+ rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail));
#ifdef __mc68000__
cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);
#endif
if (!rx_in_place) {
/* 16 byte align the data fields */
skb_reserve(skb, 2);
- memcpy(skb_put(skb,pkt_len),
- WSWAPchar(rbd->data), pkt_len);
+ memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
}
skb->protocol=eth_type_trans(skb,dev);
skb->len = pkt_len;
}
}
else {
+ DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n",
+ dev->name, rfd->stat));
lp->stats.rx_errors++;
if ((rfd->stat) & 0x0001)
lp->stats.collisions++;
/* Clear the buffer descriptor count and EOF + F flags */
- if (rbd != (struct i596_rbd *)I596_NULL)
- rbd->count=0;
- else
- printk("%s: Null rbd - oops!\n", dev->name);
+ if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+ rbd->count = 0;
+ lp->rbd_head = rbd->v_next;
+ }
/* Tidy the frame descriptor, marking it as end of list */
- rfd->rbd = (struct i596_rbd *)I596_NULL;
+ rfd->rbd = I596_NULL;
rfd->stat = 0;
rfd->cmd = CMD_EOL|CMD_FLEX;
rfd->count = 0;
/* Remove end-of-list from old end descriptor */
- lp->rx_tail->cmd = CMD_FLEX;
-
- /* Update last frame descriptor to reference the one just
- * processed */
-
- lp->rx_tail = rfd;
+ rfd->v_prev->cmd = CMD_FLEX;
/* Update record of next frame descriptor to process */
- lp->scb.rfd = rfd->next;
- rfd = WSWAPrfd(lp->scb.rfd); /* Next frame desc. to check */
+ lp->scb.rfd = rfd->b_next;
+ lp->rfd_head = rfd->v_next;
+ rfd = lp->rfd_head;
}
- if (i596_debug > 3)
- printk ("frames %d\n", frames);
+ DEB(DEB_RXFRAME,printk ("frames %d\n", frames));
return 0;
}
-static inline void i596_cleanup_cmd(struct i596_private *lp)
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
{
struct i596_cmd *ptr;
- int boguscnt = 1000;
-
- if (i596_debug > 4)
- printk("i596_cleanup_cmd\n");
- while (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
+ while (lp->cmd_head != I596_NULL) {
ptr = lp->cmd_head;
-
- lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+ lp->cmd_head = ptr->v_next;
lp->cmd_backlog--;
switch ((ptr->command) & 0x7) {
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
- ptr->next = (struct i596_cmd *) I596_NULL;
+ ptr->v_next = ptr->b_next = I596_NULL;
tx_cmd->cmd.command = 0; /* Mark as free */
break;
}
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd *) I596_NULL;
- break;
- }
default:
- ptr->next = (struct i596_cmd *) I596_NULL;
+ ptr->v_next = ptr->b_next = I596_NULL;
}
}
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
- lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+ wait_cmd(dev,lp,100,"i596_cleanup_cmd timed out");
+ lp->scb.cmd = I596_NULL;
}
static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
{
- int boguscnt = 1000;
unsigned long flags;
- if (i596_debug > 1)
- printk("i596_reset\n");
+ DEB(DEB_RESET,printk("i596_reset\n"));
spin_lock_irqsave (&lp->lock, flags);
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"i596_reset timed out");
netif_stop_queue(dev);
CA(dev);
/* wait for shutdown */
- boguscnt = 4000;
-
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,1000,"i596_reset 2 timed out");
spin_unlock_irqrestore (&lp->lock, flags);
- i596_cleanup_cmd(lp);
+ i596_cleanup_cmd(dev,lp);
i596_rx(dev);
netif_start_queue(dev);
struct i596_private *lp = (struct i596_private *) dev->priv;
int ioaddr = dev->base_addr;
unsigned long flags;
- int boguscnt = 1000;
- if (i596_debug > 4)
- printk("i596_add_cmd\n");
+ DEB(DEB_ADDCMD,printk("i596_add_cmd\n"));
cmd->status = 0;
cmd->command |= (CMD_EOL | CMD_INTR);
- cmd->next = (struct i596_cmd *) I596_NULL;
+ cmd->v_next = cmd->b_next = I596_NULL;
spin_lock_irqsave (&lp->lock, flags);
- /*
- * RGH 300597: Looks to me like there could be a race condition
- * here. Just because we havn't picked up all the command items
- * yet, doesn't mean that the 82596 hasn't finished processing
- * them. So, we may need to do a CUC_START anyway.
- * Maybe not. If it interrupts saying the CU is idle when there
- * is still something in the cmd queue, the int handler with restart
- * the CU.
- */
-
- if (lp->cmd_head != (struct i596_cmd *) I596_NULL) {
- lp->cmd_tail->next = WSWAPcmd(cmd);
+ if (lp->cmd_head != I596_NULL) {
+ lp->cmd_tail->v_next = cmd;
+ lp->cmd_tail->b_next = WSWAPcmd(virt_to_bus(&cmd->status));
} else {
lp->cmd_head = cmd;
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
- lp->scb.cmd = WSWAPcmd(cmd);
+ wait_cmd(dev,lp,100,"i596_add_cmd timed out");
+ lp->scb.cmd = WSWAPcmd(virt_to_bus(&cmd->status));
lp->scb.command = CUC_START;
CA(dev);
}
lp->cmd_tail = cmd;
lp->cmd_backlog++;
- lp->cmd_head = WSWAPcmd(lp->scb.cmd); /* Is this redundant? RGH 300597 */
-
spin_unlock_irqrestore (&lp->lock, flags);
if (lp->cmd_backlog > max_cmd_backlog) {
static int i596_open(struct net_device *dev)
{
- if (i596_debug > 1)
- printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
+ int res = 0;
- if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev))
+ DEB(DEB_OPEN,printk("%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+ if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
+ printk("%s: IRQ %d not free\n", dev->name, dev->irq);
return -EAGAIN;
+ }
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
if (request_irq(0x56, &i596_error, 0, "i82596_error", dev))
MOD_INC_USE_COUNT;
/* Initialize the 82596 memory */
- init_i596_mem(dev);
+ if (init_i596_mem(dev)) {
+ res = -EAGAIN;
+ free_irq(dev->irq, dev);
+ }
- return 0; /* Always succeed */
+ return res;
}
static void i596_tx_timeout (struct net_device *dev)
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
- printk ("%s: transmit timed out, status resetting.\n", dev->name);
+ DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
+ dev->name));
lp->stats.tx_errors++;
/* Try to restart the adaptor */
if (lp->last_restart == lp->stats.tx_packets) {
- if (i596_debug > 1)
- printk ("Resetting board.\n");
-
+ DEB(DEB_ERRORS,printk ("Resetting board.\n"));
/* Shutdown and restart */
i596_reset (dev, lp, ioaddr);
} else {
/* Issue a channel attention signal */
- if (i596_debug > 1)
- printk ("Kicking board.\n");
+ DEB(DEB_ERRORS,printk ("Kicking board.\n"));
lp->scb.command = CUC_START | RX_START;
CA (dev);
lp->last_restart = lp->stats.tx_packets;
struct i596_private *lp = (struct i596_private *) dev->priv;
struct tx_cmd *tx_cmd;
struct i596_tbd *tbd;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ dev->trans_start = jiffies;
- if (i596_debug > 2)
- printk("%s: 82596 start xmit\n", dev->name);
-
- if (i596_debug > 3)
- printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
- skb->len, (unsigned int)skb->data);
+ DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
+ skb->len, (unsigned int)skb->data));
netif_stop_queue(dev);
-
- {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- dev->trans_start = jiffies;
- tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
- tbd = lp->tbds + lp->next_tx_cmd;
+ tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+ tbd = lp->tbds + lp->next_tx_cmd;
- if (tx_cmd->cmd.command) {
- printk ("%s: xmit ring full, dropping packet.\n",
- dev->name);
- lp->stats.tx_dropped++;
+ if (tx_cmd->cmd.command) {
+ DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n",
+ dev->name));
+ lp->stats.tx_dropped++;
- dev_kfree_skb(skb);
- } else {
- if (++lp->next_tx_cmd == TX_RING_SIZE)
- lp->next_tx_cmd = 0;
- tx_cmd->tbd = WSWAPtbd(tbd);
- tbd->next = (struct i596_tbd *) I596_NULL;
+ dev_kfree_skb(skb);
+ } else {
+ if (++lp->next_tx_cmd == TX_RING_SIZE)
+ lp->next_tx_cmd = 0;
+ tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));
+ tbd->next = I596_NULL;
- tx_cmd->cmd.command = CMD_FLEX | CmdTx;
- tx_cmd->skb = skb;
+ tx_cmd->cmd.command = CMD_FLEX | CmdTx;
+ tx_cmd->skb = skb;
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tbd->pad = 0;
- tbd->size = EOF | length;
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tbd->pad = 0;
+ tbd->size = EOF | length;
- tbd->data = WSWAPchar(skb->data);
+ tbd->data = WSWAPchar(virt_to_bus(skb->data));
#ifdef __mc68000__
- cache_push(virt_to_phys(skb->data), length);
+ cache_push(virt_to_phys(skb->data), length);
#endif
- if (i596_debug > 3)
- print_eth(skb->data);
- i596_add_cmd(dev, (struct i596_cmd *) tx_cmd);
+ DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
+ i596_add_cmd(dev, &tx_cmd->cmd);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
- }
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += length;
}
netif_start_queue(dev);
return 0;
}
-static void print_eth(char *add)
+static void print_eth(unsigned char *add, char *str)
{
int i;
- printk("print_eth(%08x)\n", (unsigned int) add);
- printk("Dest ");
+ printk("i596 0x%p, ", add);
for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i]);
- printk("\n");
-
- printk("Source");
+ printk(" %02X", add[i + 6]);
+ printk(" -->");
for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char) add[i + 6]);
- printk("\n");
- printk("type %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+ printk(" %02X", add[i]);
+ printk(" %02X%02X, %s\n", add[12], add[13], str);
}
int __init i82596_probe(struct net_device *dev)
int i;
struct i596_private *lp;
char eth_addr[6];
+ static int probed = 0;
+ if (probed)
+ return -ENODEV;
+ probed++;
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
- static int probed = 0;
-#ifdef XXX_FIXME
if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
printk("Ethernet probe disabled - chip not present\n");
- return ENODEV;
+ return -ENODEV;
}
-#endif
- if (probed)
- return ENODEV;
- probed++;
memcpy(eth_addr, (void *) 0xfffc1f2c, 6); /* YUCK! Get addr from NOVRAM */
dev->base_addr = MVME_I596_BASE;
dev->irq = (unsigned) MVME16x_IRQ_I596;
}
#endif
#ifdef ENABLE_APRICOT
- int checksum = 0;
- int ioaddr = 0x300;
+ {
+ int checksum = 0;
+ int ioaddr = 0x300;
- /* this is easy the ethernet interface can only be at 0x300 */
- /* first check nothing is already registered here */
+ /* this is easy the ethernet interface can only be at 0x300 */
+ /* first check nothing is already registered here */
- if (check_region(ioaddr, I596_TOTAL_SIZE))
- return ENODEV;
+ if (check_region(ioaddr, I596_TOTAL_SIZE)) {
+ printk("82596: IO address 0x%04x in use\n", ioaddr);
+ return -ENODEV;
+ }
- for (i = 0; i < 8; i++) {
- eth_addr[i] = inb(ioaddr + 8 + i);
- checksum += eth_addr[i];
- }
+ for (i = 0; i < 8; i++) {
+ eth_addr[i] = inb(ioaddr + 8 + i);
+ checksum += eth_addr[i];
+ }
- /* checksum is a multiple of 0x100, got this wrong first time
- some machines have 0x100, some 0x200. The DOS driver doesn't
- even bother with the checksum */
+ /* checksum is a multiple of 0x100, got this wrong first time
+ some machines have 0x100, some 0x200. The DOS driver doesn't
+ even bother with the checksum */
- if (checksum % 0x100)
- return ENODEV;
+ if (checksum % 0x100)
+ return -ENODEV;
- /* Some other boards trip the checksum.. but then appear as ether
- address 0. Trap these - AC */
+ /* Some other boards trip the checksum.. but then appear as
+ * ether address 0. Trap these - AC */
- if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
- return ENODEV;
+ if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
+ return -ENODEV;
- request_region(ioaddr, I596_TOTAL_SIZE, "i596");
+ request_region(ioaddr, I596_TOTAL_SIZE, "i596");
- dev->base_addr = ioaddr;
- dev->irq = 10;
+ dev->base_addr = ioaddr;
+ dev->irq = 10;
+ }
+#endif
+ dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+ if (!dev->mem_start) {
+#ifdef ENABLE_APRICOT
+ release_region(dev->base_addr, I596_TOTAL_SIZE);
#endif
+ return -ENOMEM;
+ }
+
ether_setup(dev);
- printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr);
+ DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr));
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+ DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
- printk(" IRQ %d.\n", dev->irq);
+ DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
- if (i596_debug > 0)
- printk(version);
+ DEB(DEB_PROBE,printk(version));
/* The 82596-specific entries in the device structure. */
dev->open = i596_open;
dev->set_multicast_list = set_multicast_list;
dev->tx_timeout = i596_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-
- dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
dev->priv = (void *)(dev->mem_start);
lp = (struct i596_private *) dev->priv;
- if (i596_debug)
- printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
+ DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
dev->name, (unsigned long)lp,
- sizeof(struct i596_private), (unsigned long)&lp->scb);
+ sizeof(struct i596_private), (unsigned long)&lp->scb));
memset((void *) lp, 0, sizeof(struct i596_private));
#ifdef __mc68000__
kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);
#endif
lp->scb.command = 0;
- lp->scb.cmd = (struct i596_cmd *) I596_NULL;
- lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+ lp->scb.cmd = I596_NULL;
+ lp->scb.rfd = I596_NULL;
lp->lock = SPIN_LOCK_UNLOCKED;
return 0;
struct net_device *dev = dev_id;
struct i596_private *lp;
short ioaddr;
- int boguscnt = 2000;
unsigned short status, ack_cmd = 0;
#ifdef ENABLE_BVME6000_NET
printk("i596_interrupt(): irq %d for unknown device.\n", irq);
return;
}
- if (i596_debug > 3)
- printk("%s: i596_interrupt(): irq %d\n", dev->name, irq);
ioaddr = dev->base_addr;
lp = (struct i596_private *) dev->priv;
-
+
spin_lock (&lp->lock);
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"i596 interrupt, timeout");
status = lp->scb.status;
- if (i596_debug > 4)
- printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status);
+ DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+ dev->name, irq, status));
ack_cmd = status & 0xf000;
if ((status & 0x8000) || (status & 0x2000)) {
struct i596_cmd *ptr;
- if ((i596_debug > 4) && (status & 0x8000))
- printk("%s: i596 interrupt completed command.\n", dev->name);
- if ((i596_debug > 4) && (status & 0x2000))
- printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
+ if ((status & 0x8000))
+ DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name));
+ if ((status & 0x2000))
+ DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
- while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C)) {
+ while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {
ptr = lp->cmd_head;
- if (i596_debug > 2)
- printk("cmd_head->status = %04x, ->command = %04x\n",
- lp->cmd_head->status, lp->cmd_head->command);
- lp->cmd_head = WSWAPcmd(lp->cmd_head->next);
+ DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n",
+ lp->cmd_head->status, lp->cmd_head->command));
+ lp->cmd_head = ptr->v_next;
lp->cmd_backlog--;
switch ((ptr->command) & 0x7) {
case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
-
- if ((ptr->status) & STAT_OK) {
- if (i596_debug > 2)
- print_eth(skb->data);
- } else {
- lp->stats.tx_errors++;
- if ((ptr->status) & 0x0020)
- lp->stats.collisions++;
- if (!((ptr->status) & 0x0040))
- lp->stats.tx_heartbeat_errors++;
- if ((ptr->status) & 0x0400)
- lp->stats.tx_carrier_errors++;
- if ((ptr->status) & 0x0800)
- lp->stats.collisions++;
- if ((ptr->status) & 0x1000)
- lp->stats.tx_aborted_errors++;
- }
-
- dev_kfree_skb(skb);
-
- ptr->next = (struct i596_cmd *) I596_NULL;
- tx_cmd->cmd.command = 0; /* Mark free */
- break;
- }
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd *) I596_NULL;
- break;
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ if ((ptr->status) & STAT_OK) {
+ DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
+ } else {
+ lp->stats.tx_errors++;
+ if ((ptr->status) & 0x0020)
+ lp->stats.collisions++;
+ if (!((ptr->status) & 0x0040))
+ lp->stats.tx_heartbeat_errors++;
+ if ((ptr->status) & 0x0400)
+ lp->stats.tx_carrier_errors++;
+ if ((ptr->status) & 0x0800)
+ lp->stats.collisions++;
+ if ((ptr->status) & 0x1000)
+ lp->stats.tx_aborted_errors++;
}
+
+ dev_kfree_skb_irq(skb);
+
+ tx_cmd->cmd.command = 0; /* Mark free */
+ break;
+ }
case CmdTDR:
- {
- unsigned long status = *((unsigned long *) (ptr + 1));
-
- if (status & 0x8000) {
- if (i596_debug > 3)
- printk("%s: link ok.\n", dev->name);
- } else {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n", dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n", dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n", dev->name);
-
- if (i596_debug > 1)
- printk("%s: Time %ld.\n", dev->name, status & 0x07ff);
- }
- break;
+ {
+ unsigned short status = ((struct tdr_cmd *)ptr)->status;
+
+ if (status & 0x8000) {
+ DEB(DEB_ANY,printk("%s: link ok.\n", dev->name));
+ } else {
+ if (status & 0x4000)
+ printk("%s: Transceiver problem.\n", dev->name);
+ if (status & 0x2000)
+ printk("%s: Termination problem.\n", dev->name);
+ if (status & 0x1000)
+ printk("%s: Short circuit.\n", dev->name);
+
+ DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff));
}
+ break;
+ }
case CmdConfigure:
- {
- ptr->next = (struct i596_cmd *) I596_NULL;
- /* Zap command so set_multicast_list() knows it is free */
- ptr->command = 0;
- break;
- }
- default:
- ptr->next = (struct i596_cmd *) I596_NULL;
+ /* Zap command so set_multicast_list() knows it is free */
+ ptr->command = 0;
+ break;
}
+ ptr->v_next = ptr->b_next = I596_NULL;
lp->last_cmd = jiffies;
}
ptr = lp->cmd_head;
- while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail)) {
+ while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
ptr->command &= 0x1fff;
- ptr = WSWAPcmd(ptr->next);
+ ptr = ptr->v_next;
}
- if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) &&
- netif_running(dev))
+ if ((lp->cmd_head != I596_NULL))
ack_cmd |= CUC_START;
- lp->scb.cmd = WSWAPcmd(lp->cmd_head);
+ lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));
}
if ((status & 0x1000) || (status & 0x4000)) {
- if ((i596_debug > 4) && (status & 0x4000))
- printk("%s: i596 interrupt received a frame.\n", dev->name);
+ if ((status & 0x4000))
+ DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name));
+ i596_rx(dev);
/* Only RX_START if stopped - RGH 07-07-96 */
if (status & 0x1000) {
- if (netif_running(dev))
+ if (netif_running(dev)) {
+ DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
ack_cmd |= RX_START;
- if (i596_debug > 1)
- printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0);
+ lp->stats.rx_errors++;
+ lp->stats.rx_fifo_errors++;
+ rebuild_rx_bufs(dev);
+ }
}
- i596_rx(dev);
}
- /* acknowledge the interrupt */
-
-/* COMMENTED OUT <<<<<
- if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start))
- ack_cmd |= CUC_START;
- */
- boguscnt = 1000;
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"i596 interrupt, timeout");
lp->scb.command = ack_cmd;
#ifdef ENABLE_MVME16x_NET
#endif
CA(dev);
- if (i596_debug > 4)
- printk("%s: exiting interrupt.\n", dev->name);
+ DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name));
spin_unlock (&lp->lock);
-
return;
}
static int i596_close(struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
- int boguscnt = 2000;
unsigned long flags;
netif_stop_queue(dev);
- if (i596_debug > 1)
- printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status);
+ DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, lp->scb.status));
save_flags(flags);
cli();
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: close1 timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"close1 timed out");
lp->scb.command = CUC_ABORT | RX_ABORT;
CA(dev);
- boguscnt = 2000;
-
- while (lp->scb.command)
- if (--boguscnt == 0) {
- printk("%s: close2 timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ wait_cmd(dev,lp,100,"close2 timed out");
restore_flags(flags);
-
- i596_cleanup_cmd(lp);
+ DEB(DEB_STRUCT,i596_display_data(dev));
+ i596_cleanup_cmd(dev,lp);
#ifdef ENABLE_MVME16x_NET
if (MACH_IS_MVME16x) {
static void set_multicast_list(struct net_device *dev)
{
struct i596_private *lp = (struct i596_private *) dev->priv;
- struct i596_cmd *cmd;
int config = 0, cnt;
- if (i596_debug > 1)
- printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF");
+ DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
- if ((dev->flags & IFF_PROMISC) && !(lp->i596_config[8] & 0x01)) {
- lp->i596_config[8] |= 0x01;
+ if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
+ lp->cf_cmd.i596_config[8] |= 0x01;
config = 1;
}
- if (!(dev->flags & IFF_PROMISC) && (lp->i596_config[8] & 0x01)) {
- lp->i596_config[8] &= ~0x01;
+ if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
+ lp->cf_cmd.i596_config[8] &= ~0x01;
config = 1;
}
- if ((dev->flags & IFF_ALLMULTI) && (lp->i596_config[11] & 0x20)) {
- lp->i596_config[11] &= ~0x20;
+ if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
+ lp->cf_cmd.i596_config[11] &= ~0x20;
config = 1;
}
- if (!(dev->flags & IFF_ALLMULTI) && !(lp->i596_config[11] & 0x20)) {
- lp->i596_config[11] |= 0x20;
+ if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
+ lp->cf_cmd.i596_config[11] |= 0x20;
config = 1;
}
if (config) {
- if (lp->set_conf.command)
+ if (lp->cf_cmd.cmd.command)
printk("%s: config change request already queued\n",
dev->name);
else {
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, &lp->set_conf);
+ lp->cf_cmd.cmd.command = CmdConfigure;
+ i596_add_cmd(dev, &lp->cf_cmd.cmd);
}
}
if (dev->mc_count > 0) {
struct dev_mc_list *dmi;
unsigned char *cp;
+ struct mc_cmd *cmd;
cmd = &lp->mc_cmd;
- cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
- cp = ((unsigned char *) (cmd + 1)) + 2;
- for(dmi=dev->mc_list;cnt && dmi!=NULL;dmi=dmi->next,cnt--) {
+ cmd->cmd.command = CmdMulticastList;
+ cmd->mc_cnt = dev->mc_count * 6;
+ cp = cmd->mc_addrs;
+ for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
memcpy(cp, dmi->dmi_addr, 6);
if (i596_debug > 1)
- printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(cp + 0), *(cp + 1), *(cp + 2), *(cp + 3), *(cp + 4), *(cp + 5));
- cp += 6;
+ DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
}
- if (i596_debug > 2)
- print_eth(((char *) (cmd + 1)) + 2);
- i596_add_cmd(dev, cmd);
+ i596_add_cmd(dev, &cmd->cmd);
}
}
* XXX which may be invalid (CONFIG_060_WRITETHROUGH)
*/
- kernel_set_cachemode((u32)(dev_82596.mem_start), 4096,
+ kernel_set_cachemode((void *)(dev_82596.mem_start), 4096,
IOMAP_FULL_CACHING);
#endif
free_page ((u32)(dev_82596.mem_start));
#include "am79c961a.h"
+static int am79c961_probe1 (struct net_device *dev);
+static int am79c961_open (struct net_device *dev);
+static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
+static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
+static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
+static int am79c961_close (struct net_device *dev);
+static struct enet_statistics *am79c961_getstats (struct net_device *dev);
+static void am79c961_setmulticastlist (struct net_device *dev);
+static void am79c961_timeout(struct net_device *dev);
+
static unsigned int net_debug = NET_DEBUG;
static void
am79c961_setmulticastlist (struct net_device *dev);
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
+static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n";
#define FUNC_PROLOGUE \
struct dev_priv *priv = (struct dev_priv *)dev->priv
/* --------------------------------------------------------------------------- */
+#ifdef __arm__
static void
write_rreg (unsigned long base, unsigned int reg, unsigned short val)
{
- __asm__("
- strh %1, [%2] @ NET_RAP
- strh %0, [%2, #-4] @ NET_RDP
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ str%?h %0, [%2, #-4] @ NET_RDP
" : : "r" (val), "r" (reg), "r" (0xf0000464));
}
static inline void
write_ireg (unsigned long base, unsigned int reg, unsigned short val)
{
- __asm__("
- strh %1, [%2] @ NET_RAP
- strh %0, [%2, #8] @ NET_RDP
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ str%?h %0, [%2, #8] @ NET_RDP
" : : "r" (val), "r" (reg), "r" (0xf0000464));
}
#define am_writeword(dev,off,val)\
- __asm__("\
- strh %0, [%1]\
- " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+ __asm__("str%?h %0, [%1]" : : \
+ "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
static inline void
am_writebuffer(struct net_device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
offset = 0xe0000000 + (offset << 1);
length = (length + 1) & ~1;
if ((int)buf & 2) {
- __asm__ __volatile__("
- strh %2, [%0], #4
- " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+ __asm__ __volatile__("str%?h %2, [%0], #4"
+ : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
buf += 2;
length -= 2;
}
while (length > 8) {
unsigned int tmp, tmp2;
__asm__ __volatile__("
- ldmia %1!, {%2, %3}
- strh %2, [%0], #4
- mov %2, %2, lsr #16
- strh %2, [%0], #4
- strh %3, [%0], #4
- mov %3, %3, lsr #16
- strh %3, [%0], #4
+ ldm%?ia %1!, {%2, %3}
+ str%?h %2, [%0], #4
+ mov%? %2, %2, lsr #16
+ str%?h %2, [%0], #4
+ str%?h %3, [%0], #4
+ mov%? %3, %3, lsr #16
+ str%?h %3, [%0], #4
" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
: "0" (offset), "1" (buf));
length -= 8;
}
while (length > 0) {
- __asm__ __volatile__("
- strh %2, [%0], #4
- " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+ __asm__ __volatile__("str%?h %2, [%0], #4"
+ : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
buf += 2;
length -= 2;
}
read_rreg (unsigned int base_addr, unsigned int reg)
{
unsigned short v;
- __asm__("
- strh %1, [%2] @ NET_RAP
- ldrh %0, [%2, #-4] @ NET_IDP
+ __asm__("str%?h %1, [%2] @ NET_RAP
+ ldr%?h %0, [%2, #-4] @ NET_IDP
" : "=r" (v): "r" (reg), "r" (0xf0000464));
return v;
}
unsigned long address = 0xe0000000 + (off << 1);
unsigned short val;
- __asm__("
- ldrh %0, [%1]
- " : "=r" (val): "r" (address));
+ __asm__("ldr%?h %0, [%1]" : "=r" (val): "r" (address));
return val;
}
if ((int)buf & 2) {
unsigned int tmp;
__asm__ __volatile__("
- ldrh %2, [%0], #4
- strb %2, [%1], #1
- mov %2, %2, lsr #8
- strb %2, [%1], #1
+ ldr%?h %2, [%0], #4
+ str%?b %2, [%1], #1
+ mov%? %2, %2, lsr #8
+ str%?b %2, [%1], #1
" : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
length -= 2;
}
while (length > 8) {
unsigned int tmp, tmp2, tmp3;
__asm__ __volatile__("
- ldrh %2, [%0], #4
- ldrh %3, [%0], #4
- orr %2, %2, %3, lsl #16
- ldrh %3, [%0], #4
- ldrh %4, [%0], #4
- orr %3, %3, %4, lsl #16
- stmia %1!, {%2, %3}
+ ldr%?h %2, [%0], #4
+ ldr%?h %3, [%0], #4
+ orr%? %2, %2, %3, lsl #16
+ ldr%?h %3, [%0], #4
+ ldr%?h %4, [%0], #4
+ orr%? %3, %3, %4, lsl #16
+ stm%?ia %1!, {%2, %3}
" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
: "0" (offset), "1" (buf));
length -= 8;
while (length > 0) {
unsigned int tmp;
__asm__ __volatile__("
- ldrh %2, [%0], #4
- strb %2, [%1], #1
- mov %2, %2, lsr #8
- strb %2, [%1], #1
+ ldr%?h %2, [%0], #4
+ str%?b %2, [%1], #1
+ mov%? %2, %2, lsr #8
+ str%?b %2, [%1], #1
" : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
length -= 2;
}
}
+#else
+#error Not compatable
+#endif
static int
am79c961_ramtest(struct net_device *dev, unsigned int val)
write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
write_rreg (dev->base_addr, CSR0, CSR0_STOP);
- write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM);
+ write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
}
/*
* The PNP initialisation should have been done by the ether bootp loader.
*/
- inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */
+ inb((dev->base_addr + NET_RESET) >> 1); /* reset the device */
udelay (5);
dev->hard_start_xmit = am79c961_sendpacket;
dev->get_stats = am79c961_getstats;
dev->set_multicast_list = am79c961_setmulticastlist;
+ dev->tx_timeout = am79c961_timeout;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
memset (&priv->stats, 0, sizeof (priv->stats));
- if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev))
+ if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) {
+ MOD_DEC_USE_COUNT;
return -EAGAIN;
+ }
am79c961_init_for_open(dev);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
+
return 0;
}
static int
am79c961_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
am79c961_init(dev);
return &priv->stats;
}
+static inline u32 update_crc(u32 crc, u8 byte)
+{
+ int i;
+
+ for (i = 8; i != 0; i--) {
+ byte ^= crc & 1;
+ crc >>= 1;
+
+ if (byte & 1)
+ crc ^= 0xedb88320;
+
+ byte >>= 1;
+ }
+
+ return crc;
+}
+
+static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
+{
+ if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
+ int i, idx, bit;
+ u32 crc;
+
+ crc = 0xffffffff;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ crc = update_crc(crc, dmi->dmi_addr[i]);
+
+ idx = crc >> 30;
+ bit = (crc >> 26) & 15;
+
+ hash[idx] |= 1 << bit;
+ }
+}
+
/*
* Set or clear promiscuous/multicast mode filter for this adaptor.
- *
- * We don't attempt any packet filtering. The card may have a SEEQ 8004
- * in which does not have the other ethernet address registers present...
*/
static void am79c961_setmulticastlist (struct net_device *dev)
{
unsigned long flags;
- int i;
+ unsigned short multi_hash[4], mode;
+ int i, stopped;
- dev->flags &= ~IFF_ALLMULTI;
+ mode = MODE_PORT0;
- i = MODE_PORT0;
- if (dev->flags & IFF_PROMISC)
- i |= MODE_PROMISC;
+ if (dev->flags & IFF_PROMISC) {
+ mode |= MODE_PROMISC;
+ } else if (dev->flags & IFF_ALLMULTI) {
+ memset(multi_hash, 0xff, sizeof(multi_hash));
+ } else {
+ struct dev_mc_list *dmi;
- save_flags_cli (flags);
- write_rreg (dev->base_addr, MODE, i);
- restore_flags (flags);
+ memset(multi_hash, 0x00, sizeof(multi_hash));
+
+ for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+ am79c961_mc_hash(dmi, multi_hash);
+ }
+
+ save_flags_cli(flags);
+
+ stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
+
+ if (!stopped) {
+ /*
+ * Put the chip into suspend mode
+ */
+ write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
+
+ /*
+ * Spin waiting for chip to report suspend mode
+ */
+ while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
+ restore_flags(flags);
+ nop();
+ save_flags_cli(flags);
+ }
+ }
+
+ /*
+ * Update the multicast hash table
+ */
+ for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+ write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
+
+ /*
+ * Write the mode register
+ */
+ write_rreg(dev->base_addr, MODE, mode);
+
+ if (!stopped) {
+ /*
+ * Put the chip back into running mode
+ */
+ write_rreg(dev->base_addr, CTRL1, 0);
+ }
+
+ restore_flags(flags);
+}
+
+static void am79c961_timeout(struct net_device *dev)
+{
+ printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
+ dev->name);
+
+ /*
+ * ought to do some setup of the tx side here
+ */
+
+ netif_wake_queue(dev);
}
/*
am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned int hdraddr, bufaddr;
+ unsigned int head;
+ unsigned long flags;
- if (!dev->tbusy) {
-again:
- if (!test_and_set_bit(0, (void*)&dev->tbusy)) {
- unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned int hdraddr, bufaddr;
- unsigned long flags;
-
- hdraddr = priv->txhdr + (priv->txhead << 3);
- bufaddr = priv->txbuffer[priv->txhead];
- priv->txhead ++;
- if (priv->txhead >= TX_BUFFERS)
- priv->txhead = 0;
-
- am_writebuffer (dev, bufaddr, skb->data, length);
- am_writeword (dev, hdraddr + 4, -length);
- am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
-
- save_flags_cli (flags);
- write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
- dev->trans_start = jiffies;
- restore_flags (flags);
-
- if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
- dev->tbusy = 0;
- dev_kfree_skb (skb);
- return 0;
- } else
- printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- } else {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
- /* Try to restart the adaptor. */
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- goto again;
- }
+ head = priv->txhead;
+ hdraddr = priv->txhdr + (head << 3);
+ bufaddr = priv->txbuffer[head];
+ head += 1;
+ if (head >= TX_BUFFERS)
+ head = 0;
+
+ am_writebuffer (dev, bufaddr, skb->data, length);
+ am_writeword (dev, hdraddr + 4, -length);
+ am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
+ priv->txhead = head;
+
+ save_flags_cli (flags);
+ write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
+ dev->trans_start = jiffies;
+ restore_flags (flags);
+
+ if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
+ netif_stop_queue(dev);
+
+ dev_kfree_skb(skb);
+
+ return 0;
}
static void
printk(KERN_DEBUG "am79c961irq: %d ", irq);
#endif
- dev->interrupt = 1;
-
status = read_rreg (dev->base_addr, CSR0);
write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
if (status & CSR0_MISS)
priv->stats.rx_dropped ++;
- dev->interrupt = 0;
-
#if NET_DEBUG > 1
if(net_debug & DEBUG_INT)
printk("done\n");
am_writeword (dev, hdraddr + 6, 0);
if (status2 & TST_RTRY)
- priv->stats.collisions += 1;
+ priv->stats.collisions += 16;
if (status2 & TST_LCOL)
priv->stats.tx_window_errors ++;
if (status2 & TST_LCAR)
priv->stats.tx_packets ++;
} while (priv->txtail != priv->txhead);
- dev->tbusy = 0;
- mark_bh (NET_BH);
+ netif_wake_queue(dev);
}
-
#define CSR3_EMBA 0x0008
#define CSR3_DXMT2PD 0x0010
#define CSR3_LAPPEN 0x0020
+#define CSR3_DXSUFLO 0x0040
#define CSR3_IDONM 0x0100
#define CSR3_TINTM 0x0200
#define CSR3_RINTM 0x0400
#define CSR3_BABLM 0x4000
#define CSR3_MASKALL 0x5F00
+#define CTRL1 5
+#define CTRL1_SPND 0x0001
+
#define LADRL 8
#define LADRM1 9
#define LADRM2 10
#define TMD_ERR 0x4000
#define TMD_OWN 0x8000
-#define TST_RTRY 0x0200
-#define TST_LCAR 0x0400
+#define TST_RTRY 0x0400
+#define TST_LCAR 0x0800
#define TST_LCOL 0x1000
#define TST_UFLO 0x4000
};
extern int am79c961_probe (struct net_device *dev);
-static int am79c961_probe1 (struct net_device *dev);
-static int am79c961_open (struct net_device *dev);
-static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static void am79c961_rx (struct net_device *dev, struct dev_priv *priv);
-static void am79c961_tx (struct net_device *dev, struct dev_priv *priv);
-static int am79c961_close (struct net_device *dev);
-static struct enet_statistics *am79c961_getstats (struct net_device *dev);
-static void am79c961_setmulticastlist (struct net_device *dev);
#endif
#include <linux/modversions.h>
#endif
#include <linux/module.h>
-#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
serial_driver.driver_name = "serial";
+#ifdef CONFIG_DEVFS_FS
serial_driver.name = "tts/%d";
+#else
+ serial_driver.name = "ttyS";
+#endif
serial_driver.major = TTY_MAJOR;
serial_driver.minor_start = 64 + su_num_ports;
serial_driver.num = NR_PORTS;
memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
serial_driver.driver_name = "serial";
+#ifdef CONFIG_DEVFS_FS
serial_driver.name = "tts/%d";
+#else
+ serial_driver.name = "ttyS";
+#endif
serial_driver.major = TTY_MAJOR;
serial_driver.minor_start = 64;
serial_driver.num = NUM_CHANNELS;
}
#endif
-#ifdef CONFIG_MODULES /* a big #ifdef block... */
+/*
+ * Some host adapters that are plugging into other subsystems register
+ * their hosts through the modules entrypoints, and don't use the big
+ * list in hosts.c.
+ */
+#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE) /* a big #ifdef block... */
/*
* This entry point should be called by a loadable module if it is trying
* This can come up if you get a MEDIUM_ERROR, for example,
* as we will have "completed" all of the sectors up to and
* including the bad sector, and the leftover bit is what
- * we have to do now. This tends to be a rare occurence, so
+ * we have to do now. This tends to be a rare occurrence, so
* we aren't busting our butts to instantiate separate versions
* of this function for the 4 different flag values. We
* probably should, however.
* scsi.c allocates for this purpose
* min(64,sg_tablesize) entries.
*/
- if (req->nr_segments >= max_segments &&
+ if (req->nr_segments >= max_segments ||
req->nr_segments >= SHpnt->sg_tablesize)
return 0;
req->nr_segments++;
* check if things fit into sg_tablesize.
*/
if (req->nr_hw_segments >= SHpnt->sg_tablesize ||
- (req->nr_segments >= max_segments &&
- req->nr_segments >= SHpnt->sg_tablesize))
+ req->nr_segments >= SHpnt->sg_tablesize)
return 0;
if (req->nr_segments >= max_segments)
return 0;
/* If it would not fit into prepared memory space for sg chain,
* then don't allow the merge.
*/
- if (req->nr_segments + next->nr_segments - 1 > max_segments &&
+ if (req->nr_segments + next->nr_segments - 1 > max_segments ||
req->nr_segments + next->nr_segments - 1 > SHpnt->sg_tablesize) {
return 0;
}
}
dont_combine:
#ifdef DMA_CHUNK_SIZE
- if (req->nr_segments + next->nr_segments > max_segments &&
+ if (req->nr_segments + next->nr_segments > max_segments ||
req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
return 0;
}
* Make sure we can fix something that is the sum of the two.
* A slightly stricter test than we had above.
*/
- if (req->nr_segments + next->nr_segments > max_segments &&
+ if (req->nr_segments + next->nr_segments > max_segments ||
req->nr_segments + next->nr_segments > SHpnt->sg_tablesize) {
return 0;
} else {
/*
- * linux/drivers/sound/dmasound.h
+ * linux/drivers/sound/dmasound/dmasound.h
*
*
* Minor numbers for the sound driver.
*/
extern int dmasound_init(void);
+#ifdef MODULE
extern void dmasound_deinit(void);
+#else
+#define dmasound_deinit() do { } while (0)
+#endif
/*
int (*irqinit)(void);
#ifdef MODULE
void (*irqcleanup)(void);
-#endif /* MODULE */
+#endif
void (*init)(void);
void (*silence)(void);
int (*setFormat)(int);
/*
- * linux/drivers/sound/dmasound_atari.c
+ * linux/drivers/sound/dmasound/dmasound_atari.c
*
- * Atari DMA Sound Driver
+ * Atari TT and Falcon DMA Sound Driver
*
- * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
*/
/*
- * linux/drivers/sound/dmasound_awacs.c
+ * linux/drivers/sound/dmasound/dmasound_awacs.c
*
- * PowerMac DMA Sound Driver
+ * PowerMac `AWACS' and `Burgundy' DMA Sound Driver
*
- * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
*/
/*
- * linux/drivers/sound/dmasound.c
+ * linux/drivers/sound/dmasound/dmasound_core.c
*
*
* OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for
int __init dmasound_init(void)
{
+#ifdef MODULE
if (irq_installed)
return -EBUSY;
+#endif
/* Set up sound queue, /dev/audio and /dev/dsp. */
/*
- * linux/drivers/sound/dmasound_paula.c
+ * linux/drivers/sound/dmasound/dmasound_paula.c
*
- * Amiga DMA Sound Driver
+ * Amiga `Paula' DMA Sound Driver
*
- * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
*/
#include <linux/module.h>
+#include <linux/config.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
+#include <asm/machdep.h>
#include "dmasound.h"
static void AmiPlay(void);
static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
+#ifdef CONFIG_HEARTBEAT
+
+ /*
+ * Heartbeat interferes with sound since the 7 kHz low-pass filter and the
+ * power LED are controlled by the same line.
+ */
+
+#ifdef CONFIG_APUS
+#define mach_heartbeat ppc_md.heartbeat
+#endif
+
+static void (*saved_heartbeat)(int) = NULL;
+
+static inline void disable_heartbeat(void)
+{
+ if (mach_heartbeat) {
+ saved_heartbeat = mach_heartbeat;
+ mach_heartbeat = NULL;
+ }
+ AmiSetTreble(dmasound.treble);
+}
+
+static inline void enable_heartbeat(void)
+{
+ if (saved_heartbeat)
+ mach_heartbeat = saved_heartbeat;
+}
+#else /* !CONFIG_HEARTBEAT */
+#define disable_heartbeat() do { } while (0)
+#define enable_heartbeat() do { } while (0)
+#endif /* !CONFIG_HEARTBEAT */
+
/*** Mid level stuff *********************************************************/
custom.aud[0].audvol = custom.aud[1].audvol = 0;
custom.aud[2].audvol = custom.aud[3].audvol = 0;
custom.dmacon = AMI_AUDIO_OFF;
+ enable_heartbeat();
}
static void *AmiAlloc(unsigned int size, int flags)
for (i = 0; i < 4; i++)
custom.aud[i].audper = period;
amiga_audio_period = period;
-
- AmiSetTreble(50); /* recommended for newer amiga models */
}
ch1 = start;
}
+ disable_heartbeat();
custom.aud[0].audvol = dmasound.volume_left;
custom.aud[1].audvol = dmasound.volume_right;
if (dmasound.hard.size == 8) {
/*
- * linux/drivers/sound/dmasound_q40.c
+ * linux/drivers/sound/dmasound/dmasound_q40.c
*
* Q40 DMA Sound Driver
*
- * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ * See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
*/
static void
vidc_mksound(unsigned int hz, unsigned int ticks)
{
- printk("BEEP - %d %d!\n", hz, ticks);
+// printk("BEEP - %d %d!\n", hz, ticks);
}
static void
struct camera_state {
struct usb_device *dev; /* USB device handle */
- char inEP; /* read endpoint */
- char outEP; /* write endpoint */
+ int inEP; /* read endpoint */
+ int outEP; /* write endpoint */
const struct camera *info; /* DC-240, etc */
int subminor; /* which minor dev #? */
int isActive; /* I/O taking place? */
#include <linux/usb.h>
-#define VERSION "0.7.3"
-#define RELEASE_DATE "(15/04/2000)"
+#define VERSION "0.7.3"
+#define RELEASE_DATE "(24/04/2000)"
/* Vendor and Product Information */
#define MDC800_VENDOR_ID 0x055f
#define MDC800_PRODUCT_ID 0xa800
/* Timeouts (msec) */
-#define TO_READ_FROM_IRQ 4000
-#define TO_GET_READY 2000
#define TO_DOWNLOAD_GET_READY 1500
#define TO_DOWNLOAD_GET_BUSY 1500
-#define TO_WRITE_GET_READY 3000
+#define TO_WRITE_GET_READY 1000
#define TO_DEFAULT_COMMAND 5000
+#define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND
+#define TO_GET_READY TO_DEFAULT_COMMAND
/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
#define MDC800_DEVICE_MINOR_BASE 32
dbg ("(mdc800_usb_probe) called.");
- if (mdc800->dev != 0)
- {
- warn ("only one Mustek MDC800 is supported.");
- return 0;
- }
if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
return 0;
if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
return 0;
+ if (mdc800->dev != 0)
+ {
+ warn ("only one Mustek MDC800 is supported.");
+ return 0;
+ }
+
if (dev->descriptor.bNumConfigurations != 1)
{
err ("probe fails -> wrong Number of Configuration");
mdc800->rw_lock=0;
return -EIO;
}
- interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000);
+ interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000);
if (mdc800->state == WORKING)
{
usb_unlink_urb (mdc800->write_urb);
}
current_par.currcon = -1;
- current_par.screen_base = SCREEN2_BASE;
+ current_par.screen_base = SCREEN_BASE;
current_par.screen_base_p = SCREEN_START;
current_par.using_vram = 0;
v_sync = h_sync / (init_var.yres + init_var.upper_margin +
init_var.lower_margin + init_var.vsync_len);
- printk("Acornfb: %ldkB %cRAM, %s, using %dx%d, %d.%03dkHz, %dHz\n",
+ printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, "
+ "%d.%03dkHz, %dHz\n",
current_par.screen_size / 1024,
current_par.using_vram ? 'V' : 'D',
VIDC_NAME, init_var.xres, init_var.yres,
* mult = reg0xb0.7:0
* div1 = (reg0xb1.5:0 + 1)
* div2 = 2^(reg0xb1.7:6)
- * fpll should be between 115 and 257 MHz
- * (8696ps and 3891ps)
+ * fpll should be between 115 and 260 MHz
+ * (8696ps and 3846ps)
*/
static int
cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var)
/*
* Step 1:
- * find div2 such that 115MHz < fpll < 257MHz
+ * find div2 such that 115MHz < fpll < 260MHz
* and 0 <= div2 < 4
*/
if (current_par.dev_id == PCI_DEVICE_ID_INTERG_2010)
unsigned long new_pll;
new_pll = pll_ps / divisors[div2];
- if (8696 > new_pll && new_pll > 3891) {
+ if (8696 > new_pll && new_pll > 3846) {
pll_ps = new_pll;
break;
}
#if 0
/*
* Step 2:
- * Find fpll
- * fpll = fref * mult / div1
+ * Given pll_ps and ref_ps, find:
+ * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
+ * where { 0 < div1 < 32, 0 < mult < 256 }
+ * pll_ps_calc = div1 / (ref_ps * mult)
*
* Note! This just picks any old values at the moment,
* and as such I don't trust it. It certainly doesn't
cyber2000fb_ioctl
};
+/*
+ * Enable access to the extended registers
+ * Bug: this should track the usage of these registers
+ */
+static void cyber2000fb_enable_extregs(void)
+{
+ int old;
+
+ old = cyber2000_grphr(FUNC_CTL);
+ cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL);
+}
+
+/*
+ * Disable access to the extended registers
+ * Bug: this should track the usage of these registers
+ */
+static void cyber2000fb_disable_extregs(void)
+{
+ int old;
+
+ old = cyber2000_grphr(FUNC_CTL);
+ cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL);
+}
+
+/*
+ * Attach a capture/tv driver to the core CyberX0X0 driver.
+ */
int cyber2000fb_attach(struct cyberpro_info *info)
{
if (current_par.initialised) {
- info->dev = current_par.dev;
- info->regs = CyberRegs;
- info->fb = current_par.screen_base;
- info->fb_size = current_par.screen_size;
+ info->dev = current_par.dev;
+ info->regs = CyberRegs;
+ info->fb = current_par.screen_base;
+ info->fb_size = current_par.screen_size;
+ info->enable_extregs = cyber2000fb_enable_extregs;
+ info->disable_extregs = cyber2000fb_disable_extregs;
strncpy(info->dev_name, current_par.dev_name, sizeof(info->dev_name));
return current_par.initialised;
}
+/*
+ * Detach a capture/tv driver from the core CyberX0X0 driver.
+ */
void cyber2000fb_detach(void)
{
MOD_DEC_USE_COUNT;
v_sync = h_sync / (init_var.yres + init_var.upper_margin +
init_var.lower_margin + init_var.vsync_len);
- printk("%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ printk(KERN_INFO "%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
current_par.dev_name,
current_par.screen_size >> 10,
init_var.xres, init_var.yres,
cyber2000_outb(val, 0x3cf);
}
+static inline unsigned int cyber2000_grphr(int reg)
+{
+ cyber2000_outb(reg, 0x3ce);
+ return cyber2000_inb(0x3cf);
+}
+
static inline void cyber2000_attrw(int reg, int val)
{
cyber2000_inb(0x3da);
#define CAP_NEW_CTL2 0x89
+#define BM_CTRL0 0x9c
+#define BM_CTRL1 0x9d
+
#define CAP_MODE1 0xa4
#define CAP_MODE1_8BIT 0x01 /* enable 8bit capture mode */
#define CAP_MODE1_CCIR656 0x02 /* CCIR656 mode */
/*
* Bus-master
*/
+#define BM_VID_ADDR_LOW 0xbc040
+#define BM_VID_ADDR_HIGH 0xbc044
#define BM_ADDRESS_LOW 0xbc080
#define BM_ADDRESS_HIGH 0xbc084
#define BM_LENGTH 0xbc088
#define BM_CONTROL 0xbc08c
#define BM_CONTROL_ENABLE 0x01 /* enable transfer */
+#define BM_CONTROL_IRQEN 0x02 /* enable IRQ at end of transfer */
#define BM_CONTROL_INIT 0x04 /* initialise status & count */
#define BM_COUNT 0xbc090 /* read-only */
char *fb;
char dev_name[32];
unsigned int fb_size;
+
+ /*
+ * Use these to enable the BM or TV registers.
+ */
+ void (*enable_extregs)(void);
+ void (*disable_extregs)(void);
};
/*
#ifdef CONFIG_FB_ATY
{ "atyfb", atyfb_init, atyfb_setup },
#endif
+#ifdef CONFIG_FB_ATY128
+ { "aty128fb", aty128fb_init, aty128fb_setup },
+#endif
#ifdef CONFIG_FB_OF
/*
* Offb must be initialized _after_ all other frame buffer devices
*/
{ "offb", offb_init, offb_setup },
#endif
-#ifdef CONFIG_FB_ATY128
- { "aty128fb", aty128fb_init, aty128fb_setup },
-#endif
#ifdef CONFIG_FB_IGA
{ "igafb", igafb_init, igafb_setup },
#endif
return 0;
}
-static int adfs_writepage(struct dentry *dentry, struct page *page)
+static int adfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page, adfs_get_block);
}
static struct address_space_operations adfs_aops = {
readpage: adfs_readpage,
writepage: adfs_writepage,
+ sync_page: block_sync_page,
prepare_write: adfs_prepare_write,
commit_write: generic_commit_write,
bmap: _adfs_bmap
}
-static int affs_writepage(struct dentry *dentry, struct page *page)
+static int affs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,affs_get_block);
}
struct address_space_operations affs_aops = {
readpage: affs_readpage,
writepage: affs_writepage,
+ sync_page: block_sync_page,
prepare_write: affs_prepare_write,
commit_write: generic_commit_write,
bmap: _affs_bmap
struct autofs_dir_ent **back;
/* The following entries are for the expiry system */
unsigned long last_usage;
- struct autofs_dir_ent *exp_next;
- struct autofs_dir_ent *exp_prev;
+ struct list_head exp;
};
struct autofs_dirhash {
struct autofs_dir_ent *h[AUTOFS_HASH_SIZE];
- struct autofs_dir_ent expiry_head;
+ struct list_head expiry_head;
};
struct autofs_wait_queue {
static void autofs_init_usage(struct autofs_dirhash *dh,
struct autofs_dir_ent *ent)
{
- ent->exp_next = &dh->expiry_head;
- ent->exp_prev = dh->expiry_head.exp_prev;
- dh->expiry_head.exp_prev->exp_next = ent;
- dh->expiry_head.exp_prev = ent;
+ list_add_tail(&ent->exp, &dh->expiry_head);
ent->last_usage = jiffies;
}
static void autofs_delete_usage(struct autofs_dir_ent *ent)
{
- ent->exp_prev->exp_next = ent->exp_next;
- ent->exp_next->exp_prev = ent->exp_prev;
+ list_del(&ent->exp);
}
void autofs_update_usage(struct autofs_dirhash *dh,
struct dentry *dentry;
unsigned long timeout = sbi->exp_timeout;
- ent = dh->expiry_head.exp_next;
-
- if ( ent == &(dh->expiry_head) || sbi->catatonic )
- return NULL; /* No entries */
-
- while ( jiffies - ent->last_usage >= timeout ) {
+ while (1) {
+ if ( list_empty(&dh->expiry_head) || sbi->catatonic )
+ return NULL; /* No entries */
+ /* We keep the list sorted by last_usage and want old stuff */
+ ent = list_entry(dh->expiry_head.next, struct autofs_dir_ent, exp);
+ if (jiffies - ent->last_usage < timeout)
+ break;
/* Move to end of list in case expiry isn't desirable */
autofs_update_usage(dh, ent);
void autofs_initialize_hash(struct autofs_dirhash *dh) {
memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *));
- dh->expiry_head.exp_next = dh->expiry_head.exp_prev =
- &dh->expiry_head;
+ INIT_LIST_HEAD(&dh->expiry_head);
}
struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, struct qstr *name)
#define __NO_VERSION__
#include <linux/module.h>
-/*
- * Dummy functions - do we ever actually want to do
- * something here?
- */
-static void autofs_put_inode(struct inode *inode)
-{
-}
-
-static void autofs_delete_inode(struct inode *inode)
-{
- inode->i_size = 0;
-}
-
static void autofs_put_super(struct super_block *sb)
{
struct autofs_sb_info *sbi = autofs_sbi(sb);
static int autofs_statfs(struct super_block *sb, struct statfs *buf);
static void autofs_read_inode(struct inode *inode);
-static void autofs_write_inode(struct inode *inode);
static struct super_operations autofs_sops = {
read_inode: autofs_read_inode,
- write_inode: autofs_write_inode,
- put_inode: autofs_put_inode,
- delete_inode: autofs_delete_inode,
put_super: autofs_put_super,
statfs: autofs_statfs,
};
struct autofs_sb_info *sbi;
int minproto, maxproto;
- /* Super block already completed? */
- if (s->s_root)
- goto out_unlock;
-
sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
if ( !sbi )
goto fail_unlock;
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs_sops;
- s->s_root = NULL;
- /*
- * Get the root inode and dentry, but defer checking for errors.
- */
root_inode = iget(s, AUTOFS_ROOT_INO);
root = d_alloc_root(root_inode);
pipe = NULL;
- /*
- * Check whether somebody else completed the super block.
- */
- if (s->s_root)
- goto out_dput;
-
if (!root)
goto fail_iput;
- /* Can this call block? */
+ /* Can this call block? - WTF cares? s is locked. */
if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
printk("autofs: called with bogus options\n");
goto fail_dput;
DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
pipe = fget(pipefd);
- /*
- * Check whether somebody else completed the super block.
- */
- if (s->s_root)
- goto out_fput;
if ( !pipe ) {
printk("autofs: could not open pipe file descriptor\n");
s->s_root = root;
return s;
- /*
- * Success ... somebody else completed the super block for us.
- */
-out_unlock:
- goto out_dec;
-out_fput:
- if (pipe)
- fput(pipe);
-out_dput:
- if (root)
- dput(root);
- else
- iput(root_inode);
-out_dec:
- return s;
-
- /*
- * Failure ... clear the s_dev slot and clean up.
- */
fail_fput:
printk("autofs: pipe file descriptor does not contain proper ops\n");
- /*
- * fput() can block, so we clear the super block first.
- */
fput(pipe);
- /* fall through */
fail_dput:
- /*
- * dput() can block, so we clear the super block first.
- */
dput(root);
goto fail_free;
fail_iput:
printk("autofs: get root dentry failed\n");
- /*
- * iput() can block, so we clear the super block first.
- */
iput(root_inode);
fail_free:
kfree(sbi);
{
buf->f_type = AUTOFS_SUPER_MAGIC;
buf->f_bsize = 1024;
- buf->f_bfree = 0;
- buf->f_bavail = 0;
- buf->f_ffree = 0;
buf->f_namelen = NAME_MAX;
return 0;
}
inode->i_nlink = 1;
}
}
-
-static void autofs_write_inode(struct inode *inode)
-{
-}
autofs_say(dentry->d_name.name,dentry->d_name.len);
if (dentry->d_name.len > NAME_MAX)
- return ERR_PTR(-ENOENT);/* File name too long to exist */
+ return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
sbi = autofs_sbi(dir->i_sb);
if ( !autofs_oz_mode(sbi) )
return -EACCES;
- if ( dentry->d_name.len > NAME_MAX )
- return -ENAMETOOLONG;
-
if ( autofs_hash_lookup(dh, &dentry->d_name) )
return -EEXIST;
if ( !autofs_oz_mode(sbi) )
return -EACCES;
- if ( dentry->d_name.len > NAME_MAX )
- return -ENAMETOOLONG;
-
ent = autofs_hash_lookup(dh, &dentry->d_name);
if ( ent )
return -EEXIST;
struct autofs_sb_info *sbi;
int minproto, maxproto;
- /* Super block already completed? */
- if (s->s_root)
- goto out_unlock;
-
sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
if ( !sbi )
goto fail_unlock;
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs4_sops;
- s->s_root = NULL;
/*
* Get the root inode and dentry, but defer checking for errors.
root = d_alloc_root(root_inode);
pipe = NULL;
- /*
- * Check whether somebody else completed the super block.
- */
- if (s->s_root)
- goto out_dput;
-
if (!root)
goto fail_iput;
DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
pipe = fget(pipefd);
- /*
- * Check whether somebody else completed the super block.
- */
- if (s->s_root)
- goto out_fput;
if ( !pipe ) {
printk("autofs: could not open pipe file descriptor\n");
*/
s->s_root = root;
return s;
-
- /*
- * Success ... somebody else completed the super block for us.
- */
-out_unlock:
- goto out_dec;
-out_fput:
- if (pipe)
- fput(pipe);
-out_dput:
- if (root)
- dput(root);
- else
- iput(root_inode);
-out_dec:
- return s;
/*
- * Failure ... clear the s_dev slot and clean up.
+ * Failure ... clean up.
*/
fail_fput:
printk("autofs: pipe file descriptor does not contain proper ops\n");
{
buf->f_type = AUTOFS_SUPER_MAGIC;
buf->f_bsize = 1024;
- buf->f_bfree = 0;
- buf->f_bavail = 0;
- buf->f_ffree = 0;
buf->f_namelen = NAME_MAX;
return 0;
}
filp->f_pos = ++nr;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, nr, dentry->d_covers->d_parent->d_inode->i_ino) < 0)
+ if (filldir(dirent, "..", 2, nr, dentry->d_parent->d_inode->i_ino) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
dentry->d_name.len, dentry->d_name.name));
if (dentry->d_name.len > NAME_MAX)
- return ERR_PTR(-ENOENT);/* File name too long to exist */
+ return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
sbi = autofs4_sbi(dir->i_sb);
DPRINTK(("autofs_dir_symlink: %s <- %.*s\n", symname,
dentry->d_name.len, dentry->d_name.name));
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
-
if (!autofs4_oz_mode(sbi))
return -EACCES;
- if (dentry->d_name.len > NAME_MAX)
- return -ENAMETOOLONG;
-
- if (dentry->d_inode != NULL)
- return -EEXIST;
-
ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
if (ino == NULL)
return -ENOSPC;
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
-
- if (dentry->d_inode == NULL)
- return -ENOENT;
/* This allows root to remove symlinks */
if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
-
- if (dentry->d_inode == NULL)
- return -ENOENT;
if (!autofs4_oz_mode(sbi))
return -EACCES;
struct autofs_info *ino = autofs4_dentry_ino(dentry);
struct inode *inode;
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
-
if ( !autofs4_oz_mode(sbi) )
return -EACCES;
- if ( dentry->d_inode != NULL )
- return -EEXIST;
-
- if ( dentry->d_name.len > NAME_MAX )
- return -ENAMETOOLONG;
-
DPRINTK(("autofs_dir_mkdir: dentry %p, creating %.*s\n",
dentry, dentry->d_name.len, dentry->d_name.name));
return err;
}
-static int bfs_writepage(struct dentry *dentry, struct page *page)
+static int bfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page, bfs_get_block);
}
struct address_space_operations bfs_aops = {
readpage: bfs_readpage,
writepage: bfs_writepage,
+ sync_page: block_sync_page,
prepare_write: bfs_prepare_write,
commit_write: generic_commit_write,
bmap: bfs_bmap
kiobuf = bh->b_kiobuf;
unlock_buffer(bh);
-
- kiobuf = bh->b_kiobuf;
end_kio_request(kiobuf, uptodate);
}
return 0;
}
+int block_sync_page(struct page *page)
+{
+ run_task_queue(&tq_disk);
+ return 0;
+}
+
/* This is the interface to bdflush. As we get more sophisticated, we can
* pass tuning parameters to this "process", to adjust how it behaves.
* We would want to verify each parameter, however, to make sure that it
}
struct address_space_operations efs_aops = {
readpage: efs_readpage,
+ sync_page: block_sync_page,
bmap: _efs_bmap
};
return NULL;
}
-static int ext2_writepage(struct dentry *dentry, struct page *page)
+static int ext2_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,ext2_get_block);
}
struct address_space_operations ext2_aops = {
readpage: ext2_readpage,
writepage: ext2_writepage,
+ sync_page: block_sync_page,
prepare_write: ext2_prepare_write,
commit_write: generic_commit_write,
bmap: ext2_bmap
struct super_block * sb;
int retval;
- if (!dir || !dir->i_nlink)
- return -EINVAL;
sb = dir->i_sb;
if (!namelen)
return -EINVAL;
- /*
- * Is this a busy deleted directory? Can't create new files if so
- */
- if (dir->i_size == 0)
- {
- return -ENOENT;
- }
bh = ext2_bread (dir, 0, 0, &retval);
if (!bh)
return retval;
return 0;
}
-static int fat_writepage(struct dentry *dentry, struct page *page)
+static int fat_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,fat_get_block);
}
static struct address_space_operations fat_aops = {
readpage: fat_readpage,
writepage: fat_writepage,
+ sync_page: block_sync_page,
prepare_write: fat_prepare_write,
commit_write: generic_commit_write,
bmap: _fat_bmap
return __hfs_notify_change(dentry, attr, HFS_HDR);
}
-static int hfs_writepage(struct dentry *dentry, struct page *page)
+static int hfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,hfs_get_block);
}
struct address_space_operations hfs_aops = {
readpage: hfs_readpage,
writepage: hfs_writepage,
+ sync_page: block_sync_page,
prepare_write: hfs_prepare_write,
commit_write: generic_commit_write,
bmap: hfs_bmap
return 0;
}
-static int hpfs_writepage(struct dentry *dentry, struct page *page)
+static int hpfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,hpfs_get_block);
}
struct address_space_operations hpfs_aops = {
readpage: hpfs_readpage,
writepage: hpfs_writepage,
+ sync_page: block_sync_page,
prepare_write: hpfs_prepare_write,
commit_write: generic_commit_write,
bmap: _hpfs_bmap
hpfs_unlock_2inodes(dir, inode);
return -ENOTDIR;
}
- if (!d_unhashed(dentry)) {
- hpfs_brelse4(&qbh);
- hpfs_unlock_2inodes(dir, inode);
- return -EBUSY;
- }
hpfs_count_dnodes(dir->i_sb, inode->i_hpfs_dno, NULL, NULL, &n_items);
if (n_items) {
hpfs_brelse4(&qbh);
}
static struct address_space_operations isofs_aops = {
readpage: isofs_readpage,
+ sync_page: block_sync_page,
bmap: _isofs_bmap
};
return NULL;
}
-static int minix_writepage(struct dentry *dentry, struct page *page)
+static int minix_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,minix_get_block);
}
struct address_space_operations minix_aops = {
readpage: minix_readpage,
writepage: minix_writepage,
+ sync_page: block_sync_page,
prepare_write: minix_prepare_write,
commit_write: generic_commit_write,
bmap: minix_bmap
retval = -ENOENT;
goto end_rmdir;
}
- if (!d_unhashed(dentry)) {
- retval = -EBUSY;
- goto end_rmdir;
- }
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
de->inode = 0;
}
if (S_ISDIR(old_inode->i_mode)) {
if (new_inode) {
- retval = -EBUSY;
- if (!d_unhashed(new_dentry))
- goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
* Check whether the directory is not in use, then check
* whether it is empty.
*/
- res = -EBUSY;
- if (!d_unhashed(dentry))
- goto rmdir_done;
res = fat_dir_empty(inode);
if (res)
goto rmdir_done;
goto degenerate_case;
if (is_dir) {
if (new_inode) {
- error = -EBUSY;
- if (!d_unhashed(new_dentry))
- goto out;
error = fat_dir_empty(new_inode);
if (error)
goto out;
goto return_base;
no_inode:
err = -ENOENT;
- if (lookup_flags & LOOKUP_POSITIVE)
+ if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))
break;
- if (lookup_flags & LOOKUP_DIRECTORY)
- if (!(lookup_flags & LOOKUP_SLASHOK))
- break;
goto return_base;
lookup_parent:
nd->last = this;
+ nd->last_type = LAST_NORM;
+ if (this.name[0] != '.')
+ goto return_base;
+ if (this.len == 1)
+ nd->last_type = LAST_DOT;
+ else if (this.len == 2 && this.name[1] == '.')
+ nd->last_type = LAST_DOTDOT;
return_base:
return 0;
out_dput:
if (!nd->dentry->d_inode) {
struct nameidata nd_root;
- nd_root.last.len = 0;
+ nd_root.last_type = LAST_ROOT;
nd_root.flags = nd->flags;
nd_root.mnt = mntget(current->fs->rootmnt);
nd_root.dentry = dget(current->fs->root);
int walk_init(const char *name,unsigned int flags,struct nameidata *nd)
{
- nd->last.len = 0;
+ nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
if (*name=='/')
return walk_init_root(name,nd);
int error;
if (!victim->d_inode || victim->d_parent->d_inode != dir)
return -ENOENT;
+ if (IS_DEADDIR(dir))
+ return -ENOENT;
error = permission(dir,MAY_WRITE | MAY_EXEC);
if (error)
return error;
static inline int may_create(struct inode *dir, struct dentry *child) {
if (child->d_inode)
return -EEXIST;
+ if (IS_DEADDIR(dir))
+ return -ENOENT;
return permission(dir,MAY_WRITE | MAY_EXEC);
}
* luserdom and let him sod off - -EISDIR it is.
*/
error = -EISDIR;
- if (!nd->last.len || (nd->last.name[0] == '.' &&
- (nd->last.len == 1 ||
- (nd->last.name[1] == '.' && nd->last.len == 2))))
+ if (nd->last_type != LAST_NORM)
goto exit;
/* same for foo/ */
if (nd->last.name[nd->last.len])
goto out;
down(&nd.dentry->d_inode->i_sem);
dentry = ERR_PTR(-EEXIST);
- if (!nd.last.len || (nd.last.name[0] == '.' &&
- (nd.last.len == 1 || (nd.last.name[1] == '.' && nd.last.len == 2))))
+ if (nd.last_type != LAST_NORM)
goto fail;
dentry = lookup_hash(&nd.last, nd.dentry);
if (IS_ERR(dentry))
double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
d_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
+ if (!error)
+ dentry->d_inode->i_flags |= S_DEAD;
double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
dput(dentry);
return error;
}
-static inline int do_rmdir(const char * name)
+asmlinkage long sys_rmdir(const char * pathname)
{
- int error;
- struct dentry *dir;
+ int error = 0;
+ char * name;
struct dentry *dentry;
+ struct nameidata nd;
- dentry = lookup_dentry(name, LOOKUP_POSITIVE);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
+ name = getname(pathname);
+ if(IS_ERR(name))
+ return PTR_ERR(name);
+ lock_kernel();
+
+ if (walk_init(name, LOOKUP_PARENT, &nd))
+ error = walk_name(name, &nd);
+ if (error)
goto exit;
- dir = lock_parent(dentry);
- error = -ENOENT;
- if (check_parent(dir, dentry))
- error = vfs_rmdir(dir->d_inode, dentry);
- unlock_dir(dir);
- dput(dentry);
+ switch(nd.last_type) {
+ case LAST_DOTDOT:
+ error = -ENOTEMPTY;
+ goto exit1;
+ case LAST_ROOT: case LAST_DOT:
+ error = -EBUSY;
+ goto exit1;
+ }
+ down(&nd.dentry->d_inode->i_sem);
+ dentry = lookup_hash(&nd.last, nd.dentry);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = vfs_rmdir(nd.dentry->d_inode, dentry);
+ dput(dentry);
+ }
+ up(&nd.dentry->d_inode->i_sem);
+exit1:
+ dput(nd.dentry);
+ mntput(nd.mnt);
exit:
- return error;
-}
-
-asmlinkage long sys_rmdir(const char * pathname)
-{
- int error;
- char * tmp;
-
- tmp = getname(pathname);
- if(IS_ERR(tmp))
- return PTR_ERR(tmp);
- lock_kernel();
- error = do_rmdir(tmp);
unlock_kernel();
-
- putname(tmp);
-
+ putname(name);
return error;
}
return error;
}
-static int do_unlink(const char * name)
+asmlinkage long sys_unlink(const char * pathname)
{
- int error;
- struct dentry *dir;
+ int error = 0;
+ char * name;
struct dentry *dentry;
+ struct nameidata nd;
- dentry = lookup_dentry(name, LOOKUP_POSITIVE);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto exit;
-
- dir = lock_parent(dentry);
- error = -ENOENT;
- if (check_parent(dir, dentry))
- error = vfs_unlink(dir->d_inode, dentry);
+ name = getname(pathname);
+ if(IS_ERR(name))
+ return PTR_ERR(name);
+ lock_kernel();
- unlock_dir(dir);
- dput(dentry);
+ if (walk_init(name, LOOKUP_PARENT, &nd))
+ error = walk_name(name, &nd);
+ if (error)
+ goto exit;
+ error = -EISDIR;
+ if (nd.last_type != LAST_NORM)
+ goto exit1;
+ down(&nd.dentry->d_inode->i_sem);
+ dentry = lookup_hash(&nd.last, nd.dentry);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ /* Why not before? Because we want correct error value */
+ if (nd.last.name[nd.last.len])
+ goto slashes;
+ error = vfs_unlink(nd.dentry->d_inode, dentry);
+ exit2:
+ dput(dentry);
+ }
+ up(&nd.dentry->d_inode->i_sem);
+exit1:
+ dput(nd.dentry);
+ mntput(nd.mnt);
exit:
- return error;
-}
-
-asmlinkage long sys_unlink(const char * pathname)
-{
- int error;
- char * tmp;
-
- tmp = getname(pathname);
- if(IS_ERR(tmp))
- return PTR_ERR(tmp);
- lock_kernel();
- error = do_unlink(tmp);
unlock_kernel();
- putname(tmp);
+ putname(name);
return error;
+
+slashes:
+ error = !dentry->d_inode ? -ENOENT :
+ S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
+ goto exit2;
}
int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
&new_dir->i_zombie);
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (target) {
+ if (!error)
+ target->i_flags |= S_DEAD;
triple_up(&old_dir->i_zombie,
&new_dir->i_zombie,
&target->i_zombie);
static inline int do_rename(const char * oldname, const char * newname)
{
- int error;
+ int error = 0;
struct dentry * old_dir, * new_dir;
struct dentry * old_dentry, *new_dentry;
+ struct nameidata oldnd, newnd;
- old_dentry = lookup_dentry(oldname, LOOKUP_POSITIVE);
+ if (walk_init(oldname, LOOKUP_PARENT, &oldnd))
+ error = walk_name(oldname, &oldnd);
- error = PTR_ERR(old_dentry);
- if (IS_ERR(old_dentry))
+ if (error)
goto exit;
- {
- unsigned int flags = 0;
- if (S_ISDIR(old_dentry->d_inode->i_mode))
- flags = LOOKUP_SLASHOK;
- new_dentry = lookup_dentry(newname, flags);
- }
+ if (walk_init(newname, LOOKUP_PARENT, &newnd))
+ error = walk_name(newname, &newnd);
+ if (error)
+ goto exit1;
- error = PTR_ERR(new_dentry);
- if (IS_ERR(new_dentry))
- goto exit_old;
+ error = -EXDEV;
+ if (oldnd.mnt != newnd.mnt)
+ goto exit2;
+
+ old_dir = oldnd.dentry;
+ error = -EBUSY;
+ if (oldnd.last_type != LAST_NORM)
+ goto exit2;
- new_dir = get_parent(new_dentry);
- old_dir = get_parent(old_dentry);
+ new_dir = newnd.dentry;
+ if (newnd.last_type != LAST_NORM)
+ goto exit2;
double_lock(new_dir, old_dir);
+ old_dentry = lookup_hash(&oldnd.last, old_dir);
+ error = PTR_ERR(old_dentry);
+ if (IS_ERR(old_dentry))
+ goto exit3;
+ /* source must exist */
error = -ENOENT;
- if (check_parent(old_dir, old_dentry) && check_parent(new_dir, new_dentry))
- error = vfs_rename(old_dir->d_inode, old_dentry,
+ if (!old_dentry->d_inode)
+ goto exit4;
+ /* unless the source is a directory trailing slashes give -ENOTDIR */
+ if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
+ error = -ENOTDIR;
+ if (oldnd.last.name[oldnd.last.len])
+ goto exit4;
+ if (newnd.last.name[newnd.last.len])
+ goto exit4;
+ }
+ new_dentry = lookup_hash(&newnd.last, new_dir);
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto exit4;
+
+ error = vfs_rename(old_dir->d_inode, old_dentry,
new_dir->d_inode, new_dentry);
- double_unlock(new_dir, old_dir);
dput(new_dentry);
-exit_old:
+exit4:
dput(old_dentry);
+exit3:
+ double_up(&new_dir->d_inode->i_sem, &old_dir->d_inode->i_sem);
+exit2:
+ dput(newnd.dentry);
+ mntput(newnd.mnt);
+exit1:
+ dput(oldnd.dentry);
+ mntput(oldnd.mnt);
exit:
return error;
}
dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
+ /* Make sure all async reads have been sent off. We don't bother
+ * waiting on them though... */
+ if (file->f_mode & FMODE_READ)
+ nfs_pagein_inode(inode, 0, 0);
+
status = nfs_wb_file(inode, file);
if (!status) {
status = file->f_error;
return status;
}
+/*
+ * The following is used by wait_on_page(), generic_file_readahead()
+ * to initiate the completion of any page readahead operations.
+ */
+static int nfs_sync_page(struct page *page)
+{
+ struct inode *inode = (struct inode *)page->mapping->host;
+ unsigned long index = page_index(page);
+ unsigned int rpages, wpages;
+ int result;
+
+ if (!inode)
+ return 0;
+
+ 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 0;
+ out_bad:
+ return result;
+}
+
struct address_space_operations nfs_file_aops = {
readpage: nfs_readpage,
+ sync_page: nfs_sync_page,
writepage: nfs_writepage,
prepare_write: nfs_prepare_write,
commit_write: nfs_commit_write
NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
if (flush) {
+ nfs_pagein_inode(inode, 0, 0);
nfs_sync_file(inode, NULL, 0, 0, FLUSH_AGING);
} else if (time_after(jiffies, NFS_NEXTSCAN(inode))) {
NFS_NEXTSCAN(inode) = jiffies + NFS_WRITEBACK_LOCKDELAY;
+ nfs_pagein_timeout(inode);
nfs_flush_timeout(inode, FLUSH_AGING);
#ifdef CONFIG_NFS_V3
nfs_commit_timeout(inode, FLUSH_AGING);
#endif
}
- if (nfs_have_writebacks(inode)) {
+ if (nfs_have_writebacks(inode) || nfs_have_read(inode)) {
inode_append_flushd(inode);
if (time_after(delay, NFS_NEXTSCAN(inode)))
delay = NFS_NEXTSCAN(inode);
inode->i_rdev = 0;
NFS_FILEID(inode) = 0;
NFS_FSID(inode) = 0;
+ INIT_LIST_HEAD(&inode->u.nfs_i.read);
INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
INIT_LIST_HEAD(&inode->u.nfs_i.commit);
INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
+ inode->u.nfs_i.nread = 0;
inode->u.nfs_i.ndirty = 0;
inode->u.nfs_i.ncommit = 0;
inode->u.nfs_i.npages = 0;
/*
* The following can never actually happen...
*/
- if (nfs_have_writebacks(inode)) {
+ if (nfs_have_writebacks(inode) || nfs_have_read(inode)) {
printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
}
sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
if (server->rsize > fsinfo.rtmax)
server->rsize = fsinfo.rtmax;
- if (server->rsize > PAGE_CACHE_SIZE)
- server->rsize = PAGE_CACHE_SIZE;
if (server->wsize > fsinfo.wtmax)
server->wsize = fsinfo.wtmax;
- if (server->wsize > NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT)
- server->wsize = NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT;
+
+ server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (server->rpages > NFS_READ_MAXIOV) {
+ server->rpages = NFS_READ_MAXIOV;
+ server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+ }
+
+ server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (server->wpages > NFS_WRITE_MAXIOV) {
+ server->wpages = NFS_WRITE_MAXIOV;
+ server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+ }
maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
extern void nfs_destroy_fhcache(void);
extern int nfs_init_nfspagecache(void);
extern void nfs_destroy_nfspagecache(void);
+extern int nfs_init_readpagecache(void);
+extern int nfs_destroy_readpagecache(void);
/*
* Initialize NFS
if (err)
return err;
+ err = nfs_init_readpagecache();
+ if (err)
+ return err;
+
#ifdef CONFIG_PROC_FS
rpc_proc_register(&nfs_rpcstat);
#endif
void
cleanup_module(void)
{
+ nfs_destroy_readpagecache();
nfs_destroy_nfspagecache();
nfs_destroy_fhcache();
#ifdef CONFIG_PROC_FS
#include <linux/pagemap.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
+#include <linux/nfs_flushd.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-struct nfs_rreq {
- struct inode * ra_inode; /* inode from which to read */
- struct page * ra_page; /* page to be read */
- struct nfs_readargs ra_args; /* XDR argument struct */
- struct nfs_readres ra_res; /* ... and result struct */
- struct nfs_fattr ra_fattr; /* fattr storage */
+struct nfs_read_data {
+ struct rpc_task task;
+ struct dentry *dentry;
+ struct rpc_cred *cred;
+ struct nfs_readargs args; /* XDR argument struct */
+ struct nfs_readres res; /* ... and result struct */
+ struct nfs_fattr fattr; /* fattr storage */
+ struct list_head pages; /* Coalesced read requests */
};
+/*
+ * Local function declarations
+ */
+static void nfs_readpage_result(struct rpc_task *task);
+
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
#endif
+static kmem_cache_t *nfs_rdata_cachep = NULL;
-/*
- * Set up the NFS read request struct
- */
-static inline void
-nfs_readreq_setup(struct nfs_rreq *req, struct nfs_fh *fh,
- loff_t offset, void *buffer, unsigned int rsize)
+static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
{
- req->ra_args.fh = fh;
- req->ra_args.offset = offset;
- req->ra_args.count = rsize;
- req->ra_args.iov[0].iov_base = (void *)buffer;
- req->ra_args.iov[0].iov_len = rsize;
- req->ra_args.nriov = 1;
- req->ra_fattr.valid = 0;
- req->ra_res.fattr = &req->ra_fattr;
- req->ra_res.count = rsize;
- req->ra_res.eof = 0;
+ struct nfs_read_data *p;
+ p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NFS);
+ if (p) {
+ memset(p, 0, sizeof(*p));
+ INIT_LIST_HEAD(&p->pages);
+ }
+ return p;
}
+static __inline__ void nfs_readdata_free(struct nfs_read_data *p)
+{
+ kmem_cache_free(nfs_rdata_cachep, p);
+}
+
+static void nfs_readdata_release(struct rpc_task *task)
+{
+ struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
+ nfs_readdata_free(data);
+}
/*
* Read a page synchronously.
*/
static int
-nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
+nfs_readpage_sync(struct dentry *dentry, struct page *page)
{
- struct nfs_rreq rqst;
- struct rpc_message msg;
+ struct inode *inode = dentry->d_inode;
+ struct nfs_fattr fattr;
loff_t offset = page_offset(page);
char *buffer;
int rsize = NFS_SERVER(inode)->rsize;
- int result, refresh = 0;
+ int result;
int count = PAGE_CACHE_SIZE;
int flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
+ int eof;
dprintk("NFS: nfs_readpage_sync(%p)\n", page);
* This works now because the socket layer never tries to DMA
* into this buffer directly.
*/
- buffer = (char *) kmap(page);
-
+ buffer = (char *) kmap(page);
do {
if (count < rsize)
rsize = count;
dentry->d_parent->d_name.name, dentry->d_name.name,
(long long)offset, rsize, buffer);
- /* Set up arguments and perform rpc call */
- nfs_readreq_setup(&rqst, NFS_FH(dentry), offset, buffer, rsize);
lock_kernel();
- msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
- msg.rpc_argp = &rqst.ra_args;
- msg.rpc_resp = &rqst.ra_res;
- msg.rpc_cred = NULL;
- result = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
+ result = NFS_PROTO(inode)->read(dentry, &fattr, flags, offset,
+ rsize, buffer, &eof);
unlock_kernel();
- nfs_refresh_inode(inode, &rqst.ra_fattr);
+ nfs_refresh_inode(inode, &fattr);
/*
* Even if we had a partial success we can't mark the page
result = -EINVAL;
goto io_error;
}
- refresh = 1;
count -= result;
offset += result;
buffer += result;
memset(buffer, 0, count);
SetPageUptodate(page);
+ if (PageError(page))
+ ClearPageError(page);
result = 0;
io_error:
return result;
}
+static inline struct nfs_page *
+_nfs_find_read(struct inode *inode, struct page *page)
+{
+ struct list_head *head, *next;
+
+ head = &inode->u.nfs_i.read;
+ next = head->next;
+ while (next != head) {
+ struct nfs_page *req = nfs_list_entry(next);
+ next = next->next;
+ if (page_index(req->wb_page) != page_index(page))
+ continue;
+ req->wb_count++;
+ return req;
+ }
+ return NULL;
+}
+
+static struct nfs_page *
+nfs_find_read(struct inode *inode, struct page *page)
+{
+ struct nfs_page *req;
+ spin_lock(&nfs_wreq_lock);
+ req = _nfs_find_read(inode, page);
+ spin_unlock(&nfs_wreq_lock);
+ return req;
+}
+
/*
- * This is the callback from RPC telling us whether a reply was
- * received or some error occurred (timeout or socket shutdown).
+ * Add a request to the inode's asynchronous read list.
*/
-static void
-nfs_readpage_result(struct rpc_task *task)
+static inline void
+nfs_mark_request_read(struct nfs_page *req)
{
- struct nfs_rreq *req = (struct nfs_rreq *) task->tk_calldata;
- struct page *page = req->ra_page;
- char *address = req->ra_args.iov[0].iov_base;
- int result = task->tk_status;
- static int succ = 0, fail = 0;
-
- dprintk("NFS: %4d received callback for page %p, result %d\n",
- task->tk_pid, address, result);
-
- nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
- if (result >= 0) {
- result = req->ra_res.count;
- if (result < PAGE_CACHE_SIZE)
- memset(address + result, 0, PAGE_CACHE_SIZE - result);
- SetPageUptodate(page);
- succ++;
- } else {
- SetPageError(page);
- fail++;
- dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
+ struct inode *inode = req->wb_dentry->d_inode;
+
+ spin_lock(&nfs_wreq_lock);
+ if (list_empty(&req->wb_list)) {
+ nfs_list_add_request(req, &inode->u.nfs_i.read);
+ inode->u.nfs_i.nread++;
}
- kunmap(page);
- UnlockPage(page);
- page_cache_release(page);
+ spin_unlock(&nfs_wreq_lock);
+ /*
+ * NB: the call to inode_schedule_scan() must lie outside the
+ * spinlock since it can run flushd().
+ */
+ inode_schedule_scan(inode, req->wb_timeout);
+}
+
+static int
+nfs_readpage_async(struct dentry *dentry, struct page *page)
+{
+ struct inode *inode = dentry->d_inode;
+ struct nfs_page *req, *new = NULL;
+ int result;
+
+ for (;;) {
+ result = 0;
+ if (Page_Uptodate(page))
+ break;
- kfree(req);
+ req = nfs_find_read(inode, page);
+ if (req) {
+ if (page != req->wb_page) {
+ nfs_release_request(req);
+ nfs_pagein_inode(inode, page_index(page), 0);
+ continue;
+ }
+ nfs_release_request(req);
+ break;
+ }
+
+ if (new) {
+ nfs_lock_request(new);
+ new->wb_timeout = jiffies + NFS_READ_DELAY;
+ nfs_mark_request_read(new);
+ nfs_unlock_request(new);
+ new = NULL;
+ break;
+ }
+
+ result = -ENOMEM;
+ new = nfs_create_request(dentry, page, 0, PAGE_CACHE_SIZE);
+ if (!new)
+ break;
+ }
+
+ if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+ page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
+ nfs_pagein_inode(inode, 0, 0);
+ if (new)
+ nfs_release_request(new);
+ return result;
+}
+
+/*
+ * Set up the NFS read request struct
+ */
+static void
+nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
+{
+ struct nfs_page *req;
+ struct iovec *iov;
+ unsigned int count;
+
+ iov = data->args.iov;
+ count = 0;
+ while (!list_empty(head)) {
+ struct nfs_page *req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &data->pages);
+ iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+ iov->iov_len = req->wb_bytes;
+ count += req->wb_bytes;
+ iov++;
+ data->args.nriov++;
+ }
+ req = nfs_list_entry(data->pages.next);
+ data->dentry = req->wb_dentry;
+ data->cred = req->wb_cred;
+ data->args.fh = NFS_FH(req->wb_dentry);
+ data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+ data->args.count = count;
+ data->res.fattr = &data->fattr;
+ data->res.count = count;
+ data->res.eof = 0;
}
-static inline int
-nfs_readpage_async(struct dentry *dentry, struct inode *inode,
- struct page *page)
+static void
+nfs_async_read_error(struct list_head *head)
{
- struct rpc_message msg;
- unsigned long address;
- struct nfs_rreq *req;
- int result = -1, flags;
+ struct nfs_page *req;
+ struct page *page;
+
+ while (!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ page = req->wb_page;
+ nfs_list_remove_request(req);
+ SetPageError(page);
+ UnlockPage(page);
+ nfs_unlock_request(req);
+ nfs_release_request(req);
+ }
+}
- dprintk("NFS: nfs_readpage_async(%p)\n", page);
- if (NFS_CONGESTED(inode))
- goto out_defer;
+static int
+nfs_pagein_one(struct list_head *head, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct rpc_task *task;
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ struct nfs_read_data *data;
+ struct rpc_message msg;
+ int flags;
+ sigset_t oldset;
+
+ data = nfs_readdata_alloc();
+ if (!data)
+ goto out_bad;
+ task = &data->task;
/* N.B. Do we need to test? Never called for swapfile inode */
flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
- req = (struct nfs_rreq *) rpc_allocate(flags, sizeof(*req));
- if (!req)
- goto out_defer;
-
- address = kmap(page);
- /* Initialize request */
- /* N.B. Will the dentry remain valid for life of request? */
- nfs_readreq_setup(req, NFS_FH(dentry), page_offset(page),
- (void *) address, PAGE_CACHE_SIZE);
- req->ra_inode = inode;
- req->ra_page = page; /* count has been incremented by caller */
- /* Start the async call */
- dprintk("NFS: executing async READ request.\n");
+ nfs_read_rpcsetup(head, data);
+
+ /* Finalize the task. */
+ rpc_init_task(task, clnt, nfs_readpage_result, flags);
+ task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_readdata_release;
+#ifdef CONFIG_NFS_V3
msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
- msg.rpc_argp = &req->ra_args;
- msg.rpc_resp = &req->ra_res;
- msg.rpc_cred = NULL;
-
- result = rpc_call_async(NFS_CLIENT(inode), &msg, flags,
- nfs_readpage_result, req);
- if (result < 0)
- goto out_free;
- result = 0;
-out:
- return result;
+#else
+ msg.rpc_proc = NFSPROC_READ;
+#endif
+ msg.rpc_argp = &data->args;
+ msg.rpc_resp = &data->res;
+ msg.rpc_cred = data->cred;
-out_defer:
- dprintk("NFS: deferring async READ request.\n");
- goto out;
-out_free:
- dprintk("NFS: failed to enqueue async READ request.\n");
- kunmap(page);
- kfree(req);
- goto out;
+ /* Start the async call */
+ dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n",
+ task->tk_pid,
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ data->args.count, data->args.nriov);
+
+ rpc_clnt_sigmask(clnt, &oldset);
+ rpc_call_setup(task, &msg, 0);
+ rpc_execute(task);
+ rpc_clnt_sigunmask(clnt, &oldset);
+ return 0;
+out_bad:
+ nfs_async_read_error(head);
+ return -ENOMEM;
+}
+
+static int
+nfs_pagein_list(struct inode *inode, struct list_head *head)
+{
+ LIST_HEAD(one_request);
+ struct nfs_page *req;
+ int error = 0;
+ unsigned int pages = 0,
+ rpages = NFS_SERVER(inode)->rpages;
+
+ 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);
+ if (error < 0)
+ break;
+ }
+ if (error >= 0)
+ return pages;
+
+ nfs_async_read_error(head);
+ return error;
+}
+
+static int
+nfs_scan_read_timeout(struct inode *inode, struct list_head *dst)
+{
+ int pages;
+ spin_lock(&nfs_wreq_lock);
+ pages = nfs_scan_list_timeout(&inode->u.nfs_i.read, dst, inode);
+ inode->u.nfs_i.nread -= pages;
+ if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
+ spin_unlock(&nfs_wreq_lock);
+ return pages;
+}
+
+static int
+nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+{
+ int res;
+ spin_lock(&nfs_wreq_lock);
+ res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages);
+ inode->u.nfs_i.nread -= res;
+ if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read))
+ printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
+ spin_unlock(&nfs_wreq_lock);
+ return res;
+}
+
+int nfs_pagein_inode(struct inode *inode, unsigned long idx_start,
+ unsigned int npages)
+{
+ LIST_HEAD(head);
+ int res,
+ error = 0;
+
+ res = nfs_scan_read(inode, &head, idx_start, npages);
+ if (res)
+ error = nfs_pagein_list(inode, &head);
+ if (error < 0)
+ return error;
+ return res;
+}
+
+int nfs_pagein_timeout(struct inode *inode)
+{
+ LIST_HEAD(head);
+ int pages,
+ error = 0;
+
+ pages = nfs_scan_read_timeout(inode, &head);
+ if (pages)
+ error = nfs_pagein_list(inode, &head);
+ if (error < 0)
+ return error;
+ return pages;
+}
+
+/*
+ * This is the callback from RPC telling us whether a reply was
+ * received or some error occurred (timeout or socket shutdown).
+ */
+static void
+nfs_readpage_result(struct rpc_task *task)
+{
+ struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+ struct dentry *dentry = data->dentry;
+ struct inode *inode = dentry->d_inode;
+ int count = data->res.count;
+
+ dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
+ task->tk_pid, task->tk_status);
+
+ nfs_refresh_inode(inode, &data->fattr);
+ while (!list_empty(&data->pages)) {
+ struct nfs_page *req = nfs_list_entry(data->pages.next);
+ struct page *page = req->wb_page;
+ nfs_list_remove_request(req);
+
+ if (task->tk_status >= 0 && count >= 0) {
+ SetPageUptodate(page);
+ count -= PAGE_CACHE_SIZE;
+ } else
+ SetPageError(page);
+ 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,
+ req->wb_bytes,
+ (long long)(page_offset(page) + req->wb_offset));
+ nfs_unlock_request(req);
+ nfs_release_request(req);
+ }
}
/*
struct inode *inode = dentry->d_inode;
int error;
- lock_kernel();
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
page, PAGE_CACHE_SIZE, page->index);
- get_page(page);
-
/*
* Try to flush any pending writes to the file..
*
goto out_error;
error = -1;
- if (!IS_SWAPFILE(inode) && !PageError(page) &&
- NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
- error = nfs_readpage_async(dentry, inode, page);
+ if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
+ error = nfs_readpage_async(dentry, page);
if (error >= 0)
goto out;
- error = nfs_readpage_sync(dentry, inode, page);
+ error = nfs_readpage_sync(dentry, page);
if (error < 0 && IS_SWAPFILE(inode))
printk("Aiee.. nfs swap-in of page failed!\n");
- goto out_free;
+out:
+ return error;
out_error:
UnlockPage(page);
-out_free:
- page_cache_release(page);
-out:
- unlock_kernel();
- return error;
+ goto out;
+}
+
+int nfs_init_readpagecache(void)
+{
+ nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
+ sizeof(struct nfs_read_data),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (nfs_rdata_cachep == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void nfs_destroy_readpagecache(void)
+{
+ if (kmem_cache_destroy(nfs_rdata_cachep))
+ printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
}
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs_flushd.h>
+#include <linux/nfs_page.h>
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
/*
* Local structures
*
- * Valid flags for a dirty buffer
- */
-#define PG_BUSY 0x0001
-
-/*
* This is the struct where the WRITE/COMMIT arguments go.
*/
struct nfs_write_data {
struct rpc_task task;
- struct file *file;
+ struct dentry *dentry;
struct rpc_cred *cred;
struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */
struct list_head pages; /* Coalesced requests we wish to flush */
};
-struct nfs_page {
- struct list_head wb_hash, /* Inode */
- wb_list,
- *wb_list_head;
- struct file *wb_file;
- struct rpc_cred *wb_cred;
- struct page *wb_page; /* page to write out */
- wait_queue_head_t wb_wait; /* wait queue */
- unsigned long wb_timeout; /* when to write/commit */
- unsigned int wb_offset, /* Offset of write */
- wb_bytes, /* Length of request */
- wb_count, /* reference count */
- wb_flags;
- struct nfs_writeverf wb_verf; /* Commit cookie */
-};
-
-#define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY)
-
/*
* Local function declarations
*/
+static struct nfs_page * nfs_update_request(struct file*, struct dentry *,
+ struct page *page,
+ unsigned int, unsigned int);
+static void nfs_strategy(struct inode *inode);
static void nfs_writeback_done(struct rpc_task *);
#ifdef CONFIG_NFS_V3
static void nfs_commit_done(struct rpc_task *);
* Offset is the data offset within the page.
*/
static int
-nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
- struct page *page, unsigned long offset, unsigned int count)
+nfs_writepage_sync(struct dentry *dentry, struct page *page,
+ unsigned int offset, unsigned int count)
{
+ struct inode *inode = dentry->d_inode;
loff_t base;
unsigned int wsize = NFS_SERVER(inode)->wsize;
int result, refresh = 0, written = 0, flags;
struct nfs_writeverf verf;
lock_kernel();
- dprintk("NFS: nfs_writepage_sync(%s/%s %d@%lu/%ld)\n",
+ dprintk("NFS: nfs_writepage_sync(%s/%s %d@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->index, offset);
+ count, (long long)(page_offset(page) + offset));
buffer = (u8 *) kmap(page) + offset;
base = page_offset(page) + offset;
inode->i_size = base;
} while (count);
+ if (PageError(page))
+ ClearPageError(page);
+
io_error:
kunmap(page);
return written? written : result;
}
+static int
+nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page,
+ unsigned int offset, unsigned int count)
+{
+ struct nfs_page *req;
+ int status;
+
+ req = nfs_update_request(file, dentry, page, offset, count);
+ status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
+ if (status < 0)
+ goto out;
+ nfs_release_request(req);
+ nfs_strategy(dentry->d_inode);
+ out:
+ return status;
+}
+
/*
- * Write a page to the server. This was supposed to be used for
- * NFS swapping only.
- * FIXME: Using this for mmap is pointless, breaks asynchronous
- * writebacks, and is extremely slow.
+ * Write an mmapped page to the server.
*/
int
-nfs_writepage(struct dentry * dentry, struct page *page)
+nfs_writepage(struct file *file, struct dentry * dentry, struct page *page)
{
struct inode *inode = dentry->d_inode;
unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
if (page->index >= end_index+1 || !offset)
return -EIO;
do_it:
- err = nfs_writepage_sync(dentry, inode, page, 0, offset);
- if ( err == offset) return 0;
+ if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) {
+ err = nfs_writepage_async(file, dentry, page, 0, offset);
+ if (err >= 0)
+ goto out_ok;
+ }
+ err = nfs_writepage_sync(dentry, page, 0, offset);
+ if ( err == offset)
+ goto out_ok;
return err;
+ out_ok:
+ return 0;
}
/*
return 0;
}
-static inline struct nfs_page *
-nfs_inode_wb_entry(struct list_head *head)
-{
- return list_entry(head, struct nfs_page, wb_hash);
-}
-
/*
* Insert a write request into an inode
*/
}
if (!NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
- inode = req->wb_file->f_dentry->d_inode;
+ inode = req->wb_dentry->d_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 (!nfs_have_writebacks(inode))
+ if (!nfs_have_writebacks(inode) && !nfs_have_read(inode))
inode_remove_flushd(inode);
spin_unlock(&nfs_wreq_lock);
nfs_release_request(req);
return NULL;
}
-struct nfs_page *
+static struct nfs_page *
nfs_find_request(struct inode *inode, struct page *page)
{
struct nfs_page *req;
return req;
}
-static inline struct nfs_page *
-nfs_list_entry(struct list_head *head)
-{
- return list_entry(head, struct nfs_page, wb_list);
-}
-
/*
* Insert a write request into a sorted list
*/
-static inline void
-nfs_list_add_request(struct nfs_page *req, struct list_head *head)
+void nfs_list_add_request(struct nfs_page *req, struct list_head *head)
{
struct list_head *prev;
printk(KERN_ERR "NFS: Add to list failed!\n");
return;
}
- if (list_empty(&req->wb_hash)) {
- printk(KERN_ERR "NFS: Unhashed request attempted added to a list!\n");
- return;
- }
if (!NFS_WBACK_BUSY(req))
printk(KERN_ERR "NFS: unlocked request attempted added to list!\n");
prev = head->prev;
/*
* Insert a write request into an inode
*/
-static inline void
-nfs_list_remove_request(struct nfs_page *req)
+void nfs_list_remove_request(struct nfs_page *req)
{
if (list_empty(&req->wb_list))
return;
static inline void
nfs_mark_request_dirty(struct nfs_page *req)
{
- struct inode *inode = req->wb_file->f_dentry->d_inode;
+ struct inode *inode = req->wb_dentry->d_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_file->f_dentry->d_inode;
+ struct inode *inode = req->wb_dentry->d_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_file->f_dentry->d_inode;
+ struct inode *inode = req->wb_dentry->d_inode;
spin_lock(&nfs_wreq_lock);
if (list_empty(&req->wb_list)) {
}
#endif
-/*
- * Lock the page of an asynchronous request
- */
-static inline int
-nfs_lock_request(struct nfs_page *req)
-{
- if (NFS_WBACK_BUSY(req))
- return 0;
- req->wb_count++;
- req->wb_flags |= PG_BUSY;
- return 1;
-}
-
-static inline void
-nfs_unlock_request(struct nfs_page *req)
-{
- if (!NFS_WBACK_BUSY(req)) {
- printk(KERN_ERR "NFS: Invalid unlock attempted\n");
- return;
- }
- req->wb_flags &= ~PG_BUSY;
- wake_up(&req->wb_wait);
- nfs_release_request(req);
-}
-
/*
* Create a write request.
* Page must be locked by the caller. This makes sure we never create
* two different requests for the same page, and avoids possible deadlock
* when we reach the hard limit on the number of dirty pages.
*/
-static struct nfs_page *
-nfs_create_request(struct inode *inode, struct file *file, struct page *page,
- unsigned int offset, unsigned int count)
+struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page,
+ unsigned int offset, unsigned int count)
{
+ struct inode *inode = dentry->d_inode;
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct nfs_page *req = NULL;
long timeout;
/* Deal with hard/soft limits.
*/
do {
- /* If we're over the soft limit, flush out old requests */
- if (nfs_nr_requests >= MAX_REQUEST_SOFT)
- nfs_wb_file(inode, file);
-
- /* If we're still over the soft limit, wake up some requests */
+ /* If we're over the global soft limit, wake up all requests */
if (nfs_nr_requests >= MAX_REQUEST_SOFT) {
dprintk("NFS: hit soft limit (%d requests)\n",
nfs_nr_requests);
nfs_wake_flushd();
}
- /* If we haven't reached the hard limit yet,
+ /* If we haven't reached the local hard limit yet,
* try to allocate the request struct */
- if (nfs_nr_requests < MAX_REQUEST_HARD) {
+ if (cache->nr_requests < MAX_REQUEST_HARD) {
req = nfs_page_alloc();
if (req != NULL)
break;
/* We're over the hard limit. Wait for better times */
dprintk("NFS: create_request sleeping (total %d pid %d)\n",
- nfs_nr_requests, current->pid);
+ cache->nr_requests, current->pid);
timeout = 1 * HZ;
if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) {
sleep_on_timeout(&cache->request_wait, timeout);
dprintk("NFS: create_request waking up (tot %d pid %d)\n",
- nfs_nr_requests, current->pid);
+ cache->nr_requests, current->pid);
} while (!req);
if (!req)
return NULL;
* long write-back delay. This will be adjusted in
* update_nfs_request below if the region is not locked. */
req->wb_page = page;
- atomic_inc(&page->count);
+ get_page(page);
req->wb_offset = offset;
req->wb_bytes = count;
- /* If the region is locked, adjust the timeout */
- if (region_locked(inode, req))
- req->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
- else
- req->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
- req->wb_file = file;
+ req->wb_dentry = dget(dentry);
req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
- get_file(file);
req->wb_count = 1;
/* register request's existence */
void
nfs_release_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_file->f_dentry->d_inode;
+ struct inode *inode = req->wb_dentry->d_inode;
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct page *page = req->wb_page;
printk(KERN_ERR "NFS: Request released while still locked!\n");
rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
- fput(req->wb_file);
+ if (req->wb_file)
+ fput(req->wb_file);
+ dput(req->wb_dentry);
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_file->f_dentry->d_inode;
+ struct inode *inode = req->wb_dentry->d_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
int retval;
* Scan cluster for dirty pages and send as many of them to the
* server as possible.
*/
-static int
-nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode)
+int nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode)
{
struct list_head *p;
struct nfs_page *req;
}
#endif
-static int
-nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+int nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
{
struct list_head *p;
struct nfs_page *req;
#endif
-static int
-coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages)
+int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages)
{
struct nfs_page *req = NULL;
unsigned int pages = 0;
if (prev) {
if (req->wb_file != prev->wb_file)
break;
-
+ if (req->wb_dentry != prev->wb_dentry)
+ break;
+ if (req->wb_cred != prev->wb_cred)
+ break;
if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
break;
* Note: Should always be called with the Page Lock held!
*/
static struct nfs_page *
-nfs_update_request(struct file* file, struct page *page,
- unsigned long offset, unsigned int bytes)
+nfs_update_request(struct file* file, struct dentry *dentry, struct page *page,
+ unsigned int offset, unsigned int bytes)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
struct nfs_page *req, *new = NULL;
unsigned long rqend, end;
}
spin_unlock(&nfs_wreq_lock);
+
/* Create the request. It's safe to sleep in this call because
* we only get here if the page is locked.
+ *
+ * If we're over the soft limit, flush out old requests
*/
- new = nfs_create_request(inode, file, page, offset, bytes);
+ if (file && nfs_nr_requests >= MAX_REQUEST_SOFT)
+ nfs_wb_file(inode, file);
+ new = nfs_create_request(dentry, page, offset, bytes);
if (!new)
return ERR_PTR(-ENOMEM);
+ if (file) {
+ new->wb_file = file;
+ get_file(file);
+ }
+ /* If the region is locked, adjust the timeout */
+ if (region_locked(inode, new))
+ new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
+ else
+ new->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
}
/* We have a request for our page.
*/
#define NFS_STRATEGY_PAGES 8
static void
-nfs_strategy(struct file *file)
+nfs_strategy(struct inode *inode)
{
- struct inode *inode = file->f_dentry->d_inode;
unsigned int dirty, wpages;
dirty = inode->u.nfs_i.ndirty;
- wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT;
+ wpages = NFS_SERVER(inode)->wpages;
#ifdef CONFIG_NFS_V3
if (NFS_PROTO(inode)->version == 2) {
if (dirty >= NFS_STRATEGY_PAGES * wpages)
- nfs_flush_file(inode, file, 0, 0, 0);
+ nfs_flush_file(inode, NULL, 0, 0, 0);
} else {
if (dirty >= wpages)
- nfs_flush_file(inode, file, 0, 0, 0);
+ nfs_flush_file(inode, NULL, 0, 0, 0);
+ if (inode->u.nfs_i.ncommit > NFS_STRATEGY_PAGES * wpages &&
+ nfs_nr_requests > MAX_REQUEST_SOFT)
+ nfs_commit_file(inode, NULL, 0, 0, 0);
}
#else
if (dirty >= NFS_STRATEGY_PAGES * wpages)
- nfs_flush_file(inode, file, 0, 0, 0);
+ nfs_flush_file(inode, NULL, 0, 0, 0);
#endif
/*
- * If we're running out of requests, flush out everything
+ * If we're running out of free requests, flush out everything
* in order to reduce memory useage...
*/
- if (nfs_nr_requests > MAX_REQUEST_SOFT)
- nfs_wb_file(inode, file);
+ if (inode->u.nfs_i.npages > MAX_REQUEST_SOFT)
+ nfs_wb_all(inode);
}
int
* things with a page scheduled for an RPC call (e.g. invalidate it).
*/
int
-nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count)
+nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
* page synchronously.
*/
if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
- return nfs_writepage_sync(dentry, inode, page, offset, count);
+ return nfs_writepage_sync(dentry, 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, dentry, page, offset, count);
status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
if (status != -EBUSY)
break;
* of requests.
*/
if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE)
- nfs_strategy(file);
+ nfs_strategy(inode);
}
nfs_release_request(req);
done:
data->args.nriov++;
}
req = nfs_list_entry(data->pages.next);
- data->file = req->wb_file;
+ data->dentry = req->wb_dentry;
data->cred = req->wb_cred;
- data->args.fh = NFS_FH(req->wb_file->f_dentry);
+ data->args.fh = NFS_FH(req->wb_dentry);
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 file *file, int how)
+nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
{
- struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_write_data *data;
struct nfs_page *req;
int error = 0;
unsigned int pages = 0,
- wpages = NFS_SERVER(inode)->wsize >> PAGE_CACHE_SHIFT;
+ wpages = NFS_SERVER(inode)->wpages;
while (!list_empty(head)) {
- pages += coalesce_requests(head, &one_request, wpages);
+ pages += nfs_coalesce_requests(head, &one_request, wpages);
req = nfs_list_entry(one_request.next);
- error = nfs_flush_one(&one_request, req->wb_file, how);
+ error = nfs_flush_one(&one_request, req->wb_dentry, 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->file->f_dentry;
+ struct dentry *dentry = data->dentry;
struct inode *inode = dentry->d_inode;
struct nfs_page *req;
+ struct page *page;
dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
task->tk_pid, task->tk_status);
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
+ page = req->wb_page;
- kunmap(req->wb_page);
+ kunmap(page);
dprintk("NFS: write (%s/%s %d@%Ld)",
- req->wb_file->f_dentry->d_parent->d_name.name,
- req->wb_file->f_dentry->d_name.name,
+ req->wb_dentry->d_parent->d_name.name,
+ req->wb_dentry->d_name.name,
req->wb_bytes,
- (long long)(page_offset(req->wb_page) + req->wb_offset));
+ (long long)(page_offset(page) + req->wb_offset));
if (task->tk_status < 0) {
- req->wb_file->f_error = task->tk_status;
+ ClearPageUptodate(page);
+ SetPageError(page);
+ if (req->wb_file)
+ req->wb_file->f_error = task->tk_status;
nfs_inode_remove_request(req);
dprintk(", error = %d\n", task->tk_status);
goto next;
end = 0;
start = ~0;
req = nfs_list_entry(head->next);
- data->file = req->wb_file;
+ dentry = req->wb_dentry;
+ data->dentry = dentry;
data->cred = req->wb_cred;
- dentry = data->file->f_dentry;
inode = dentry->d_inode;
while (!list_empty(head)) {
struct nfs_page *req;
nfs_commit_list(struct list_head *head, int how)
{
struct rpc_message msg;
- struct file *file;
struct rpc_clnt *clnt;
struct nfs_write_data *data;
struct rpc_task *task;
/* Set up the argument struct */
nfs_commit_rpcsetup(head, data);
req = nfs_list_entry(data->pages.next);
- file = req->wb_file;
- clnt = NFS_CLIENT(file->f_dentry->d_inode);
+ clnt = NFS_CLIENT(req->wb_dentry->d_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->file->f_dentry;
+ struct dentry *dentry = data->dentry;
struct inode *inode = dentry->d_inode;
dprintk("NFS: %4d nfs_commit_done (status %d)\n",
nfs_list_remove_request(req);
dprintk("NFS: commit (%s/%s %d@%Ld)",
- req->wb_file->f_dentry->d_parent->d_name.name,
- req->wb_file->f_dentry->d_name.name,
+ req->wb_dentry->d_parent->d_name.name,
+ req->wb_dentry->d_name.name,
req->wb_bytes,
(long long)(page_offset(req->wb_page) + req->wb_offset));
if (task->tk_status < 0) {
- req->wb_file->f_error = task->tk_status;
+ if (req->wb_file)
+ req->wb_file->f_error = task->tk_status;
nfs_inode_remove_request(req);
dprintk(", error = %d\n", task->tk_status);
goto next;
#endif
};
-static int ntfs_writepage(struct dentry *dentry, struct page *page)
+static int ntfs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,ntfs_get_block);
}
struct address_space_operations ntfs_aops = {
readpage: ntfs_readpage,
writepage: ntfs_writepage,
+ sync_page: block_sync_page,
prepare_write: ntfs_prepare_write,
commit_write: generic_commit_write,
bmap: _ntfs_bmap
return;
}
-static int qnx4_writepage(struct dentry *dentry, struct page *page)
+static int qnx4_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,qnx4_get_block);
}
struct address_space_operations qnx4_aops = {
readpage: qnx4_readpage,
writepage: qnx4_writepage,
+ sync_page: block_sync_page,
prepare_write: qnx4_prepare_write,
commit_write: generic_commit_write,
bmap: qnx4_bmap
goto end_rmdir;
}
#endif
- if (!d_unhashed(dentry)) {
- retval = -EBUSY;
- goto end_rmdir;
- }
if (inode->i_nlink != 2) {
QNX4DEBUG(("empty directory has nlink!=2 (%d)\n", inode->i_nlink));
}
* Writing: just make sure the page gets marked dirty, so that
* the page stealer won't grab it.
*/
-static int ramfs_writepage(struct dentry * dentry, struct page *page)
+static int ramfs_writepage(struct file *file, struct dentry * dentry, struct page *page)
{
SetPageDirty(page);
return 0;
if (!file->f_op || !file->f_op->readdir)
goto out;
down(&inode->i_sem);
- res = file->f_op->readdir(file, buf, filler);
+ down(&inode->i_zombie);
+ res = -ENOENT;
+ if (!IS_DEADDIR(inode))
+ res = file->f_op->readdir(file, buf, filler);
+ up(&inode->i_zombie);
up(&inode->i_sem);
out:
return res;
* We are called with the page locked and the caller unlocks.
*/
static int
-smb_writepage(struct dentry *dentry, struct page *page)
+smb_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
struct inode *inode = dentry->d_inode;
unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
return NULL;
}
-static int sysv_writepage(struct dentry *dentry, struct page *page)
+static int sysv_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,sysv_get_block);
}
struct address_space_operations sysv_aops = {
readpage: sysv_readpage,
writepage: sysv_writepage,
+ sync_page: block_sync_page,
prepare_write: sysv_prepare_write,
commit_write: generic_commit_write,
bmap: sysv_bmap
retval = -ENOTEMPTY;
goto end_rmdir;
}
- if (!d_unhashed(dentry)) {
- retval = -EBUSY;
- goto end_rmdir;
- }
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n", inode->i_nlink);
de->inode = 0;
}
if (S_ISDIR(old_inode->i_mode)) {
if (new_inode) {
- retval = -EBUSY;
- if (!d_unhashed(new_dentry))
- goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
return 0;
}
-static int udf_adinicb_writepage(struct dentry *dentry, struct page *page)
+static int udf_adinicb_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
struct inode *inode = (struct inode *)page->mapping->host;
struct address_space_operations udf_adinicb_aops = {
readpage: udf_adinicb_readpage,
writepage: udf_adinicb_writepage,
+ sync_page: block_sync_page,
prepare_write: udf_adinicb_prepare_write,
commit_write: udf_adinicb_commit_write,
};
udf_trunc(inode);
}
-static int udf_writepage(struct dentry *dentry, struct page *page)
+static int udf_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page, udf_get_block);
}
struct address_space_operations udf_aops = {
readpage: udf_readpage,
writepage: udf_writepage,
+ sync_page: block_sync_page,
prepare_write: udf_prepare_write,
commit_write: generic_commit_write,
bmap: udf_bmap,
mark_buffer_dirty(bh, 1);
udf_release_data(bh);
- inode->i_data.a_ops->writepage(NULL, page);
+ inode->i_data.a_ops->writepage(NULL, NULL, page);
UnlockPage(page);
page_cache_release(page);
Uint32 extoffset, elen, offset;
struct buffer_head *bh = NULL;
- *err = -EINVAL;
- if (!dir || !dir->i_nlink)
- return NULL;
sb = dir->i_sb;
if (dentry->d_name.len)
}
else if (dir->i_size != 0)
{
+ /* WTF??? */
*err = -ENOENT;
return NULL;
}
if (new_inode)
{
- retval = -EBUSY;
- if (!d_unhashed(new_dentry))
- goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
return NULL;
}
-static int ufs_writepage(struct dentry *dentry, struct page *page)
+static int ufs_writepage(struct file *file, struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,ufs_getfrag_block);
}
struct address_space_operations ufs_aops = {
readpage: ufs_readpage,
writepage: ufs_writepage,
+ sync_page: block_sync_page,
prepare_write: ufs_prepare_write,
commit_write: generic_commit_write,
bmap: ufs_bmap
*err = -EINVAL;
*res_dir = NULL;
- if (!dir || !dir->i_nlink)
- return NULL;
sb = dir->i_sb;
flags = sb->u.ufs_sb.s_flags;
if (!namelen)
return NULL;
- /*
- * Is this a busy deleted directory? Can't create new files if so
- */
- if (dir->i_size == 0)
- {
- *err = -ENOENT;
- return NULL;
- }
bh = ufs_bread (dir, 0, 0, err);
if (!bh)
return NULL;
struct buffer_head *bh = NULL;
struct msdos_dir_entry *de;
- if (!d_unhashed(dentry))
- return -EBUSY;
-
res = fat_dir_empty(dentry->d_inode);
if (res)
return res;
}
if (is_dir) {
- res =-EBUSY;
- if (!d_unhashed(new_dentry))
- goto rename_done;
res = fat_dir_empty(new_inode);
if (res)
goto rename_done;
* Screen mapping information
*/
#define SCREEN_START 0x02000000
-#define SCREEN2_END 0x02078000
-#define SCREEN2_BASE 0x02000000
-#define SCREEN1_END 0x02000000
-#define SCREEN1_BASE 0x01f88000
+#define SCREEN_END 0x02078000
+#define SCREEN_BASE 0x02000000
#ifndef __ASSEMBLY__
/* Let's define SCREEN_START for CL7500, even though it's a lie. */
#define SCREEN_START 0x02000000 /* VRAM */
-#define SCREEN2_END 0xe0000000
-#define SCREEN2_BASE 0xd8000000
-#define SCREEN1_END 0xd8000000
-#define SCREEN1_BASE 0xd0000000
+#define SCREEN_END 0xdfc00000
+#define SCREEN_BASE 0xdf800000
#define FLUSH_BASE 0xdf000000
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END (PAGE_OFFSET + 0x1c000000)
/*
* linux/include/asm-arm/arch-ebsa110/hardware.h
*
- * Copyright (C) 1996-1999 Russell King.
+ * Copyright (C) 1996-2000 Russell King.
*
* This file contains the hardware definitions of the EBSA-110.
*/
* RAM definitions
*/
#define FLUSH_BASE_PHYS 0x40000000
-#define UNCACHEABLE_ADDR 0xf3000000
#else /* __ASSEMBLY__ */
#define FLUSH_BASE 0xdf000000
#define PCIO_BASE 0xf0000000
+#define UNCACHEABLE_ADDR 0xf3000000
+
#define PARAMS_BASE (PAGE_OFFSET + 0x400)
#endif
request_resource(&ioport_resource, &pic2_resource);
setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
setup_arm_irq(isa_irq, &irq_cascade);
+
+ /*
+ * On the NetWinder, don't automatically
+ * enable ISA IRQ11 when it is requested.
+ * There appears to be a missing pull-up
+ * resistor on this line.
+ */
+ if (machine_is_netwinder())
+ irq_desc[_ISA_IRQ(11)].noautoenable = 1;
}
}
timer_irq.handler = isa_timer_interrupt;
irq = IRQ_ISA_TIMER;
}
- setup_arm_irq(IRQ_ISA_TIMER, &timer_irq);
+ setup_arm_irq(irq, &timer_irq);
}
* divided by a 4-bit prescaler. Other boards use an
* ISA derived timer, and this is unused.
*/
-#define CLOCK_TICK_RATE (50000000 / 16)
+#define CLOCK_TICK_RATE (mem_fclk_21285 / 16)
#define IO_BASE 0xe0000000
#define SCREEN_START 0x02000000 /* VRAM */
-#define SCREEN2_END 0xe0000000
-#define SCREEN2_BASE 0xd8000000
-#define SCREEN1_END 0xd8000000
-#define SCREEN1_BASE 0xd0000000
+#define SCREEN_END 0xdfc00000
+#define SCREEN_BASE 0xdf800000
#define FLUSH_BASE 0xdf000000
#define UNCACHEABLE_ADDR 0xdf010000
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END (PAGE_OFFSET + 0x1c000000)
#ifndef __ASM_ARM_ATOMIC_H
#define __ASM_ARM_ATOMIC_H
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
#error SMP not supported
#endif
-#include <linux/config.h>
-
#ifdef CONFIG_ARCH_CO285
typedef struct { volatile int counter; } atomic_t;
#else
#ifndef __ASM_HARDIRQ_H
#define __ASM_HARDIRQ_H
+#include <linux/config.h>
#include <linux/threads.h>
extern unsigned int local_irq_count[NR_CPUS];
#define in_irq() (local_irq_count[smp_processor_id()] != 0)
-#ifndef __SMP__
+#ifndef CONFIG_SMP
#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
#define hardirq_endlock(cpu) do { } while (0)
#else
#error SMP not supported
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
#endif /* __ASM_HARDIRQ_H */
extern inline dma_addr_t
pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
{
- consistent_sync(ptr, size, 3);
+ consistent_sync(ptr, size, direction);
return virt_to_bus(ptr);
}
int i;
for (i = 0; i < nents; i++, sg++)
- consistent_sync(sg->address, sg->length, 3);
+ consistent_sync(sg->address, sg->length, direction);
return nents;
}
extern inline void
pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
{
- consistent_sync(bus_to_virt(dma_handle), size, 3);
+ consistent_sync(bus_to_virt(dma_handle), size, direction);
}
/* Make physical memory consistent for a set of streaming
*/
#ifndef CONFIG_NO_PGT_CACHE
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
extern struct pgtable_cache_struct {
unsigned long *pgd_cache;
#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0))
/*
- * Permanent address of a page.
+ * Permanent address of a page. We never have highmem, so this is trivial.
*/
-#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define page_address(page) ((page)->virtual)
#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT))
#define pte_page(x) (mem_map + pte_pagenr(x))
return pte;
}
-#define mk_pte(page,pgprot) \
-({ \
- pte_t __pte; \
- pte_val(__pte) = PHYS_OFFSET + \
- (((page) - mem_map) << PAGE_SHIFT) + \
- pgprot_val(pgprot); \
- __pte; \
+#define mk_pte(page,pgprot) \
+({ \
+ pte_t __pte; \
+ pte_val(__pte) = __pa(page_address(page)) + \
+ pgprot_val(pgprot); \
+ __pte; \
})
/*
extern const char xchg_str[];
+#include <linux/config.h>
#include <asm/proc-fns.h>
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
#define local_irq_disable() __cli()
#define local_irq_enable() __sti()
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#error SMP not supported
#else
* PTE functions *
****************/
-/* PTE types (actially level 2 descriptor) */
+/* PTE types (actually level 2 descriptor) */
#define PTE_TYPE_MASK 0x0003
#define PTE_TYPE_FAULT 0x0000
#define PTE_TYPE_LARGE 0x0001
* The following macros handle the cache and bufferable bits...
*/
#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG
-#define _L_PTE_READ L_PTE_USER | L_PTE_CACHEABLE
+#define _L_PTE_READ L_PTE_USER | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
#define PAGE_NONE __pgprot(_L_PTE_DEFAULT)
-#define PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE)
-#define PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE | L_PTE_WRITE)
-#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE)
+#define PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
+#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
#define PAGE_KERNEL __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
#define _PAGE_CHG_MASK (PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
#ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H
+#include <linux/config.h>
+
extern const char xchg_str[];
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
#define local_irq_disable() __cli()
#define local_irq_enable() __sti()
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#error SMP not supported
#else
unsigned long system_rev; /* 76 */
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
+ unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
} u1;
#ifndef __ASM_SMP_H
#define __ASM_SMP_H
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
#error SMP not supported
#endif
#define __HAVE_ARCH_MEMCPY
#define __HAVE_ARCH_MEMMOVE
#define __HAVE_ARCH_MEMCHR
+extern void * memchr(const void *cs, int c, size_t count);
+
#define __HAVE_ARCH_MEMZERO
#define __HAVE_ARCH_MEMSET
extern unsigned int system_rev;
extern unsigned int system_serial_low;
extern unsigned int system_serial_high;
+extern unsigned int mem_fclk_21285;
/* The type of machine we're running on */
extern unsigned int __machine_arch_type;
-/* see arch/arm/kernel/setup.c for a description of these */
+/* see arch/arm/kernel/arch.c for a description of these */
#define MACH_TYPE_EBSA110 0
#define MACH_TYPE_RISCPC 1
#define MACH_TYPE_NEXUSPCI 3
#define MACH_TYPE_LACIE_NAS 13
#define MACH_TYPE_CLPS7500 14
#define MACH_TYPE_SHARK 15
-#define MACH_TYPE_SA1100 16
+#define MACH_TYPE_BRUTUS 16
#define MACH_TYPE_PERSONAL_SERVER 17
+#define MACH_TYPE_BITSY 22
+#define MACH_TYPE_THINCLIENT 24
+#define MACH_TYPE_ASSABET 25
+#define MACH_TYPE_VICTOR 26
+#define MACH_TYPE_LART 27
/*
* Sort out a definition for machine_arch_type
# define machine_is_shark() (0)
#endif
-#ifdef CONFIG_ARCH_SA1100
+#ifdef CONFIG_SA1100_BRUTUS
# ifdef machine_arch_type
# undef machine_arch_type
# define machine_arch_type __machine_arch_type
# else
-# define machine_arch_type MACH_TYPE_SA1100
+# define machine_arch_type MACH_TYPE_BRUTUS
# endif
-# define machine_is_sa1100() (machine_arch_type == MACH_TYPE_SA1100)
+# define machine_is_brutus() (machine_arch_type == MACH_TYPE_BRUTUS)
#else
-# define machine_is_sa1100() (0)
+# define machine_is_brutus() (0)
#endif
#ifdef CONFIG_ARCH_PERSONAL_SERVER
# define machine_is_personal_server() (0)
#endif
+#ifdef CONFIG_SA1100_ITSY
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_ITSY
+# endif
+# define machine_is_itsy() (machine_arch_type == MACH_TYPE_ITSY)
+#else
+# define machine_is_itsy() (0)
+#endif
+
+#ifdef CONFIG_SA1100_EMPEG
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_EMPEG
+# endif
+# define machine_is_empeg() (machine_arch_type == MACH_TYPE_EMPEG)
+#else
+# define machine_is_empeg() (0)
+#endif
+
+#ifdef CONFIG_SA1100_ASSABET
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_ASSABET
+# endif
+# define machine_is_assabet() (machine_arch_type == MACH_TYPE_ASSABET)
+#else
+# define machine_is_assabet() (0)
+#endif
+
+#ifdef CONFIG_SA1100_VICTOR
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_VICTOR
+# endif
+# define machine_is_victor() (machine_arch_type == MACH_TYPE_VICTOR)
+#else
+# define machine_is_victor() (0)
+#endif
+
+#ifdef CONFIG_SA1100_LART
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_LART
+# endif
+# define machine_is_lart() (machine_arch_type == MACH_TYPE_LART)
+#else
+# define machine_is_lart() (0)
+#endif
+
+#ifdef CONFIG_SA1100_BITSY
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_BITSY
+# endif
+# define machine_is_bitsy() (machine_arch_type == MACH_TYPE_BITSY)
+#else
+# define machine_is_bitsy() (0)
+#endif
+
+#ifdef CONFIG_SA1100_TIFON
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_TIFON
+# endif
+# define machine_is_tifon() (machine_arch_type == MACH_TYPE_TIFON)
+#else
+# define machine_is_tifon() (0)
+#endif
+
+#ifdef CONFIG_SA1100_PLEB
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_PLEB
+# endif
+# define machine_is_pleb() (machine_arch_type == MACH_TYPE_PLEB)
+#else
+# define machine_is_pleb() (0)
+#endif
+
+#ifdef CONFIG_SA1100_THINCLIENT
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_THINCLIENT
+# endif
+# define machine_is_thinclient() (machine_arch_type == MACH_TYPE_THINCLIENT)
+#else
+# define machine_is_thinclient() (0)
+#endif
+
+#ifdef CONFIG_SA1100_PENNY
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_PENNY
+# endif
+# define machine_is_penny() (machine_arch_type == MACH_TYPE_PENNY)
+#else
+# define machine_is_penny() (0)
+#endif
+
#ifndef machine_arch_type
#define machine_arch_type __machine_arch_type
#endif
}
#define start_thread(regs, new_eip, new_esp) do { \
- __asm__("movl %w0,%%fs ; movl %w0,%%gs": :"r" (0)); \
+ __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \
set_fs(USER_DS); \
regs->xds = __USER_DS; \
regs->xes = __USER_DS; \
#define SPINLOCK_MAGIC_INIT /* */
#endif
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 SPINLOCK_MAGIC_INIT }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
/*
* We make no fairness assumptions. They have a cost.
*/
-#define spin_unlock_wait(x) do { barrier(); } while(((volatile spinlock_t *)(x))->lock)
-#define spin_is_locked(x) ((x)->lock != 0)
+#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0)
+#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
#define spin_lock_string \
"\n1:\t" \
- "lock ; btsl $0,%0\n\t" \
- "jc 2f\n" \
+ "lock ; decb %0\n\t" \
+ "js 2f\n" \
".section .text.lock,\"ax\"\n" \
"2:\t" \
- "testb $1,%0\n\t" \
+ "cmpb $0,%0\n\t" \
"rep;nop\n\t" \
- "jne 2b\n\t" \
+ "jle 2b\n\t" \
"jmp 1b\n" \
".previous"
/*
- * Sadly, some early PPro chips require the locked access,
- * otherwise we could just always simply do
- *
- * #define spin_unlock_string \
- * "movb $0,%0"
- *
- * Which is noticeably faster.
+ * This works. Despite all the confusion.
*/
#define spin_unlock_string \
- "lock ; btrl $0,%0"
+ "movb $1,%0"
+
+/*
+ * Won't work on i386-SMP. Does anybody care?
+ */
+static inline int spin_trylock(spinlock_t *lock)
+{
+ char oldval;
+ __asm__ __volatile__(
+ "lock ; cmpxchg %b2,%1"
+ :"=a" (oldval), "=m" (__dummy_lock(lock))
+ :"q" (0), "0" (1));
+ return oldval > 0;
+}
extern inline void spin_lock(spinlock_t *lock)
{
#if SPINLOCK_DEBUG
if (lock->magic != SPINLOCK_MAGIC)
BUG();
- if (!lock->lock)
+ if (!spin_is_locked(lock))
BUG();
#endif
__asm__ __volatile__(
:"=m" (__dummy_lock(lock)));
}
-#define spin_trylock(lock) ({ !test_and_set_bit(0,(lock)); })
-
/*
* Read-write spinlocks, allowing multiple readers
* but only one writer.
*
*/
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
typedef struct { volatile int counter; } atomic_t;
#else
typedef struct { int counter; } atomic_t;
* Copyright (C) 1999 Kaz Kojima
*/
+#include <linux/config.h>
+
extern __inline__ void __delay(unsigned long loops)
{
__asm__ __volatile__(
}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define __udelay_val cpu_data[smp_processor_id()].udelay_val
#else
#define __udelay_val loops_per_sec
#ifndef __ASM_SH_HARDIRQ_H
#define __ASM_SH_HARDIRQ_H
+#include <linux/config.h>
#include <linux/threads.h>
extern unsigned int local_irq_count[NR_CPUS];
#define in_irq() (local_irq_count[smp_processor_id()] != 0)
-#ifndef __SMP__
+#ifndef CONFIG_SMP
#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
#define hardirq_endlock(cpu) do { } while (0)
#error Super-H SMP is not available
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
#endif /* __ASM_SH_HARDIRQ_H */
* for more details.
*/
-#ifndef __SMP__
+#include <linux/config.h>
+
+#ifndef CONFIG_SMP
#define lock_kernel() do { } while(0)
#define unlock_kernel() do { } while(0)
spin_lock(&kernel_flag); \
} while (0)
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
#endif /* __ASM_SH_SMPLOCK_H */
* Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
*/
+#include <linux/config.h>
+
/*
* switch_to() should switch tasks to task nr n, first
*/
unsigned long seg;
} mm_segment_t;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#error no SMP SuperH
#else
#define prepare_to_switch() do { } while(0)
#define local_irq_disable() __cli()
#define local_irq_enable() __sti()
-#ifdef __SMP__
+#ifdef CONFIG_SMP
extern void __global_cli(void);
extern void __global_sti(void);
#define ASIZ_mm_env_start 0x00000004
#define AOFF_mm_env_end 0x0000006c
#define ASIZ_mm_env_end 0x00000004
-#define AOFF_mm_rss 0x00000070
+#define AOFF_mm_min_flt 0x00000070
+#define ASIZ_mm_min_flt 0x00000004
+#define AOFF_mm_maj_flt 0x00000074
+#define ASIZ_mm_maj_flt 0x00000004
+#define AOFF_mm_rss 0x00000078
#define ASIZ_mm_rss 0x00000004
-#define AOFF_mm_total_vm 0x00000074
+#define AOFF_mm_total_vm 0x0000007c
#define ASIZ_mm_total_vm 0x00000004
-#define AOFF_mm_locked_vm 0x00000078
+#define AOFF_mm_locked_vm 0x00000080
#define ASIZ_mm_locked_vm 0x00000004
-#define AOFF_mm_def_flags 0x0000007c
+#define AOFF_mm_def_flags 0x00000084
#define ASIZ_mm_def_flags 0x00000004
-#define AOFF_mm_cpu_vm_mask 0x00000080
+#define AOFF_mm_cpu_vm_mask 0x00000088
#define ASIZ_mm_cpu_vm_mask 0x00000004
-#define AOFF_mm_swap_cnt 0x00000084
+#define AOFF_mm_swap_cnt 0x0000008c
#define ASIZ_mm_swap_cnt 0x00000004
-#define AOFF_mm_swap_address 0x00000088
+#define AOFF_mm_swap_address 0x00000090
#define ASIZ_mm_swap_address 0x00000004
-#define AOFF_mm_segments 0x0000008c
+#define AOFF_mm_segments 0x00000094
#define ASIZ_mm_segments 0x00000004
#define AOFF_thread_uwinmask 0x00000000
#define ASIZ_thread_uwinmask 0x00000004
#define ASIZ_mm_env_start 0x00000004
#define AOFF_mm_env_end 0x00000074
#define ASIZ_mm_env_end 0x00000004
-#define AOFF_mm_rss 0x00000078
+#define AOFF_mm_min_flt 0x00000078
+#define ASIZ_mm_min_flt 0x00000004
+#define AOFF_mm_maj_flt 0x0000007c
+#define ASIZ_mm_maj_flt 0x00000004
+#define AOFF_mm_rss 0x00000080
#define ASIZ_mm_rss 0x00000004
-#define AOFF_mm_total_vm 0x0000007c
+#define AOFF_mm_total_vm 0x00000084
#define ASIZ_mm_total_vm 0x00000004
-#define AOFF_mm_locked_vm 0x00000080
+#define AOFF_mm_locked_vm 0x00000088
#define ASIZ_mm_locked_vm 0x00000004
-#define AOFF_mm_def_flags 0x00000084
+#define AOFF_mm_def_flags 0x0000008c
#define ASIZ_mm_def_flags 0x00000004
-#define AOFF_mm_cpu_vm_mask 0x00000088
+#define AOFF_mm_cpu_vm_mask 0x00000090
#define ASIZ_mm_cpu_vm_mask 0x00000004
-#define AOFF_mm_swap_cnt 0x0000008c
+#define AOFF_mm_swap_cnt 0x00000094
#define ASIZ_mm_swap_cnt 0x00000004
-#define AOFF_mm_swap_address 0x00000090
+#define AOFF_mm_swap_address 0x00000098
#define ASIZ_mm_swap_address 0x00000004
-#define AOFF_mm_segments 0x00000094
+#define AOFF_mm_segments 0x0000009c
#define ASIZ_mm_segments 0x00000004
#define AOFF_thread_uwinmask 0x00000000
#define ASIZ_thread_uwinmask 0x00000004
#define ASIZ_mm_env_start 0x00000008
#define AOFF_mm_env_end 0x000000c8
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x000000d0
+#define AOFF_mm_min_flt 0x000000d0
+#define ASIZ_mm_min_flt 0x00000008
+#define AOFF_mm_maj_flt 0x000000d8
+#define ASIZ_mm_maj_flt 0x00000008
+#define AOFF_mm_rss 0x000000e0
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x000000d8
+#define AOFF_mm_total_vm 0x000000e8
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x000000e0
+#define AOFF_mm_locked_vm 0x000000f0
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x000000e8
+#define AOFF_mm_def_flags 0x000000f8
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_cpu_vm_mask 0x000000f0
+#define AOFF_mm_cpu_vm_mask 0x00000100
#define ASIZ_mm_cpu_vm_mask 0x00000008
-#define AOFF_mm_swap_cnt 0x000000f8
+#define AOFF_mm_swap_cnt 0x00000108
#define ASIZ_mm_swap_cnt 0x00000008
-#define AOFF_mm_swap_address 0x00000100
+#define AOFF_mm_swap_address 0x00000110
#define ASIZ_mm_swap_address 0x00000008
-#define AOFF_mm_segments 0x00000108
+#define AOFF_mm_segments 0x00000118
#define ASIZ_mm_segments 0x00000008
-#define ASIZ_mm 0x00000110
+#define ASIZ_mm 0x00000120
#define AOFF_thread_ksp 0x00000000
#define ASIZ_thread_ksp 0x00000008
#define AOFF_thread_wstate 0x00000008
#define ASIZ_mm_env_start 0x00000008
#define AOFF_mm_env_end 0x000000c8
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x000000d0
+#define AOFF_mm_min_flt 0x000000d0
+#define ASIZ_mm_min_flt 0x00000008
+#define AOFF_mm_maj_flt 0x000000d8
+#define ASIZ_mm_maj_flt 0x00000008
+#define AOFF_mm_rss 0x000000e0
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x000000d8
+#define AOFF_mm_total_vm 0x000000e8
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x000000e0
+#define AOFF_mm_locked_vm 0x000000f0
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x000000e8
+#define AOFF_mm_def_flags 0x000000f8
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_cpu_vm_mask 0x000000f0
+#define AOFF_mm_cpu_vm_mask 0x00000100
#define ASIZ_mm_cpu_vm_mask 0x00000008
-#define AOFF_mm_swap_cnt 0x000000f8
+#define AOFF_mm_swap_cnt 0x00000108
#define ASIZ_mm_swap_cnt 0x00000008
-#define AOFF_mm_swap_address 0x00000100
+#define AOFF_mm_swap_address 0x00000110
#define ASIZ_mm_swap_address 0x00000008
-#define AOFF_mm_segments 0x00000108
+#define AOFF_mm_segments 0x00000118
#define ASIZ_mm_segments 0x00000008
-#define ASIZ_mm 0x00000110
+#define ASIZ_mm 0x00000120
#define AOFF_thread_ksp 0x00000000
#define ASIZ_thread_ksp 0x00000008
#define AOFF_thread_wstate 0x00000008
#define ASIZ_mm_env_start 0x00000008
#define AOFF_mm_env_end 0x000000d8
#define ASIZ_mm_env_end 0x00000008
-#define AOFF_mm_rss 0x000000e0
+#define AOFF_mm_min_flt 0x000000e0
+#define ASIZ_mm_min_flt 0x00000008
+#define AOFF_mm_maj_flt 0x000000e8
+#define ASIZ_mm_maj_flt 0x00000008
+#define AOFF_mm_rss 0x000000f0
#define ASIZ_mm_rss 0x00000008
-#define AOFF_mm_total_vm 0x000000e8
+#define AOFF_mm_total_vm 0x000000f8
#define ASIZ_mm_total_vm 0x00000008
-#define AOFF_mm_locked_vm 0x000000f0
+#define AOFF_mm_locked_vm 0x00000100
#define ASIZ_mm_locked_vm 0x00000008
-#define AOFF_mm_def_flags 0x000000f8
+#define AOFF_mm_def_flags 0x00000108
#define ASIZ_mm_def_flags 0x00000008
-#define AOFF_mm_cpu_vm_mask 0x00000100
+#define AOFF_mm_cpu_vm_mask 0x00000110
#define ASIZ_mm_cpu_vm_mask 0x00000008
-#define AOFF_mm_swap_cnt 0x00000108
+#define AOFF_mm_swap_cnt 0x00000118
#define ASIZ_mm_swap_cnt 0x00000008
-#define AOFF_mm_swap_address 0x00000110
+#define AOFF_mm_swap_address 0x00000120
#define ASIZ_mm_swap_address 0x00000008
-#define AOFF_mm_segments 0x00000118
+#define AOFF_mm_segments 0x00000128
#define ASIZ_mm_segments 0x00000008
-#define ASIZ_mm 0x00000120
+#define ASIZ_mm 0x00000130
#define AOFF_thread_ksp 0x00000000
#define ASIZ_thread_ksp 0x00000008
#define AOFF_thread_wstate 0x00000008
#else /* (__SMP__) */
-#include <linux/spinlock.h>
-
static __inline__ int irqs_running(void)
{
enum brlock_indices idx = BR_GLOBALIRQ_LOCK;
#define MS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
* as nfs_rename() will be cleaned up
*/
+#define S_DEAD (1<<16) /* removed, but still open directory */
/*
* Flags that can be altered by MS_REMOUNT
#define IS_NOATIME(inode) __IS_FLG(inode, MS_NOATIME)
#define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME)
+#define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
struct address_space;
struct address_space_operations {
- int (*writepage) (struct dentry *, struct page *);
+ int (*writepage)(struct file *, struct dentry *, struct page *);
int (*readpage)(struct dentry *, struct page *);
+ int (*sync_page)(struct page *);
int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
struct vfsmount *mnt;
struct qstr last;
unsigned int flags;
+ int last_type;
};
#define FASYNC_MAGIC 0x4601
* NOTE:
* read, write, poll, fsync, readv, writev can be called
* without the big kernel lock held in all filesystems.
- * fasync can be called at interrupt time.
*/
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
*/
#define LOOKUP_FOLLOW (1)
#define LOOKUP_DIRECTORY (2)
-#define LOOKUP_SLASHOK (4)
-#define LOOKUP_CONTINUE (8)
-#define LOOKUP_POSITIVE (16)
-#define LOOKUP_PARENT (32)
-#define LOOKUP_NOALT (64)
+#define LOOKUP_CONTINUE (4)
+#define LOOKUP_POSITIVE (8)
+#define LOOKUP_PARENT (16)
+#define LOOKUP_NOALT (32)
+/*
+ * Type of the last component on LOOKUP_PARENT
+ */
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT };
/*
* "descriptor" for what we're up to with a read for sendfile().
extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
unsigned long *);
+extern int block_sync_page(struct page *);
+
int generic_block_bmap(struct address_space *, long, get_block_t *);
int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
#ifndef _LINUX_INTERRUPT_H
#define _LINUX_INTERRUPT_H
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/cache.h>
extern struct tasklet_head tasklet_vec[NR_CPUS];
extern struct tasklet_head tasklet_hi_vec[NR_CPUS];
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define tasklet_trylock(t) (!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state))
#define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { /* NOTHING */ }
#define tasklet_unlock(t) clear_bit(TASKLET_STATE_RUN, &(t)->state)
extern void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define SMP_TIMER_NAME(name) name##__thr
tasklet_schedule(&(task)); \
}
-#else /* __SMP__ */
+#else /* CONFIG_SMP */
#define SMP_TIMER_NAME(name) name
#define SMP_TIMER_DEFINE(name, task)
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
/* Old BH definitions */
* The upper limit on timeouts for the exponential backoff algorithm.
*/
#define NFS_MAX_RPC_TIMEOUT (6*HZ)
+#define NFS_READ_DELAY (2*HZ)
#define NFS_WRITEBACK_DELAY (5*HZ)
#define NFS_WRITEBACK_LOCKDELAY (60*HZ)
#define NFS_COMMIT_DELAY (5*HZ)
/*
* linux/fs/nfs/write.c
*/
-extern int nfs_writepage(struct dentry *, struct page *);
-extern int nfs_check_failed_request(struct inode *);
-extern struct nfs_page* nfs_find_request(struct inode *, struct page *);
-extern void nfs_release_request(struct nfs_page *req);
+extern int nfs_writepage(struct file *file, struct dentry *, struct page *);
extern int nfs_flush_incompatible(struct file *file, struct page *page);
-extern int nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int);
+extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
/*
* Try to write back everything synchronously (but check the
* return value!)
extern int nfs_commit_timeout(struct inode *, int);
#endif
+static inline int
+nfs_have_read(struct inode *inode)
+{
+ return !list_empty(&inode->u.nfs_i.read);
+}
+
static inline int
nfs_have_writebacks(struct inode *inode)
{
* linux/fs/nfs/read.c
*/
extern int nfs_readpage(struct dentry *, struct page *);
+extern int nfs_pagein_inode(struct inode *, unsigned long, unsigned int);
+extern int nfs_pagein_timeout(struct inode *);
/*
* linux/fs/mount_clnt.c
/*
* This is the list of dirty unwritten pages.
*/
+ struct list_head read;
struct list_head dirty;
struct list_head commit;
struct list_head writeback;
- unsigned int ndirty,
+ unsigned int nread,
+ ndirty,
ncommit,
npages;
struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
int flags; /* various flags */
unsigned int rsize; /* read size */
+ unsigned int rpages; /* read size (in pages) */
unsigned int wsize; /* write size */
+ unsigned int wpages; /* write size (in pages) */
unsigned int dtsize; /* readdir size */
unsigned int bsize; /* server block size */
unsigned int acregmin; /* attr cache timeouts */
--- /dev/null
+/*
+ * linux/include/linux/nfs_page.h
+ *
+ * Copyright (C) 2000 Trond Myklebust
+ *
+ * NFS page cache wrapper.
+ */
+
+#ifndef _LINUX_NFS_PAGE_H
+#define _LINUX_NFS_PAGE_H
+
+
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/nfs_xdr.h>
+
+/*
+ * Valid flags for a dirty buffer
+ */
+#define PG_BUSY 0x0001
+
+struct nfs_page {
+ struct list_head wb_hash, /* Inode */
+ wb_list, /* Defines state of page: */
+ *wb_list_head; /* read/write/commit */
+ struct file *wb_file;
+ struct dentry *wb_dentry;
+ struct rpc_cred *wb_cred;
+ struct page *wb_page; /* page to read in/write out */
+ wait_queue_head_t wb_wait; /* wait queue */
+ unsigned long wb_timeout; /* when to read/write/commit */
+ unsigned int wb_offset, /* Offset of read/write */
+ wb_bytes, /* Length of request */
+ wb_count, /* reference count */
+ wb_flags;
+ struct nfs_writeverf wb_verf; /* Commit cookie */
+};
+
+#define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY)
+
+extern struct nfs_page *nfs_create_request(struct dentry *dentry,
+ struct page *page,
+ unsigned int offset,
+ unsigned int count);
+extern void nfs_release_request(struct nfs_page *req);
+
+
+extern void nfs_list_add_request(struct nfs_page *req,
+ struct list_head *head);
+extern void nfs_list_remove_request(struct nfs_page *req);
+
+extern int nfs_scan_list_timeout(struct list_head *head,
+ struct list_head *dst,
+ struct inode *inode);
+extern int nfs_scan_list(struct list_head *src, struct list_head *dst,
+ struct file *file, unsigned long idx_start,
+ unsigned int npages);
+extern int nfs_coalesce_requests(struct list_head *src, struct list_head *dst,
+ unsigned int maxpages);
+
+extern spinlock_t nfs_wreq_lock;
+
+/*
+ * Lock the page of an asynchronous request
+ */
+static __inline__ int
+nfs_lock_request(struct nfs_page *req)
+{
+ if (NFS_WBACK_BUSY(req))
+ return 0;
+ req->wb_count++;
+ req->wb_flags |= PG_BUSY;
+ return 1;
+}
+
+static __inline__ void
+nfs_unlock_request(struct nfs_page *req)
+{
+ if (!NFS_WBACK_BUSY(req)) {
+ printk(KERN_ERR "NFS: Invalid unlock attempted\n");
+ return;
+ }
+ req->wb_flags &= ~PG_BUSY;
+ wake_up(&req->wb_wait);
+ nfs_release_request(req);
+}
+
+static __inline__ struct nfs_page *
+nfs_list_entry(struct list_head *head)
+{
+ return list_entry(head, struct nfs_page, wb_list);
+}
+
+static __inline__ struct nfs_page *
+nfs_inode_wb_entry(struct list_head *head)
+{
+ return list_entry(head, struct nfs_page, wb_hash);
+}
+
+#endif /* _LINUX_NFS_PAGE_H */
extern unsigned long event;
+#include <linux/config.h>
#include <linux/binfmts.h>
#include <linux/personality.h>
#include <linux/threads.h>
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define set_task_state(tsk, state_value) \
set_mb((tsk)->state, (state_value))
#else
#define __set_current_state(state_value) \
do { current->state = (state_value); } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define set_current_state(state_value) \
set_mb(current->state, (state_value))
#else
* Alan Cox. <alan@redhat.com>
*/
-#ifdef __SMP__
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
#include <asm/smp.h>
#ifndef __LINUX_SMPLOCK_H
#define __LINUX_SMPLOCK_H
-#ifndef __SMP__
+#include <linux/config.h>
+
+#ifndef CONFIG_SMP
#define lock_kernel() do { } while(0)
#define unlock_kernel() do { } while(0)
#include <asm/smplock.h>
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
#endif
#ifndef __LINUX_SPINLOCK_H
#define __LINUX_SPINLOCK_H
+#include <linux/config.h>
+
/*
* These are the generic versions of the spinlocks and read-write
* locks..
#define write_unlock_irq(lock) do { write_unlock(lock); local_irq_enable(); } while (0)
#define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#include <asm/spinlock.h>
#else /* !SMP */
#ifndef _LINUX_THREADS_H
#define _LINUX_THREADS_H
+#include <linux/config.h>
+
/*
* The default limit for the nr of threads is now in
* /proc/sys/kernel/max-threads.
*/
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define NR_CPUS 32 /* Max processors that can be running in SMP */
#else
#define NR_CPUS 1
#ifndef _LINUX_TIMER_H
#define _LINUX_TIMER_H
+#include <linux/config.h>
+
/*
* Old-style timers. Please don't use for any new code.
*
{
timer->next = NULL;
timer->prev = NULL;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
timer->running = 0;
#endif
}
return timer->prev != NULL;
}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define timer_exit(t) do { (t)->running = 0; mb(); } while (0)
#define timer_set_running(t) do { (t)->running = 1; mb(); } while (0)
#define timer_is_running(t) ((t)->running != 0)
EXPORT_SYMBOL(block_write_full_page);
EXPORT_SYMBOL(block_read_full_page);
EXPORT_SYMBOL(block_prepare_write);
+EXPORT_SYMBOL(block_sync_page);
EXPORT_SYMBOL(cont_prepare_write);
EXPORT_SYMBOL(generic_commit_write);
EXPORT_SYMBOL(generic_block_bmap);
atomic_dec(&page_cache_size);
}
+static inline int sync_page(struct page *page)
+{
+ struct address_space *mapping = page->mapping;
+
+ if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
+ return mapping->a_ops->sync_page(page);
+ return 0;
+}
+
/*
* Remove a page from the page cache and free it. Caller has to make
* sure the page is locked and that nobody else uses it - or that usage
if (!PageLocked(page))
PAGE_BUG(page);
+ /* Initiate completion of any async operations */
+ sync_page(page);
+
spin_lock(&pagecache_lock);
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
struct list_head *head, *curr;
struct page * page;
+ repeat:
head = &inode->i_mapping->pages;
spin_lock(&pagecache_lock);
curr = head->next;
/* We cannot invalidate a locked page */
if (TryLockPage(page))
continue;
+ spin_unlock(&pagecache_lock);
lru_cache_del(page);
- remove_page_from_inode_queue(page);
- remove_page_from_hash_queue(page);
- page->mapping = NULL;
+ remove_inode_page(page);
UnlockPage(page);
-
page_cache_release(page);
+ goto repeat;
}
spin_unlock(&pagecache_lock);
}
add_wait_queue(&page->wait, &wait);
do {
- run_task_queue(&tq_disk);
+ sync_page(page);
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!PageLocked(page))
break;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- run_task_queue(&tq_disk);
+ sync_page(page);
__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
add_wait_queue(&page->wait, &wait);
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- run_task_queue(&tq_disk);
+ sync_page(page);
__set_task_state(tsk, TASK_UNINTERRUPTIBLE);
add_wait_queue(&page->wait, &wait);
* mmap_sem is held.
*/
lock_page(page);
- result = inode->i_mapping->a_ops->writepage(dentry, page);
+ result = inode->i_mapping->a_ops->writepage(file, dentry, page);
UnlockPage(page);
return result;
}
error = vma->vm_ops->sync(vma, start, end-start, flags);
if (!error && (flags & MS_SYNC)) {
struct file * file = vma->vm_file;
- if (file)
- error = file_fsync(file, file->f_dentry);
+ if (file && file->f_op && file->f_op->fsync)
+ error = file->f_op->fsync(file, file->f_dentry);
}
return error;
}
#include <asm/pgtable.h>
+static struct address_space_operations swap_aops = {
+ sync_page: block_sync_page
+};
+
struct address_space swapper_space = {
{ /* pages */
&swapper_space.pages, /* .next */
&swapper_space.pages /* .prev */
},
- 0 /* nrpages */
+ 0, /* nrpages */
+ &swap_aops,
};
#ifdef SWAP_CACHE_INFO
}
#endif
- size = sprintf(buffer+len,
- "%u.%u.%u.%u0x%-10x0x%-10x%s",
- NIPQUAD(*(u32*)n->primary_key),
- hatype,
- arp_state_to_flags(n),
- hbuffer);
- size += sprintf(buffer+len+size,
- " %-17s %s\n",
- "*", dev->name);
+ {
+ char tbuf[16];
+ sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key));
+
+ size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s",
+ tbuf,
+ hatype,
+ arp_state_to_flags(n),
+ hbuffer);
+
+ size += sprintf(buffer+len+size,
+ " %-8s %s\n",
+ "*", dev->name);
+ }
+
read_unlock(&n->lock);
len += size;
define_bool "$var" "n"
return
;;
- m)
- eval "$var=y"
- ;;
esac
shift
done