diff -Nru a/Documentation/BK-usage/bk-kernel-howto.txt b/Documentation/BK-usage/bk-kernel-howto.txt
--- a/Documentation/BK-usage/bk-kernel-howto.txt Mon Apr 22 15:32:18 2002
+++ b/Documentation/BK-usage/bk-kernel-howto.txt Mon Apr 22 15:32:18 2002
@@ -27,7 +27,7 @@
and merges. You will need to take a few minutes to think about
how to best work under BitKeeper, and re-optimize things a bit.
In some sense it is a bit radical, because it might described as
-tossing changes out into a maelstrom and having them them magically
+tossing changes out into a maelstrom and having them magically
land at the right destination... but I'm getting ahead of myself.
Let's start with this progression:
diff -Nru a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
--- a/Documentation/DocBook/kernel-hacking.tmpl Mon Apr 22 15:32:19 2002
+++ b/Documentation/DocBook/kernel-hacking.tmpl Mon Apr 22 15:32:19 2002
@@ -1025,7 +1025,7 @@
Similar to EXPORT_SYMBOL() except that the
symbols exported by EXPORT_SYMBOL_GPL() can
only be seen by modules with a
- MODULE_LICENCE() that specifies a GPL
+ MODULE_LICENSE() that specifies a GPL
compatible license.
diff -Nru a/Documentation/filesystems/Exporting b/Documentation/filesystems/Exporting
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/Documentation/filesystems/Exporting Mon Apr 22 15:32:19 2002
@@ -0,0 +1,176 @@
+
+Making Filesystems Exportable
+=============================
+
+Most filesystem operations require a dentry (or two) as a starting
+point. Local applications have a reference-counted hold on suitable
+dentrys via open file descriptors or cwd/root. However remote
+applications that access a filesystem via a remote filesystem protocol
+such as NFS may not be able to hold such a reference, and so need a
+different way to refer to a particular dentry. As the alternative
+form of reference needs to be stable across renames, truncates, and
+server-reboot (among other things, though these tend to be the most
+problematic), there is no simple answer like 'filename'.
+
+The mechanism discussed here allows each filesystem implementation to
+specify how to generate an opaque (out side of the filesystem) byte
+string for any dentry, and how to find an appropriate dentry for any
+given opaque byte string.
+This byte string will be called a "filehandle fragment" as it
+corresponds to part of an NFS filehandle.
+
+A filesystem which supports the mapping between filehandle fragments
+and dentrys will be termed "exportable".
+
+
+
+Dcache Issues
+-------------
+
+The dcache normally contains a proper prefix of any given filesystem
+tree. This means that if any filesystem object is in the dcache, then
+all of the ancestors of that filesystem object are also in the dcache.
+As normal access is by filename this prefix is created naturally and
+maintained easily (by each object maintaining a reference count on
+it's parent).
+
+However when objects are included into the dcache by interpreting a
+filehandle fragment, there is no automatic creation of a path prefix
+for the object. This leads to two related but distinct features of
+the dcache that are not needed for normal filesystem access.
+
+1/ The dcache must sometimes contain objects that are not part of the
+ proper prefix. i.e that are not connected to the root.
+2/ The dcache must be prepared for a newly found (via ->lookup) directory
+ to already have a (non-connected) dentry, and must be able to move
+ that dentry into place (based on the parent and name in the
+ ->lookup). This is particuarly needed for directories as
+ it is a dcache invarient that directories only have one dentry.
+
+To implement these features, the dcache has:
+
+a/ A dentry flag DCACHE_DISCONNECTED which is set on
+ and dentry that might not be part of the proper prefix.
+ This is set when anonymous dentries are created, and cleared when a
+ dentry is noticed to be a child on a dentry which is in the proper
+ prefix.
+
+b/ A per-superblock list "s_anon" of dentries which are the roots of
+ subtrees that are not in the proper prefix. These dentries, as
+ well as the proper prefix, need to be released at unmount time. As
+ these dentries will not be hashed, they are linked together on the
+ d_hash list_head.
+
+c/ Helper routines to allocate anonymous dentries, and to help attach
+ loose directory dentries at lookup time. They are:
+ d_alloc_anon(inode) will return a dentry for the given inode.
+ If the inode already has a dentry, one of those is returned.
+ If it doesn't, a new anonymous (IS_ROOT and
+ DCACHE_DISCONNECTED) dentry is allocated and attached.
+ In the case of a directory, care is taken that only one dentry
+ can ever be attached.
+ d_splice_alias(inode, dentry) will make sure that there is a
+ dentry with the same name and parent as the given dentry, and
+ which refers to the given inode.
+ If the inode is a directory and already has a dentry, then that
+ dentry is d_moved over the given dentry.
+ If the passed dentry gets attached, care is taken that this is
+ mutually exclusive to a d_alloc_anon operation.
+ If the passed dentry is used, NULL is returned, else the used
+ dentry is returned. This corresponds to the calling pattern of
+ ->lookup.
+
+
+Filesystem Issues
+-----------------
+
+For a filesystem to be exportable it must:
+
+ 1/ provide the filehandle fragment routines described below.
+ 2/ make sure that d_splice_alias is used rather than d_add
+ when ->lookup finds an inode for a given parent and name.
+ Typically the ->lookup routine will end:
+ if (inode)
+ return d_splice(inode, dentry);
+ d_add(dentry, inode);
+ return NULL;
+ }
+
+
+
+ A file system implementation declares that instances of the filesystem
+are exportable by setting the s_export_op field in the struct
+super_block. This field must point to a "struct export_operations"
+struct which could potentially be full of NULLs, though normally at
+least get_parent will be set.
+
+ The primary operations are decode_fh and encode_fh.
+decode_fh takes a filehandle fragment and tries to find or create a
+dentry for the object referred to by the filehandle.
+encode_fh takes a dentry and creates a filehandle fragment which can
+later be used to find/create a dentry for the same object.
+
+decode_fh will probably make use of "find_exported_dentry".
+This function lives in the "exportfs" module which a filesystem does
+not need unless it is being exported. So rather that calling
+find_exported_dentry directly, each filesystem should call it through
+the find_exported_dentry pointer in it's export_operations table.
+This field is set correctly by the exporting agent (e.g. nfsd) when a
+filesystem is exported, and before any export operations are called.
+
+find_exported_dentry needs three support functions from the
+filesystem:
+ get_name. When given a parent dentry and a child dentry, this
+ should find a name in the directory identified by the parent
+ dentry, which leads to the object identified by the child dentry.
+ If no get_name function is supplied, a default implementation
+ which used vfs_readdir to find potential names, and matches inode
+ numbers to find the correct match.
+
+ get_parent. When given a dentry for a directory, this should return
+ a dentry for the parent. Quite possibly the parent dentry will
+ have been allocated by d_alloc_anon.
+ The default get_parent function just returns an error so any
+ filehandle lookup that requires finding a parent will fail.
+ ->lookup("..") is *not* used as a default as it can leave ".."
+ entries in the dcache which are too messy to work with.
+
+ get_dentry. When given a opaque datum, this should find the
+ implied object and create a dentry for it (possibly with
+ d_alloc_anon).
+ The opaque datum is whatever is passed down by the decode_fh
+ function, and is often simply a fragment of the filehandle
+ fragment.
+ decode_fh passes two datums through find_exported_dentry. One that
+ should be used to identify the target object, and one that can be
+ used to identify the objects parent, should that be necessary.
+ The default get_dentry function assumes that the datum contains an
+ inode number and a generation number, and it attempts to get the
+ inode using "iget" and check it's validity by matching the
+ generation number. A filesystem should only depend on the default
+ if iget can safely be used this way.
+
+If decode_fh and/or encode_fh are left as NULL, then default
+implementations are used. These defaults are suitable for ext2 and
+extremely similar filesystems (like ext3).
+
+The default encode_fh creates a filehandle fragment from the inode
+number and generation number of the target together with the inode
+number and generation number of the parent (if the parent is
+required).
+
+The default decode_fh extract the target and parent datums from the
+filehandle assuming the format used by the default encode_fh and
+passed them to find_exported_dentry.
+
+
+A filehandle fragment consists of an array of 1 or more 4byte words.
+Together with a one byte "type".
+The decode_fh routine should not depend on the stated size that is
+passed to it. This size may be larger than the original filehandle
+generated by encode_fh, in which case it will have been padded with
+nuls. Rather, the encode_fh routine should choose a "type" which
+indicates the decode_fh how much of the filehandle is valid, and how
+it should be interpreted.
+
+
diff -Nru a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog
--- a/Documentation/filesystems/devfs/ChangeLog Mon Apr 22 15:32:18 2002
+++ b/Documentation/filesystems/devfs/ChangeLog Mon Apr 22 15:32:18 2002
@@ -1905,3 +1905,10 @@
- Fixed bitfield data type for
- Made major bitfield type and initialiser 64 bit safe
+===============================================================================
+Changes for patch v210
+
+- Updated fs/devfs/util.c to fix shift warning on 64 bit machines
+ Thanks to Anton Blanchard
+
+- Updated README from master HTML file
diff -Nru a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README
--- a/Documentation/filesystems/devfs/README Mon Apr 22 15:32:19 2002
+++ b/Documentation/filesystems/devfs/README Mon Apr 22 15:32:19 2002
@@ -3,7 +3,7 @@
Linux Devfs (Device File System) FAQ
Richard Gooch
-4-APR-2002
+7-APR-2002
Document languages:
@@ -1589,6 +1589,20 @@
mount devfs manually in your boot scripts with:
mount -t none devfs /dev
+
+
+Mount by volume LABEL= doesn't work with
+devfs
+
+Most probably you are not mounting devfs onto /dev. What
+happens is that if your kernel config has CONFIG_DEVFS_FS=y
+then the contents of /proc/partitions will have the devfs
+names (such as scsi/host0/bus0/target0/lun0/part1). The
+contents of /proc/partitions are used by mount(8) when
+mounting by volume label. If devfs is not mounted on /dev,
+then mount(8) will fail to find devices. The solution is to
+make sure that devfs is mounted on /dev. See above for how to
+do that.
diff -Nru a/Documentation/filesystems/porting b/Documentation/filesystems/porting
--- a/Documentation/filesystems/porting Mon Apr 22 15:32:19 2002
+++ b/Documentation/filesystems/porting Mon Apr 22 15:32:19 2002
@@ -1,7 +1,7 @@
Changes since 2.5.0:
---
-[recommeneded]
+[recommended]
New helpers: sb_bread(), sb_getblk(), sb_get_hash_table(), set_bh(),
sb_set_blocksize() and sb_min_blocksize().
@@ -9,7 +9,7 @@
Use them.
---
-[recommeneded]
+[recommended]
New methods: ->alloc_inode() and ->destroy_inode().
@@ -123,3 +123,19 @@
->setattr() is called without BKL now. Caller _always_ holds ->i_sem, so
watch for ->i_sem-grabbing code that might be used by your ->setattr().
Callers of notify_change() need ->i_sem now.
+
+---
+[recommended]
+
+New super_block field "struct export_operations *s_export_op" for
+explicit support for exporting, e.g. via NFS. The structure is fully
+documented at its declaration in include/linux/fs.h, and in
+Documentation/filesystems/Exporting.
+
+Briefly it allows for the definition of decode_fh and encode_fh operations
+to encode and decode filehandles, and allows the filesystem to use
+a standard helper function for decode_fh, and provide file-system specific
+support for this helper, particularly get_parent.
+
+It is planned that this will be required for exporting once the code
+settles down a bit.
diff -Nru a/Documentation/ide.txt b/Documentation/ide.txt
--- a/Documentation/ide.txt Mon Apr 22 15:32:18 2002
+++ b/Documentation/ide.txt Mon Apr 22 15:32:18 2002
@@ -1,71 +1,16 @@
-ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.2/2.3/2.4
-===============================================================================
- +-----------------------------------------------------------------+
- | The hdparm utility for controlling various IDE features is |
- | packaged separately. Look for it on popular linux FTP sites. |
- +-----------------------------------------------------------------+
-
-See description later on below for handling BIG IDE drives with >1024 cyls.
-
-Major features of the 2.1/2.2 IDE driver ("NEW!" marks changes since 2.0.xx):
-
-NEW! - support for IDE ATAPI *floppy* drives
- - support for IDE ATAPI *tape* drives, courtesy of Gadi Oxman
- (re-run MAKEDEV.ide to create the tape device entries in /dev/)
- - support for up to *four* IDE interfaces on one or more IRQs
- - support for any mix of up to *eight* IDE drives
- - support for reading IDE ATAPI cdrom drives (NEC,MITSUMI,VERTOS,SONY)
- - support for audio functions
- - auto-detection of interfaces, drives, IRQs, and disk geometries
- - "single" drives should be jumpered as "master", not "slave"
- (both are now probed for)
- - support for BIOSs which report "more than 16 heads" on disk drives
- - uses LBA (slightly faster) on disk drives which support it
- - support for lots of fancy (E)IDE drive functions with hdparm utility
- - optional (compile time) support for 32-bit VLB data transfers
- - support for IDE multiple (block) mode (same as hd.c)
- - support for interrupt unmasking during I/O (better than hd.c)
- - improved handshaking and error detection/recovery
- - can co-exist with hd.c controlling the first interface
- - run-time selectable 32bit interface support (using hdparm-2.3)
- - support for reliable operation of buggy RZ1000 interfaces
- - PCI support is automatic when rz1000 support is configured
- - support for reliable operation of buggy CMD-640 interfaces
- - PCI support is automatic when cmd640 support is configured
- - for VLB, use kernel command line option: ide0=cmd640_vlb
- - this support also enables the secondary i/f when needed
- - interface PIO timing & prefetch parameter support
- - experimental support for UMC 8672 interfaces
- - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f
- - use kernel command line option: ide0=ht6560b
- - experimental support for various IDE chipsets
- - use appropriate kernel command line option from list below
- - support for drives with a stuck WRERR_STAT bit
- - support for removable devices, including door lock/unlock
- - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay"
- - works with Linux fdisk, LILO, loadlin, bootln, etc..
- - mostly transparent support for EZ-Drive disk translation software
- - to use LILO with EZ, install LILO on the linux partition
- rather than on the master boot record, and then mark the
- linux partition as "bootable" or "active" using fdisk.
- (courtesy of Juha Laiho ).
- - auto-detect of disk translations by examining partition table
- - ide-cd.c now compiles separate from ide.c
- - ide-cd.c now supports door locking and auto-loading.
- - Also preliminary support for multisession
- and direct reads of audio data.
- - experimental support for Promise DC4030VL caching interface card
- - email thanks/problems to: peterd@pnd-pc.demon.co.uk
- - the hdparm-3.1 package can be used to set PIO modes for some chipsets.
-NEW! - support for setting PIO modes with the OPTi 82C621, courtesy of Jaromir Koutek.
-NEW! - support for loadable modules
-NEW! - optional SCSI host adapter emulation for ATAPI devices
-NEW! - generic PCI Bus-Master DMA support
-NEW! - works with most Pentium PCI systems, chipsets, add-on cards
-NEW! - works with regular DMA as well as Ultra DMA
-NEW! - automatically probes for all PCI IDE interfaces
-NEW! - generic support for using BIOS-configured Ultra-DMA (UDMA) transfers
+
+
+ Information regarding the Enhanced IDE drive in Linux 2.5
+
+
+==============================================================================
+
+
+ The hdparm utility can be used to controll various IDE features on a
+ running system. It is packaged separately. Please Look for it on popular
+ linux FTP sites.
+
*** IMPORTANT NOTICES: BUGGY IDE CHIPSETS CAN CORRUPT DATA!!
@@ -92,9 +37,9 @@
***
*** Use of the "serialize" option is no longer necessary.
-This is the multiple IDE interface driver, as evolved from hd.c.
-It supports up to six IDE interfaces, on one or more IRQs (usually 14 & 15).
-There can be up to two drives per interface, as per the ATA-2 spec.
+This is the multiple IDE interface driver, as evolved from hd.c. It supports
+up to 9 IDE interfaces per default, on one or more IRQs (usually 14 & 15).
+There can be up to two drives per interface, as per the ATA-6 spec.
Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
@@ -103,16 +48,14 @@
fifth.. ide4, usually PCI, probed
sixth.. ide5, usually PCI, probed
-To access devices on interfaces > ide0, device entries must first be
-created in /dev for them. To create such entries, simply run the included
-shell script: /usr/src/linux/scripts/MAKEDEV.ide
-
-Apparently many older releases of Slackware had incorrect entries
-in /dev for hdc* and hdd* -- this can also be corrected by running MAKEDEV.ide
-
-ide.c automatically probes for most IDE interfaces (including all PCI ones),
-for the drives/geometries attached to those interfaces, and for the
-IRQ numbers being used by the interfaces (normally 14, 15 for ide0/ide1).
+To access devices on interfaces > ide0, device entries please make sure that
+device files for them are present in /dev. If not, please create such
+entries, by simply running the included shell script:
+/usr/src/linux/scripts/MAKEDEV.ide
+
+This driver automatically probes for most IDE interfaces (including all PCI
+ones), for the drives/geometries attached to those interfaces, and for the IRQ
+lines being used by the interfaces (normally 14, 15 for ide0/ide1).
For special cases, interfaces may be specified using kernel "command line"
options. For example,
@@ -170,11 +113,11 @@
hdc=768,16,32
hdc=noprobe
-Note that when only one IDE device is attached to an interface,
-it should be jumpered as "single" or "master", *not* "slave".
-Many folks have had "trouble" with cdroms because of this requirement,
-so ide.c now probes for both units, though success is more likely
-when the drive is jumpered correctly.
+Note that when only one IDE device is attached to an interface, it should be
+jumpered as "single" or "master", *not* "slave". Many folks have had
+"trouble" with cdroms because of this requirement, so the driver now probes
+for both units, though success is more likely when the drive is jumpered
+correctly.
Courtesy of Scott Snyder and others, the driver supports ATAPI cdrom drives
such as the NEC-260 and the new MITSUMI triple/quad speed drives.
@@ -193,8 +136,8 @@
(/dev/hdc). To mount a CD in the cdrom drive, one would use something like:
ln -sf /dev/hdc /dev/cdrom
- mkdir /cd
- mount /dev/cdrom /cd -t iso9660 -o ro
+ mkdir /mnt/cdrom
+ mount /dev/cdrom /mnt/cdrom -t iso9660 -o ro
If, after doing all of the above, mount doesn't work and you see
errors from the driver (with dmesg) complaining about `status=0xff',
@@ -274,8 +217,6 @@
older/odd IDE drives.
"hdx=slow" : insert a huge pause after each access to the data
port. Should be used only as a last resort.
- "hdx=swapdata" : when the drive is a disk, byte swap all data
-
"hdxlun=xx" : set the drive last logical unit
"idebus=xx" : inform IDE driver of VESA/PCI bus speed in MHz,
@@ -307,8 +248,9 @@
"idex=reset" : reset interface after probe
"idex=dma" : automatically configure/use DMA if possible.
- The following are valid ONLY on ide0,
- and the defaults for the base,ctl ports must not be altered.
+The following are valid ONLY on ide0, which usually corresponds to the first
+ATA interface found on the particular host, and the defaults for the base,ctl
+ports must not be altered.
"ide0=dtc2278" : probe/support DTC2278 interface
"ide0=ht6560b" : probe/support HT6560B interface
@@ -329,179 +271,21 @@
IDE = Integrated Drive Electronics, meaning that each drive has a built-in
controller, which is why an "IDE interface card" is not a "controller card".
-IDE drives are designed to attach almost directly to the ISA bus of an AT-style
-computer. The typical IDE interface card merely provides I/O port address
-decoding and tri-state buffers, although several newer localbus cards go much
-beyond the basics. When purchasing a localbus IDE interface, avoid cards with
-an onboard BIOS and those which require special drivers. Instead, look for a
-card which uses hardware switches/jumpers to select the interface timing speed,
-to allow much faster data transfers than the original 8MHz ISA bus allows.
-
ATA = AT (the old IBM 286 computer) Attachment Interface, a draft American
National Standard for connecting hard drives to PCs. This is the official
name for "IDE".
-The latest standards define some enhancements, known as the ATA-2 spec,
+The latest standards define some enhancements, known as the ATA-6 spec,
which grew out of vendor-specific "Enhanced IDE" (EIDE) implementations.
ATAPI = ATA Packet Interface, a new protocol for controlling the drives,
similar to SCSI protocols, created at the same time as the ATA2 standard.
-ATAPI is currently used for controlling CDROM and TAPE devices, and will
-likely also soon be used for Floppy drives, removable R/W cartridges,
-and for high capacity hard disk drives.
-
-How To Use *Big* ATA/IDE drives with Linux
-------------------------------------------
-The ATA Interface spec for IDE disk drives allows a total of 28 bits
-(8 bits for sector, 16 bits for cylinder, and 4 bits for head) for addressing
-individual disk sectors of 512 bytes each (in "Linear Block Address" (LBA)
-mode, there is still only a total of 28 bits available in the hardware).
-This "limits" the capacity of an IDE drive to no more than 128GB (Giga-bytes).
-All current day IDE drives are somewhat smaller than this upper limit, and
-within a few years, ATAPI disk drives will raise the limit considerably.
-
-All IDE disk drives "suffer" from a "16-heads" limitation: the hardware has
-only a four bit field for head selection, restricting the number of "physical"
-heads to 16 or less. Since the BIOS usually has a 63 sectors/track limit,
-this means that all IDE drivers larger than 504MB (528Meg) must use a "physical"
-geometry with more than 1024 cylinders.
-
- (1024cyls * 16heads * 63sects * 512bytes/sector) / (1024 * 1024) == 504MB
-
-(Some BIOSs (and controllers with onboard BIOS) pretend to allow "32" or "64"
- heads per drive (discussed below), but can only do so by playing games with
- the real (hidden) geometry, which is always limited to 16 or fewer heads).
-
-This presents two problems to most systems:
-
- 1. The INT13 interface to the BIOS only allows 10-bits for cylinder
- addresses, giving a limit of 1024cyls for programs which use it.
-
- 2. The physical geometry fields of the disk partition table only
- allow 10-bits for cylinder addresses, giving a similar limit of 1024
- cyls for operating systems that do not use the "sector count" fields
- instead of the physical Cyl/Head/Sect (CHS) geometry fields.
-
-Neither of these limitations affects Linux itself, as it (1) does not use the
-BIOS for disk access, and it (2) is clever enough to use the "sector count"
-fields of the partition table instead of the physical CHS geometry fields.
-
- a) Most folks use LILO to load linux. LILO uses the INT13 interface
- to the BIOS to load the kernel at boot time. Therefore, LILO can only
- load linux if the files it needs (usually just the kernel images) are
- located below the magic 1024 cylinder "boundary" (more on this later).
-
- b) Many folks also like to have bootable DOS partitions on their
- drive(s). DOS also uses the INT13 interface to the BIOS, not only
- for booting, but also for operation after booting. Therefore, DOS
- can normally only access partitions which are contained entirely below
- the magic 1024 cylinder "boundary".
-
-There are at least seven commonly used schemes for kludging DOS to work
-around this "limitation". In the long term, the problem is being solved
-by introduction of an alternative BIOS interface that does not have the
-same limitations as the INT13 interface. New versions of DOS are expected
-to detect and use this interface in systems whose BIOS provides it.
-
-But in the present day, alternative solutions are necessary.
-
-The most popular solution in newer systems is to have the BIOS shift bits
-between the cylinder and head number fields. This is activated by entering
-a translated logical geometry into the BIOS/CMOS setup for the drive.
-Thus, if the drive has a geometry of 2100/16/63 (CHS), then the BIOS could
-present a "logical" geometry of 525/64/63 by "shifting" two bits from the
-cylinder number into the head number field for purposes of the partition table,
-CMOS setup, and INT13 interfaces. Linux kernels 1.1.39 and higher detect and
-"handle" this translation automatically, making this a rather painless solution
-for the 1024 cyls problem. If for some reason Linux gets confused (unlikely),
-then use the kernel command line parameters to pass the *logical* geometry,
-as in: hda=525,64,63
-
-If the BIOS does not support this form of drive translation, then several
-options remain, listed below in order of popularity:
-
- - use a partition below the 1024 cyl boundary to hold the linux
- boot files (kernel images and /boot directory), and place the rest
- of linux anywhere else on the drive. These files can reside in a DOS
- partition, or in a tailor-made linux boot partition.
- - use DiskManager software from OnTrack, supplied free with
- many new hard drive purchases.
- - use EZ-Drive software (similar to DiskManager). Note though,
- that LILO must *not* use the MBR when EZ-Drive is present.
- Instead, install LILO on the first sector of your linux partition,
- and mark it as "active" or "bootable" with fdisk.
- - boot from a floppy disk instead of the hard drive (takes 10 seconds).
-
-If you cannot use drive translation, *and* your BIOS also restricts you to
-entering no more than 1024 cylinders in the geometry field in the CMOS setup,
-then just set it to 1024. As of v3.5 of this driver, Linux automatically
-determines the *real* number of cylinders for fdisk to use, allowing easy
-access to the full disk capacity without having to fiddle around.
-
-Regardless of what you do, all DOS partitions *must* be contained entirely
-within the first 1024 logical cylinders. For a 1Gig WD disk drive, here's
-a good "half and half" partitioning scheme to start with:
-
- geometry = 2100/16/63
- /dev/hda1 from cyl 1 to 992 dos
- /dev/hda2 from cyl 993 to 1023 swap
- /dev/hda3 from cyl 1024 to 2100 linux
-
-To ensure that LILO can boot linux, the boot files (kernel and /boot/*)
-must reside within the first 1024 cylinders of the drive. If your linux
-root partition is *not* completely within the first 1024 cyls (quite common),
-then you can use LILO to boot linux from files on your DOS partition
-by doing the following after installing Slackware (or whatever):
-
- 0. Boot from the "boot floppy" created during the installation
- 1. Mount your DOS partition as /dos (and stick it in /etc/fstab)
- 2. Move /boot to /dos/boot with: cp -a /boot /dos ; rm -r /boot
- 3. Create a symlink for LILO to use with: ln -s /dos/boot /boot
- 4. Move your kernel (/vmlinuz) to /boot/vmlinuz: mv /vmlinuz /boot
- 5. Edit /etc/lilo.conf to change /vmlinuz to /boot/vmlinuz
- 6. Re-run LILO with: lilo
-
- A danger with this approach is that whenever an MS-DOS "defragmentation"
- program is run (like Norton "speeddisk"), it may move the Linux boot
- files around, confusing LILO and making the (Linux) system unbootable.
- Be sure to keep a kernel "boot floppy" at hand for such circumstances.
- A possible workaround is to mark the Linux files as S+H+R (System,
- Hidden, Readonly), to prevent most defragmentation programs from
- moving the files around.
-
-If you "don't do DOS", then partition as you please, but remember to create
-a small partition to hold the /boot directory (and vmlinuz) as described above
-such that they stay within the first 1024 cylinders.
-
-Note that when creating partitions that span beyond cylinder 1024,
-Linux fdisk will complain about "Partition X has different physical/logical
-endings" and emit messages such as "This is larger than 1024, and may cause
-problems with some software". Ignore this for linux partitions. The "some
-software" refers to DOS, the BIOS, and LILO, as described previously.
-
-Western Digital ships a "DiskManager 6.03" diskette with all of their big
-hard drives. Use BIOS translation instead of this if possible, as it is a
-more generally compatible method of achieving the same results (DOS access
-to the entire disk). However, if you must use DiskManager, it now works
-with Linux 1.3.x in most cases. Let me know if you still have trouble.
-
-My recommendations to anyone who asks about NEW systems are:
-
- - buy a motherboard that uses the Intel Triton chipset -- very common.
- - use IDE for the first two drives, placing them on separate interfaces.
- - very fast 7200rpm drives are now available
- (though many problems have been reported with Seagate ones).
- - place the IDE cdrom drive as slave on either interface.
- - if additional disks are to be connected, consider your needs:
- - fileserver? Buy a SC200 SCSI adaptor for the next few drives.
- - personal system? Use IDE for the next two drives.
- - still not enough? Keep adding SC200 SCSI cards as needed.
-
-Most manufacturers make both IDE and SCSI versions of each of their drives.
-The IDE ones are usually as fast and cheaper, due to lower command overhead
-and the higher data transfer speed of UDMA2. But fast/ultrawide/superlative
-SCSI is still king of the heap, especially for servers, if you've got the bucks.
+ATAPI is currently used for controlling CDROM, TAPE and FLOPPY (ZIP or
+LS120/240) devices, removable R/W cartridges, and for high capacity hard disk
+drives.
mlord@pobox.com
--
-For current maintainers of this stuff, see the linux/MAINTAINERS file.
+Wed Apr 17 22:52:44 CEST 2002 edited by Marcin Dalecki
+
+For current maintainers of this stuff, please see the linux/MAINTAINERS file.
diff -Nru a/Documentation/usb/dc2xx.txt b/Documentation/usb/dc2xx.txt
--- a/Documentation/usb/dc2xx.txt Mon Apr 22 15:32:19 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,111 +0,0 @@
-14 April 2000
-david-b@pacbell.net
-
-This is an overview of how to use the "dc2xx" USB driver with certain
-digital still cameras from Kodak and other vendors.
-
-
-CAMERAS
-
-This driver will mostly be used with Kodak DC-2xx series digital still
-cameras, but it should be trivial to tell it about several non-Kodak
-USB-enabled cameras.
-
-You'll most likely want to hook it up to recent versions of "gPhoto"
-(www.gphoto.org), since version 0.4 and later know how to use it to talk
-to Kodak DC-240 and DC-280 cameras over USB.
-
-In addition the DC-220, DC-260, DC-265, and DC-290 are also recognized.
-However, like other cameras using the "Digita OS" (from www.flashpoint.com)
-there is no gPhoto support for this camera. There is a python script
-for accessing these cameras (see archives of the linux-usb mailing list)
-and a "Digita Services" library that can also use this driver.
-
-The HP PhotoSmart C500 should also work, since it's another Digita camera
-with USB support.
-
-
-USB HARDWARE
-
-Recent kernels have had no particular problems using this driver with
-either OHCI or UHCI chipsets, and have worked on the PowerMac platform.
-
-Note that in some cases changes in BIOS settings may be needed before
-your USB works. At least one user has reported a need for SMP-related
-settings as well, and some old hardware may not handle USB correctly.
-
-
-SETUP
-
-Configure in the DC2XX USB driver, and have it in your kernel. It works
-as a module, or compiled in directly.
-
-Create at least one device, perhaps like this (both read and write):
-
- # mknod -m 0660 /dev/usb/dc2xx0 c 180 80
- # mknod -m 0660 /dev/usb/dc2xx1 c 180 81
- ...
-
-NOTE: you would normally configure PAM so that the user logged in at
-the console is granted ownership of these devices. console.perms(5)
-explains how to do this.
-
-The driver supports multiple device nodes. The USB framework supports
-a maximum of sixteen device nodes (up to minor device number 96).
-
-When you plug in one camera, it will use the first device node (dc2xx0
-in the example above). A second camera will use the second device node,
-and so on.
-
-
-SANITY TESTING
-
-First: if you've got /proc support, make sure that the driver has hooked
-itself up correctly.
-
- - You should see an entry in /proc/bus/usb/drivers for "dc2xx",
- if you enabled USB /proc support and correctly mounted the
- usbdevfs on /proc/bus/usb.
-
-Second: when you connect your camera to the computer, does it get recognized
-by the driver? (Make sure the camera is powered on!)
-
- - if you've got /proc/bus/usb/devices, you should see an entry
- something like this. The "ProdID" may be different if you didn't
- plug in a DC-240, as may the strings presented, but "Driver=dc2xx"
- had better be there.
-
- T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0
- D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
- P: Vendor=040a ProdID=0120 Rev= 1.08
- S: Manufacturer=Eastman Kodak Company
- S: Product=KODAK DC240 Zoom Digital Camera
- C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
- I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
- E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
- E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
-
- - see if "dmesg" output tells you that you plugged in your camera.
-
- Manufacturer: Eastman Kodak Company
- Product: KODAK DC240 Zoom Digital Camera
- dc2xx.c: USB Camera #0 connected
-
-Third: (optional) can you use gPhoto to talk to the camera?
-
- - When you configure your camera, tell it to use "/dev/usb/dc2xx0"
- (or whatever name you used). Right now, gPhoto emits a diagnostic
- message (non-GUI) saying that it since it didn't act like a TTY,
- it's assuming it's got a USB connection.
-
- - With the camera turned on, get the "camera summary". It'll
- talk to the camera -- and tell you you're using USB.
-
-If you got that far, you should be able to use everything fine.
-
-
-ADDITIONAL INFORMATION
-
-You may find that you need more driver-specific information, which is
-currently accessible through a link from http://www.linux-usb.org/
-along with other Linux USB resources.
diff -Nru a/Makefile b/Makefile
--- a/Makefile Mon Apr 22 15:32:18 2002
+++ b/Makefile Mon Apr 22 15:32:18 2002
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 5
-SUBLEVEL = 8
+SUBLEVEL = 9
EXTRAVERSION =
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -347,9 +347,9 @@
$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
TAGS: dummy
- etags `find include/asm-$(ARCH) -name '*.h'`
- find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a
- find $(SUBDIRS) init -name '*.[ch]' | xargs etags -a
+ { find include/asm-${ARCH} -name '*.h' -print ; \
+ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
+ find $(SUBDIRS) init -name '*.[ch]' ; } | grep -v SCCS | etags -
# Exuberant ctags works better with -I
tags: dummy
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make Mon Apr 22 15:32:19 2002
+++ b/Rules.make Mon Apr 22 15:32:19 2002
@@ -126,8 +126,10 @@
# for make >= 3.78 the following is cleaner:
# multi-used := $(foreach m,$(obj-y) $(obj-m), $(if $($(basename $(m))-objs), $(m)))
-multi-used-y := $(sort $(foreach m,$(obj-y),$(patsubst %,$(m),$($(basename $(m))-objs))))
-multi-used-m := $(sort $(foreach m,$(obj-m),$(patsubst %,$(m),$($(basename $(m))-objs))))
+__obj-y = $(filter-out export.o,$(obj-y))
+__obj-m = $(filter-out export.o,$(obj-m))
+multi-used-y := $(sort $(foreach m,$(__obj-y),$(patsubst %,$(m),$($(basename $(m))-objs))))
+multi-used-m := $(sort $(foreach m,$(__obj-m),$(patsubst %,$(m),$($(basename $(m))-objs))))
ld-multi-used-y := $(filter-out $(list-multi),$(multi-used-y))
ld-multi-used-m := $(filter-out $(list-multi),$(multi-used-m))
ld-multi-objs-y := $(foreach m, $(ld-multi-used-y), $($(basename $(m))-objs))
diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in
--- a/arch/alpha/config.in Mon Apr 22 15:32:19 2002
+++ b/arch/alpha/config.in Mon Apr 22 15:32:19 2002
@@ -324,14 +324,7 @@
source net/ax25/Config.in
-mainmenu_option next_comment
-comment 'ISDN subsystem'
-
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
-fi
-endmenu
+source drivers/isdn/Config.in
mainmenu_option next_comment
comment 'Old CD-ROM drivers (not SCSI, not IDE)'
diff -Nru a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
--- a/arch/alpha/kernel/osf_sys.c Mon Apr 22 15:32:18 2002
+++ b/arch/alpha/kernel/osf_sys.c Mon Apr 22 15:32:18 2002
@@ -219,7 +219,7 @@
* isn't actually going to matter, as if the parent happens
* to change we can happily return either of the pids.
*/
- (®s)->r20 = tsk->p_opptr->pid;
+ (®s)->r20 = tsk->real_parent->pid;
return tsk->pid;
}
diff -Nru a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
--- a/arch/alpha/kernel/process.c Mon Apr 22 15:32:19 2002
+++ b/arch/alpha/kernel/process.c Mon Apr 22 15:32:19 2002
@@ -54,15 +54,21 @@
return 0;
}
+void default_idle(void)
+{
+ barrier();
+}
+
void
cpu_idle(void)
{
while (1) {
+ void (*idle)(void) = default_idle;
/* FIXME -- EV6 and LCA45 know how to power down
the CPU. */
while (!need_resched())
- barrier();
+ idle();
schedule();
}
}
diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c Mon Apr 22 15:32:19 2002
+++ b/arch/alpha/kernel/ptrace.c Mon Apr 22 15:32:19 2002
@@ -292,7 +292,7 @@
if (request != PTRACE_KILL)
goto out;
}
- if (child->p_pptr != current) {
+ if (child->parent != current) {
DBG(DBG_MEM, ("child not parent of this process\n"));
goto out;
}
diff -Nru a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c
--- a/arch/alpha/kernel/semaphore.c Mon Apr 22 15:32:19 2002
+++ b/arch/alpha/kernel/semaphore.c Mon Apr 22 15:32:19 2002
@@ -5,8 +5,8 @@
* (C) Copyright 1999, 2000 Richard Henderson
*/
+#include
#include
-
/*
* Semaphores are implemented using a two-way counter:
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c Mon Apr 22 15:32:19 2002
+++ b/arch/alpha/kernel/signal.c Mon Apr 22 15:32:19 2002
@@ -661,8 +661,8 @@
info.si_signo = signr;
info.si_errno = 0;
info.si_code = SI_USER;
- info.si_pid = current->p_pptr->pid;
- info.si_uid = current->p_pptr->uid;
+ info.si_pid = current->parent->pid;
+ info.si_uid = current->parent->uid;
}
/* If the (new) signal is now blocked, requeue it. */
@@ -701,7 +701,7 @@
case SIGSTOP:
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1]
+ if (!(current->parent->sig->action[SIGCHLD-1]
.sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/alpha/math-emu/Makefile b/arch/alpha/math-emu/Makefile
--- a/arch/alpha/math-emu/Makefile Mon Apr 22 15:32:18 2002
+++ b/arch/alpha/math-emu/Makefile Mon Apr 22 15:32:18 2002
@@ -11,11 +11,8 @@
else
-list-multi := math-emu.o
math-emu-objs := math.o qrnnd.o
obj-m := math-emu.o
-math-emu.o: $(math-emu-objs)
- $(LD) -r -o $@ $(math-emu-objs)
endif
diff -Nru a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
--- a/arch/alpha/mm/init.c Mon Apr 22 15:32:19 2002
+++ b/arch/alpha/mm/init.c Mon Apr 22 15:32:19 2002
@@ -283,7 +283,7 @@
unsigned long dma_pfn, high_pfn;
dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- high_pfn = max_low_pfn;
+ high_pfn = max_pfn = max_low_pfn;
if (dma_pfn >= high_pfn)
zones_size[ZONE_DMA] = high_pfn;
diff -Nru a/arch/arm/Config.help b/arch/arm/Config.help
--- a/arch/arm/Config.help Mon Apr 22 15:32:18 2002
+++ b/arch/arm/Config.help Mon Apr 22 15:32:18 2002
@@ -836,3 +836,153 @@
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.
+CONFIG_ZBOOT_ROM
+ Say Y here if you intend to execute your compressed kernel image (zImage)
+ directly from ROM or flash. If unsure, say N.
+
+CONFIG_ZBOOT_ROM_TEXT
+ The base address for zImage. Unless you have special requirements, you
+ should not change this value.
+
+CONFIG_ZBOOT_ROM_BSS
+ The base address of 64KiB of read/write memory, which must be available
+ while the decompressor is running. Unless you have special requirements,
+ you should not change this value.
+
+CONFIG_CPU_FREQ
+ CPU clock scaling allows you to change the clock speed of the
+ running CPU on the fly. This is a nice method to save battery power,
+ because the lower the clock speed, the less power the CPU
+ consumes. Note that this driver doesn't automatically change the CPU
+ clock speed, you need some userland tools (which still have to be
+ written) to implement the policy. If you don't understand what this
+ is all about, it's safe to say 'N'.
+
+CONFIG_ARCH_EDB7211
+ Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211
+ evaluation board.
+
+CONFIG_SA1100_H3100
+ Say Y here if you intend to run this kernel on the Compaq iPAQ
+ H3100 handheld computer. Information about this machine and the
+ Linux port to this machine can be found at:
+
+
+
+
+CONFIG_SA1100_H3800
+ Say Y here if you intend to run this kernel on the Compaq iPAQ H3800
+ series handheld computer. Information about this machine and the
+ Linux port to this machine can be found at:
+
+
+
+
+CONFIG_H3600_SLEEVE
+ Choose this option to enable support for extension packs (sleeves)
+ for the Compaq iPAQ H3XXX series of handheld computers. This option
+ is required for the CF, PCMCIA, Bluetooth and GSM/GPRS extension
+ packs.
+
+CONFIG_SA1100_GRAPHICSMASTER
+ Say Y here if you are using an Applied Data Systems Intel(R)
+ StrongARM(R) SA-1100 based Graphics Master SBC with SA-1111
+ StrongARM companion chip. See
+ for information
+ on this system.
+
+CONFIG_SA1100_ADSBITSY
+ Say Y here if you are using Applied Data Systems Intel(R)
+ StrongARM(R) 1110 based Bitsy, 3 x 5 inches in size, Compaq - IPAQ -
+ like platform. See
+ for more
+ information.
+
+CONFIG_SA1100_ITSY
+ Say Y here if you are using the Compaq Itsy experimental pocket
+ computer. See for
+ more information.
+
+CONFIG_SA1100_HUW_WEBPANEL
+ Say Y here to support the HuW Webpanel produced by Hoeft & Wessel
+ AG. English-language website is at
+ ; credits and build instructions
+ at Documentation/arm/SA1100/HUW_WEBPANEL.
+
+CONFIG_SA1100_PLEB
+ Say Y here if you are using a Portable Linux Embedded Board
+ (also known as PLEB). See
+ for more information.
+
+CONFIG_SA1100_SHERMAN
+ Say Y here to support the Blazie Engineering `Sherman' StrongARM
+ 1110-based SBC, used primarily in assistance products for the
+ visually impaired. The company is now Freedom Scientific, with
+ a website at . The
+ Sherman product, however, appears to have been discontinued.
+
+CONFIG_SA1100_YOPY
+ Say Y here to support the Yopy PDA. Product information at
+ . See Documentation/arm/SA110/Yopy
+ for more.
+
+CONFIG_SA1100_CERF_CPLD
+ Say Y here to support the Linux CerfPDA development kit from
+ Intrinsyc. This is a StrongARM-1110-based reference platform for
+ designing custom PDAs. Product info is at
+ .
+
+CONFIG_SA1100_FREEBIRD
+ Support the FreeBird board used in Coventive embedded products. See
+ Documentation/arm/SA1100/Freebird for more.
+
+CONFIG_SA1100_PT_SYSTEM3
+ Say Y here if you intend to build a kernel suitable to run on
+ a Pruftechnik Digital Board. For more information see
+
+
+CONFIG_CPU_ARM926T
+ This is a variant of the ARM920. It has slightly different
+ instruction sequences for cache and TLB operations. Curiously,
+ there is no documentation on it at the ARM corporate website.
+
+ Say Y if you want support for the ARM926T processor.
+ Otherwise, say N.
+
+CONFIG_SA1100_JORNADA720
+ Say Y here if you want to build a kernel for the HP Jornada 720
+ handheld computer. See
+ for details.
+
+CONFIG_SA1100_OMNIMETER
+ Say Y here if you are using the inhand electronics OmniMeter. See
+ for details.
+
+CONFIG_SA1100_SIMPAD
+ The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
+ are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
+ FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
+ PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
+ like CL4 in additional it has a PCMCIA-Slot. For more information
+ visit .
+
+CONFIG_ARCH_CDB89712
+ This is an evaluation board from Cirrus for the CS89712 processor.
+ The board includes 2 serial ports, Ethernet, IRDA, and expansion
+ headers. It comes with 16 MB SDRAM and 8 MB flash ROM.
+
+CONFIG_ARCH_AUTCPU12
+ Say Y if you intend to run the kernel on the autronix autcpu12
+ board. This board is based on a Cirrus Logic CS89712.
+
+CONFIG_EP72XX_ROM_BOOT
+ If you say Y here, your CLPS711x-based kernel will use the bootstrap
+ mode memory map instead of the normal memory map.
+
+ Processors derived from the Cirrus CLPS-711X core support two boot
+ modes. Normal mode boots from the external memory device at CS0.
+ Bootstrap mode rearranges parts of the memory map, placing an
+ internal 128 byte bootstrap ROM at CS0. This option performs the
+ address map changes required to support booting in this mode.
+
+ You almost surely want to say N here.
diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
--- a/arch/arm/boot/Makefile Mon Apr 22 15:32:18 2002
+++ b/arch/arm/boot/Makefile Mon Apr 22 15:32:18 2002
@@ -5,31 +5,31 @@
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (C) 1995-2000 Russell King
+# Copyright (C) 1995-2002 Russell King
#
SYSTEM =$(TOPDIR)/vmlinux
ifeq ($(CONFIG_CPU_26),y)
-ZTEXTADDR = 0x02080000
+ZRELADDR = 0x02080000
PARAMS_PHYS = 0x0207c000
INITRD_PHYS = 0x02180000
INITRD_VIRT = 0x02180000
endif
ifeq ($(CONFIG_ARCH_RPC),y)
-ZTEXTADDR = 0x10008000
+ZRELADDR = 0x10008000
PARAMS_PHYS = 0x10000100
INITRD_PHYS = 0x18000000
INITRD_VIRT = 0xc8000000
endif
ifeq ($(CONFIG_ARCH_CLPS7500),y)
-ZTEXTADDR = 0x10008000
+ZRELADDR = 0x10008000
endif
ifeq ($(CONFIG_ARCH_EBSA110),y)
-ZTEXTADDR = 0x00008000
+ZRELADDR = 0x00008000
PARAMS_PHYS = 0x00000400
INITRD_PHYS = 0x00800000
INITRD_VIRT = 0xc0800000
@@ -41,41 +41,34 @@
endif
ifeq ($(CONFIG_FOOTBRIDGE),y)
-ZTEXTADDR = 0x00008000
+ZRELADDR = 0x00008000
PARAMS_PHYS = 0x00000100
INITRD_PHYS = 0x00800000
INITRD_VIRT = 0xc0800000
endif
ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
-ZTEXTADDR = 0x00008000
+ZRELADDR = 0x00008000
PARAMS_PHYS = 0x00000100
INITRD_PHYS = 0x00800000
INITRD_VIRT = 0xc0800000
endif
ifeq ($(CONFIG_ARCH_CAMELOT),y)
-ZTEXTADDR = 0x00008000
+ZRELADDR = 0x00008000
endif
ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
-ZTEXTADDR = 0x40008000
+ZRELADDR = 0x40008000
endif
ifeq ($(CONFIG_ARCH_L7200),y)
-# RAM based kernel
-#ZTEXTADDR = 0xf0400000
-#ZRELADDR = 0xf0008000
-
-# FLASH based kernel
-ZTEXTADDR = 0x00010000
ZRELADDR = 0xf0008000
-ZBSSADDR = 0xf03e0000
endif
# The standard locations for stuff on CLPS711x type processors
ifeq ($(CONFIG_ARCH_CLPS711X),y)
-ZTEXTADDR = 0xc0028000
+ZRELADDR = 0xc0028000
PARAMS_PHYS = 0xc0000100
endif
@@ -90,60 +83,40 @@
endif
ifeq ($(CONFIG_ARCH_SA1100),y)
-ZTEXTADDR = 0xc0008000
ZRELADDR = 0xc0008000
-ifeq ($(CONFIG_SA1100_VICTOR),y)
- ZTEXTADDR = 0x00002000
- ZBSSADDR = 0xc0200000
-endif
-ifeq ($(CONFIG_SA1100_SHERMAN),y)
- ZTEXTADDR = 0x00050000
- ZBSSADDR = 0xc0200000
-endif
-ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
- ZTEXTADDR = 0xC0200000
-endif
-ifeq ($(CONFIG_SA1100_GRAPHICSMASTER),y)
- ZTEXTADDR = 0xC0400000
-endif
-ifeq ($(CONFIG_SA1100_ADSBITSY),y)
- ZTEXTADDR = 0xC0400000
-endif
-ifeq ($(CONFIG_SA1100_YOPY),y)
- ZTEXTADDR = 0x00080000
- ZBSSADDR = 0xc0200000
-endif
+# No defconfig file to move this into...
+#ifeq ($(CONFIG_SA1100_YOPY),y)
+# ZTEXTADDR = 0x00080000
+# ZBSSADDR = 0xc0200000
+#endif
ifeq ($(CONFIG_SA1111),y)
ZRELADDR = 0xc0208000
endif
endif
ifeq ($(CONFIG_ARCH_ANAKIN),y)
-ZTEXTADDR = 0x20008000
+ZRELADDR = 0x20008000
endif
ifeq ($(CONFIG_ARCH_IQ80310),y)
ZRELADDR = 0xa0008000
-
-# for serial upload
-ZTEXTADDR = 0xa1008000
-
-# for direct flash execution
-# ZTEXTADDR = 0x00060000
-# ZBSSADDR = 0xa1008000
endif
ifeq ($(CONFIG_ARCH_ADIFCC),y)
ZRELADDR = 0xc0008000
-ZTEXTADDR = 0xc1000000
endif
#
-# If you don't define ZRELADDR above,
-# then it defaults to ZTEXTADDR
+# We now have a PIC decompressor implementation. Decompressors running
+# from RAM should not define ZTEXTADDR. Decompressors running directly
+# from ROM or Flash must define ZTEXTADDR (preferably via the config)
#
-ifeq ($(ZRELADDR),)
-ZRELADDR = $(ZTEXTADDR)
+ifeq ($(CONFIG_ZBOOT_ROM),y)
+ZTEXTADDR =0x$(CONFIG_ZBOOT_ROM_TEXT)
+ZBSSADDR =0x$(CONFIG_ZBOOT_ROM_BSS)
+else
+ZTEXTADDR =0
+ZBSSADDR =ALIGN(4)
endif
export SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS INITRD_VIRT PARAMS_PHYS
diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
--- a/arch/arm/boot/compressed/Makefile Mon Apr 22 15:32:18 2002
+++ b/arch/arm/boot/compressed/Makefile Mon Apr 22 15:32:18 2002
@@ -9,7 +9,7 @@
HEAD = head.o
OBJS = misc.o
-CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_BOOT)
+CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_BOOT) -fpic
FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c
ZLDFLAGS = -p -X -T vmlinux.lds
@@ -65,13 +65,7 @@
OBJS += head-xscale.o
endif
-SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;
-
-ifneq ($(ZBSSADDR),)
-SEDFLAGS += s/BSS_START/$(ZBSSADDR)/
-else
-SEDFLAGS += s/BSS_START/ALIGN(4)/
-endif
+SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/
LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
diff -Nru a/arch/arm/boot/compressed/head-clps7500.S b/arch/arm/boot/compressed/head-clps7500.S
--- a/arch/arm/boot/compressed/head-clps7500.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head-clps7500.S Mon Apr 22 15:32:19 2002
@@ -13,7 +13,7 @@
/* This branch is taken if the CPU memory width matches the
actual device in use. The default at power on is 16 bits
so we must be prepared for a mismatch. */
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
2:
b 1f
.word 0xffff
diff -Nru a/arch/arm/boot/compressed/head-epxa10db.S b/arch/arm/boot/compressed/head-epxa10db.S
--- a/arch/arm/boot/compressed/head-epxa10db.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head-epxa10db.S Mon Apr 22 15:32:19 2002
@@ -1,5 +1,5 @@
#include
#include
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
mov r7, #MACH_TYPE_CAMELOT
diff -Nru a/arch/arm/boot/compressed/head-ftvpci.S b/arch/arm/boot/compressed/head-ftvpci.S
--- a/arch/arm/boot/compressed/head-ftvpci.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head-ftvpci.S Mon Apr 22 15:32:19 2002
@@ -13,7 +13,7 @@
* 2 of the License, or (at your option) any later version.
*/
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
ftv_start:
mcr p15, 0, r0, c7, c5, 0 @ flush I cache
mrc p15, 0, r0, c1, c0
diff -Nru a/arch/arm/boot/compressed/head-integrator.S b/arch/arm/boot/compressed/head-integrator.S
--- a/arch/arm/boot/compressed/head-integrator.S Mon Apr 22 15:32:18 2002
+++ b/arch/arm/boot/compressed/head-integrator.S Mon Apr 22 15:32:18 2002
@@ -1,4 +1,4 @@
#include
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
mov r7, #MACH_TYPE_INTEGRATOR
diff -Nru a/arch/arm/boot/compressed/head-l7200.S b/arch/arm/boot/compressed/head-l7200.S
--- a/arch/arm/boot/compressed/head-l7200.S Mon Apr 22 15:32:18 2002
+++ b/arch/arm/boot/compressed/head-l7200.S Mon Apr 22 15:32:18 2002
@@ -13,7 +13,7 @@
#error What am I doing here...
#endif
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
__L7200_start:
mov r0, #0x00100000 @ FLASH address of initrd
diff -Nru a/arch/arm/boot/compressed/head-netwinder.S b/arch/arm/boot/compressed/head-netwinder.S
--- a/arch/arm/boot/compressed/head-netwinder.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head-netwinder.S Mon Apr 22 15:32:19 2002
@@ -1,50 +1,13 @@
/*
* linux/arch/arm/boot/compressed/head-netwinder.S
*
- * Copyright (C) 2000 Russell King
+ * Copyright (C) 2000-2002 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#define K(a,b,c) ((a) << 24 | (b) << 12 | (c))
+ .section ".start", "ax"
- .section ".start", #alloc, #execinstr
-
- /*
- * check to see if we are running from the correct address.
- * If not, we move ourselves in a two stage process. Firstly,
- * we copy the start of the kernel (which includes this code)
- * to 0x8000, and then jump to this code to continue with the
- * rest (since this code will get overwritten).
- */
- adr r2, 1f
- ldmdb r2, {r9, r10}
- and r3, r2, #0xc000
- teq r3, #0x8000 @ correctly located?
- beq 2f @ skip this code
- bic r3, r2, #0xc000
- orr r3, r3, #0x8000
- mov r0, r3 @ new address if '1'
- mov r4, #64 @ number of bytes to copy
- sub r5, r10, r9 @ total number of bytes to copy
- b 1f
-
- .word _start
- .word __bss_start
-
-1:
- .rept 4
- ldmia r2!, {r6, r9, r10, r11}
- stmia r3!, {r6, r9, r10, r11}
- .endr
- subs r4, r4, #64
- bcs 1b
- movs r4, r5 @ remaining length
- mov r5, #0 @ no more to copy
- movne pc, r0 @ jump back to 1 (in the newly copied
- @ code)
- mov r7, #5 @ only here to fix NeTTroms which dont
- mov r8, #2 << 24 @ scheduled for removal in 2.5.xx
- orr r8, r8, #5 << 12
-2:
+ mov r7, #5
+ mov r8, #0
diff -Nru a/arch/arm/boot/compressed/head-sa1100.S b/arch/arm/boot/compressed/head-sa1100.S
--- a/arch/arm/boot/compressed/head-sa1100.S Mon Apr 22 15:32:18 2002
+++ b/arch/arm/boot/compressed/head-sa1100.S Mon Apr 22 15:32:18 2002
@@ -11,7 +11,7 @@
#include
#include
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
__SA1100_start:
diff -Nru a/arch/arm/boot/compressed/head-shark.S b/arch/arm/boot/compressed/head-shark.S
--- a/arch/arm/boot/compressed/head-shark.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head-shark.S Mon Apr 22 15:32:19 2002
@@ -16,7 +16,7 @@
#include
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
b __beginning
diff -Nru a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S
--- a/arch/arm/boot/compressed/head-xscale.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head-xscale.S Mon Apr 22 15:32:19 2002
@@ -9,7 +9,7 @@
#include
#include
- .section ".start", #alloc, #execinstr
+ .section ".start", "ax"
__XScale_start:
diff -Nru a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
--- a/arch/arm/boot/compressed/head.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/head.S Mon Apr 22 15:32:19 2002
@@ -132,10 +132,28 @@
*/
.text
-1: adr r2, LC0
- ldmia r2, {r2, r3, r4, r5, sp}
+ adr r0, LC0
+ ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp}
+ subs r0, r0, r1 @ calculate the delta offset
+
+ teq r0, #0 @ if delta is zero, we're
+ beq not_relocated @ running at the address we
+ @ were linked at.
+
+ add r2, r2, r0 @ different address, so we
+ add r3, r3, r0 @ need to fix up various
+ add r5, r5, r0 @ pointers.
+ add r6, r6, r0
+ add ip, ip, r0
+ add sp, sp, r0
+
+1: ldr r1, [r6, #0] @ relocate entries in the GOT
+ add r1, r1, r0 @ table. This fixes up the
+ str r1, [r6], #4 @ C references.
+ cmp r6, ip
+ blt 1b
- mov r0, #0
+not_relocated: mov r0, #0
1: str r0, [r2], #4 @ clear bss
str r0, [r2], #4
str r0, [r2], #4
@@ -149,17 +167,26 @@
mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max
- teq r4, r5 @ will we overwrite ourselves?
- moveq r5, r2 @ decompress after image
- movne r5, r4 @ decompress to final location
+/*
+ * Check to see if we will overwrite ourselves.
+ * r4 = final kernel address
+ * r5 = start of this image
+ * r2 = end of malloc space (and therefore this image)
+ * We basically want:
+ * r4 >= r2 -> OK
+ * r4 + image length <= r5 -> OK
+ */
+ cmp r4, r2
+ bhs wont_overwrite
+ add r0, r4, #4096*1024 @ 4MB largest kernel size
+ cmp r0, r5
+ bls wont_overwrite
+ mov r5, r2 @ decompress after malloc space
mov r0, r5
mov r3, r7
bl SYMBOL_NAME(decompress_kernel)
- teq r4, r5 @ do we need to relocate
- beq call_kernel @ the kernel?
-
add r0, r0, #127
bic r0, r0, #127 @ align the kernel length
/*
@@ -184,12 +211,26 @@
bl cache_clean_flush
add pc, r5, r0 @ call relocation code
+/*
+ * We're not in danger of overwriting ourselves. Do this the simple way.
+ *
+ * r4 = kernel execution address
+ * r7 = architecture ID
+ */
+wont_overwrite: mov r0, r4
+ mov r3, r7
+ bl SYMBOL_NAME(decompress_kernel)
+ b call_kernel
+
.type LC0, #object
-LC0: .word __bss_start
- .word _end
- .word _load_addr
- .word _start
- .word user_stack+4096
+LC0: .word LC0 @ r1
+ .word __bss_start @ r2
+ .word _end @ r3
+ .word _load_addr @ r4
+ .word _start @ r5
+ .word _got_start @ r6
+ .word _got_end @ r7
+ .word user_stack+4096 @ r8
.size LC0, . - LC0
/*
@@ -206,26 +247,15 @@
* r7 = architecture number
* r8 = run-time address of "start"
* On exit,
- * r0, r1, r2, r3, r8, r9 corrupted
+ * r1, r2, r3, r8, r9, r12 corrupted
* This routine must preserve:
* r4, r5, r6, r7
*/
.align 5
-cache_on: ldr r1, proc_sa110_type
- eor r1, r1, r6
- movs r1, r1, lsr #5 @ catch SA110 and SA1100
- beq 1f
- ldr r1, proc_sa1110_type
- eor r1, r1, r6
- movs r1, r1, lsr #4
- beq 1f
- ldr r1, proc_xscale_type
- eor r1, r1, r6
- movs r1, r1, lsr #16
-@ movne pc, lr
- bne cache_off
-1:
- sub r3, r4, #16384 @ Page directory size
+cache_on: mov r3, #8 @ cache_on function
+ b call_cache_fn
+
+__cache_on: sub r3, r4, #16384 @ Page directory size
bic r3, r3, #0xff @ Align the pointer
bic r3, r3, #0x3f00
/*
@@ -277,8 +307,9 @@
mov pc, lr
/*
- * This code is relocatable. It is relocated by the above code to the end
- * of the kernel and executed there. During this time, we have no stacks.
+ * All code following this line is relocatable. It is relocated by
+ * the above code to the end of the decompressed kernel image and
+ * executed there. During this time, we have no stacks.
*
* r0 = decompressed kernel length
* r1-r3 = unused
@@ -309,47 +340,101 @@
mov pc, r4 @ call kernel
/*
- * Here follow the relocatable cache support functions for
- * the various processors.
+ * Here follow the relocatable cache support functions for the
+ * various processors. This is a generic hook for locating an
+ * entry and jumping to an instruction at the specified offset
+ * from the start of the block. Please note this is all position
+ * independent code.
+ *
+ * r1 = corrupted
+ * r2 = corrupted
+ * r3 = block offset
+ * r6 = CPU ID
+ * r12 = corrupted
+ */
+
+call_cache_fn: adr r12, proc_types
+1: ldr r1, [r12, #0] @ get value
+ ldr r2, [r12, #4] @ get mask
+ eor r1, r1, r6 @ (real ^ match)
+ tst r1, r2 @ & mask
+ addeq pc, r12, r3 @ call cache function
+ add r12, r12, #4*5
+ b 1b
+
+/*
+ * Table for cache operations. This is basically:
+ * - CPU ID match
+ * - CPU ID mask
+ * - 'cache on' method instruction
+ * - 'cache off' method instruction
+ * - 'cache flush' method instruction
+ *
+ * We match an entry using: ((real_id ^ match) & mask) == 0
+ *
+ * Writethrough caches generally only need 'on' and 'off'
+ * methods. Writeback caches _must_ have the flush method
+ * defined.
*/
+ .type proc_types,#object
+proc_types:
+ .word 0x41560600 @ ARM6/610
+ .word 0xffffffe0
+ b __arm6_cache_off
+ b __arm6_cache_off
+ mov pc, lr
+
+ .word 0x41007000 @ ARM7/710
+ .word 0xfff8fe00
+ b __arm7_cache_off
+ b __arm7_cache_off
+ mov pc, lr
+
+ .word 0x41807200 @ ARM720T (writethrough)
+ .word 0xffffff00
+ b __cache_on
+ b __armv4_cache_off
+ mov pc, lr
+
+ .word 0x4401a100 @ sa110 / sa1100
+ .word 0xffffffe0
+ b __cache_on
+ b __armv4_cache_off
+ b __armv4_cache_flush
+
+ .word 0x6901b110 @ sa1110
+ .word 0xfffffff0
+ b __cache_on
+ b __armv4_cache_off
+ b __armv4_cache_flush
+
+ .word 0x69050000 @ xscale
+ .word 0xffff0000
+ b __cache_on
+ b __armv4_cache_off
+ b __armv4_cache_flush
- .type proc_sa110_type,#object
-proc_sa110_type:
- .word 0x4401a100
- .size proc_sa110_type, . - proc_sa110_type
-
- .type proc_sa1110_type,#object
-proc_sa1110_type:
- .word 0x6901b110
- .size proc_sa1110_type, . - proc_sa1110_type
+ .word 0 @ unrecognised type
+ .word 0
+ mov pc, lr
+ mov pc, lr
+ mov pc, lr
+
+ .size proc_types, . - proc_types
/*
* Turn off the Cache and MMU. ARMv3 does not support
* reading the control register, but ARMv4 does.
*
* On entry, r6 = processor ID
- * On exit, r0, r1 corrupted
+ * On exit, r0, r1, r2, r3, r12 corrupted
* This routine must preserve: r4, r6, r7
*/
.align 5
-cache_off:
-#ifdef CONFIG_CPU_ARM610
- eor r1, r6, #0x41000000
- eor r1, r1, #0x00560000
- bic r1, r1, #0x0000001f
- teq r1, #0x00000600
- mov r0, #0x00000060 @ ARM6 control reg.
- beq __armv3_cache_off
-#endif
-#ifdef CONFIG_CPU_ARM710
- eor r1, r6, #0x41000000
- bic r1, r1, #0x00070000
- bic r1, r1, #0x000000ff
- teq r1, #0x00007000 @ ARM7
- teqne r1, #0x00007100 @ ARM710
- mov r0, #0x00000070 @ ARM7 control reg.
- beq __armv3_cache_off
-#endif
+cache_off: mov r3, #12 @ cache_off function
+ b call_cache_fn
+
+__armv4_cache_off:
mrc p15, 0, r0, c1, c0
bic r0, r0, #0x000d
mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
@@ -358,6 +443,14 @@
mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4
mov pc, lr
+__arm6_cache_off:
+ mov r0, #0x00000060 @ ARM6 control reg.
+ b __armv3_cache_off
+
+__arm7_cache_off:
+ mov r0, #0x00000070 @ ARM7 control reg.
+ b __armv3_cache_off
+
__armv3_cache_off:
mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
mov r0, #0
@@ -371,25 +464,16 @@
* On entry,
* r6 = processor ID
* On exit,
- * r1, r2, r12 corrupted
+ * r1, r2, r3, r12 corrupted
* This routine must preserve:
- * r4, r6, r7
+ * r0, r4, r5, r6, r7
*/
.align 5
cache_clean_flush:
- ldr r1, proc_sa110_type
- eor r1, r1, r6
- movs r1, r1, lsr #5 @ catch SA110 and SA1100
- beq 1f
- ldr r1, proc_sa1110_type
- eor r1, r1, r6
- movs r1, r1, lsr #4
- beq 1f
- ldr r1, proc_xscale_type
- eor r1, r1, r6
- movs r1, r1, lsr #16
- movne pc, lr
-1:
+ mov r3, #16
+ b call_cache_fn
+
+__armv4_cache_flush:
bic r1, pc, #31
add r2, r1, #65536 @ 2x the largest dcache size
1: ldr r12, [r1], #32 @ s/w flush D cache
@@ -400,12 +484,6 @@
mcr p15, 0, r1, c7, c10, 4 @ drain WB
mov pc, lr
- .type proc_xscale_type,#object
-proc_xscale_type:
- .word 0x69050000
- .size proc_xscale_type, . - proc_xscale_type
-
-
/*
* Various debugging routines for printing hex characters and
* memory, which again must be relocatable.
@@ -481,5 +559,5 @@
reloc_end:
.align
- .section ".stack"
+ .section ".stack", "aw"
user_stack: .space 4096
diff -Nru a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in
--- a/arch/arm/boot/compressed/vmlinux.lds.in Mon Apr 22 15:32:19 2002
+++ b/arch/arm/boot/compressed/vmlinux.lds.in Mon Apr 22 15:32:19 2002
@@ -35,29 +35,26 @@
_etext = .;
- .data : {
- *(.data)
- }
-
+ _got_start = .;
+ .got : { *(.got) }
+ _got_end = .;
+ .got.plt : { *(.got.plt) }
+ .data : { *(.data) }
_edata = .;
. = BSS_START;
__bss_start = .;
- .bss : {
- *(.bss)
- }
+ .bss : { *(.bss) }
_end = .;
- .stack : {
- *(.stack)
- }
+ .stack (NOLOAD) : { *(.stack) }
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
}
diff -Nru a/arch/arm/config.in b/arch/arm/config.in
--- a/arch/arm/config.in Mon Apr 22 15:32:19 2002
+++ b/arch/arm/config.in Mon Apr 22 15:32:19 2002
@@ -433,6 +433,12 @@
define_bool CONFIG_FIQ n
fi
+# Compressed boot loader in ROM. Yes, we really want to ask about
+# TEXT and BSS so we preserve their values in the config files.
+bool 'Compressed boot loader in ROM/flash' CONFIG_ZBOOT_ROM
+hex 'Compressed ROM boot loader base address' CONFIG_ZBOOT_ROM_TEXT 0
+hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0
+
if [ "$CONFIG_ARCH_SA1100" = "y" -o \
"$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL
@@ -573,14 +579,7 @@
source drivers/message/i2o/Config.in
-mainmenu_option next_comment
-comment 'ISDN subsystem'
-
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
-fi
-endmenu
+source drivers/isdn/Config.in
#
# input before char - char/joystick depends on it. As does USB.
diff -Nru a/arch/arm/def-configs/iq80310 b/arch/arm/def-configs/iq80310
--- a/arch/arm/def-configs/iq80310 Mon Apr 22 15:32:19 2002
+++ b/arch/arm/def-configs/iq80310 Mon Apr 22 15:32:19 2002
@@ -139,6 +139,9 @@
#
# General setup
#
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=0x00060000
+CONFIG_ZBOOT_ROM_BSS=0xa1008000
CONFIG_PCI=y
# CONFIG_ISA is not set
# CONFIG_ISA_DMA is not set
diff -Nru a/arch/arm/def-configs/lusl7200 b/arch/arm/def-configs/lusl7200
--- a/arch/arm/def-configs/lusl7200 Mon Apr 22 15:32:19 2002
+++ b/arch/arm/def-configs/lusl7200 Mon Apr 22 15:32:19 2002
@@ -23,6 +23,9 @@
# CONFIG_CPU_26 is not set
CONFIG_CPU_32v4=y
CONFIG_CPU_ARM720=y
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=0x00010000
+CONFIG_ZBOOT_ROM_BSS=0xf03e0000
# CONFIG_PCI is not set
# CONFIG_ISA is not set
# CONFIG_ISA_DMA is not set
diff -Nru a/arch/arm/def-configs/shark b/arch/arm/def-configs/shark
--- a/arch/arm/def-configs/shark Mon Apr 22 15:32:18 2002
+++ b/arch/arm/def-configs/shark Mon Apr 22 15:32:18 2002
@@ -15,7 +15,14 @@
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
#
# Loadable module support
@@ -96,6 +103,7 @@
# CONFIG_SA1100_VICTOR is not set
# CONFIG_SA1100_XP860 is not set
# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
# CONFIG_SA1100_USB is not set
# CONFIG_SA1100_USB_NETLINK is not set
# CONFIG_SA1100_USB_CHAR is not set
@@ -124,6 +132,7 @@
#
# CONFIG_CPU_32v3 is not set
CONFIG_CPU_32v4=y
+# CONFIG_CPU_32v5 is not set
# CONFIG_CPU_ARM610 is not set
# CONFIG_CPU_ARM710 is not set
# CONFIG_CPU_ARM720T is not set
@@ -133,13 +142,17 @@
# CONFIG_CPU_ARM1020 is not set
CONFIG_CPU_SA110=y
# CONFIG_CPU_SA1100 is not set
+# CONFIG_CPU_XSCALE is not set
# CONFIG_XSCALE_PMU is not set
-# CONFIG_ARM_THUMB is not set
-# CONFIG_DISCONTIGMEM is not set
+
+#
+# Processor Features
+#
#
# General setup
#
+# CONFIG_DISCONTIGMEM is not set
CONFIG_PCI=y
# CONFIG_PCI_HOST_PLX90X0 is not set
CONFIG_PCI_HOST_VIA82C505=y
@@ -149,10 +162,6 @@
# CONFIG_PCI_NAMES is not set
# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
#
# At least one math emulation must be selected
@@ -165,6 +174,7 @@
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
# CONFIG_APM is not set
# CONFIG_ARTHUR is not set
CONFIG_LEDS=y
@@ -195,6 +205,7 @@
#
# CONFIG_PNP is not set
# CONFIG_ISAPNP is not set
+# CONFIG_PNPBIOS is not set
#
# Block devices
@@ -229,7 +240,7 @@
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER is not set
CONFIG_FILTER=y
CONFIG_UNIX=y
@@ -239,6 +250,7 @@
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_IPV6 is not set
@@ -280,6 +292,7 @@
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
@@ -290,7 +303,6 @@
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNBMAC is not set
# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
@@ -306,12 +318,9 @@
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
CONFIG_CS89x0=y
-# CONFIG_DE2104X is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
# CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
# CONFIG_LNE390 is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
@@ -323,13 +332,13 @@
# CONFIG_8139TOO_PIO is not set
# CONFIG_8139TOO_TUNE_TWISTER is not set
# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_VIA_RHINE_MMIO is not set
-# CONFIG_WINBOND_840 is not set
# CONFIG_NET_POCKET is not set
#
@@ -337,11 +346,13 @@
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PLIP is not set
@@ -367,6 +378,11 @@
# CONFIG_WAN is not set
#
+# "Tulip" family network device support
+#
+# CONFIG_NET_TULIP is not set
+
+#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
@@ -382,7 +398,7 @@
CONFIG_IDE=y
#
-# IDE, ATA and ATAPI Block devices
+# ATA and ATAPI Block devices
#
CONFIG_BLK_DEV_IDE=y
@@ -393,6 +409,7 @@
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
# CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -409,7 +426,7 @@
# CONFIG_BLK_DEV_IDESCSI is not set
#
-# IDE chipset support/bugfixes
+# IDE chipset support
#
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
@@ -420,7 +437,6 @@
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_IDEDMA_AUTO is not set
# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
# CONFIG_BLK_DEV_ATARAID is not set
# CONFIG_BLK_DEV_ATARAID_PDC is not set
# CONFIG_BLK_DEV_ATARAID_HPT is not set
@@ -520,13 +536,23 @@
# CONFIG_ISDN is not set
#
-# Input core support
+# Input device support
#
# CONFIG_INPUT is not set
# CONFIG_INPUT_KEYBDEV is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_GAMEPORT_NS558 is not set
+# CONFIG_GAMEPORT_L4 is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_GAMEPORT_PCIGAME is not set
+# CONFIG_GAMEPORT_FM801 is not set
+# CONFIG_GAMEPORT_CS461x is not set
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_SERPORT is not set
#
# Character devices
@@ -541,6 +567,24 @@
#
# Serial drivers
#
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+
+#
+# ARM Serial drivers
+#
+# CONFIG_ATOMWIDE_SERIAL is not set
+# CONFIG_DUALSP_SERIAL is not set
# CONFIG_SERIAL_ANAKIN is not set
# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
# CONFIG_SERIAL_AMBA is not set
@@ -554,16 +598,6 @@
# CONFIG_SERIAL_UART00_CONSOLE is not set
# CONFIG_SERIAL_SA1100 is not set
# CONFIG_SERIAL_SA1100_CONSOLE is not set
-# CONFIG_SERIAL_8250 is not set
-# CONFIG_SERIAL_8250_CONSOLE is not set
-# CONFIG_ATOMWIDE_SERIAL is not set
-# CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_RSA is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
CONFIG_PRINTER=m
@@ -596,19 +630,6 @@
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
# CONFIG_QIC02_TAPE is not set
#
@@ -664,6 +685,9 @@
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
@@ -694,6 +718,7 @@
# CONFIG_ROOT_NFS is not set
# CONFIG_NFSD is not set
# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
@@ -707,7 +732,6 @@
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
#
# Partition Types
@@ -797,6 +821,7 @@
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_VIRTUAL is not set
@@ -813,6 +838,11 @@
# Sound
#
CONFIG_SOUND=m
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
# CONFIG_SOUND_BT878 is not set
# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_EMU10K1 is not set
@@ -866,6 +896,11 @@
# CONFIG_SOUND_TVMIXER is not set
#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
# Multimedia Capabilities Port drivers
#
# CONFIG_MCP is not set
@@ -875,111 +910,14 @@
# CONFIG_MCP_UCB1200_TS is not set
#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-# CONFIG_USB_OHCI_SA1111 is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-# Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-# Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
+# Console Switches
#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_SWITCHES is not set
#
-# USB Miscellaneous drivers
+# USB support
#
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB is not set
#
# Bluetooth support
@@ -992,7 +930,6 @@
CONFIG_NO_FRAME_POINTER=y
CONFIG_DEBUG_USER=y
# CONFIG_DEBUG_INFO is not set
-# CONFIG_NO_PGT_CACHE is not set
# CONFIG_DEBUG_KERNEL is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_MAGIC_SYSRQ is not set
@@ -1008,3 +945,5 @@
# Library routines
#
CONFIG_CRC32=y
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Nru a/arch/arm/def-configs/sherman b/arch/arm/def-configs/sherman
--- a/arch/arm/def-configs/sherman Mon Apr 22 15:32:18 2002
+++ b/arch/arm/def-configs/sherman Mon Apr 22 15:32:18 2002
@@ -47,6 +47,9 @@
#
# General setup
#
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=0x00050000
+CONFIG_ZBOOT_ROM_BSS=0xc0200000
# CONFIG_NET is not set
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
diff -Nru a/arch/arm/def-configs/victor b/arch/arm/def-configs/victor
--- a/arch/arm/def-configs/victor Mon Apr 22 15:32:18 2002
+++ b/arch/arm/def-configs/victor Mon Apr 22 15:32:18 2002
@@ -46,6 +46,9 @@
#
# General setup
#
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=0x00002000
+CONFIG_ZBOOT_ROM_BSS=0xc0200000
# CONFIG_NET is not set
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
--- a/arch/arm/kernel/armksyms.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/armksyms.c Mon Apr 22 15:32:19 2002
@@ -68,6 +68,7 @@
extern void __udivmoddi4(void);
extern void __udivsi3(void);
extern void __umodsi3(void);
+extern void abort(void);
extern void ret_from_exception(void);
extern void fpundefinstr(void);
diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
--- a/arch/arm/kernel/bios32.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/bios32.c Mon Apr 22 15:32:19 2002
@@ -426,6 +426,9 @@
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= features;
pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+ SMP_CACHE_BYTES >> 2);
}
/*
diff -Nru a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
--- a/arch/arm/kernel/dma.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/dma.c Mon Apr 22 15:32:19 2002
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/entry-armv.S Mon Apr 22 15:32:19 2002
@@ -756,7 +756,6 @@
#ifdef CONFIG_PREEMPT
ldr r0, [r8, #TI_FLAGS] @ get flags
tst r0, #_TIF_NEED_RESCHED
- ldrne r6, .LCirq_stat
blne svc_preempt
preempt_return:
ldr r0, [r8, #TI_PREEMPT] @ read preempt value
@@ -770,20 +769,20 @@
#ifdef CONFIG_PREEMPT
svc_preempt: teq r9, #0 @ was preempt count = 0
+ ldreq r6, .LCirq_stat
movne pc, lr @ no
ldr r0, [r6, #4] @ local_irq_count
ldr r1, [r6, #8] @ local_bh_count
adds r0, r0, r1
movne pc, lr
- ldr r1, [r8, #TI_TASK]
- set_cpsr_c r2, #MODE_SVC @ enable IRQs
- str r0, [r1, #0] @ current->state = TASK_RUNNING
-1: bl SYMBOL_NAME(schedule)
+ mov r7, #PREEMPT_ACTIVE
+ str r7, [r8, #TI_PREEMPT] @ set PREEMPT_ACTIVE
+1: set_cpsr_c r2, #MODE_SVC @ enable IRQs
+ bl SYMBOL_NAME(schedule)
set_cpsr_c r0, #PSR_I_BIT | MODE_SVC @ disable IRQs
- ldr r0, [r8, #TI_FLAGS]
+ ldr r0, [r8, #TI_FLAGS] @ get new tasks TI_FLAGS
tst r0, #_TIF_NEED_RESCHED
- beq preempt_return
- set_cpsr_c r0, #MODE_SVC @ enable IRQs
+ beq preempt_return @ go again
b 1b
#endif
diff -Nru a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
--- a/arch/arm/kernel/entry-common.S Mon Apr 22 15:32:18 2002
+++ b/arch/arm/kernel/entry-common.S Mon Apr 22 15:32:18 2002
@@ -76,6 +76,9 @@
* This is how we return from a fork.
*/
ENTRY(ret_from_fork)
+#ifdef CONFIG_PREEMPT
+ bl schedule_tail
+#endif
get_thread_info tsk
ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
mov why, #1
diff -Nru a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
--- a/arch/arm/kernel/irq.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/kernel/irq.c Mon Apr 22 15:32:18 2002
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/process.c Mon Apr 22 15:32:19 2002
@@ -31,14 +31,6 @@
#include
#include
-/*
- * Values for cpu_do_idle()
- */
-#define IDLE_WAIT_SLOW 0
-#define IDLE_WAIT_FAST 1
-#define IDLE_CLOCK_SLOW 2
-#define IDLE_CLOCK_FAST 3
-
extern const char *processor_modes[];
extern void setup_mm_for_reboot(char mode);
@@ -78,6 +70,18 @@
void (*pm_power_off)(void);
/*
+ * This is our default idle handler. We need to disable
+ * interrupts here to ensure we don't miss a wakeup call.
+ */
+void default_idle(void)
+{
+ __cli();
+ if (!need_resched() && !hlt_counter)
+ arch_idle();
+ __sti();
+}
+
+/*
* The idle thread. We try to conserve power, while trying to keep
* overall latency low. The architecture specific idle is passed
* a value to indicate the level of "idleness" of the system.
@@ -89,7 +93,7 @@
while (1) {
void (*idle)(void) = pm_idle;
if (!idle)
- idle = arch_idle;
+ idle = default_idle;
leds_event(led_idle_start);
while (!need_resched())
idle();
diff -Nru a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c
--- a/arch/arm/kernel/semaphore.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/semaphore.c Mon Apr 22 15:32:19 2002
@@ -13,6 +13,7 @@
*/
#include
#include
+#include
#include
diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
--- a/arch/arm/kernel/setup.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/kernel/setup.c Mon Apr 22 15:32:18 2002
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
#include
@@ -188,7 +189,7 @@
{
unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
- printk("%s size %dK associativity %d line length %d sets %d\n",
+ printk("%s: %d bytes, associativity %d, %d byte lines, %d sets\n",
prefix,
mult << (8 + CACHE_SIZE(cache)),
(mult << CACHE_ASSOC(cache)) >> 1,
@@ -255,7 +256,7 @@
cpu_user = *list->user;
#endif
- printk("Processor: %s %s revision %d\n",
+ printk("CPU: %s %s revision %d\n",
proc_info.manufacturer, proc_info.cpu_name,
(int)processor_id & 15);
diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/kernel/signal.c Mon Apr 22 15:32:18 2002
@@ -628,14 +628,12 @@
case SIGSTOP: {
struct signal_struct *sig;
+ current->state = TASK_STOPPED;
current->exit_code = signr;
sig = current->parent->sig;
- preempt_disable();
- current->state = TASK_STOPPED;
if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
- preempt_enable();
continue;
}
diff -Nru a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
--- a/arch/arm/kernel/time.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/time.c Mon Apr 22 15:32:19 2002
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
--- a/arch/arm/kernel/traps.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/kernel/traps.c Mon Apr 22 15:32:19 2002
@@ -546,12 +546,14 @@
void __init trap_init(void)
{
- extern void __trap_init(void *);
+ extern void __trap_init(unsigned long);
+ unsigned long base = vectors_base();
- __trap_init((void *)vectors_base());
- if (vectors_base() != 0)
- printk(KERN_DEBUG "Relocating machine vectors to 0x%08x\n",
- vectors_base());
+ __trap_init(base);
+ flush_icache_range(base, base + PAGE_SIZE);
+ if (base != 0)
+ printk(KERN_DEBUG "Relocating machine vectors to 0x%08lx\n",
+ base);
#ifdef CONFIG_CPU_32
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
#endif
diff -Nru a/arch/arm/mach-clps711x/edb7211-mm.c b/arch/arm/mach-clps711x/edb7211-mm.c
--- a/arch/arm/mach-clps711x/edb7211-mm.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-clps711x/edb7211-mm.c Mon Apr 22 15:32:19 2002
@@ -26,11 +26,10 @@
#include
#include
#include
+#include
#include
-#define MB1 1048576 /* one megabyte == size of an MMU section */
-
extern void clps711x_map_io(void);
/*
@@ -56,12 +55,12 @@
/* virtual, physical, length, domain, r, w, c, b */
/* memory-mapped extra keyboard row and CS8900A Ethernet chip */
- { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, MB1, DOMAIN_IO, 0, 1, 0, 0 },
- { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, MB1, DOMAIN_IO, 0, 1, 0, 0 },
+ { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, SZ_1M, DOMAIN_IO, 0, 1, 0, 0 },
+ { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 0, 1, 0, 0 },
/* flash banks */
- { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, MB1 * 8, DOMAIN_KERNEL, 0, 1, 0, 0 },
- { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, MB1 * 8, DOMAIN_KERNEL, 0, 1, 0, 0 },
+ { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, SZ_8M, DOMAIN_KERNEL, 0, 1, 0, 0 },
+ { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, SZ_8M, DOMAIN_KERNEL, 0, 1, 0, 0 },
LAST_DESC
};
diff -Nru a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c
--- a/arch/arm/mach-footbridge/isa-irq.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-footbridge/isa-irq.c Mon Apr 22 15:32:19 2002
@@ -106,8 +106,10 @@
static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
-void __init isa_init_irq(unsigned int irq)
+void __init isa_init_irq(unsigned int host_irq)
{
+ unsigned int irq;
+
/*
* Setup, and then probe for an ISA PIC
* If the PIC is not there, then we
@@ -133,10 +135,10 @@
outb(0xff, PIC_MASK_HI);/* mask all IRQs */
} else {
printk(KERN_INFO "IRQ: ISA PIC not found\n");
- irq = -1;
+ host_irq = (unsigned int)-1;
}
- if (irq != -1) {
+ if (host_irq != (unsigned int)-1) {
for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
set_irq_chip(irq, &isa_lo_chip);
set_irq_handler(irq, do_level_IRQ);
@@ -153,7 +155,7 @@
request_resource(&ioport_resource, &pic2_resource);
setup_irq(IRQ_ISA_CASCADE, &irq_cascade);
- set_irq_chained_handler(irq, isa_irq_handler);
+ set_irq_chained_handler(host_irq, isa_irq_handler);
/*
* On the NetWinder, don't automatically
diff -Nru a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
--- a/arch/arm/mach-sa1100/Makefile Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-sa1100/Makefile Mon Apr 22 15:32:19 2002
@@ -1,9 +1,6 @@
#
# Makefile for the linux kernel.
#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
USE_STANDARD_AS_RULE := true
@@ -115,7 +112,6 @@
obj-$(CONFIG_LEDS) += $(led-y)
# SA1110 USB client support
-list-multi += sa1100usb_core.o
sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o
obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o
obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o
@@ -125,7 +121,3 @@
obj-$(CONFIG_PM) += pm.o sleep.o
include $(TOPDIR)/Rules.make
-
-sa1100usb_core.o: $(sa1100usb_core-objs)
- $(LD) -r -o $@ $(sa1100usb_core-objs)
-
diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c
--- a/arch/arm/mach-sa1100/adsbitsy.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/mach-sa1100/adsbitsy.c Mon Apr 22 15:32:18 2002
@@ -52,27 +52,11 @@
/*
* Probe for SA1111.
*/
- ret = sa1111_probe(0x18000000);
+ ret = sa1111_init(NULL, 0x18000000, IRQ_GPIO0);
if (ret < 0)
return ret;
/*
- * We found it. Wake the chip up.
- */
- sa1111_wake();
-
- /*
- * The SDRAM configuration of the SA1110 and the SA1111 must
- * match. This is very important to ensure that SA1111 accesses
- * don't corrupt the SDRAM. Note that this ungates the SA1111's
- * MBGNT signal, so we must have called sa1110_mb_disable()
- * beforehand.
- */
- sa1111_configure_smc(1,
- FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
- FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
- /*
* Enable PWM control for LCD
*/
SKPCR |= SKPCR_PWMCLKEN;
@@ -80,20 +64,6 @@
SKPEN0 = 1;
SKPWM1 = 0x01; // Backlight
SKPEN1 = 1;
-
- /*
- * We only need to turn on DCLK whenever we want to use the
- * DMA. It can otherwise be held firmly in the off position.
- */
- SKPCR |= SKPCR_DCLKEN;
-
- /*
- * Enable the SA1110 memory bus request and grant signals.
- */
- sa1110_mb_enable();
-
- set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_RISING_EDGE);
- sa1111_init_irq(IRQ_GPIO0);
return 0;
}
diff -Nru a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
--- a/arch/arm/mach-sa1100/badge4.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/mach-sa1100/badge4.c Mon Apr 22 15:32:18 2002
@@ -34,8 +34,6 @@
static int __init badge4_sa1111_init(void)
{
- int ret;
-
/*
* Ensure that the memory bus request/grant signals are setup,
* and the grant is held in its inactive state
@@ -45,40 +43,7 @@
/*
* Probe for SA1111.
*/
- ret = sa1111_probe(BADGE4_SA1111_BASE);
- if (ret < 0)
- return ret;
-
- /*
- * We found it. Wake the chip up.
- */
- sa1111_wake();
-
- /*
- * The SDRAM configuration of the SA1110 and the SA1111 must
- * match. This is very important to ensure that SA1111 accesses
- * don't corrupt the SDRAM. Note that this ungates the SA1111's
- * MBGNT signal, so we must have called sa1110_mb_disable()
- * beforehand.
- */
- sa1111_configure_smc(1,
- FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
- FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
- /*
- * We only need to turn on DCLK whenever we want to use the
- * DMA. It can otherwise be held firmly in the off position.
- */
- SKPCR |= SKPCR_DCLKEN;
-
- /*
- * Enable the SA1110 memory bus request and grant signals.
- */
- sa1110_mb_enable();
-
- sa1111_init_irq(BADGE4_IRQ_GPIO_SA1111);
-
- return 0;
+ return sa1111_init(NULL, BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111);
}
static int __init badge4_init(void)
diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c
--- a/arch/arm/mach-sa1100/graphicsmaster.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-sa1100/graphicsmaster.c Mon Apr 22 15:32:19 2002
@@ -42,27 +42,11 @@
/*
* Probe for SA1111.
*/
- ret = sa1111_probe(0x18000000);
+ ret = sa1111_init(NULL, 0x18000000, ADS_EXT_IRQ(0));
if (ret < 0)
return ret;
/*
- * We found it. Wake the chip up.
- */
- sa1111_wake();
-
- /*
- * The SDRAM configuration of the SA1110 and the SA1111 must
- * match. This is very important to ensure that SA1111 accesses
- * don't corrupt the SDRAM. Note that this ungates the SA1111's
- * MBGNT signal, so we must have called sa1110_mb_disable()
- * beforehand.
- */
- sa1111_configure_smc(1,
- FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
- FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
- /*
* Enable PWM control for LCD
*/
SKPCR |= SKPCR_PWMCLKEN;
@@ -70,19 +54,6 @@
SKPEN0 = 1;
SKPWM1 = 0x01; // Backlight
SKPEN1 = 1;
-
- /*
- * We only need to turn on DCLK whenever we want to use the
- * DMA. It can otherwise be held firmly in the off position.
- */
- SKPCR |= SKPCR_DCLKEN;
-
- /*
- * Enable the SA1110 memory bus request and grant signals.
- */
- sa1110_mb_enable();
-
- sa1111_init_irq(ADS_EXT_IRQ(0));
return 0;
}
diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
--- a/arch/arm/mach-sa1100/neponset.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-sa1100/neponset.c Mon Apr 22 15:32:19 2002
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
@@ -21,6 +22,10 @@
#include "sa1111.h"
+static struct device neponset_device = {
+ name: "Neponset",
+ bus_id: "nep_bus",
+};
/*
* Install handler for Neponset IRQ. Note that we have to loop here
@@ -125,6 +130,10 @@
return -ENODEV;
}
+ ret = device_register(&neponset_device);
+ if (ret)
+ return ret;
+
neponset_init_irq();
/*
@@ -139,45 +148,9 @@
/* FIXME: setup MSC2 */
/*
- * Probe for a SA1111.
- */
- ret = sa1111_probe(0x40000000);
- if (ret < 0)
- return ret;
-
- /*
- * We found it. Wake the chip up.
+ * Probe and initialise the SA1111.
*/
- sa1111_wake();
-
- /*
- * The SDRAM configuration of the SA1110 and the SA1111 must
- * match. This is very important to ensure that SA1111 accesses
- * don't corrupt the SDRAM. Note that this ungates the SA1111's
- * MBGNT signal, so we must have called sa1110_mb_disable()
- * beforehand.
- */
- sa1111_configure_smc(1,
- FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
- FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
- /*
- * We only need to turn on DCLK whenever we want to use the
- * DMA. It can otherwise be held firmly in the off position.
- */
- SKPCR |= SKPCR_DCLKEN;
-
- /*
- * Enable the SA1110 memory bus request and grant signals.
- */
- sa1110_mb_enable();
-
- /*
- * Initialise SA1111 IRQs
- */
- sa1111_init_irq(IRQ_NEPONSET_SA1111);
-
- return 0;
+ return sa1111_init(&neponset_device, 0x40000000, IRQ_NEPONSET_SA1111);
}
__initcall(neponset_init);
diff -Nru a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c
--- a/arch/arm/mach-sa1100/pfs168.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/mach-sa1100/pfs168.c Mon Apr 22 15:32:18 2002
@@ -35,40 +35,7 @@
/*
* Probe for SA1111.
*/
- ret = sa1111_probe(0x40000000);
- if (ret < 0)
- return ret;
-
- /*
- * We found it. Wake the chip up.
- */
- sa1111_wake();
-
- /*
- * The SDRAM configuration of the SA1110 and the SA1111 must
- * match. This is very important to ensure that SA1111 accesses
- * don't corrupt the SDRAM. Note that this ungates the SA1111's
- * MBGNT signal, so we must have called sa1110_mb_disable()
- * beforehand.
- */
- sa1111_configure_smc(1,
- FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
- FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
- /*
- * We only need to turn on DCLK whenever we want to use the
- * DMA. It can otherwise be held firmly in the off position.
- */
- SKPCR |= SKPCR_DCLKEN;
-
- /*
- * Enable the SA1110 memory bus request and grant signals.
- */
- sa1110_mb_enable();
-
- sa1111_init_irq(IRQ_GPIO25); /* SA1111 IRQ on GPIO 25 */
-
- return 0;
+ return sa1111_init(NULL, 0x40000000, IRQ_GPIO25);
}
__initcall(pfs168_init);
diff -Nru a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c
--- a/arch/arm/mach-sa1100/sa1111.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-sa1100/sa1111.c Mon Apr 22 15:32:19 2002
@@ -23,8 +23,11 @@
#include
#include
#include
+#include
+#include
#include
+#include
#include
#include
@@ -32,11 +35,9 @@
#include "sa1111.h"
-struct resource sa1111_resource = {
- name: "SA1111",
-};
+struct sa1111_device *sa1111;
-EXPORT_SYMBOL(sa1111_resource);
+EXPORT_SYMBOL(sa1111);
/*
* SA1111 interrupt support. Since clearing an IRQ while there are
@@ -65,6 +66,9 @@
for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
if (stat1 & 1)
do_edge_IRQ(i, irq_desc + i, regs);
+
+ /* For level-based interrupts */
+ desc->chip->unmask(irq);
}
#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START))
@@ -198,7 +202,7 @@
type: sa1111_type_highirq,
};
-void __init sa1111_init_irq(int irq_nr)
+static void __init sa1111_init_irq(int irq_nr)
{
unsigned int irq;
@@ -239,6 +243,21 @@
set_irq_chained_handler(irq_nr, sa1111_irq_handler);
}
+static int sa1111_suspend(struct device *dev, u32 state, u32 level)
+{
+ return 0;
+}
+
+static int sa1111_resume(struct device *dev, u32 level)
+{
+ return 0;
+}
+
+static struct device_driver sa1111_device_driver = {
+ suspend: sa1111_suspend,
+ resume: sa1111_resume,
+};
+
/**
* sa1111_probe - probe for a single SA1111 chip.
* @phys_addr: physical address of device.
@@ -251,38 +270,71 @@
* %-EBUSY physical address already marked in-use.
* %0 successful.
*/
-int __init sa1111_probe(unsigned long phys_addr)
+static int __init
+sa1111_probe(struct device *parent, unsigned long phys_addr)
{
+ struct sa1111_device *sa;
unsigned long id;
int ret = -ENODEV;
- sa1111_resource.start = phys_addr;
- sa1111_resource.end = phys_addr + 0x2000;
+ sa = kmalloc(sizeof(struct sa1111_device), GFP_KERNEL);
+ if (!sa)
+ return -ENOMEM;
+
+ memset(sa, 0, sizeof(struct sa1111_device));
- if (request_resource(&iomem_resource, &sa1111_resource)) {
+ sa->resource.name = "SA1111";
+ sa->resource.start = phys_addr;
+ sa->resource.end = phys_addr + 0x2000;
+
+ if (request_resource(&iomem_resource, &sa->resource)) {
ret = -EBUSY;
goto out;
}
+ /* eventually ioremap... */
+ sa->base = (void *)0xf4000000;
+ if (!sa->base) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
/*
* Probe for the chip. Only touch the SBI registers.
*/
- id = SBI_SKID;
+ id = readl(sa->base + SA1111_SKID);
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
ret = -ENODEV;
- goto release;
+ goto unmap;
}
+ /*
+ * We found the chip.
+ */
+ strcpy(sa->dev.name, "SA1111");
+ sprintf(sa->dev.bus_id, "%8.8lx", phys_addr);
+ sa->dev.parent = parent;
+ sa->dev.driver = &sa1111_device_driver;
+
+ ret = device_register(&sa->dev);
+ if (ret)
+ printk("sa1111 device_register failed: %d\n", ret);
+
printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
"silicon revision %lx, metal revision %lx\n",
(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
+ sa1111 = sa;
+
return 0;
+ unmap:
+// iounmap(sa->base);
release:
- release_resource(&sa1111_resource);
+ release_resource(&sa->resource);
out:
+ kfree(sa);
return ret;
}
@@ -302,7 +354,8 @@
*/
void sa1111_wake(void)
{
- unsigned long flags;
+ struct sa1111_device *sa = sa1111;
+ unsigned long flags, r;
local_irq_save(flags);
@@ -317,8 +370,11 @@
/*
* Turn VCO on, and disable PLL Bypass.
*/
- SBI_SKCR &= ~SKCR_VCO_OFF;
- SBI_SKCR |= SKCR_PLL_BYPASS | SKCR_OE_EN;
+ r = readl(sa->base + SA1111_SKCR);
+ r &= ~SKCR_VCO_OFF;
+ writel(r, sa->base + SA1111_SKCR);
+ r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
+ writel(r, sa->base + SA1111_SKCR);
/*
* Wait lock time. SA1111 manual _doesn't_
@@ -329,7 +385,8 @@
/*
* Enable RCLK. We also ensure that RDYEN is set.
*/
- SBI_SKCR |= SKCR_RCLKEN | SKCR_RDYEN;
+ r |= SKCR_RCLKEN | SKCR_RDYEN;
+ writel(r, sa->base + SA1111_SKCR);
/*
* Wait 14 RCLK cycles for the chip to finish coming out
@@ -340,18 +397,26 @@
/*
* Ensure all clocks are initially off.
*/
- SKPCR = 0;
+ writel(0, sa->base + SA1111_SKPCR);
local_irq_restore(flags);
}
void sa1111_doze(void)
{
- if (SKPCR & SKPCR_UCLKEN) {
+ struct sa1111_device *sa = sa1111;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
+ local_irq_restore(flags);
printk("SA1111 doze mode refused\n");
return;
}
- SBI_SKCR &= ~SKCR_RCLKEN;
+
+ writel(readl(sa->base + SA1111_SKCR) & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
+ local_irq_restore(flags);
}
/*
@@ -359,12 +424,13 @@
*/
void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency)
{
+ struct sa1111_device *sa = sa1111;
unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
if (cas_latency == 3)
smcr |= SMCR_CLAT;
- SBI_SMCR = smcr;
+ writel(smcr, sa->base + SA1111_SMCR);
}
/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
@@ -432,3 +498,46 @@
}
EXPORT_SYMBOL(sa1111_check_dma_bug);
+
+int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
+{
+ int ret;
+
+ ret = sa1111_probe(parent, phys);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * We found it. Wake the chip up.
+ */
+ sa1111_wake();
+
+ /*
+ * The SDRAM configuration of the SA1110 and the SA1111 must
+ * match. This is very important to ensure that SA1111 accesses
+ * don't corrupt the SDRAM. Note that this ungates the SA1111's
+ * MBGNT signal, so we must have called sa1110_mb_disable()
+ * beforehand.
+ */
+ sa1111_configure_smc(1,
+ FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+ FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+ /*
+ * We only need to turn on DCLK whenever we want to use the
+ * DMA. It can otherwise be held firmly in the off position.
+ */
+ SKPCR |= SKPCR_DCLKEN;
+
+ /*
+ * Enable the SA1110 memory bus request and grant signals.
+ */
+ sa1110_mb_enable();
+
+ /*
+ * Initialise SA1111 IRQs
+ */
+ sa1111_init_irq(irq);
+
+ return 0;
+}
diff -Nru a/arch/arm/mach-sa1100/sa1111.h b/arch/arm/mach-sa1100/sa1111.h
--- a/arch/arm/mach-sa1100/sa1111.h Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-sa1100/sa1111.h Mon Apr 22 15:32:19 2002
@@ -1,11 +1,13 @@
/*
* linux/arch/arm/mach-sa1100/sa1111.h
*/
+struct device;
/*
* Probe for a SA1111 chip.
*/
-extern int sa1111_probe(unsigned long phys);
+extern int
+sa1111_init(struct device *parent, unsigned long phys, unsigned int irq);
/*
* Wake up a SA1111 chip.
@@ -16,9 +18,3 @@
* Doze the SA1111 chip.
*/
extern void sa1111_doze(void);
-
-/*
- * Configure the SA1111 shared memory controller.
- */
-extern void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency);
-extern void sa1111_init_irq(int irq_nr);
diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c
--- a/arch/arm/mach-sa1100/system3.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-sa1100/system3.c Mon Apr 22 15:32:19 2002
@@ -426,44 +426,11 @@
/*
* Probe for a SA1111.
*/
- ret = sa1111_probe(PT_SA1111_BASE);
+ ret = sa1111_init(NULL, PT_SA1111_BASE, IRQ_SYSTEM3_SA1111);
if (ret < 0) {
printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" );
goto DONE;
}
-
- /*
- * We found it. Wake the chip up.
- */
- sa1111_wake();
-
- /*
- * The SDRAM configuration of the SA1110 and the SA1111 must
- * match. This is very important to ensure that SA1111 accesses
- * don't corrupt the SDRAM. Note that this ungates the SA1111's
- * MBGNT signal, so we must have called sa1110_mb_disable()
- * beforehand.
- */
- sa1111_configure_smc(1,
- FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
- FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
- /*
- * We only need to turn on DCLK whenever we want to use the
- * DMA. It can otherwise be held firmly in the off position.
- */
- SKPCR |= SKPCR_DCLKEN;
-
- /*
- * Enable the SA1110 memory bus request and grant signals.
- */
- sa1110_mb_enable();
-
- /*
- * Initialise SA1111 IRQs
- */
- sa1111_init_irq(IRQ_SYSTEM3_SA1111);
-
#if defined( CONFIG_CPU_FREQ )
ret = cpufreq_register_notifier(&system3_clkchg_block);
diff -Nru a/arch/arm/mach-shark/pci.c b/arch/arm/mach-shark/pci.c
--- a/arch/arm/mach-shark/pci.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mach-shark/pci.c Mon Apr 22 15:32:19 2002
@@ -20,6 +20,8 @@
else return 255;
}
+extern void __init via82c505_preinit(void *sysdata);
+
struct hw_pci shark_pci __initdata = {
setup: via82c505_setup,
swizzle: pci_std_swizzle,
diff -Nru a/arch/arm/mm/abort-ev5ej.S b/arch/arm/mm/abort-ev5ej.S
--- a/arch/arm/mm/abort-ev5ej.S Mon Apr 22 15:32:18 2002
+++ b/arch/arm/mm/abort-ev5ej.S Mon Apr 22 15:32:18 2002
@@ -28,7 +28,7 @@
ldrneh r3, [r2] @ read aborted thumb instruction
ldreq r3, [r2] @ read aborted ARM instruction
movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20
- tst r2, #1 << 20 @ L = 1 -> write
+ tst r3, #1 << 20 @ L = 1 -> write
orreq r1, r1, #1 << 8 @ yes.
1: mov pc, lr
diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
--- a/arch/arm/mm/consistent.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mm/consistent.c Mon Apr 22 15:32:19 2002
@@ -25,10 +25,12 @@
/*
* This allocates one page of cache-coherent memory space and returns
- * both the virtual and a "dma" address to that space. It is not clear
- * whether this could be called from an interrupt context or not. For
- * now, we expressly forbid it, especially as some of the stuff we do
- * here is not interrupt context safe.
+ * both the virtual and a "dma" address to that space.
+ *
+ * We should allow this function to be called from interrupt context.
+ * However, we call ioremap, which needs to fiddle around with various
+ * things (like the vmlist_lock, and allocating page tables). These
+ * things aren't interrupt safe (yet).
*
* Note that this does *not* zero the allocated area!
*/
@@ -36,8 +38,9 @@
{
struct page *page, *end, *free;
unsigned long order;
- void *ret, *virt;
+ void *ret;
+ /* FIXME */
if (in_interrupt())
BUG();
@@ -48,22 +51,22 @@
if (!page)
goto no_page;
- /*
- * We could do with a page_to_phys and page_to_bus here.
- */
- virt = page_address(page);
- *dma_handle = virt_to_bus(virt);
- ret = __ioremap(virt_to_phys(virt), size, 0);
+ *dma_handle = page_to_bus(page);
+ ret = __ioremap(page_to_phys(page), size, 0);
if (!ret)
goto no_remap;
#if 0 /* ioremap_does_flush_cache_all */
- /*
- * we need to ensure that there are no cachelines in use, or
- * worse dirty in this area. Really, we don't need to do
- * this since __ioremap does a flush_cache_all() anyway. --rmk
- */
- invalidate_dcache_range(virt, virt + size);
+ {
+ void *virt = page_address(page);
+
+ /*
+ * we need to ensure that there are no cachelines in use, or
+ * worse dirty in this area. Really, we don't need to do
+ * this since __ioremap does a flush_cache_all() anyway. --rmk
+ */
+ invalidate_dcache_range(virt, virt + size);
+ }
#endif
/*
@@ -72,7 +75,6 @@
* We also mark the pages in use as reserved so that
* remap_page_range works.
*/
- page = virt_to_page(virt);
free = page + (size >> PAGE_SHIFT);
end = page + (1 << order);
@@ -93,18 +95,12 @@
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handle)
{
- void *__ret;
- int __gfp = GFP_KERNEL;
+ int gfp = GFP_KERNEL;
-#ifdef CONFIG_PCI
- if ((hwdev) == NULL ||
- (hwdev)->dma_mask != 0xffffffff)
-#endif
- __gfp |= GFP_DMA;
+ if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+ gfp |= GFP_DMA;
- __ret = consistent_alloc(__gfp, (size),
- (handle));
- return __ret;
+ return consistent_alloc(gfp, size, handle);
}
/*
@@ -114,19 +110,16 @@
void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
{
struct page *page, *end;
- void *virt;
if (in_interrupt())
BUG();
- virt = bus_to_virt(handle);
-
/*
* More messing around with the MM internals. This is
* sick, but then so is remap_page_range().
*/
size = PAGE_ALIGN(size);
- page = virt_to_page(virt);
+ page = virt_to_page(bus_to_virt(handle));
end = page + (size >> PAGE_SHIFT);
for (; page < end; page++)
diff -Nru a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c
--- a/arch/arm/mm/minicache.c Mon Apr 22 15:32:18 2002
+++ b/arch/arm/mm/minicache.c Mon Apr 22 15:32:18 2002
@@ -44,7 +44,7 @@
unsigned long map_page_minicache(unsigned long virt)
{
set_pte(minicache_pte, mk_pte_phys(__pa(virt), minicache_pgprot));
- flush_kern_tlb_page(minicache_address);
+ flush_tlb_kernel_page(minicache_address);
return minicache_address;
}
diff -Nru a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
--- a/arch/arm/mm/proc-xscale.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mm/proc-xscale.S Mon Apr 22 15:32:19 2002
@@ -723,7 +723,6 @@
.word cpu_xscale_set_pgd
.word cpu_xscale_set_pmd
.word cpu_xscale_set_pte
-
.size xscale_processor_functions, . - xscale_processor_functions
.type cpu_80200_info, #object
@@ -779,6 +778,5 @@
.long xscale_processor_functions
.long v4wbi_tlb_fns
.long v5te_mc_user_fns
- .size __cotulla_proc_info, . - __cotulla_proc_info
.size __pxa250_proc_info, . - __pxa250_proc_info
diff -Nru a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S
--- a/arch/arm/mm/tlb-v3.S Mon Apr 22 15:32:18 2002
+++ b/arch/arm/mm/tlb-v3.S Mon Apr 22 15:32:18 2002
@@ -53,6 +53,7 @@
act_mm r3 @ get current->active_mm
teq r2, r3 @ == mm ?
movne pc, lr @ no, we dont do anything
+ENTRY(v3_flush_kern_tlb_range)
bic r0, r0, #0x0ff
bic r0, r0, #0xf00
1: mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry
@@ -87,5 +88,6 @@
.long v3_flush_user_tlb_mm
.long v3_flush_user_tlb_range
.long v3_flush_user_tlb_page
+ .long v3_flush_kern_tlb_range
.long v3_flush_kern_tlb_page
.size v3_tlb_fns, . - v3_tlb_fns
diff -Nru a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S
--- a/arch/arm/mm/tlb-v4.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mm/tlb-v4.S Mon Apr 22 15:32:19 2002
@@ -42,7 +42,7 @@
/*
* v4_flush_user_tlb_range(start, end, mm)
*
- * Invalidate a range of TLB entries in the specified address space.
+ * Invalidate a range of TLB entries in the specified user address space.
*
* - start - range start address
* - end - range end address
@@ -86,6 +86,27 @@
mov pc, lr
/*
+ * v4_flush_kerm_tlb_range(start, end)
+ *
+ * Invalidate a range of TLB entries in the specified kernel
+ * address range.
+ *
+ * - start - virtual address (may not be aligned)
+ * - end - virtual address (may not be aligned)
+ */
+ .align 5
+ENTRY(v4_flush_kern_tlb_range)
+ bic r0, r0, #0x0ff
+ bic r0, r0, #0xf00
+1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
+ add r0, r0, #PAGE_SZ
+ cmp r0, r1
+ blo 1b
+ mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB
+ mov pc, lr
+
+
+/*
* v4_flush_kern_tlb_page(kaddr)
*
* Invalidate the TLB entry for the specified page. The address
@@ -106,5 +127,6 @@
.long v4_flush_user_tlb_mm
.long v4_flush_user_tlb_range
.long v4_flush_user_tlb_page
+ .long v4_flush_kern_tlb_range
.long v4_flush_kern_tlb_page
.size v4_tlb_fns, . - v4_tlb_fns
diff -Nru a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S
--- a/arch/arm/mm/tlb-v4wb.S Mon Apr 22 15:32:19 2002
+++ b/arch/arm/mm/tlb-v4wb.S Mon Apr 22 15:32:19 2002
@@ -88,7 +88,41 @@
mcr p15, 0, r3, c7, c10, 4 @ drain WB
tst r2, #VM_EXEC
mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB
+ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
+ mov pc, lr
+
+/*
+ * v4_flush_kerm_tlb_range(start, end)
+ *
+ * Invalidate a range of TLB entries in the specified kernel
+ * address range.
+ *
+ * - start - virtual address (may not be aligned)
+ * - end - virtual address (may not be aligned)
+ */
+ENTRY(v4wb_flush_kern_tlb_range)
+ mov r3, #0
+ mcr p15, 0, r3, c7, c10, 4 @ drain WB
+ bic r0, r0, #0x0ff
+ bic r0, r0, #0xf00
+ mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB
+1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
+ add r0, r0, #PAGE_SZ
+ cmp r0, r1
+ blo 1b
+ mov pc, lr
+
+/*
+ * v4_flush_kern_tlb_page(kaddr)
+ *
+ * Invalidate the TLB entry for the specified page. The address
+ * will be in the kernels virtual memory space. Current uses
+ * only require the D-TLB to be invalidated.
+ *
+ * - kaddr - Kernel virtual memory address
+ */
ENTRY(v4wb_flush_kern_tlb_page)
+ mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
mov pc, lr
@@ -107,14 +141,17 @@
*/
.align 5
ENTRY(v4wbi_flush_user_tlb_range)
+ vma_vm_mm ip, r2
act_mm r3 @ get current->active_mm
- teq r2, r3 @ == mm ?
+ eors r3, ip, r3 @ == mm ?
movne pc, lr @ no, we dont do anything
mov r3, #0
mcr p15, 0, r3, c7, c10, 4 @ drain WB
+ vma_vm_flags r2, r2
bic r0, r0, #0x0ff
bic r0, r0, #0xf00
-1: mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
+1: tst r2, #VM_EXEC
+ mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
add r0, r0, #PAGE_SZ
cmp r0, r1
@@ -140,7 +177,23 @@
mcr p15, 0, r3, c7, c10, 4 @ drain WB
tst r2, #VM_EXEC
mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
+ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
+ mov pc, lr
+
+ENTRY(v4wbi_flush_kern_tlb_range)
+ mov r3, #0
+ mcr p15, 0, r3, c7, c10, 4 @ drain WB
+ bic r0, r0, #0x0ff
+ bic r0, r0, #0xf00
+1: mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
+ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
+ add r0, r0, #PAGE_SZ
+ cmp r0, r1
+ blo 1b
+ mov pc, lr
+
ENTRY(v4wbi_flush_kern_tlb_page)
+ mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
mov pc, lr
@@ -152,6 +205,7 @@
.long v4wb_flush_user_tlb_mm
.long v4wb_flush_user_tlb_range
.long v4wb_flush_user_tlb_page
+ .long v4wb_flush_kern_tlb_range
.long v4wb_flush_kern_tlb_page
.size v4wb_tlb_fns, . - v4wb_tlb_fns
@@ -161,5 +215,6 @@
.long v4wbi_flush_user_tlb_mm
.long v4wbi_flush_user_tlb_range
.long v4wbi_flush_user_tlb_page
+ .long v4wbi_flush_kern_tlb_range
.long v4wbi_flush_kern_tlb_page
.size v4wbi_tlb_fns, . - v4wbi_tlb_fns
diff -Nru a/arch/arm/nwfpe/Makefile b/arch/arm/nwfpe/Makefile
--- a/arch/arm/nwfpe/Makefile Mon Apr 22 15:32:18 2002
+++ b/arch/arm/nwfpe/Makefile Mon Apr 22 15:32:18 2002
@@ -1,6 +1,4 @@
#
-# linux/arch/arm/nwfpe/Makefile
-#
# Copyright (C) 1998, 1999, 2001 Philip Blundell
#
@@ -12,8 +10,6 @@
obj-m :=
obj-n :=
-list-multi := nwfpe.o
-
obj-$(CONFIG_FPE_NWFPE) += nwfpe.o
nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
@@ -27,6 +23,3 @@
endif
include $(TOPDIR)/Rules.make
-
-nwfpe.o: $(nwfpe-objs)
- $(LD) -r -o $@ $(nwfpe-objs)
diff -Nru a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c
--- a/arch/arm/nwfpe/fpmodule.c Mon Apr 22 15:32:19 2002
+++ b/arch/arm/nwfpe/fpmodule.c Mon Apr 22 15:32:19 2002
@@ -28,6 +28,7 @@
#include
/* XXX */
+#include
#include
#include
#include
diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
--- a/arch/arm/tools/mach-types Mon Apr 22 15:32:19 2002
+++ b/arch/arm/tools/mach-types Mon Apr 22 15:32:19 2002
@@ -6,7 +6,7 @@
# To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk
#
-# Last update: Sun Mar 24 11:48:10 2002
+# Last update: Fri Mar 29 15:51:20 2002
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -179,3 +179,4 @@
active SA1100_ACTIVE ACTIVE 168
iq80321 ARCH_IQ80321 IQ80321 169
wid SA1100_WID WID 170
+sabinal ARCH_SABINAL SABINAL 171
diff -Nru a/arch/cris/config.in b/arch/cris/config.in
--- a/arch/cris/config.in Mon Apr 22 15:32:18 2002
+++ b/arch/cris/config.in Mon Apr 22 15:32:18 2002
@@ -185,15 +185,7 @@
source net/irda/Config.in
-mainmenu_option next_comment
-comment 'ISDN subsystem'
-if [ "$CONFIG_NET" != "n" ]; then
- tristate 'ISDN support' CONFIG_ISDN
- if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
- fi
-fi
-endmenu
+source drivers/isdn/Config.in
mainmenu_option next_comment
comment 'Old CD-ROM drivers (not SCSI, not IDE)'
diff -Nru a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
--- a/arch/cris/drivers/ide.c Mon Apr 22 15:32:19 2002
+++ b/arch/cris/drivers/ide.c Mon Apr 22 15:32:19 2002
@@ -272,13 +272,17 @@
printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
/* first initialize the channel interface data */
-
+
for(h = 0; h < MAX_HWIFS; h++) {
struct ata_channel *hwif = &ide_hwifs[h];
+
hwif->chipset = ide_etrax100;
hwif->tuneproc = &tune_e100_ide;
hwif->dmaproc = &e100_dmaproc;
- hwif->ideproc = &e100_ideproc;
+ hwif->ata_read = e100_ide_input_data;
+ hwif->ata_write = e100_ide_output_data;
+ hwif->atapi_read = e100_atapi_read;
+ hwif->atapi_write = e100_atapi_write;
}
/* actually reset and configure the etrax100 ide/ata interface */
@@ -375,12 +379,12 @@
* so if an odd bytecount is specified, be sure that there's at least one
* extra byte allocated for the buffer.
*/
-static void
-e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+static void
+e100_atapi_read(ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
ide_ioreg_t data_reg = IDE_DATA_REG;
- D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ D(printk("atapi_read, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));
if(bytecount & 1) {
@@ -454,12 +458,12 @@
#endif
}
-static void
-e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+static void
+e100_atapi_write(ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
ide_ioreg_t data_reg = IDE_DATA_REG;
- D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ D(printk("atapi_write, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));
if(bytecount & 1) {
@@ -544,7 +548,7 @@
static void
e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
- e100_atapi_input_bytes(drive, buffer, wcount << 2);
+ e100_atapi_read(drive, buffer, wcount << 2);
}
/*
@@ -553,33 +557,7 @@
static void
e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
- e100_atapi_output_bytes(drive, buffer, wcount << 2);
-}
-
-/*
- * The multiplexor for ide_xxxput_data and atapi calls
- */
-static void
-e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
- void *buffer, unsigned int length)
-{
- switch (func) {
- case ideproc_ide_input_data:
- e100_ide_input_data(drive, buffer, length);
- break;
- case ideproc_ide_output_data:
- e100_ide_input_data(drive, buffer, length);
- break;
- case ideproc_atapi_input_bytes:
- e100_atapi_input_bytes(drive, buffer, length);
- break;
- case ideproc_atapi_output_bytes:
- e100_atapi_output_bytes(drive, buffer, length);
- break;
- default:
- printk("e100_ideproc: unsupported func %d!\n", func);
- break;
- }
+ e100_atapi_write(drive, buffer, wcount << 2);
}
/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in Mon Apr 22 15:32:19 2002
+++ b/arch/i386/config.in Mon Apr 22 15:32:19 2002
@@ -88,7 +88,6 @@
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
- define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
define_bool CONFIG_X86_PPRO_FENCE y
fi
@@ -96,14 +95,12 @@
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
- define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
if [ "$CONFIG_MPENTIUM4" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 7
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
- define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
if [ "$CONFIG_MK6" = "y" ]; then
@@ -117,7 +114,6 @@
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
define_bool CONFIG_X86_USE_3DNOW y
- define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
if [ "$CONFIG_MELAN" = "y" ]; then
@@ -348,15 +344,7 @@
source net/irda/Config.in
-mainmenu_option next_comment
-comment 'ISDN subsystem'
-if [ "$CONFIG_NET" != "n" ]; then
- tristate 'ISDN support' CONFIG_ISDN
- if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
- fi
-fi
-endmenu
+source drivers/isdn/Config.in
mainmenu_option next_comment
comment 'Old CD-ROM drivers (not SCSI, not IDE)'
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig Mon Apr 22 15:32:18 2002
+++ b/arch/i386/defconfig Mon Apr 22 15:32:18 2002
@@ -56,7 +56,6 @@
CONFIG_X86_L1_CACHE_SHIFT=5
CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
-CONFIG_X86_PGE=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_MCE=y
# CONFIG_X86_MCE_NONFATAL is not set
@@ -529,7 +528,7 @@
#
# ISDN subsystem
#
-# CONFIG_ISDN is not set
+# CONFIG_ISDN_BOOL is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
@@ -693,6 +692,7 @@
# CONFIG_NFSD_TCP is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
+CONFIG_EXPORTFS=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
@@ -864,7 +864,6 @@
#
# USB Imaging devices
#
-# CONFIG_USB_DC2XX is not set
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_MICROTEK is not set
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/bluesmoke.c Mon Apr 22 15:32:19 2002
@@ -33,9 +33,9 @@
* P4/Xeon Thermal transition interrupt handler
*/
+#ifdef CONFIG_X86_LOCAL_APIC
static void intel_thermal_interrupt(struct pt_regs *regs)
{
-#ifdef CONFIG_X86_LOCAL_APIC
u32 l, h;
unsigned int cpu = smp_processor_id();
@@ -48,8 +48,8 @@
} else {
printk(KERN_INFO "CPU#%d: Temperature/speed normal\n", cpu);
}
-#endif
}
+#endif
static void unexpected_thermal_interrupt(struct pt_regs *regs)
{
@@ -76,11 +76,11 @@
unsigned int cpu = smp_processor_id();
/* Thermal monitoring */
- if (!test_bit(X86_FEATURE_ACPI, &c->x86_capability))
+ if (!test_bit(X86_FEATURE_ACPI, c->x86_capability))
return; /* -ENODEV */
/* Clock modulation */
- if (!test_bit(X86_FEATURE_ACC, &c->x86_capability))
+ if (!test_bit(X86_FEATURE_ACC, c->x86_capability))
return; /* -ENODEV */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
diff -Nru a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
--- a/arch/i386/kernel/i387.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/i387.c Mon Apr 22 15:32:19 2002
@@ -31,13 +31,21 @@
* value at reset if we support XMM instructions and then
* remeber the current task has used the FPU.
*/
-void init_fpu(void)
+void init_fpu(struct task_struct *tsk)
{
- __asm__("fninit");
- if ( cpu_has_xmm )
- load_mxcsr(0x1f80);
-
- current->used_math = 1;
+ if (cpu_has_fxsr) {
+ memset(&tsk->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
+ tsk->thread.i387.fxsave.cwd = 0x37f;
+ if (cpu_has_xmm)
+ tsk->thread.i387.fxsave.mxcsr = 0x1f80;
+ } else {
+ memset(&tsk->thread.i387.fsave, 0, sizeof(struct i387_fsave_struct));
+ tsk->thread.i387.fsave.cwd = 0xffff037f;
+ tsk->thread.i387.fsave.swd = 0xffff0000;
+ tsk->thread.i387.fsave.twd = 0xffffffff;
+ tsk->thread.i387.fsave.fos = 0xffff0000;
+ }
+ tsk->used_math = 1;
}
/*
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/io_apic.c Mon Apr 22 15:32:19 2002
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
@@ -183,6 +184,86 @@
clear_IO_APIC_pin(apic, pin);
}
+static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
+{
+ unsigned long flags;
+
+ /*
+ * Only the first 8 bits are valid.
+ */
+ mask = mask << 24;
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __DO_ACTION(1, = mask, )
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+#if CONFIG_SMP
+
+typedef struct {
+ unsigned int cpu;
+ unsigned long timestamp;
+} ____cacheline_aligned irq_balance_t;
+
+static irq_balance_t irq_balance[NR_IRQS] __cacheline_aligned
+ = { [ 0 ... NR_IRQS-1 ] = { 1, 0 } };
+
+extern unsigned long irq_affinity [NR_IRQS];
+
+#endif
+
+#define IDLE_ENOUGH(cpu,now) \
+ (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1))
+
+#define IRQ_ALLOWED(cpu,allowed_mask) \
+ ((1 << cpu) & (allowed_mask))
+
+static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction)
+{
+ int search_idle = 1;
+ int cpu = curr_cpu;
+
+ goto inside;
+
+ do {
+ if (unlikely(cpu == curr_cpu))
+ search_idle = 0;
+inside:
+ if (direction == 1) {
+ cpu++;
+ if (cpu >= smp_num_cpus)
+ cpu = 0;
+ } else {
+ cpu--;
+ if (cpu == -1)
+ cpu = smp_num_cpus-1;
+ }
+ } while (!IRQ_ALLOWED(cpu,allowed_mask) ||
+ (search_idle && !IDLE_ENOUGH(cpu,now)));
+
+ return cpu;
+}
+
+static inline void balance_irq(int irq)
+{
+#if CONFIG_SMP
+ irq_balance_t *entry = irq_balance + irq;
+ unsigned long now = jiffies;
+
+ if (unlikely(entry->timestamp != now)) {
+ unsigned long allowed_mask;
+ int random_number;
+
+ rdtscl(random_number);
+ random_number &= 1;
+
+ allowed_mask = cpu_online_map & irq_affinity[irq];
+ entry->timestamp = now;
+ entry->cpu = move(entry->cpu, allowed_mask, now, random_number);
+ set_ioapic_affinity(irq, 1 << entry->cpu);
+ }
+#endif
+}
+
/*
* support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
* specific CPU-side IRQs.
@@ -672,8 +753,7 @@
}
/*
- * Set up the 8259A-master output pin as broadcast to all
- * CPUs.
+ * Set up the 8259A-master output pin:
*/
void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
{
@@ -1193,6 +1273,7 @@
*/
static void ack_edge_ioapic_irq(unsigned int irq)
{
+ balance_irq(irq);
if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
== (IRQ_PENDING | IRQ_DISABLED))
mask_IO_APIC_irq(irq);
@@ -1232,6 +1313,7 @@
unsigned long v;
int i;
+ balance_irq(irq);
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
@@ -1288,19 +1370,6 @@
static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
-static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
-{
- unsigned long flags;
- /*
- * Only the first 8 bits are valid.
- */
- mask = mask << 24;
-
- spin_lock_irqsave(&ioapic_lock, flags);
- __DO_ACTION(1, = mask, )
- spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
/*
* Level and edge triggered IO-APIC interrupts need different handling,
* so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -1590,6 +1659,7 @@
printk(KERN_INFO "...trying to set up timer as ExtINT IRQ...");
+ timer_ack = 0;
init_8259A(0);
make_8259A_irq(0);
apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c Mon Apr 22 15:32:18 2002
+++ b/arch/i386/kernel/irq.c Mon Apr 22 15:32:18 2002
@@ -1073,7 +1073,7 @@
static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
-static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
static int irq_affinity_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
diff -Nru a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
--- a/arch/i386/kernel/microcode.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/microcode.c Mon Apr 22 15:32:19 2002
@@ -338,7 +338,7 @@
return -EINVAL;
}
if ((len >> PAGE_SHIFT) > num_physpages) {
- printk(KERN_ERR "microcode: too much data (max %d pages)\n", num_physpages);
+ printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
return -EINVAL;
}
down_write(µcode_rwsem);
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/mpparse.c Mon Apr 22 15:32:19 2002
@@ -38,6 +38,8 @@
int apic_version [MAX_APICS];
int mp_bus_id_to_type [MAX_MP_BUSSES];
int mp_bus_id_to_node [MAX_MP_BUSSES];
+int mp_bus_id_to_local [MAX_MP_BUSSES];
+int quad_local_to_mp_bus_id [NR_CPUS/4][4];
int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
int mp_current_pci_id;
@@ -237,13 +239,17 @@
static void __init MP_bus_info (struct mpc_config_bus *m)
{
char str[7];
+ int quad;
memcpy(str, m->mpc_bustype, 6);
str[6] = 0;
if (clustered_apic_mode) {
- mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad;
- printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]);
+ quad = translation_table[mpc_record]->trans_quad;
+ mp_bus_id_to_node[m->mpc_busid] = quad;
+ mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
+ quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
+ printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad);
} else {
Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
}
@@ -320,13 +326,14 @@
static void __init MP_translation_info (struct mpc_config_translation *m)
{
- printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type,
- m->trans_quad, m->trans_global, m->trans_local);
+ printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);
if (mpc_record >= MAX_MPC_ENTRY)
printk("MAX_MPC_ENTRY exceeded!\n");
else
translation_table[mpc_record] = m; /* stash this for later */
+ if (m->trans_quad+1 > numnodes)
+ numnodes = m->trans_quad+1;
}
/*
@@ -491,10 +498,6 @@
}
}
++mpc_record;
- }
- if (clustered_apic_mode && nr_ioapics > 2) {
- /* don't initialise IO apics on secondary quads */
- nr_ioapics = 2;
}
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
diff -Nru a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
--- a/arch/i386/kernel/pci-pc.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/pci-pc.c Mon Apr 22 15:32:19 2002
@@ -1091,8 +1091,9 @@
*/
int pxb, reg;
u8 busno, suba, subb;
+#ifdef CONFIG_MULTIQUAD
int quad = BUS2QUAD(d->bus->number);
-
+#endif
printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
reg = 0xd0;
for(pxb=0; pxb<2; pxb++) {
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c Mon Apr 22 15:32:18 2002
+++ b/arch/i386/kernel/process.c Mon Apr 22 15:32:18 2002
@@ -142,6 +142,7 @@
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
+ irq_stat[smp_processor_id()].idle_timestamp = jiffies;
while (!need_resched())
idle();
schedule();
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/setup.c Mon Apr 22 15:32:19 2002
@@ -2153,6 +2153,11 @@
strcpy(c->x86_model_id, p);
#ifdef CONFIG_SMP
+ /* PGE CPUID bug: Pentium4 supports PGE, but seems to have SMP bugs.. */
+ if ( c->x86 == 15 )
+ clear_bit(X86_FEATURE_PGE, c->x86_capability);
+
+
if (test_bit(X86_FEATURE_HT, c->x86_capability)) {
extern int phys_proc_id[NR_CPUS];
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c Mon Apr 22 15:32:19 2002
+++ b/arch/i386/kernel/traps.c Mon Apr 22 15:32:19 2002
@@ -757,13 +757,12 @@
*/
asmlinkage void math_state_restore(struct pt_regs regs)
{
+ struct task_struct *tsk = current;
clts(); /* Allow maths ops (or we recurse) */
- if (current->used_math) {
- restore_fpu(current);
- } else {
- init_fpu();
- }
+ if (!tsk->used_math)
+ init_fpu(tsk);
+ restore_fpu(tsk);
set_thread_flag(TIF_USEDFPU); /* So we fnsave on switch_to() */
}
diff -Nru a/arch/ia64/Config.help b/arch/ia64/Config.help
--- a/arch/ia64/Config.help Mon Apr 22 15:32:19 2002
+++ b/arch/ia64/Config.help Mon Apr 22 15:32:19 2002
@@ -414,12 +414,18 @@
HP-simulator For the HP simulator
( ).
+ HP-zx1 For HP zx1 platforms.
SN1-simulator For the SGI SN1 simulator.
DIG-compliant For DIG ("Developer's Interface Guide") compliant
- system.
+ systems.
If you don't know what to do, choose "generic".
+CONFIG_IA64_HP_ZX1
+ Build a kernel that runs on HP zx1-based systems. This adds support
+ for the zx1 IOMMU and makes root bus bridges appear in PCI config space
+ (required for zx1 agpgart support).
+
CONFIG_IA64_PAGE_SIZE_4KB
This lets you select the page size of the kernel. For best IA-64
performance, a page size of 8KB or 16KB is recommended. For best
@@ -439,6 +445,32 @@
Select this option to build a kernel for an Itanium prototype system
with a B-step CPU. You have a B-step CPU if the "revision" field in
/proc/cpuinfo has a value in the range from 1 to 4.
+
+CONFIG_IA64_SGI_AUTOTEST
+ Build a kernel used for hardware validation. If you include the
+ keyword "autotest" on the boot command line, the kernel does NOT boot.
+ Instead, it starts all cpus and runs cache coherency tests instead.
+
+ If unsure, say N.
+
+CONFIG_IA64_SGI_SN_DEBUG
+ Turns on extra debugging code in the SGI SN (Scalable NUMA) platform
+ for IA64. Unless you are debugging problems on an SGI SN IA64 box,
+ say N.
+
+CONFIG_IA64_SGI_SN_SIM
+ If you are compiling a kernel that will run under SGI's IA64
+ simulator (Medusa) then say Y, otherwise say N.
+
+CONFIG_SERIAL_SGI_L1_PROTOCOL
+ Uses protocol mode instead of raw mode for the level 1 console on the
+ SGI SN (Scalable NUMA) platform for IA64. If you are compiling for
+ an SGI SN box then Y is the recommended value, otherwise say N.
+
+CONFIG_PCIBA
+ IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable
+ NUMA) platform for IA64. Unless you are compiling a kernel for an
+ SGI SN IA64 box, say N.
CONFIG_IA64_MCA
Say Y here to enable machine check support for IA-64. If you're
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile Mon Apr 22 15:32:18 2002
+++ b/arch/ia64/Makefile Mon Apr 22 15:32:18 2002
@@ -22,7 +22,7 @@
# -ffunction-sections
CFLAGS_KERNEL := -mconstant-gp
-GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
+GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
ifneq ($(GCC_VERSION),2)
CFLAGS += -frename-registers --param max-inline-insns=2000
@@ -33,16 +33,11 @@
endif
ifdef CONFIG_IA64_GENERIC
- CORE_FILES := arch/$(ARCH)/hp/hp.a \
- arch/$(ARCH)/sn/sn.o \
- arch/$(ARCH)/dig/dig.a \
- arch/$(ARCH)/sn/io/sgiio.o \
+ CORE_FILES := arch/$(ARCH)/hp/hp.o \
+ arch/$(ARCH)/dig/dig.a \
$(CORE_FILES)
SUBDIRS := arch/$(ARCH)/hp \
- arch/$(ARCH)/sn/sn1 \
- arch/$(ARCH)/sn \
arch/$(ARCH)/dig \
- arch/$(ARCH)/sn/io \
$(SUBDIRS)
else # !GENERIC
@@ -50,7 +45,16 @@
ifdef CONFIG_IA64_HP_SIM
SUBDIRS := arch/$(ARCH)/hp \
$(SUBDIRS)
- CORE_FILES := arch/$(ARCH)/hp/hp.a \
+ CORE_FILES := arch/$(ARCH)/hp/hp.o \
+ $(CORE_FILES)
+endif
+
+ifdef CONFIG_IA64_HP_ZX1
+ SUBDIRS := arch/$(ARCH)/hp \
+ arch/$(ARCH)/dig \
+ $(SUBDIRS)
+ CORE_FILES := arch/$(ARCH)/hp/hp.o \
+ arch/$(ARCH)/dig/dig.a \
$(CORE_FILES)
endif
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
--- a/arch/ia64/config.in Mon Apr 22 15:32:19 2002
+++ b/arch/ia64/config.in Mon Apr 22 15:32:19 2002
@@ -22,6 +22,7 @@
"generic CONFIG_IA64_GENERIC \
DIG-compliant CONFIG_IA64_DIG \
HP-simulator CONFIG_IA64_HP_SIM \
+ HP-zx1 CONFIG_IA64_HP_ZX1 \
SGI-SN1 CONFIG_IA64_SGI_SN1 \
SGI-SN2 CONFIG_IA64_SGI_SN2" generic
@@ -56,7 +57,7 @@
fi
fi
-if [ "$CONFIG_IA64_DIG" = "y" ]; then
+if [ "$CONFIG_IA64_GENERIC" = "y" ] || [ "$CONFIG_IA64_DIG" = "y" ] || [ "$CONFIG_IA64_HP_ZX1" = "y" ]; then
bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
define_bool CONFIG_PM y
fi
@@ -173,14 +174,7 @@
source net/ax25/Config.in
-mainmenu_option next_comment
-comment 'ISDN subsystem'
-
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
- source drivers/isdn/Config.in
-fi
-endmenu
+source drivers/isdn/Config.in
mainmenu_option next_comment
comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig Mon Apr 22 15:32:18 2002
+++ b/arch/ia64/defconfig Mon Apr 22 15:32:18 2002
@@ -23,7 +23,7 @@
# CONFIG_KMOD is not set
#
-# General setup
+# Processor type and features
#
CONFIG_IA64=y
# CONFIG_ISA is not set
@@ -32,21 +32,22 @@
# CONFIG_SBUS is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
CONFIG_ITANIUM=y
# CONFIG_MCKINLEY is not set
# CONFIG_IA64_GENERIC is not set
CONFIG_IA64_DIG=y
# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_HP_ZX1 is not set
# CONFIG_IA64_SGI_SN1 is not set
# CONFIG_IA64_SGI_SN2 is not set
# CONFIG_IA64_PAGE_SIZE_4KB is not set
# CONFIG_IA64_PAGE_SIZE_8KB is not set
CONFIG_IA64_PAGE_SIZE_16KB=y
# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
CONFIG_IA64_BRL_EMU=y
# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
CONFIG_IA64_L1_CACHE_SHIFT=6
@@ -60,15 +61,23 @@
CONFIG_EFI_VARS=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-CONFIG_ACPI_BUSMGR=y
-CONFIG_ACPI_SYS=y
-CONFIG_ACPI_CPU=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_AC=y
-CONFIG_ACPI_EC=y
-CONFIG_ACPI_CMBATT=y
-CONFIG_ACPI_THERMAL=y
+CONFIG_ACPI_FAN=m
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_THERMAL=m
+# CONFIG_ACPI_DEBUG is not set
CONFIG_PCI=y
CONFIG_PCI_NAMES=y
# CONFIG_HOTPLUG is not set
@@ -231,15 +240,13 @@
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_HPT34X_AUTODMA is not set
# CONFIG_BLK_DEV_HPT366 is not set
-CONFIG_BLK_DEV_PIIX=y
-# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC_ADMA is not set
@@ -254,7 +261,6 @@
# CONFIG_IDEDMA_IVB is not set
# CONFIG_IDEDMA_AUTO is not set
# CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
# CONFIG_BLK_DEV_ATARAID is not set
# CONFIG_BLK_DEV_ATARAID_PDC is not set
# CONFIG_BLK_DEV_ATARAID_HPT is not set
@@ -691,8 +697,6 @@
# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
-CONFIG_EFI_PARTITION=y
-# CONFIG_DEVFS_GUID is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
@@ -726,6 +730,7 @@
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
@@ -814,8 +819,9 @@
# USB Device Class drivers
#
# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
# CONFIG_USB_STORAGE is not set
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
@@ -825,13 +831,12 @@
# CONFIG_USB_STORAGE_HP8200e is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
#
# USB Human Interface Devices (HID)
#
CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
CONFIG_USB_HIDDEV=y
CONFIG_USB_KBD=m
CONFIG_USB_MOUSE=m
@@ -849,23 +854,24 @@
#
# USB Multimedia devices
#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
# CONFIG_USB_OV511 is not set
# CONFIG_USB_PWC is not set
# CONFIG_USB_SE401 is not set
# CONFIG_USB_STV680 is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_KONICAWC is not set
#
# USB Network adaptors
#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
# CONFIG_USB_CATC is not set
# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
#
@@ -897,9 +903,11 @@
# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
# CONFIG_USB_SERIAL_CYBERJACK is not set
# CONFIG_USB_SERIAL_XIRCOM is not set
# CONFIG_USB_SERIAL_OMNINET is not set
@@ -907,8 +915,10 @@
#
# USB Miscellaneous drivers
#
-# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
#
# Library routines
@@ -936,11 +946,3 @@
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_IA64_DEBUG_CMPXCHG is not set
# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KDB_OFF is not set
-
-#
-# Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Nru a/arch/ia64/dig/setup.c b/arch/ia64/dig/setup.c
--- a/arch/ia64/dig/setup.c Mon Apr 22 15:32:19 2002
+++ b/arch/ia64/dig/setup.c Mon Apr 22 15:32:19 2002
@@ -33,9 +33,6 @@
* is sufficient (the IDE driver will autodetect the drive geometry).
*/
char drive_info[4*16];
-extern int pcat_compat;
-
-unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */
void __init
dig_setup (char **cmdline_p)
@@ -85,16 +82,4 @@
void __init
dig_irq_init (void)
{
- if (pcat_compat) {
- /*
- * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
- * enabled.
- */
- printk("%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
- outb(0xff, 0xA1);
- outb(0xff, 0x21);
- } else {
- printk("%s: System doesn't have PC-AT compatible dual-8259 setup. "
- "Nothing to be done\n", __FUNCTION__);
- }
}
diff -Nru a/arch/ia64/hp/Config.in b/arch/ia64/hp/Config.in
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/Config.in Mon Apr 22 15:32:19 2002
@@ -0,0 +1,9 @@
+mainmenu_option next_comment
+comment 'HP Simulator drivers'
+
+bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
+bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
+if [ "$CONFIG_SCSI" != "n" ]; then
+ bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
+fi
+endmenu
diff -Nru a/arch/ia64/hp/Makefile b/arch/ia64/hp/Makefile
--- a/arch/ia64/hp/Makefile Mon Apr 22 15:32:19 2002
+++ b/arch/ia64/hp/Makefile Mon Apr 22 15:32:19 2002
@@ -1,23 +1,15 @@
-#
-# ia64/platform/hp/Makefile
-#
-# Copyright (C) 2002 Hewlett-Packard Co.
-# David Mosberger-Tang
-# Copyright (C) 1999 Silicon Graphics, Inc.
-# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
-#
+# arch/ia64/hp/Makefile
+# Copyright (c) 2002 Matthew Wilcox for Hewlett Packard
-all: hp.a
+ALL_SUB_DIRS := sim zx1 common
-O_TARGET := hp.a
+O_TARGET := hp.o
-obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o
-obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o
+subdir-$(CONFIG_IA64_GENERIC) += $(ALL_SUB_DIRS)
+subdir-$(CONFIG_IA64_HP_SIM) += sim
+subdir-$(CONFIG_IA64_HP_ZX1) += zx1 common
-obj-$(CONFIG_SIMETH) += simeth.o
-obj-$(CONFIG_SIM_SERIAL) += simserial.o
-obj-$(CONFIG_SCSI_SIM) += simscsi.o
-
-clean::
+SUB_DIRS := $(subdir-y)
+obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/hp/common/Makefile b/arch/ia64/hp/common/Makefile
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/common/Makefile Mon Apr 22 15:32:19 2002
@@ -0,0 +1,28 @@
+#
+# ia64/platform/hp/common/Makefile
+#
+# Copyright (C) 2002 Hewlett Packard
+# Copyright (C) Alex Williamson (alex_williamson@hp.com)
+#
+
+O_TARGET := common.o
+
+export-objs := sba_iommu.o
+
+obj-y := sba_iommu.o
+
+include $(TOPDIR)/Rules.make
+#
+# ia64/platform/hp/common/Makefile
+#
+# Copyright (C) 2002 Hewlett Packard
+# Copyright (C) Alex Williamson (alex_williamson@hp.com)
+#
+
+O_TARGET := common.o
+
+export-objs := sba_iommu.o
+
+obj-y := sba_iommu.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/common/sba_iommu.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,3700 @@
+/*
+** IA64 System Bus Adapter (SBA) I/O MMU manager
+**
+** (c) Copyright 2002 Alex Williamson
+** (c) Copyright 2002 Hewlett-Packard Company
+**
+** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code)
+** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+**
+** This module initializes the IOC (I/O Controller) found on HP
+** McKinley machines and their successors.
+**
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include /* ia64_get_itc() */
+#include
+#include /* PAGE_OFFSET */
+#include
+
+
+#define DRIVER_NAME "SBA"
+
+#ifndef CONFIG_IA64_HP_PROTO
+#define ALLOW_IOV_BYPASS
+#endif
+#define ENABLE_MARK_CLEAN
+/*
+** The number of debug flags is a clue - this code is fragile.
+*/
+#undef DEBUG_SBA_INIT
+#undef DEBUG_SBA_RUN
+#undef DEBUG_SBA_RUN_SG
+#undef DEBUG_SBA_RESOURCE
+#undef ASSERT_PDIR_SANITY
+#undef DEBUG_LARGE_SG_ENTRIES
+#undef DEBUG_BYPASS
+
+#define SBA_INLINE __inline__
+/* #define SBA_INLINE */
+
+#ifdef DEBUG_SBA_INIT
+#define DBG_INIT(x...) printk(x)
+#else
+#define DBG_INIT(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN
+#define DBG_RUN(x...) printk(x)
+#else
+#define DBG_RUN(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN_SG
+#define DBG_RUN_SG(x...) printk(x)
+#else
+#define DBG_RUN_SG(x...)
+#endif
+
+
+#ifdef DEBUG_SBA_RESOURCE
+#define DBG_RES(x...) printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+#ifdef DEBUG_BYPASS
+#define DBG_BYPASS(x...) printk(x)
+#else
+#define DBG_BYPASS(x...)
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+#define ASSERT(expr) \
+ if(!(expr)) { \
+ printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
+ panic(#expr); \
+ }
+#else
+#define ASSERT(expr)
+#endif
+
+#define KB(x) ((x) * 1024)
+#define MB(x) (KB (KB (x)))
+#define GB(x) (MB (KB (x)))
+
+/*
+** The number of pdir entries to "free" before issueing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#define DELAYED_RESOURCE_CNT 16
+
+#define DEFAULT_DMA_HINT_REG 0
+
+#define ZX1_FUNC_ID_VALUE ((PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP)
+#define ZX1_MC_ID ((PCI_DEVICE_ID_HP_ZX1_MC << 16) | PCI_VENDOR_ID_HP)
+
+#define SBA_FUNC_ID 0x0000 /* function id */
+#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+
+#define SBA_FUNC_SIZE 0x10000 /* SBA configuration function reg set */
+
+unsigned int __initdata zx1_func_offsets[] = {0x1000, 0x4000, 0x8000,
+ 0x9000, 0xa000, -1};
+
+#define SBA_IOC_OFFSET 0x1000
+
+#define MAX_IOC 1 /* we only have 1 for now*/
+
+#define IOC_IBASE 0x300 /* IO TLB */
+#define IOC_IMASK 0x308
+#define IOC_PCOM 0x310
+#define IOC_TCNFG 0x318
+#define IOC_PDIR_BASE 0x320
+
+#define IOC_IOVA_SPACE_BASE 0x40000000 /* IOVA ranges start at 1GB */
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** IOVP_SIZE could only be greater than PAGE_SIZE if we are
+** confident the drivers really only touch the next physical
+** page iff that driver instance owns it.
+*/
+#define IOVP_SIZE PAGE_SIZE
+#define IOVP_SHIFT PAGE_SHIFT
+#define IOVP_MASK PAGE_MASK
+
+struct ioc {
+ unsigned long ioc_hpa; /* I/O MMU base address */
+ char *res_map; /* resource map, bit == pdir entry */
+ u64 *pdir_base; /* physical base address */
+ unsigned long ibase; /* pdir IOV Space base */
+ unsigned long imask; /* pdir IOV Space mask */
+
+ unsigned long *res_hint; /* next avail IOVP - circular search */
+ spinlock_t res_lock;
+ unsigned long hint_mask_pdir; /* bits used for DMA hints */
+ unsigned int res_bitshift; /* from the RIGHT! */
+ unsigned int res_size; /* size of resource map in bytes */
+ unsigned int hint_shift_pdir;
+ unsigned long dma_mask;
+#if DELAYED_RESOURCE_CNT > 0
+ int saved_cnt;
+ struct sba_dma_pair {
+ dma_addr_t iova;
+ size_t size;
+ } saved[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef CONFIG_PROC_FS
+#define SBA_SEARCH_SAMPLE 0x100
+ unsigned long avg_search[SBA_SEARCH_SAMPLE];
+ unsigned long avg_idx; /* current index into avg_search */
+ unsigned long used_pages;
+ unsigned long msingle_calls;
+ unsigned long msingle_pages;
+ unsigned long msg_calls;
+ unsigned long msg_pages;
+ unsigned long usingle_calls;
+ unsigned long usingle_pages;
+ unsigned long usg_calls;
+ unsigned long usg_pages;
+#ifdef ALLOW_IOV_BYPASS
+ unsigned long msingle_bypass;
+ unsigned long usingle_bypass;
+ unsigned long msg_bypass;
+#endif
+#endif
+
+ /* STUFF We don't need in performance path */
+ unsigned int pdir_size; /* in bytes, determined by IOV Space size */
+};
+
+struct sba_device {
+ struct sba_device *next; /* list of SBA's in system */
+ const char *name;
+ unsigned long sba_hpa; /* base address */
+ spinlock_t sba_lock;
+ unsigned int flags; /* state/functionality enabled */
+ unsigned int hw_rev; /* HW revision of chip */
+
+ unsigned int num_ioc; /* number of on-board IOC's */
+ struct ioc ioc[MAX_IOC];
+};
+
+
+static struct sba_device *sba_list;
+static int sba_count;
+static int reserve_sba_gart = 1;
+
+#define sba_sg_iova(sg) (sg->address)
+#define sba_sg_len(sg) (sg->length)
+#define sba_sg_buffer(sg) (sg->orig_address)
+
+/* REVISIT - fix me for multiple SBAs/IOCs */
+#define GET_IOC(dev) (sba_list->ioc)
+#define SBA_SET_AGP(sba_dev) (sba_dev->flags |= 0x1)
+#define SBA_GET_AGP(sba_dev) (sba_dev->flags & 0x1)
+
+/*
+** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
+** (or rather not merge) DMA's into managable chunks.
+** On parisc, this is more of the software/tuning constraint
+** rather than the HW. I/O MMU allocation alogorithms can be
+** faster with smaller size is (to some degree).
+*/
+#define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE)
+
+/* Looks nice and keeps the compiler happy */
+#define SBA_DEV(d) ((struct sba_device *) (d))
+
+#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
+
+/************************************
+** SBA register read and write support
+**
+** BE WARNED: register writes are posted.
+** (ie follow writes which must reach HW with a read)
+**
+*/
+#define READ_REG(addr) __raw_readq(addr)
+#define WRITE_REG(val, addr) __raw_writeq(val, addr)
+
+#ifdef DEBUG_SBA_INIT
+
+/**
+ * sba_dump_tlb - debugging only - print IOMMU operating parameters
+ * @hpa: base address of the IOMMU
+ *
+ * Print the size/location of the IO MMU PDIR.
+ */
+static void
+sba_dump_tlb(char *hpa)
+{
+ DBG_INIT("IO TLB at 0x%p\n", (void *)hpa);
+ DBG_INIT("IOC_IBASE : %016lx\n", READ_REG(hpa+IOC_IBASE));
+ DBG_INIT("IOC_IMASK : %016lx\n", READ_REG(hpa+IOC_IMASK));
+ DBG_INIT("IOC_TCNFG : %016lx\n", READ_REG(hpa+IOC_TCNFG));
+ DBG_INIT("IOC_PDIR_BASE: %016lx\n", READ_REG(hpa+IOC_PDIR_BASE));
+ DBG_INIT("\n");
+}
+#endif
+
+
+#ifdef ASSERT_PDIR_SANITY
+
+/**
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ * @pide: pdir index.
+ *
+ * Print one entry of the IO MMU PDIR in human readable form.
+ */
+static void
+sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
+{
+ /* start printing from lowest pde in rval */
+ u64 *ptr = &(ioc->pdir_base[pide & ~(BITS_PER_LONG - 1)]);
+ unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
+ uint rcnt;
+
+ /* printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n", */
+ printk("SBA: %s rp %p bit %d rval 0x%lx\n",
+ msg, rptr, pide & (BITS_PER_LONG - 1), *rptr);
+
+ rcnt = 0;
+ while (rcnt < BITS_PER_LONG) {
+ printk("%s %2d %p %016Lx\n",
+ (rcnt == (pide & (BITS_PER_LONG - 1)))
+ ? " -->" : " ",
+ rcnt, ptr, *ptr );
+ rcnt++;
+ ptr++;
+ }
+ printk("%s", msg);
+}
+
+
+/**
+ * sba_check_pdir - debugging only - consistency checker
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ *
+ * Verify the resource map and pdir state is consistent
+ */
+static int
+sba_check_pdir(struct ioc *ioc, char *msg)
+{
+ u64 *rptr_end = (u64 *) &(ioc->res_map[ioc->res_size]);
+ u64 *rptr = (u64 *) ioc->res_map; /* resource map ptr */
+ u64 *pptr = ioc->pdir_base; /* pdir ptr */
+ uint pide = 0;
+
+ while (rptr < rptr_end) {
+ u64 rval;
+ int rcnt; /* number of bits we might check */
+
+ rval = *rptr;
+ rcnt = 64;
+
+ while (rcnt) {
+ /* Get last byte and highest bit from that */
+ u32 pde = ((u32)((*pptr >> (63)) & 0x1));
+ if ((rval & 0x1) ^ pde)
+ {
+ /*
+ ** BUMMER! -- res_map != pdir --
+ ** Dump rval and matching pdir entries
+ */
+ sba_dump_pdir_entry(ioc, msg, pide);
+ return(1);
+ }
+ rcnt--;
+ rval >>= 1; /* try the next bit */
+ pptr++;
+ pide++;
+ }
+ rptr++; /* look at next word of res_map */
+ }
+ /* It'd be nice if we always got here :^) */
+ return 0;
+}
+
+
+/**
+ * sba_dump_sg - debugging only - print Scatter-Gather list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: head of the SG list
+ * @nents: number of entries in SG list
+ *
+ * print the SG list so we can verify it's correct by hand.
+ */
+static void
+sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+ while (nents-- > 0) {
+ printk(" %d : %08lx/%05x %p\n",
+ nents,
+ (unsigned long) sba_sg_iova(startsg),
+ sba_sg_len(startsg),
+ sba_sg_buffer(startsg));
+ startsg++;
+ }
+}
+static void
+sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+ struct scatterlist *the_sg = startsg;
+ int the_nents = nents;
+
+ while (the_nents-- > 0) {
+ if (sba_sg_buffer(the_sg) == 0x0UL)
+ sba_dump_sg(NULL, startsg, nents);
+ the_sg++;
+ }
+}
+
+#endif /* ASSERT_PDIR_SANITY */
+
+
+
+
+/**************************************************************
+*
+* I/O Pdir Resource Management
+*
+* Bits set in the resource map are in use.
+* Each bit can represent a number of pages.
+* LSbs represent lower addresses (IOVA's).
+*
+***************************************************************/
+#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */
+
+/* Convert from IOVP to IOVA and vice versa. */
+#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir)))
+#define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase))
+
+/* FIXME : review these macros to verify correctness and usage */
+#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT)
+
+#define RESMAP_MASK(n) ~(~0UL << (n))
+#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1)
+
+
+/**
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @bits_wanted: number of entries we need.
+ *
+ * Find consecutive free bits in resource bitmap.
+ * Each bit represents one entry in the IO Pdir.
+ * Cool perf optimization: search for log2(size) bits at a time.
+ */
+static SBA_INLINE unsigned long
+sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
+{
+ unsigned long *res_ptr = ioc->res_hint;
+ unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
+ unsigned long pide = ~0UL;
+
+ ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
+ ASSERT(res_ptr < res_end);
+ if (bits_wanted > (BITS_PER_LONG/2)) {
+ /* Search word at a time - no mask needed */
+ for(; res_ptr < res_end; ++res_ptr) {
+ if (*res_ptr == 0) {
+ *res_ptr = RESMAP_MASK(bits_wanted);
+ pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+ pide <<= 3; /* convert to bit address */
+ break;
+ }
+ }
+ /* point to the next word on next pass */
+ res_ptr++;
+ ioc->res_bitshift = 0;
+ } else {
+ /*
+ ** Search the resource bit map on well-aligned values.
+ ** "o" is the alignment.
+ ** We need the alignment to invalidate I/O TLB using
+ ** SBA HW features in the unmap path.
+ */
+ unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT);
+ uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
+ unsigned long mask;
+
+ if (bitshiftcnt >= BITS_PER_LONG) {
+ bitshiftcnt = 0;
+ res_ptr++;
+ }
+ mask = RESMAP_MASK(bits_wanted) << bitshiftcnt;
+
+ DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
+ while(res_ptr < res_end)
+ {
+ DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr);
+ ASSERT(0 != mask);
+ if(0 == ((*res_ptr) & mask)) {
+ *res_ptr |= mask; /* mark resources busy! */
+ pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+ pide <<= 3; /* convert to bit address */
+ pide += bitshiftcnt;
+ break;
+ }
+ mask <<= o;
+ bitshiftcnt += o;
+ if (0 == mask) {
+ mask = RESMAP_MASK(bits_wanted);
+ bitshiftcnt=0;
+ res_ptr++;
+ }
+ }
+ /* look in the same word on the next pass */
+ ioc->res_bitshift = bitshiftcnt + bits_wanted;
+ }
+
+ /* wrapped ? */
+ if (res_end <= res_ptr) {
+ ioc->res_hint = (unsigned long *) ioc->res_map;
+ ioc->res_bitshift = 0;
+ } else {
+ ioc->res_hint = res_ptr;
+ }
+ return (pide);
+}
+
+
+/**
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @size: number of bytes to create a mapping for
+ *
+ * Given a size, find consecutive unmarked and then mark those bits in the
+ * resource bit map.
+ */
+static int
+sba_alloc_range(struct ioc *ioc, size_t size)
+{
+ unsigned int pages_needed = size >> IOVP_SHIFT;
+#ifdef CONFIG_PROC_FS
+ unsigned long itc_start = ia64_get_itc();
+#endif
+ unsigned long pide;
+
+ ASSERT(pages_needed);
+ ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+ ASSERT(pages_needed <= BITS_PER_LONG);
+ ASSERT(0 == (size & ~IOVP_MASK));
+
+ /*
+ ** "seek and ye shall find"...praying never hurts either...
+ */
+
+ pide = sba_search_bitmap(ioc, pages_needed);
+ if (pide >= (ioc->res_size << 3)) {
+ pide = sba_search_bitmap(ioc, pages_needed);
+ if (pide >= (ioc->res_size << 3))
+ panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
+ }
+
+#ifdef ASSERT_PDIR_SANITY
+ /* verify the first enable bit is clear */
+ if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) {
+ sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide);
+ }
+#endif
+
+ DBG_RES("%s(%x) %d -> %lx hint %x/%x\n",
+ __FUNCTION__, size, pages_needed, pide,
+ (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
+ ioc->res_bitshift );
+
+#ifdef CONFIG_PROC_FS
+ {
+ unsigned long itc_end = ia64_get_itc();
+ unsigned long tmp = itc_end - itc_start;
+ /* check for roll over */
+ itc_start = (itc_end < itc_start) ? -(tmp) : (tmp);
+ }
+ ioc->avg_search[ioc->avg_idx++] = itc_start;
+ ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1;
+
+ ioc->used_pages += pages_needed;
+#endif
+
+ return (pide);
+}
+
+
+/**
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO virtual address which was previously allocated.
+ * @size: number of bytes to create a mapping for
+ *
+ * clear bits in the ioc's resource map
+ */
+static SBA_INLINE void
+sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
+{
+ unsigned long iovp = SBA_IOVP(ioc, iova);
+ unsigned int pide = PDIR_INDEX(iovp);
+ unsigned int ridx = pide >> 3; /* convert bit to byte address */
+ unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]);
+
+ int bits_not_wanted = size >> IOVP_SHIFT;
+
+ /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
+ unsigned long m = RESMAP_MASK(bits_not_wanted) << (pide & (BITS_PER_LONG - 1));
+
+ DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
+ __FUNCTION__, (uint) iova, size,
+ bits_not_wanted, m, pide, res_ptr, *res_ptr);
+
+#ifdef CONFIG_PROC_FS
+ ioc->used_pages -= bits_not_wanted;
+#endif
+
+ ASSERT(m != 0);
+ ASSERT(bits_not_wanted);
+ ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+ ASSERT(bits_not_wanted <= BITS_PER_LONG);
+ ASSERT((*res_ptr & m) == m); /* verify same bits are set */
+ *res_ptr &= ~m;
+}
+
+
+/**************************************************************
+*
+* "Dynamic DMA Mapping" support (aka "Coherent I/O")
+*
+***************************************************************/
+
+#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir)
+
+
+/**
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr: pointer to IO PDIR entry
+ * @vba: Virtual CPU address of buffer to map
+ *
+ * SBA Mapping Routine
+ *
+ * Given a virtual address (vba, arg1) sba_io_pdir_entry()
+ * loads the I/O PDIR entry pointed to by pdir_ptr (arg0).
+ * Each IO Pdir entry consists of 8 bytes as shown below
+ * (LSB == bit 0):
+ *
+ * 63 40 11 7 0
+ * +-+---------------------+----------------------------------+----+--------+
+ * |V| U | PPN[39:12] | U | FF |
+ * +-+---------------------+----------------------------------+----+--------+
+ *
+ * V == Valid Bit
+ * U == Unused
+ * PPN == Physical Page Number
+ *
+ * The physical address fields are filled with the results of virt_to_phys()
+ * on the vba.
+ */
+
+#if 1
+#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL)
+#else
+void SBA_INLINE
+sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba)
+{
+ *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL);
+}
+#endif
+
+#ifdef ENABLE_MARK_CLEAN
+/**
+ * Since DMA is i-cache coherent, any (complete) pages that were written via
+ * DMA can be marked as "clean" so that update_mmu_cache() doesn't have to
+ * flush them when they get mapped into an executable vm-area.
+ */
+static void
+mark_clean (void *addr, size_t size)
+{
+ unsigned long pg_addr, end;
+
+ pg_addr = PAGE_ALIGN((unsigned long) addr);
+ end = (unsigned long) addr + size;
+ while (pg_addr + PAGE_SIZE <= end) {
+ struct page *page = virt_to_page(pg_addr);
+ set_bit(PG_arch_1, &page->flags);
+ pg_addr += PAGE_SIZE;
+ }
+}
+#endif
+
+/**
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO Virtual Address mapped earlier
+ * @byte_cnt: number of bytes this mapping covers.
+ *
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * corresponding IO TLB entry. The PCOM (Purge Command Register)
+ * is to purge stale entries in the IO TLB when unmapping entries.
+ *
+ * The PCOM register supports purging of multiple pages, with a minium
+ * of 1 page and a maximum of 2GB. Hardware requires the address be
+ * aligned to the size of the range being purged. The size of the range
+ * must be a power of 2. The "Cool perf optimization" in the
+ * allocation routine helps keep that true.
+ */
+static SBA_INLINE void
+sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
+{
+ u32 iovp = (u32) SBA_IOVP(ioc,iova);
+
+ int off = PDIR_INDEX(iovp);
+
+ /* Must be non-zero and rounded up */
+ ASSERT(byte_cnt > 0);
+ ASSERT(0 == (byte_cnt & ~IOVP_MASK));
+
+#ifdef ASSERT_PDIR_SANITY
+ /* Assert first pdir entry is set */
+ if (!(ioc->pdir_base[off] >> 60)) {
+ sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp));
+ }
+#endif
+
+ if (byte_cnt <= IOVP_SIZE)
+ {
+ ASSERT(off < ioc->pdir_size);
+
+ iovp |= IOVP_SHIFT; /* set "size" field for PCOM */
+
+ /*
+ ** clear I/O PDIR entry "valid" bit
+ ** Do NOT clear the rest - save it for debugging.
+ ** We should only clear bits that have previously
+ ** been enabled.
+ */
+ ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+ } else {
+ u32 t = get_order(byte_cnt) + PAGE_SHIFT;
+
+ iovp |= t;
+ ASSERT(t <= 31); /* 2GB! Max value of "size" field */
+
+ do {
+ /* verify this pdir entry is enabled */
+ ASSERT(ioc->pdir_base[off] >> 63);
+ /* clear I/O Pdir entry "valid" bit first */
+ ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+ off++;
+ byte_cnt -= IOVP_SIZE;
+ } while (byte_cnt > 0);
+ }
+
+ WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+}
+
+/**
+ * sba_map_single - map one buffer and return IOVA for DMA
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @addr: driver buffer to map.
+ * @size: number of bytes to map in driver buffer.
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+dma_addr_t
+sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+{
+ struct ioc *ioc;
+ unsigned long flags;
+ dma_addr_t iovp;
+ dma_addr_t offset;
+ u64 *pdir_start;
+ int pide;
+#ifdef ALLOW_IOV_BYPASS
+ unsigned long pci_addr = virt_to_phys(addr);
+#endif
+
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+ /*
+ ** Check if the PCI device can DMA to ptr... if so, just return ptr
+ */
+ if ((pci_addr & ~dev->dma_mask) == 0) {
+ /*
+ ** Device is bit capable of DMA'ing to the buffer...
+ ** just return the PCI address of ptr
+ */
+#ifdef CONFIG_PROC_FS
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ ioc->msingle_bypass++;
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+ DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
+ dev->dma_mask, pci_addr);
+ return pci_addr;
+ }
+#endif
+
+ ASSERT(size > 0);
+ ASSERT(size <= DMA_CHUNK_SIZE);
+
+ /* save offset bits */
+ offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
+
+ /* round up to nearest IOVP_SIZE */
+ size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
+
+ spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef ASSERT_PDIR_SANITY
+ if (sba_check_pdir(ioc,"Check before sba_map_single()"))
+ panic("Sanity check failed");
+#endif
+
+#ifdef CONFIG_PROC_FS
+ ioc->msingle_calls++;
+ ioc->msingle_pages += size >> IOVP_SHIFT;
+#endif
+ pide = sba_alloc_range(ioc, size);
+ iovp = (dma_addr_t) pide << IOVP_SHIFT;
+
+ DBG_RUN("%s() 0x%p -> 0x%lx\n",
+ __FUNCTION__, addr, (long) iovp | offset);
+
+ pdir_start = &(ioc->pdir_base[pide]);
+
+ while (size > 0) {
+ ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
+ sba_io_pdir_entry(pdir_start, (unsigned long) addr);
+
+ DBG_RUN(" pdir 0x%p %lx\n", pdir_start, *pdir_start);
+
+ addr += IOVP_SIZE;
+ size -= IOVP_SIZE;
+ pdir_start++;
+ }
+ /* form complete address */
+#ifdef ASSERT_PDIR_SANITY
+ sba_check_pdir(ioc,"Check after sba_map_single()");
+#endif
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+ return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
+}
+
+/**
+ * sba_unmap_single - unmap one IOVA and free resources
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @iova: IOVA of driver buffer previously mapped.
+ * @size: number of bytes mapped in driver buffer.
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size,
+ int direction)
+{
+ struct ioc *ioc;
+#if DELAYED_RESOURCE_CNT > 0
+ struct sba_dma_pair *d;
+#endif
+ unsigned long flags;
+ dma_addr_t offset;
+
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+ if ((iova & ioc->imask) != ioc->ibase) {
+ /*
+ ** Address does not fall w/in IOVA, must be bypassing
+ */
+#ifdef CONFIG_PROC_FS
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ ioc->usingle_bypass++;
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+ DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova);
+
+#ifdef ENABLE_MARK_CLEAN
+ if (direction == PCI_DMA_FROMDEVICE) {
+ mark_clean(phys_to_virt(iova), size);
+ }
+#endif
+ return;
+ }
+#endif
+ offset = iova & ~IOVP_MASK;
+
+ DBG_RUN("%s() iovp 0x%lx/%x\n",
+ __FUNCTION__, (long) iova, size);
+
+ iova ^= offset; /* clear offset bits */
+ size += offset;
+ size = ROUNDUP(size, IOVP_SIZE);
+
+ spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef CONFIG_PROC_FS
+ ioc->usingle_calls++;
+ ioc->usingle_pages += size >> IOVP_SHIFT;
+#endif
+
+#if DELAYED_RESOURCE_CNT > 0
+ d = &(ioc->saved[ioc->saved_cnt]);
+ d->iova = iova;
+ d->size = size;
+ if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+ int cnt = ioc->saved_cnt;
+ while (cnt--) {
+ sba_mark_invalid(ioc, d->iova, d->size);
+ sba_free_range(ioc, d->iova, d->size);
+ d--;
+ }
+ ioc->saved_cnt = 0;
+ READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
+ }
+#else /* DELAYED_RESOURCE_CNT == 0 */
+ sba_mark_invalid(ioc, iova, size);
+ sba_free_range(ioc, iova, size);
+ READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
+#endif /* DELAYED_RESOURCE_CNT == 0 */
+#ifdef ENABLE_MARK_CLEAN
+ if (direction == PCI_DMA_FROMDEVICE) {
+ u32 iovp = (u32) SBA_IOVP(ioc,iova);
+ int off = PDIR_INDEX(iovp);
+ void *addr;
+
+ if (size <= IOVP_SIZE) {
+ addr = phys_to_virt(ioc->pdir_base[off] &
+ ~0xE000000000000FFFULL);
+ mark_clean(addr, size);
+ } else {
+ size_t byte_cnt = size;
+
+ do {
+ addr = phys_to_virt(ioc->pdir_base[off] &
+ ~0xE000000000000FFFULL);
+ mark_clean(addr, min(byte_cnt, IOVP_SIZE));
+ off++;
+ byte_cnt -= IOVP_SIZE;
+
+ } while (byte_cnt > 0);
+ }
+ }
+#endif
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+ /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
+ ** For Astro based systems this isn't a big deal WRT performance.
+ ** As long as 2.4 kernels copyin/copyout data from/to userspace,
+ ** we don't need the syncdma. The issue here is I/O MMU cachelines
+ ** are *not* coherent in all cases. May be hwrev dependent.
+ ** Need to investigate more.
+ asm volatile("syncdma");
+ */
+}
+
+
+/**
+ * sba_alloc_consistent - allocate/map shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size: number of bytes mapped in driver buffer.
+ * @dma_handle: IOVA of new buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void *
+sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+ void *ret;
+
+ if (!hwdev) {
+ /* only support PCI */
+ *dma_handle = 0;
+ return 0;
+ }
+
+ ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
+
+ if (ret) {
+ memset(ret, 0, size);
+ *dma_handle = sba_map_single(hwdev, ret, size, 0);
+ }
+
+ return ret;
+}
+
+
+/**
+ * sba_free_consistent - free/unmap shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size: number of bytes mapped in driver buffer.
+ * @vaddr: virtual address IOVA of "consistent" buffer.
+ * @dma_handler: IO virtual address of "consistent" buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ sba_unmap_single(hwdev, dma_handle, size, 0);
+ free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x1UL
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+int dump_run_sg = 0;
+#endif
+
+
+/**
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
+ */
+
+static SBA_INLINE int
+sba_fill_pdir(
+ struct ioc *ioc,
+ struct scatterlist *startsg,
+ int nents)
+{
+ struct scatterlist *dma_sg = startsg; /* pointer to current DMA */
+ int n_mappings = 0;
+ u64 *pdirp = 0;
+ unsigned long dma_offset = 0;
+
+ dma_sg--;
+ while (nents-- > 0) {
+ int cnt = sba_sg_len(startsg);
+ sba_sg_len(startsg) = 0;
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+ if (dump_run_sg)
+ printk(" %2d : %08lx/%05x %p\n",
+ nents,
+ (unsigned long) sba_sg_iova(startsg), cnt,
+ sba_sg_buffer(startsg)
+ );
+#else
+ DBG_RUN_SG(" %d : %08lx/%05x %p\n",
+ nents,
+ (unsigned long) sba_sg_iova(startsg), cnt,
+ sba_sg_buffer(startsg)
+ );
+#endif
+ /*
+ ** Look for the start of a new DMA stream
+ */
+ if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
+ u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+ dma_offset = (unsigned long) pide & ~IOVP_MASK;
+ sba_sg_iova(startsg) = 0;
+ dma_sg++;
+ sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+ pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+ n_mappings++;
+ }
+
+ /*
+ ** Look for a VCONTIG chunk
+ */
+ if (cnt) {
+ unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+ ASSERT(pdirp);
+
+ /* Since multiple Vcontig blocks could make up
+ ** one DMA stream, *add* cnt to dma_len.
+ */
+ sba_sg_len(dma_sg) += cnt;
+ cnt += dma_offset;
+ dma_offset=0; /* only want offset on first chunk */
+ cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+ ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+ do {
+ sba_io_pdir_entry(pdirp, vaddr);
+ vaddr += IOVP_SIZE;
+ cnt -= IOVP_SIZE;
+ pdirp++;
+ } while (cnt > 0);
+ }
+ startsg++;
+ }
+#ifdef DEBUG_LARGE_SG_ENTRIES
+ dump_run_sg = 0;
+#endif
+ return(n_mappings);
+}
+
+
+/*
+** Two address ranges are DMA contiguous *iff* "end of prev" and
+** "start of next" are both on a page boundry.
+**
+** (shift left is a quick trick to mask off upper bits)
+*/
+#define DMA_CONTIG(__X, __Y) \
+ (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
+static SBA_INLINE int
+sba_coalesce_chunks( struct ioc *ioc,
+ struct scatterlist *startsg,
+ int nents)
+{
+ struct scatterlist *vcontig_sg; /* VCONTIG chunk head */
+ unsigned long vcontig_len; /* len of VCONTIG chunk */
+ unsigned long vcontig_end;
+ struct scatterlist *dma_sg; /* next DMA stream head */
+ unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+ int n_mappings = 0;
+
+ while (nents > 0) {
+ unsigned long vaddr = (unsigned long) (startsg->address);
+
+ /*
+ ** Prepare for first/next DMA stream
+ */
+ dma_sg = vcontig_sg = startsg;
+ dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+ vcontig_end += vaddr;
+ dma_offset = vaddr & ~IOVP_MASK;
+
+ /* PARANOID: clear entries */
+ sba_sg_buffer(startsg) = sba_sg_iova(startsg);
+ sba_sg_iova(startsg) = 0;
+ sba_sg_len(startsg) = 0;
+
+ /*
+ ** This loop terminates one iteration "early" since
+ ** it's always looking one "ahead".
+ */
+ while (--nents > 0) {
+ unsigned long vaddr; /* tmp */
+
+ startsg++;
+
+ /* catch brokenness in SCSI layer */
+ ASSERT(startsg->length <= DMA_CHUNK_SIZE);
+
+ /*
+ ** First make sure current dma stream won't
+ ** exceed DMA_CHUNK_SIZE if we coalesce the
+ ** next entry.
+ */
+ if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
+ break;
+
+ /*
+ ** Then look for virtually contiguous blocks.
+ **
+ ** append the next transaction?
+ */
+ vaddr = (unsigned long) sba_sg_iova(startsg);
+ if (vcontig_end == vaddr)
+ {
+ vcontig_len += sba_sg_len(startsg);
+ vcontig_end += sba_sg_len(startsg);
+ dma_len += sba_sg_len(startsg);
+ sba_sg_buffer(startsg) = (char *)vaddr;
+ sba_sg_iova(startsg) = 0;
+ sba_sg_len(startsg) = 0;
+ continue;
+ }
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+ dump_run_sg = (vcontig_len > IOVP_SIZE);
+#endif
+
+ /*
+ ** Not virtually contigous.
+ ** Terminate prev chunk.
+ ** Start a new chunk.
+ **
+ ** Once we start a new VCONTIG chunk, dma_offset
+ ** can't change. And we need the offset from the first
+ ** chunk - not the last one. Ergo Successive chunks
+ ** must start on page boundaries and dove tail
+ ** with it's predecessor.
+ */
+ sba_sg_len(vcontig_sg) = vcontig_len;
+
+ vcontig_sg = startsg;
+ vcontig_len = sba_sg_len(startsg);
+
+ /*
+ ** 3) do the entries end/start on page boundaries?
+ ** Don't update vcontig_end until we've checked.
+ */
+ if (DMA_CONTIG(vcontig_end, vaddr))
+ {
+ vcontig_end = vcontig_len + vaddr;
+ dma_len += vcontig_len;
+ sba_sg_buffer(startsg) = (char *)vaddr;
+ sba_sg_iova(startsg) = 0;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ /*
+ ** End of DMA Stream
+ ** Terminate last VCONTIG block.
+ ** Allocate space for DMA stream.
+ */
+ sba_sg_len(vcontig_sg) = vcontig_len;
+ dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+ ASSERT(dma_len <= DMA_CHUNK_SIZE);
+ sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG
+ | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
+ | dma_offset);
+ n_mappings++;
+ }
+
+ return n_mappings;
+}
+
+
+/**
+ * sba_map_sg - map Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist: array of buffer/length pairs
+ * @nents: number of entries in list
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
+ int direction)
+{
+ struct ioc *ioc;
+ int coalesced, filled = 0;
+ unsigned long flags;
+#ifdef ALLOW_IOV_BYPASS
+ struct scatterlist *sg;
+#endif
+
+ DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+ if (dev->dma_mask >= ioc->dma_mask) {
+ for (sg = sglist ; filled < nents ; filled++, sg++){
+ sba_sg_buffer(sg) = sba_sg_iova(sg);
+ sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+ }
+#ifdef CONFIG_PROC_FS
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ ioc->msg_bypass++;
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+ return filled;
+ }
+#endif
+ /* Fast path single entry scatterlists. */
+ if (nents == 1) {
+ sba_sg_buffer(sglist) = sba_sg_iova(sglist);
+ sba_sg_iova(sglist) = (char *)sba_map_single(dev,
+ sba_sg_buffer(sglist),
+ sba_sg_len(sglist), direction);
+#ifdef CONFIG_PROC_FS
+ /*
+ ** Should probably do some stats counting, but trying to
+ ** be precise quickly starts wasting CPU time.
+ */
+#endif
+ return 1;
+ }
+
+ spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef ASSERT_PDIR_SANITY
+ if (sba_check_pdir(ioc,"Check before sba_map_sg()"))
+ {
+ sba_dump_sg(ioc, sglist, nents);
+ panic("Check before sba_map_sg()");
+ }
+#endif
+
+#ifdef CONFIG_PROC_FS
+ ioc->msg_calls++;
+#endif
+
+ /*
+ ** First coalesce the chunks and allocate I/O pdir space
+ **
+ ** If this is one DMA stream, we can properly map using the
+ ** correct virtual address associated with each DMA page.
+ ** w/o this association, we wouldn't have coherent DMA!
+ ** Access to the virtual address is what forces a two pass algorithm.
+ */
+ coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+
+ /*
+ ** Program the I/O Pdir
+ **
+ ** map the virtual addresses to the I/O Pdir
+ ** o dma_address will contain the pdir index
+ ** o dma_len will contain the number of bytes to map
+ ** o address contains the virtual address.
+ */
+ filled = sba_fill_pdir(ioc, sglist, nents);
+
+#ifdef ASSERT_PDIR_SANITY
+ if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
+ {
+ sba_dump_sg(ioc, sglist, nents);
+ panic("Check after sba_map_sg()\n");
+ }
+#endif
+
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+ ASSERT(coalesced == filled);
+ DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+
+ return filled;
+}
+
+
+/**
+ * sba_unmap_sg - unmap Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist: array of buffer/length pairs
+ * @nents: number of entries in list
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
+ int direction)
+{
+ struct ioc *ioc;
+#ifdef ASSERT_PDIR_SANITY
+ unsigned long flags;
+#endif
+
+ DBG_RUN_SG("%s() START %d entries, %p,%x\n",
+ __FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef CONFIG_PROC_FS
+ ioc->usg_calls++;
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ sba_check_pdir(ioc,"Check before sba_unmap_sg()");
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+ while (sba_sg_len(sglist) && nents--) {
+
+ sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
+ sba_sg_len(sglist), direction);
+#ifdef CONFIG_PROC_FS
+ /*
+ ** This leaves inconsistent data in the stats, but we can't
+ ** tell which sg lists were mapped by map_single and which
+ ** were coalesced to a single entry. The stats are fun,
+ ** but speed is more important.
+ */
+ ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+#endif
+ ++sglist;
+ }
+
+ DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents);
+
+#ifdef ASSERT_PDIR_SANITY
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ sba_check_pdir(ioc,"Check after sba_unmap_sg()");
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+}
+
+unsigned long
+sba_dma_address (struct scatterlist *sg)
+{
+ return ((unsigned long)sba_sg_iova(sg));
+}
+
+/**************************************************************
+*
+* Initialization and claim
+*
+***************************************************************/
+
+
+static void
+sba_ioc_init(struct sba_device *sba_dev, struct ioc *ioc, int ioc_num)
+{
+ u32 iova_space_size, iova_space_mask;
+ void * pdir_base;
+ int pdir_size, iov_order, tcnfg;
+
+ /*
+ ** Firmware programs the maximum IOV space size into the imask reg
+ */
+ iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
+#ifdef CONFIG_IA64_HP_PROTO
+ if (!iova_space_size)
+ iova_space_size = GB(1);
+#endif
+
+ /*
+ ** iov_order is always based on a 1GB IOVA space since we want to
+ ** turn on the other half for AGP GART.
+ */
+ iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
+ ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+
+ DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits) PDIR size 0x%0x\n",
+ __FUNCTION__, ioc->ioc_hpa, iova_space_size>>20,
+ iov_order + PAGE_SHIFT, ioc->pdir_size);
+
+ /* FIXME : DMA HINTs not used */
+ ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
+ ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
+
+ ioc->pdir_base =
+ pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
+ if (NULL == pdir_base)
+ {
+ panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
+ }
+ memset(pdir_base, 0, pdir_size);
+
+ DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
+ __FUNCTION__, pdir_base, pdir_size,
+ ioc->hint_shift_pdir, ioc->hint_mask_pdir);
+
+ ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
+ WRITE_REG(virt_to_phys(pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
+
+ DBG_INIT(" base %p\n", pdir_base);
+
+ /* build IMASK for IOC and Elroy */
+ iova_space_mask = 0xffffffff;
+ iova_space_mask <<= (iov_order + PAGE_SHIFT);
+
+#ifdef CONFIG_IA64_HP_PROTO
+ /*
+ ** REVISIT - this is a kludge, but we won't be supporting anything but
+ ** zx1 2.0 or greater for real. When fw is in shape, ibase will
+ ** be preprogrammed w/ the IOVA hole base and imask will give us
+ ** the size.
+ */
+ if ((sba_dev->hw_rev & 0xFF) < 0x20) {
+ DBG_INIT("%s() Found SBA rev < 2.0, setting IOVA base to 0. This device will not be supported in the future.\n", __FUNCTION__);
+ ioc->ibase = 0x0;
+ } else
+#endif
+ ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & 0xFFFFFFFEUL;
+
+ ioc->imask = iova_space_mask; /* save it */
+
+ DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
+ __FUNCTION__, ioc->ibase, ioc->imask);
+
+ /*
+ ** FIXME: Hint registers are programmed with default hint
+ ** values during boot, so hints should be sane even if we
+ ** can't reprogram them the way drivers want.
+ */
+
+ WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
+
+ /*
+ ** Setting the upper bits makes checking for bypass addresses
+ ** a little faster later on.
+ */
+ ioc->imask |= 0xFFFFFFFF00000000UL;
+
+ /* Set I/O PDIR Page size to system page size */
+ switch (PAGE_SHIFT) {
+ case 12: /* 4K */
+ tcnfg = 0;
+ break;
+ case 13: /* 8K */
+ tcnfg = 1;
+ break;
+ case 14: /* 16K */
+ tcnfg = 2;
+ break;
+ case 16: /* 64K */
+ tcnfg = 3;
+ break;
+ }
+ WRITE_REG(tcnfg, ioc->ioc_hpa+IOC_TCNFG);
+
+ /*
+ ** Program the IOC's ibase and enable IOVA translation
+ ** Bit zero == enable bit.
+ */
+ WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa+IOC_IBASE);
+
+ /*
+ ** Clear I/O TLB of any possible entries.
+ ** (Yes. This is a bit paranoid...but so what)
+ */
+ WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM);
+
+ /*
+ ** If an AGP device is present, only use half of the IOV space
+ ** for PCI DMA. Unfortunately we can't know ahead of time
+ ** whether GART support will actually be used, for now we
+ ** can just key on an AGP device found in the system.
+ ** We program the next pdir index after we stop w/ a key for
+ ** the GART code to handshake on.
+ */
+ if (SBA_GET_AGP(sba_dev)) {
+ DBG_INIT("%s() AGP Device found, reserving 512MB for GART support\n", __FUNCTION__);
+ ioc->pdir_size /= 2;
+ ((u64 *)pdir_base)[PDIR_INDEX(iova_space_size/2)] = 0x0000badbadc0ffeeULL;
+ }
+
+ DBG_INIT("%s() DONE\n", __FUNCTION__);
+}
+
+
+
+/**************************************************************************
+**
+** SBA initialization code (HW and SW)
+**
+** o identify SBA chip itself
+** o FIXME: initialize DMA hints for reasonable defaults
+**
+**************************************************************************/
+
+static void
+sba_hw_init(struct sba_device *sba_dev)
+{
+ int i;
+ int num_ioc;
+ u64 dma_mask;
+ u32 func_id;
+
+ /*
+ ** Identify the SBA so we can set the dma_mask. We can make a virtual
+ ** dma_mask of the memory subsystem such that devices not implmenting
+ ** a full 64bit mask might still be able to bypass efficiently.
+ */
+ func_id = READ_REG(sba_dev->sba_hpa + SBA_FUNC_ID);
+
+ if (func_id == ZX1_FUNC_ID_VALUE) {
+ dma_mask = 0xFFFFFFFFFFUL;
+ } else {
+ dma_mask = 0xFFFFFFFFFFFFFFFFUL;
+ }
+
+ DBG_INIT("%s(): ioc->dma_mask == 0x%lx\n", __FUNCTION__, dma_mask);
+
+ /*
+ ** Leaving in the multiple ioc code from parisc for the future,
+ ** currently there are no muli-ioc mckinley sbas
+ */
+ sba_dev->ioc[0].ioc_hpa = SBA_IOC_OFFSET;
+ num_ioc = 1;
+
+ sba_dev->num_ioc = num_ioc;
+ for (i = 0; i < num_ioc; i++) {
+ sba_dev->ioc[i].dma_mask = dma_mask;
+ sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa;
+ sba_ioc_init(sba_dev, &(sba_dev->ioc[i]), i);
+ }
+}
+
+static void
+sba_common_init(struct sba_device *sba_dev)
+{
+ int i;
+
+ /* add this one to the head of the list (order doesn't matter)
+ ** This will be useful for debugging - especially if we get coredumps
+ */
+ sba_dev->next = sba_list;
+ sba_list = sba_dev;
+ sba_count++;
+
+ for(i=0; i< sba_dev->num_ioc; i++) {
+ int res_size;
+
+ /* resource map size dictated by pdir_size */
+ res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
+ res_size >>= 3; /* convert bit count to byte count */
+ DBG_INIT("%s() res_size 0x%x\n",
+ __FUNCTION__, res_size);
+
+ sba_dev->ioc[i].res_size = res_size;
+ sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
+
+ if (NULL == sba_dev->ioc[i].res_map)
+ {
+ panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ );
+ }
+
+ memset(sba_dev->ioc[i].res_map, 0, res_size);
+ /* next available IOVP - circular search */
+ if ((sba_dev->hw_rev & 0xFF) >= 0x20) {
+ sba_dev->ioc[i].res_hint = (unsigned long *)
+ sba_dev->ioc[i].res_map;
+ } else {
+ u64 reserved_iov;
+
+ /* Yet another 1.x hack */
+ printk("zx1 1.x: Starting resource hint offset into IOV space to avoid initial zero value IOVA\n");
+ sba_dev->ioc[i].res_hint = (unsigned long *)
+ &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]);
+
+ sba_dev->ioc[i].res_map[0] = 0x1;
+ sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
+
+ for (reserved_iov = 0xA0000 ; reserved_iov < 0xC0000 ; reserved_iov += IOVP_SIZE) {
+ u64 *res_ptr = sba_dev->ioc[i].res_map;
+ int index = PDIR_INDEX(reserved_iov);
+ int res_word;
+ u64 mask;
+
+ res_word = (int)(index / BITS_PER_LONG);
+ mask = 0x1UL << (index - (res_word * BITS_PER_LONG));
+ res_ptr[res_word] |= mask;
+ sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (0x80000000000000FFULL | reserved_iov);
+
+ }
+ }
+
+#ifdef ASSERT_PDIR_SANITY
+ /* Mark first bit busy - ie no IOVA 0 */
+ sba_dev->ioc[i].res_map[0] = 0x1;
+ sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
+#endif
+
+ DBG_INIT("%s() %d res_map %x %p\n", __FUNCTION__,
+ i, res_size, (void *)sba_dev->ioc[i].res_map);
+ }
+
+ sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;
+}
+
+#ifdef CONFIG_PROC_FS
+static int sba_proc_info(char *buf, char **start, off_t offset, int len)
+{
+ struct sba_device *sba_dev = sba_list;
+ struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
+ int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
+ unsigned long i = 0, avg = 0, min, max;
+
+ sprintf(buf, "%s rev %d.%d\n",
+ "Hewlett Packard zx1 SBA",
+ ((sba_dev->hw_rev >> 4) & 0xF),
+ (sba_dev->hw_rev & 0xF)
+ );
+ sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n",
+ buf,
+ (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+ total_pages);
+
+ sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf,
+ total_pages - ioc->used_pages, ioc->used_pages,
+ (int) (ioc->used_pages * 100 / total_pages));
+
+ sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
+ buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
+
+ min = max = ioc->avg_search[0];
+ for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
+ avg += ioc->avg_search[i];
+ if (ioc->avg_search[i] > max) max = ioc->avg_search[i];
+ if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
+ }
+ avg /= SBA_SEARCH_SAMPLE;
+ sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+ buf, min, avg, max);
+
+ sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->msingle_calls, ioc->msingle_pages,
+ (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+#ifdef ALLOW_IOV_BYPASS
+ sprintf(buf, "%spci_map_single(): %12ld bypasses\n",
+ buf, ioc->msingle_bypass);
+#endif
+
+ sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->usingle_calls, ioc->usingle_pages,
+ (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls));
+#ifdef ALLOW_IOV_BYPASS
+ sprintf(buf, "%spci_unmap_single: %12ld bypasses\n",
+ buf, ioc->usingle_bypass);
+#endif
+
+ sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->msg_calls, ioc->msg_pages,
+ (int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
+#ifdef ALLOW_IOV_BYPASS
+ sprintf(buf, "%spci_map_sg() : %12ld bypasses\n",
+ buf, ioc->msg_bypass);
+#endif
+
+ sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->usg_calls, ioc->usg_pages,
+ (int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+
+ return strlen(buf);
+}
+
+static int
+sba_resource_map(char *buf, char **start, off_t offset, int len)
+{
+ struct ioc *ioc = sba_list->ioc; /* FIXME: Multi-IOC support! */
+ unsigned int *res_ptr = (unsigned int *)ioc->res_map;
+ int i;
+
+ buf[0] = '\0';
+ for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
+ if ((i & 7) == 0)
+ strcat(buf,"\n ");
+ sprintf(buf, "%s %08x", buf, *res_ptr);
+ }
+ strcat(buf, "\n");
+
+ return strlen(buf);
+}
+#endif
+
+/*
+** Determine if sba should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip and tell other partners in crime they
+** have work to do.
+*/
+void __init sba_init(void)
+{
+ struct sba_device *sba_dev;
+ u32 func_id, hw_rev;
+ u32 *func_offset = NULL;
+ int i, agp_found = 0;
+ static char sba_rev[6];
+ struct pci_dev *device = NULL;
+ u64 hpa = 0;
+
+ if (!(device = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_SBA, NULL)))
+ return;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (pci_resource_flags(device, i) == IORESOURCE_MEM) {
+ hpa = ioremap(pci_resource_start(device, i),
+ pci_resource_len(device, i));
+ break;
+ }
+ }
+
+ func_id = READ_REG(hpa + SBA_FUNC_ID);
+
+ if (func_id == ZX1_FUNC_ID_VALUE) {
+ (void)strcpy(sba_rev, "zx1");
+ func_offset = zx1_func_offsets;
+ } else {
+ return;
+ }
+
+ /* Read HW Rev First */
+ hw_rev = READ_REG(hpa + SBA_FCLASS) & 0xFFUL;
+
+ /*
+ * Not all revision registers of the chipset are updated on every
+ * turn. Must scan through all functions looking for the highest rev
+ */
+ if (func_offset) {
+ for (i = 0 ; func_offset[i] != -1 ; i++) {
+ u32 func_rev;
+
+ func_rev = READ_REG(hpa + SBA_FCLASS + func_offset[i]) & 0xFFUL;
+ DBG_INIT("%s() func offset: 0x%x rev: 0x%x\n",
+ __FUNCTION__, func_offset[i], func_rev);
+ if (func_rev > hw_rev)
+ hw_rev = func_rev;
+ }
+ }
+
+ printk(KERN_INFO "%s found %s %d.%d at %s, HPA 0x%lx\n", DRIVER_NAME,
+ sba_rev, ((hw_rev >> 4) & 0xF), (hw_rev & 0xF),
+ device->slot_name, hpa);
+
+ if ((hw_rev & 0xFF) < 0x20) {
+ printk(KERN_INFO "%s WARNING rev 2.0 or greater will be required for IO MMU support in the future\n", DRIVER_NAME);
+#ifndef CONFIG_IA64_HP_PROTO
+ panic("%s: CONFIG_IA64_HP_PROTO MUST be enabled to support SBA rev less than 2.0", DRIVER_NAME);
+#endif
+ }
+
+ sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
+ if (NULL == sba_dev) {
+ printk(KERN_ERR DRIVER_NAME " - couldn't alloc sba_device\n");
+ return;
+ }
+
+ memset(sba_dev, 0, sizeof(struct sba_device));
+
+ for(i=0; iioc[i].res_lock));
+
+ sba_dev->hw_rev = hw_rev;
+ sba_dev->sba_hpa = hpa;
+
+ /*
+ * We need to check for an AGP device, if we find one, then only
+ * use part of the IOVA space for PCI DMA, the rest is for GART.
+ * REVISIT for multiple IOC.
+ */
+ pci_for_each_dev(device)
+ agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);
+
+ if (agp_found && reserve_sba_gart)
+ SBA_SET_AGP(sba_dev);
+
+ sba_hw_init(sba_dev);
+ sba_common_init(sba_dev);
+
+#ifdef CONFIG_PROC_FS
+ {
+ struct proc_dir_entry * proc_mckinley_root;
+
+ proc_mckinley_root = proc_mkdir("bus/mckinley",0);
+ create_proc_info_entry(sba_rev, 0, proc_mckinley_root, sba_proc_info);
+ create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map);
+ }
+#endif
+}
+
+static int __init
+nosbagart (char *str)
+{
+ reserve_sba_gart = 0;
+ return 1;
+}
+
+__setup("nosbagart",nosbagart);
+
+EXPORT_SYMBOL(sba_init);
+EXPORT_SYMBOL(sba_map_single);
+EXPORT_SYMBOL(sba_unmap_single);
+EXPORT_SYMBOL(sba_map_sg);
+EXPORT_SYMBOL(sba_unmap_sg);
+EXPORT_SYMBOL(sba_dma_address);
+EXPORT_SYMBOL(sba_alloc_consistent);
+EXPORT_SYMBOL(sba_free_consistent);
+/*
+** IA64 System Bus Adapter (SBA) I/O MMU manager
+**
+** (c) Copyright 2002 Alex Williamson
+** (c) Copyright 2002 Hewlett-Packard Company
+**
+** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code)
+** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+**
+** This module initializes the IOC (I/O Controller) found on HP
+** McKinley machines and their successors.
+**
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include /* ia64_get_itc() */
+#include
+#include /* PAGE_OFFSET */
+#include
+
+
+#define DRIVER_NAME "SBA"
+
+#ifndef CONFIG_IA64_HP_PROTO
+#define ALLOW_IOV_BYPASS
+#endif
+#define ENABLE_MARK_CLEAN
+/*
+** The number of debug flags is a clue - this code is fragile.
+*/
+#undef DEBUG_SBA_INIT
+#undef DEBUG_SBA_RUN
+#undef DEBUG_SBA_RUN_SG
+#undef DEBUG_SBA_RESOURCE
+#undef ASSERT_PDIR_SANITY
+#undef DEBUG_LARGE_SG_ENTRIES
+#undef DEBUG_BYPASS
+
+#define SBA_INLINE __inline__
+/* #define SBA_INLINE */
+
+#ifdef DEBUG_SBA_INIT
+#define DBG_INIT(x...) printk(x)
+#else
+#define DBG_INIT(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN
+#define DBG_RUN(x...) printk(x)
+#else
+#define DBG_RUN(x...)
+#endif
+
+#ifdef DEBUG_SBA_RUN_SG
+#define DBG_RUN_SG(x...) printk(x)
+#else
+#define DBG_RUN_SG(x...)
+#endif
+
+
+#ifdef DEBUG_SBA_RESOURCE
+#define DBG_RES(x...) printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+#ifdef DEBUG_BYPASS
+#define DBG_BYPASS(x...) printk(x)
+#else
+#define DBG_BYPASS(x...)
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+#define ASSERT(expr) \
+ if(!(expr)) { \
+ printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
+ panic(#expr); \
+ }
+#else
+#define ASSERT(expr)
+#endif
+
+#define KB(x) ((x) * 1024)
+#define MB(x) (KB (KB (x)))
+#define GB(x) (MB (KB (x)))
+
+/*
+** The number of pdir entries to "free" before issueing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#define DELAYED_RESOURCE_CNT 16
+
+#define DEFAULT_DMA_HINT_REG 0
+
+#define ZX1_FUNC_ID_VALUE ((PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP)
+#define ZX1_MC_ID ((PCI_DEVICE_ID_HP_ZX1_MC << 16) | PCI_VENDOR_ID_HP)
+
+#define SBA_FUNC_ID 0x0000 /* function id */
+#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+
+#define SBA_FUNC_SIZE 0x10000 /* SBA configuration function reg set */
+
+unsigned int __initdata zx1_func_offsets[] = {0x1000, 0x4000, 0x8000,
+ 0x9000, 0xa000, -1};
+
+#define SBA_IOC_OFFSET 0x1000
+
+#define MAX_IOC 1 /* we only have 1 for now*/
+
+#define IOC_IBASE 0x300 /* IO TLB */
+#define IOC_IMASK 0x308
+#define IOC_PCOM 0x310
+#define IOC_TCNFG 0x318
+#define IOC_PDIR_BASE 0x320
+
+#define IOC_IOVA_SPACE_BASE 0x40000000 /* IOVA ranges start at 1GB */
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** IOVP_SIZE could only be greater than PAGE_SIZE if we are
+** confident the drivers really only touch the next physical
+** page iff that driver instance owns it.
+*/
+#define IOVP_SIZE PAGE_SIZE
+#define IOVP_SHIFT PAGE_SHIFT
+#define IOVP_MASK PAGE_MASK
+
+struct ioc {
+ unsigned long ioc_hpa; /* I/O MMU base address */
+ char *res_map; /* resource map, bit == pdir entry */
+ u64 *pdir_base; /* physical base address */
+ unsigned long ibase; /* pdir IOV Space base */
+ unsigned long imask; /* pdir IOV Space mask */
+
+ unsigned long *res_hint; /* next avail IOVP - circular search */
+ spinlock_t res_lock;
+ unsigned long hint_mask_pdir; /* bits used for DMA hints */
+ unsigned int res_bitshift; /* from the RIGHT! */
+ unsigned int res_size; /* size of resource map in bytes */
+ unsigned int hint_shift_pdir;
+ unsigned long dma_mask;
+#if DELAYED_RESOURCE_CNT > 0
+ int saved_cnt;
+ struct sba_dma_pair {
+ dma_addr_t iova;
+ size_t size;
+ } saved[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef CONFIG_PROC_FS
+#define SBA_SEARCH_SAMPLE 0x100
+ unsigned long avg_search[SBA_SEARCH_SAMPLE];
+ unsigned long avg_idx; /* current index into avg_search */
+ unsigned long used_pages;
+ unsigned long msingle_calls;
+ unsigned long msingle_pages;
+ unsigned long msg_calls;
+ unsigned long msg_pages;
+ unsigned long usingle_calls;
+ unsigned long usingle_pages;
+ unsigned long usg_calls;
+ unsigned long usg_pages;
+#ifdef ALLOW_IOV_BYPASS
+ unsigned long msingle_bypass;
+ unsigned long usingle_bypass;
+ unsigned long msg_bypass;
+#endif
+#endif
+
+ /* STUFF We don't need in performance path */
+ unsigned int pdir_size; /* in bytes, determined by IOV Space size */
+};
+
+struct sba_device {
+ struct sba_device *next; /* list of SBA's in system */
+ const char *name;
+ unsigned long sba_hpa; /* base address */
+ spinlock_t sba_lock;
+ unsigned int flags; /* state/functionality enabled */
+ unsigned int hw_rev; /* HW revision of chip */
+
+ unsigned int num_ioc; /* number of on-board IOC's */
+ struct ioc ioc[MAX_IOC];
+};
+
+
+static struct sba_device *sba_list;
+static int sba_count;
+static int reserve_sba_gart = 1;
+
+#define sba_sg_iova(sg) (sg->address)
+#define sba_sg_len(sg) (sg->length)
+#define sba_sg_buffer(sg) (sg->orig_address)
+
+/* REVISIT - fix me for multiple SBAs/IOCs */
+#define GET_IOC(dev) (sba_list->ioc)
+#define SBA_SET_AGP(sba_dev) (sba_dev->flags |= 0x1)
+#define SBA_GET_AGP(sba_dev) (sba_dev->flags & 0x1)
+
+/*
+** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
+** (or rather not merge) DMA's into managable chunks.
+** On parisc, this is more of the software/tuning constraint
+** rather than the HW. I/O MMU allocation alogorithms can be
+** faster with smaller size is (to some degree).
+*/
+#define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE)
+
+/* Looks nice and keeps the compiler happy */
+#define SBA_DEV(d) ((struct sba_device *) (d))
+
+#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
+
+/************************************
+** SBA register read and write support
+**
+** BE WARNED: register writes are posted.
+** (ie follow writes which must reach HW with a read)
+**
+*/
+#define READ_REG(addr) __raw_readq(addr)
+#define WRITE_REG(val, addr) __raw_writeq(val, addr)
+
+#ifdef DEBUG_SBA_INIT
+
+/**
+ * sba_dump_tlb - debugging only - print IOMMU operating parameters
+ * @hpa: base address of the IOMMU
+ *
+ * Print the size/location of the IO MMU PDIR.
+ */
+static void
+sba_dump_tlb(char *hpa)
+{
+ DBG_INIT("IO TLB at 0x%p\n", (void *)hpa);
+ DBG_INIT("IOC_IBASE : %016lx\n", READ_REG(hpa+IOC_IBASE));
+ DBG_INIT("IOC_IMASK : %016lx\n", READ_REG(hpa+IOC_IMASK));
+ DBG_INIT("IOC_TCNFG : %016lx\n", READ_REG(hpa+IOC_TCNFG));
+ DBG_INIT("IOC_PDIR_BASE: %016lx\n", READ_REG(hpa+IOC_PDIR_BASE));
+ DBG_INIT("\n");
+}
+#endif
+
+
+#ifdef ASSERT_PDIR_SANITY
+
+/**
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ * @pide: pdir index.
+ *
+ * Print one entry of the IO MMU PDIR in human readable form.
+ */
+static void
+sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
+{
+ /* start printing from lowest pde in rval */
+ u64 *ptr = &(ioc->pdir_base[pide & ~(BITS_PER_LONG - 1)]);
+ unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
+ uint rcnt;
+
+ /* printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n", */
+ printk("SBA: %s rp %p bit %d rval 0x%lx\n",
+ msg, rptr, pide & (BITS_PER_LONG - 1), *rptr);
+
+ rcnt = 0;
+ while (rcnt < BITS_PER_LONG) {
+ printk("%s %2d %p %016Lx\n",
+ (rcnt == (pide & (BITS_PER_LONG - 1)))
+ ? " -->" : " ",
+ rcnt, ptr, *ptr );
+ rcnt++;
+ ptr++;
+ }
+ printk("%s", msg);
+}
+
+
+/**
+ * sba_check_pdir - debugging only - consistency checker
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @msg: text to print ont the output line.
+ *
+ * Verify the resource map and pdir state is consistent
+ */
+static int
+sba_check_pdir(struct ioc *ioc, char *msg)
+{
+ u64 *rptr_end = (u64 *) &(ioc->res_map[ioc->res_size]);
+ u64 *rptr = (u64 *) ioc->res_map; /* resource map ptr */
+ u64 *pptr = ioc->pdir_base; /* pdir ptr */
+ uint pide = 0;
+
+ while (rptr < rptr_end) {
+ u64 rval;
+ int rcnt; /* number of bits we might check */
+
+ rval = *rptr;
+ rcnt = 64;
+
+ while (rcnt) {
+ /* Get last byte and highest bit from that */
+ u32 pde = ((u32)((*pptr >> (63)) & 0x1));
+ if ((rval & 0x1) ^ pde)
+ {
+ /*
+ ** BUMMER! -- res_map != pdir --
+ ** Dump rval and matching pdir entries
+ */
+ sba_dump_pdir_entry(ioc, msg, pide);
+ return(1);
+ }
+ rcnt--;
+ rval >>= 1; /* try the next bit */
+ pptr++;
+ pide++;
+ }
+ rptr++; /* look at next word of res_map */
+ }
+ /* It'd be nice if we always got here :^) */
+ return 0;
+}
+
+
+/**
+ * sba_dump_sg - debugging only - print Scatter-Gather list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: head of the SG list
+ * @nents: number of entries in SG list
+ *
+ * print the SG list so we can verify it's correct by hand.
+ */
+static void
+sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+ while (nents-- > 0) {
+ printk(" %d : %08lx/%05x %p\n",
+ nents,
+ (unsigned long) sba_sg_iova(startsg),
+ sba_sg_len(startsg),
+ sba_sg_buffer(startsg));
+ startsg++;
+ }
+}
+static void
+sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
+{
+ struct scatterlist *the_sg = startsg;
+ int the_nents = nents;
+
+ while (the_nents-- > 0) {
+ if (sba_sg_buffer(the_sg) == 0x0UL)
+ sba_dump_sg(NULL, startsg, nents);
+ the_sg++;
+ }
+}
+
+#endif /* ASSERT_PDIR_SANITY */
+
+
+
+
+/**************************************************************
+*
+* I/O Pdir Resource Management
+*
+* Bits set in the resource map are in use.
+* Each bit can represent a number of pages.
+* LSbs represent lower addresses (IOVA's).
+*
+***************************************************************/
+#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */
+
+/* Convert from IOVP to IOVA and vice versa. */
+#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir)))
+#define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase))
+
+/* FIXME : review these macros to verify correctness and usage */
+#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT)
+
+#define RESMAP_MASK(n) ~(~0UL << (n))
+#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1)
+
+
+/**
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @bits_wanted: number of entries we need.
+ *
+ * Find consecutive free bits in resource bitmap.
+ * Each bit represents one entry in the IO Pdir.
+ * Cool perf optimization: search for log2(size) bits at a time.
+ */
+static SBA_INLINE unsigned long
+sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted)
+{
+ unsigned long *res_ptr = ioc->res_hint;
+ unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]);
+ unsigned long pide = ~0UL;
+
+ ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
+ ASSERT(res_ptr < res_end);
+ if (bits_wanted > (BITS_PER_LONG/2)) {
+ /* Search word at a time - no mask needed */
+ for(; res_ptr < res_end; ++res_ptr) {
+ if (*res_ptr == 0) {
+ *res_ptr = RESMAP_MASK(bits_wanted);
+ pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+ pide <<= 3; /* convert to bit address */
+ break;
+ }
+ }
+ /* point to the next word on next pass */
+ res_ptr++;
+ ioc->res_bitshift = 0;
+ } else {
+ /*
+ ** Search the resource bit map on well-aligned values.
+ ** "o" is the alignment.
+ ** We need the alignment to invalidate I/O TLB using
+ ** SBA HW features in the unmap path.
+ */
+ unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT);
+ uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
+ unsigned long mask;
+
+ if (bitshiftcnt >= BITS_PER_LONG) {
+ bitshiftcnt = 0;
+ res_ptr++;
+ }
+ mask = RESMAP_MASK(bits_wanted) << bitshiftcnt;
+
+ DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
+ while(res_ptr < res_end)
+ {
+ DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr);
+ ASSERT(0 != mask);
+ if(0 == ((*res_ptr) & mask)) {
+ *res_ptr |= mask; /* mark resources busy! */
+ pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+ pide <<= 3; /* convert to bit address */
+ pide += bitshiftcnt;
+ break;
+ }
+ mask <<= o;
+ bitshiftcnt += o;
+ if (0 == mask) {
+ mask = RESMAP_MASK(bits_wanted);
+ bitshiftcnt=0;
+ res_ptr++;
+ }
+ }
+ /* look in the same word on the next pass */
+ ioc->res_bitshift = bitshiftcnt + bits_wanted;
+ }
+
+ /* wrapped ? */
+ if (res_end <= res_ptr) {
+ ioc->res_hint = (unsigned long *) ioc->res_map;
+ ioc->res_bitshift = 0;
+ } else {
+ ioc->res_hint = res_ptr;
+ }
+ return (pide);
+}
+
+
+/**
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @size: number of bytes to create a mapping for
+ *
+ * Given a size, find consecutive unmarked and then mark those bits in the
+ * resource bit map.
+ */
+static int
+sba_alloc_range(struct ioc *ioc, size_t size)
+{
+ unsigned int pages_needed = size >> IOVP_SHIFT;
+#ifdef CONFIG_PROC_FS
+ unsigned long itc_start = ia64_get_itc();
+#endif
+ unsigned long pide;
+
+ ASSERT(pages_needed);
+ ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+ ASSERT(pages_needed <= BITS_PER_LONG);
+ ASSERT(0 == (size & ~IOVP_MASK));
+
+ /*
+ ** "seek and ye shall find"...praying never hurts either...
+ */
+
+ pide = sba_search_bitmap(ioc, pages_needed);
+ if (pide >= (ioc->res_size << 3)) {
+ pide = sba_search_bitmap(ioc, pages_needed);
+ if (pide >= (ioc->res_size << 3))
+ panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
+ }
+
+#ifdef ASSERT_PDIR_SANITY
+ /* verify the first enable bit is clear */
+ if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) {
+ sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide);
+ }
+#endif
+
+ DBG_RES("%s(%x) %d -> %lx hint %x/%x\n",
+ __FUNCTION__, size, pages_needed, pide,
+ (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
+ ioc->res_bitshift );
+
+#ifdef CONFIG_PROC_FS
+ {
+ unsigned long itc_end = ia64_get_itc();
+ unsigned long tmp = itc_end - itc_start;
+ /* check for roll over */
+ itc_start = (itc_end < itc_start) ? -(tmp) : (tmp);
+ }
+ ioc->avg_search[ioc->avg_idx++] = itc_start;
+ ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1;
+
+ ioc->used_pages += pages_needed;
+#endif
+
+ return (pide);
+}
+
+
+/**
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO virtual address which was previously allocated.
+ * @size: number of bytes to create a mapping for
+ *
+ * clear bits in the ioc's resource map
+ */
+static SBA_INLINE void
+sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
+{
+ unsigned long iovp = SBA_IOVP(ioc, iova);
+ unsigned int pide = PDIR_INDEX(iovp);
+ unsigned int ridx = pide >> 3; /* convert bit to byte address */
+ unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]);
+
+ int bits_not_wanted = size >> IOVP_SHIFT;
+
+ /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
+ unsigned long m = RESMAP_MASK(bits_not_wanted) << (pide & (BITS_PER_LONG - 1));
+
+ DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
+ __FUNCTION__, (uint) iova, size,
+ bits_not_wanted, m, pide, res_ptr, *res_ptr);
+
+#ifdef CONFIG_PROC_FS
+ ioc->used_pages -= bits_not_wanted;
+#endif
+
+ ASSERT(m != 0);
+ ASSERT(bits_not_wanted);
+ ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE);
+ ASSERT(bits_not_wanted <= BITS_PER_LONG);
+ ASSERT((*res_ptr & m) == m); /* verify same bits are set */
+ *res_ptr &= ~m;
+}
+
+
+/**************************************************************
+*
+* "Dynamic DMA Mapping" support (aka "Coherent I/O")
+*
+***************************************************************/
+
+#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir)
+
+
+/**
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr: pointer to IO PDIR entry
+ * @vba: Virtual CPU address of buffer to map
+ *
+ * SBA Mapping Routine
+ *
+ * Given a virtual address (vba, arg1) sba_io_pdir_entry()
+ * loads the I/O PDIR entry pointed to by pdir_ptr (arg0).
+ * Each IO Pdir entry consists of 8 bytes as shown below
+ * (LSB == bit 0):
+ *
+ * 63 40 11 7 0
+ * +-+---------------------+----------------------------------+----+--------+
+ * |V| U | PPN[39:12] | U | FF |
+ * +-+---------------------+----------------------------------+----+--------+
+ *
+ * V == Valid Bit
+ * U == Unused
+ * PPN == Physical Page Number
+ *
+ * The physical address fields are filled with the results of virt_to_phys()
+ * on the vba.
+ */
+
+#if 1
+#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL)
+#else
+void SBA_INLINE
+sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba)
+{
+ *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL);
+}
+#endif
+
+#ifdef ENABLE_MARK_CLEAN
+/**
+ * Since DMA is i-cache coherent, any (complete) pages that were written via
+ * DMA can be marked as "clean" so that update_mmu_cache() doesn't have to
+ * flush them when they get mapped into an executable vm-area.
+ */
+static void
+mark_clean (void *addr, size_t size)
+{
+ unsigned long pg_addr, end;
+
+ pg_addr = PAGE_ALIGN((unsigned long) addr);
+ end = (unsigned long) addr + size;
+ while (pg_addr + PAGE_SIZE <= end) {
+ struct page *page = virt_to_page(pg_addr);
+ set_bit(PG_arch_1, &page->flags);
+ pg_addr += PAGE_SIZE;
+ }
+}
+#endif
+
+/**
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @iova: IO Virtual Address mapped earlier
+ * @byte_cnt: number of bytes this mapping covers.
+ *
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
+ * corresponding IO TLB entry. The PCOM (Purge Command Register)
+ * is to purge stale entries in the IO TLB when unmapping entries.
+ *
+ * The PCOM register supports purging of multiple pages, with a minium
+ * of 1 page and a maximum of 2GB. Hardware requires the address be
+ * aligned to the size of the range being purged. The size of the range
+ * must be a power of 2. The "Cool perf optimization" in the
+ * allocation routine helps keep that true.
+ */
+static SBA_INLINE void
+sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
+{
+ u32 iovp = (u32) SBA_IOVP(ioc,iova);
+
+ int off = PDIR_INDEX(iovp);
+
+ /* Must be non-zero and rounded up */
+ ASSERT(byte_cnt > 0);
+ ASSERT(0 == (byte_cnt & ~IOVP_MASK));
+
+#ifdef ASSERT_PDIR_SANITY
+ /* Assert first pdir entry is set */
+ if (!(ioc->pdir_base[off] >> 60)) {
+ sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp));
+ }
+#endif
+
+ if (byte_cnt <= IOVP_SIZE)
+ {
+ ASSERT(off < ioc->pdir_size);
+
+ iovp |= IOVP_SHIFT; /* set "size" field for PCOM */
+
+ /*
+ ** clear I/O PDIR entry "valid" bit
+ ** Do NOT clear the rest - save it for debugging.
+ ** We should only clear bits that have previously
+ ** been enabled.
+ */
+ ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+ } else {
+ u32 t = get_order(byte_cnt) + PAGE_SHIFT;
+
+ iovp |= t;
+ ASSERT(t <= 31); /* 2GB! Max value of "size" field */
+
+ do {
+ /* verify this pdir entry is enabled */
+ ASSERT(ioc->pdir_base[off] >> 63);
+ /* clear I/O Pdir entry "valid" bit first */
+ ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+ off++;
+ byte_cnt -= IOVP_SIZE;
+ } while (byte_cnt > 0);
+ }
+
+ WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+}
+
+/**
+ * sba_map_single - map one buffer and return IOVA for DMA
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @addr: driver buffer to map.
+ * @size: number of bytes to map in driver buffer.
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+dma_addr_t
+sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+{
+ struct ioc *ioc;
+ unsigned long flags;
+ dma_addr_t iovp;
+ dma_addr_t offset;
+ u64 *pdir_start;
+ int pide;
+#ifdef ALLOW_IOV_BYPASS
+ unsigned long pci_addr = virt_to_phys(addr);
+#endif
+
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+ /*
+ ** Check if the PCI device can DMA to ptr... if so, just return ptr
+ */
+ if ((pci_addr & ~dev->dma_mask) == 0) {
+ /*
+ ** Device is bit capable of DMA'ing to the buffer...
+ ** just return the PCI address of ptr
+ */
+#ifdef CONFIG_PROC_FS
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ ioc->msingle_bypass++;
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+ DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
+ dev->dma_mask, pci_addr);
+ return pci_addr;
+ }
+#endif
+
+ ASSERT(size > 0);
+ ASSERT(size <= DMA_CHUNK_SIZE);
+
+ /* save offset bits */
+ offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
+
+ /* round up to nearest IOVP_SIZE */
+ size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
+
+ spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef ASSERT_PDIR_SANITY
+ if (sba_check_pdir(ioc,"Check before sba_map_single()"))
+ panic("Sanity check failed");
+#endif
+
+#ifdef CONFIG_PROC_FS
+ ioc->msingle_calls++;
+ ioc->msingle_pages += size >> IOVP_SHIFT;
+#endif
+ pide = sba_alloc_range(ioc, size);
+ iovp = (dma_addr_t) pide << IOVP_SHIFT;
+
+ DBG_RUN("%s() 0x%p -> 0x%lx\n",
+ __FUNCTION__, addr, (long) iovp | offset);
+
+ pdir_start = &(ioc->pdir_base[pide]);
+
+ while (size > 0) {
+ ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
+ sba_io_pdir_entry(pdir_start, (unsigned long) addr);
+
+ DBG_RUN(" pdir 0x%p %lx\n", pdir_start, *pdir_start);
+
+ addr += IOVP_SIZE;
+ size -= IOVP_SIZE;
+ pdir_start++;
+ }
+ /* form complete address */
+#ifdef ASSERT_PDIR_SANITY
+ sba_check_pdir(ioc,"Check after sba_map_single()");
+#endif
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+ return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
+}
+
+/**
+ * sba_unmap_single - unmap one IOVA and free resources
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @iova: IOVA of driver buffer previously mapped.
+ * @size: number of bytes mapped in driver buffer.
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size,
+ int direction)
+{
+ struct ioc *ioc;
+#if DELAYED_RESOURCE_CNT > 0
+ struct sba_dma_pair *d;
+#endif
+ unsigned long flags;
+ dma_addr_t offset;
+
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+ if ((iova & ioc->imask) != ioc->ibase) {
+ /*
+ ** Address does not fall w/in IOVA, must be bypassing
+ */
+#ifdef CONFIG_PROC_FS
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ ioc->usingle_bypass++;
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+ DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova);
+
+#ifdef ENABLE_MARK_CLEAN
+ if (direction == PCI_DMA_FROMDEVICE) {
+ mark_clean(phys_to_virt(iova), size);
+ }
+#endif
+ return;
+ }
+#endif
+ offset = iova & ~IOVP_MASK;
+
+ DBG_RUN("%s() iovp 0x%lx/%x\n",
+ __FUNCTION__, (long) iova, size);
+
+ iova ^= offset; /* clear offset bits */
+ size += offset;
+ size = ROUNDUP(size, IOVP_SIZE);
+
+ spin_lock_irqsave(&ioc->res_lock, flags);
+#ifdef CONFIG_PROC_FS
+ ioc->usingle_calls++;
+ ioc->usingle_pages += size >> IOVP_SHIFT;
+#endif
+
+#if DELAYED_RESOURCE_CNT > 0
+ d = &(ioc->saved[ioc->saved_cnt]);
+ d->iova = iova;
+ d->size = size;
+ if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+ int cnt = ioc->saved_cnt;
+ while (cnt--) {
+ sba_mark_invalid(ioc, d->iova, d->size);
+ sba_free_range(ioc, d->iova, d->size);
+ d--;
+ }
+ ioc->saved_cnt = 0;
+ READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
+ }
+#else /* DELAYED_RESOURCE_CNT == 0 */
+ sba_mark_invalid(ioc, iova, size);
+ sba_free_range(ioc, iova, size);
+ READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
+#endif /* DELAYED_RESOURCE_CNT == 0 */
+#ifdef ENABLE_MARK_CLEAN
+ if (direction == PCI_DMA_FROMDEVICE) {
+ u32 iovp = (u32) SBA_IOVP(ioc,iova);
+ int off = PDIR_INDEX(iovp);
+ void *addr;
+
+ if (size <= IOVP_SIZE) {
+ addr = phys_to_virt(ioc->pdir_base[off] &
+ ~0xE000000000000FFFULL);
+ mark_clean(addr, size);
+ } else {
+ size_t byte_cnt = size;
+
+ do {
+ addr = phys_to_virt(ioc->pdir_base[off] &
+ ~0xE000000000000FFFULL);
+ mark_clean(addr, min(byte_cnt, IOVP_SIZE));
+ off++;
+ byte_cnt -= IOVP_SIZE;
+
+ } while (byte_cnt > 0);
+ }
+ }
+#endif
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+ /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
+ ** For Astro based systems this isn't a big deal WRT performance.
+ ** As long as 2.4 kernels copyin/copyout data from/to userspace,
+ ** we don't need the syncdma. The issue here is I/O MMU cachelines
+ ** are *not* coherent in all cases. May be hwrev dependent.
+ ** Need to investigate more.
+ asm volatile("syncdma");
+ */
+}
+
+
+/**
+ * sba_alloc_consistent - allocate/map shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size: number of bytes mapped in driver buffer.
+ * @dma_handle: IOVA of new buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void *
+sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+ void *ret;
+
+ if (!hwdev) {
+ /* only support PCI */
+ *dma_handle = 0;
+ return 0;
+ }
+
+ ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
+
+ if (ret) {
+ memset(ret, 0, size);
+ *dma_handle = sba_map_single(hwdev, ret, size, 0);
+ }
+
+ return ret;
+}
+
+
+/**
+ * sba_free_consistent - free/unmap shared mem for DMA
+ * @hwdev: instance of PCI owned by the driver that's asking.
+ * @size: number of bytes mapped in driver buffer.
+ * @vaddr: virtual address IOVA of "consistent" buffer.
+ * @dma_handler: IO virtual address of "consistent" buffer.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ sba_unmap_single(hwdev, dma_handle, size, 0);
+ free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x1UL
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+int dump_run_sg = 0;
+#endif
+
+
+/**
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
+ */
+
+static SBA_INLINE int
+sba_fill_pdir(
+ struct ioc *ioc,
+ struct scatterlist *startsg,
+ int nents)
+{
+ struct scatterlist *dma_sg = startsg; /* pointer to current DMA */
+ int n_mappings = 0;
+ u64 *pdirp = 0;
+ unsigned long dma_offset = 0;
+
+ dma_sg--;
+ while (nents-- > 0) {
+ int cnt = sba_sg_len(startsg);
+ sba_sg_len(startsg) = 0;
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+ if (dump_run_sg)
+ printk(" %2d : %08lx/%05x %p\n",
+ nents,
+ (unsigned long) sba_sg_iova(startsg), cnt,
+ sba_sg_buffer(startsg)
+ );
+#else
+ DBG_RUN_SG(" %d : %08lx/%05x %p\n",
+ nents,
+ (unsigned long) sba_sg_iova(startsg), cnt,
+ sba_sg_buffer(startsg)
+ );
+#endif
+ /*
+ ** Look for the start of a new DMA stream
+ */
+ if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
+ u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+ dma_offset = (unsigned long) pide & ~IOVP_MASK;
+ sba_sg_iova(startsg) = 0;
+ dma_sg++;
+ sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+ pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+ n_mappings++;
+ }
+
+ /*
+ ** Look for a VCONTIG chunk
+ */
+ if (cnt) {
+ unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+ ASSERT(pdirp);
+
+ /* Since multiple Vcontig blocks could make up
+ ** one DMA stream, *add* cnt to dma_len.
+ */
+ sba_sg_len(dma_sg) += cnt;
+ cnt += dma_offset;
+ dma_offset=0; /* only want offset on first chunk */
+ cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+ ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+ do {
+ sba_io_pdir_entry(pdirp, vaddr);
+ vaddr += IOVP_SIZE;
+ cnt -= IOVP_SIZE;
+ pdirp++;
+ } while (cnt > 0);
+ }
+ startsg++;
+ }
+#ifdef DEBUG_LARGE_SG_ENTRIES
+ dump_run_sg = 0;
+#endif
+ return(n_mappings);
+}
+
+
+/*
+** Two address ranges are DMA contiguous *iff* "end of prev" and
+** "start of next" are both on a page boundry.
+**
+** (shift left is a quick trick to mask off upper bits)
+*/
+#define DMA_CONTIG(__X, __Y) \
+ (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg: list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
+static SBA_INLINE int
+sba_coalesce_chunks( struct ioc *ioc,
+ struct scatterlist *startsg,
+ int nents)
+{
+ struct scatterlist *vcontig_sg; /* VCONTIG chunk head */
+ unsigned long vcontig_len; /* len of VCONTIG chunk */
+ unsigned long vcontig_end;
+ struct scatterlist *dma_sg; /* next DMA stream head */
+ unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+ int n_mappings = 0;
+
+ while (nents > 0) {
+ unsigned long vaddr = (unsigned long) (startsg->address);
+
+ /*
+ ** Prepare for first/next DMA stream
+ */
+ dma_sg = vcontig_sg = startsg;
+ dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+ vcontig_end += vaddr;
+ dma_offset = vaddr & ~IOVP_MASK;
+
+ /* PARANOID: clear entries */
+ sba_sg_buffer(startsg) = sba_sg_iova(startsg);
+ sba_sg_iova(startsg) = 0;
+ sba_sg_len(startsg) = 0;
+
+ /*
+ ** This loop terminates one iteration "early" since
+ ** it's always looking one "ahead".
+ */
+ while (--nents > 0) {
+ unsigned long vaddr; /* tmp */
+
+ startsg++;
+
+ /* catch brokenness in SCSI layer */
+ ASSERT(startsg->length <= DMA_CHUNK_SIZE);
+
+ /*
+ ** First make sure current dma stream won't
+ ** exceed DMA_CHUNK_SIZE if we coalesce the
+ ** next entry.
+ */
+ if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE)
+ break;
+
+ /*
+ ** Then look for virtually contiguous blocks.
+ **
+ ** append the next transaction?
+ */
+ vaddr = (unsigned long) sba_sg_iova(startsg);
+ if (vcontig_end == vaddr)
+ {
+ vcontig_len += sba_sg_len(startsg);
+ vcontig_end += sba_sg_len(startsg);
+ dma_len += sba_sg_len(startsg);
+ sba_sg_buffer(startsg) = (char *)vaddr;
+ sba_sg_iova(startsg) = 0;
+ sba_sg_len(startsg) = 0;
+ continue;
+ }
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+ dump_run_sg = (vcontig_len > IOVP_SIZE);
+#endif
+
+ /*
+ ** Not virtually contigous.
+ ** Terminate prev chunk.
+ ** Start a new chunk.
+ **
+ ** Once we start a new VCONTIG chunk, dma_offset
+ ** can't change. And we need the offset from the first
+ ** chunk - not the last one. Ergo Successive chunks
+ ** must start on page boundaries and dove tail
+ ** with it's predecessor.
+ */
+ sba_sg_len(vcontig_sg) = vcontig_len;
+
+ vcontig_sg = startsg;
+ vcontig_len = sba_sg_len(startsg);
+
+ /*
+ ** 3) do the entries end/start on page boundaries?
+ ** Don't update vcontig_end until we've checked.
+ */
+ if (DMA_CONTIG(vcontig_end, vaddr))
+ {
+ vcontig_end = vcontig_len + vaddr;
+ dma_len += vcontig_len;
+ sba_sg_buffer(startsg) = (char *)vaddr;
+ sba_sg_iova(startsg) = 0;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ /*
+ ** End of DMA Stream
+ ** Terminate last VCONTIG block.
+ ** Allocate space for DMA stream.
+ */
+ sba_sg_len(vcontig_sg) = vcontig_len;
+ dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+ ASSERT(dma_len <= DMA_CHUNK_SIZE);
+ sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG
+ | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
+ | dma_offset);
+ n_mappings++;
+ }
+
+ return n_mappings;
+}
+
+
+/**
+ * sba_map_sg - map Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist: array of buffer/length pairs
+ * @nents: number of entries in list
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
+ int direction)
+{
+ struct ioc *ioc;
+ int coalesced, filled = 0;
+ unsigned long flags;
+#ifdef ALLOW_IOV_BYPASS
+ struct scatterlist *sg;
+#endif
+
+ DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef ALLOW_IOV_BYPASS
+ if (dev->dma_mask >= ioc->dma_mask) {
+ for (sg = sglist ; filled < nents ; filled++, sg++){
+ sba_sg_buffer(sg) = sba_sg_iova(sg);
+ sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+ }
+#ifdef CONFIG_PROC_FS
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ ioc->msg_bypass++;
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+ return filled;
+ }
+#endif
+ /* Fast path single entry scatterlists. */
+ if (nents == 1) {
+ sba_sg_buffer(sglist) = sba_sg_iova(sglist);
+ sba_sg_iova(sglist) = (char *)sba_map_single(dev,
+ sba_sg_buffer(sglist),
+ sba_sg_len(sglist), direction);
+#ifdef CONFIG_PROC_FS
+ /*
+ ** Should probably do some stats counting, but trying to
+ ** be precise quickly starts wasting CPU time.
+ */
+#endif
+ return 1;
+ }
+
+ spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef ASSERT_PDIR_SANITY
+ if (sba_check_pdir(ioc,"Check before sba_map_sg()"))
+ {
+ sba_dump_sg(ioc, sglist, nents);
+ panic("Check before sba_map_sg()");
+ }
+#endif
+
+#ifdef CONFIG_PROC_FS
+ ioc->msg_calls++;
+#endif
+
+ /*
+ ** First coalesce the chunks and allocate I/O pdir space
+ **
+ ** If this is one DMA stream, we can properly map using the
+ ** correct virtual address associated with each DMA page.
+ ** w/o this association, we wouldn't have coherent DMA!
+ ** Access to the virtual address is what forces a two pass algorithm.
+ */
+ coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+
+ /*
+ ** Program the I/O Pdir
+ **
+ ** map the virtual addresses to the I/O Pdir
+ ** o dma_address will contain the pdir index
+ ** o dma_len will contain the number of bytes to map
+ ** o address contains the virtual address.
+ */
+ filled = sba_fill_pdir(ioc, sglist, nents);
+
+#ifdef ASSERT_PDIR_SANITY
+ if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
+ {
+ sba_dump_sg(ioc, sglist, nents);
+ panic("Check after sba_map_sg()\n");
+ }
+#endif
+
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+ ASSERT(coalesced == filled);
+ DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
+
+ return filled;
+}
+
+
+/**
+ * sba_unmap_sg - unmap Scatter/Gather list
+ * @dev: instance of PCI owned by the driver that's asking.
+ * @sglist: array of buffer/length pairs
+ * @nents: number of entries in list
+ * @direction: R/W or both.
+ *
+ * See Documentation/DMA-mapping.txt
+ */
+void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
+ int direction)
+{
+ struct ioc *ioc;
+#ifdef ASSERT_PDIR_SANITY
+ unsigned long flags;
+#endif
+
+ DBG_RUN_SG("%s() START %d entries, %p,%x\n",
+ __FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+
+ ioc = GET_IOC(dev);
+ ASSERT(ioc);
+
+#ifdef CONFIG_PROC_FS
+ ioc->usg_calls++;
+#endif
+
+#ifdef ASSERT_PDIR_SANITY
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ sba_check_pdir(ioc,"Check before sba_unmap_sg()");
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+ while (sba_sg_len(sglist) && nents--) {
+
+ sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
+ sba_sg_len(sglist), direction);
+#ifdef CONFIG_PROC_FS
+ /*
+ ** This leaves inconsistent data in the stats, but we can't
+ ** tell which sg lists were mapped by map_single and which
+ ** were coalesced to a single entry. The stats are fun,
+ ** but speed is more important.
+ */
+ ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+#endif
+ ++sglist;
+ }
+
+ DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents);
+
+#ifdef ASSERT_PDIR_SANITY
+ spin_lock_irqsave(&ioc->res_lock, flags);
+ sba_check_pdir(ioc,"Check after sba_unmap_sg()");
+ spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
+
+}
+
+unsigned long
+sba_dma_address (struct scatterlist *sg)
+{
+ return ((unsigned long)sba_sg_iova(sg));
+}
+
+/**************************************************************
+*
+* Initialization and claim
+*
+***************************************************************/
+
+
+static void
+sba_ioc_init(struct sba_device *sba_dev, struct ioc *ioc, int ioc_num)
+{
+ u32 iova_space_size, iova_space_mask;
+ void * pdir_base;
+ int pdir_size, iov_order, tcnfg;
+
+ /*
+ ** Firmware programs the maximum IOV space size into the imask reg
+ */
+ iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
+#ifdef CONFIG_IA64_HP_PROTO
+ if (!iova_space_size)
+ iova_space_size = GB(1);
+#endif
+
+ /*
+ ** iov_order is always based on a 1GB IOVA space since we want to
+ ** turn on the other half for AGP GART.
+ */
+ iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
+ ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+
+ DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits) PDIR size 0x%0x\n",
+ __FUNCTION__, ioc->ioc_hpa, iova_space_size>>20,
+ iov_order + PAGE_SHIFT, ioc->pdir_size);
+
+ /* FIXME : DMA HINTs not used */
+ ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
+ ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
+
+ ioc->pdir_base =
+ pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
+ if (NULL == pdir_base)
+ {
+ panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
+ }
+ memset(pdir_base, 0, pdir_size);
+
+ DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
+ __FUNCTION__, pdir_base, pdir_size,
+ ioc->hint_shift_pdir, ioc->hint_mask_pdir);
+
+ ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
+ WRITE_REG(virt_to_phys(pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
+
+ DBG_INIT(" base %p\n", pdir_base);
+
+ /* build IMASK for IOC and Elroy */
+ iova_space_mask = 0xffffffff;
+ iova_space_mask <<= (iov_order + PAGE_SHIFT);
+
+#ifdef CONFIG_IA64_HP_PROTO
+ /*
+ ** REVISIT - this is a kludge, but we won't be supporting anything but
+ ** zx1 2.0 or greater for real. When fw is in shape, ibase will
+ ** be preprogrammed w/ the IOVA hole base and imask will give us
+ ** the size.
+ */
+ if ((sba_dev->hw_rev & 0xFF) < 0x20) {
+ DBG_INIT("%s() Found SBA rev < 2.0, setting IOVA base to 0. This device will not be supported in the future.\n", __FUNCTION__);
+ ioc->ibase = 0x0;
+ } else
+#endif
+ ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & 0xFFFFFFFEUL;
+
+ ioc->imask = iova_space_mask; /* save it */
+
+ DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
+ __FUNCTION__, ioc->ibase, ioc->imask);
+
+ /*
+ ** FIXME: Hint registers are programmed with default hint
+ ** values during boot, so hints should be sane even if we
+ ** can't reprogram them the way drivers want.
+ */
+
+ WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
+
+ /*
+ ** Setting the upper bits makes checking for bypass addresses
+ ** a little faster later on.
+ */
+ ioc->imask |= 0xFFFFFFFF00000000UL;
+
+ /* Set I/O PDIR Page size to system page size */
+ switch (PAGE_SHIFT) {
+ case 12: /* 4K */
+ tcnfg = 0;
+ break;
+ case 13: /* 8K */
+ tcnfg = 1;
+ break;
+ case 14: /* 16K */
+ tcnfg = 2;
+ break;
+ case 16: /* 64K */
+ tcnfg = 3;
+ break;
+ }
+ WRITE_REG(tcnfg, ioc->ioc_hpa+IOC_TCNFG);
+
+ /*
+ ** Program the IOC's ibase and enable IOVA translation
+ ** Bit zero == enable bit.
+ */
+ WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa+IOC_IBASE);
+
+ /*
+ ** Clear I/O TLB of any possible entries.
+ ** (Yes. This is a bit paranoid...but so what)
+ */
+ WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM);
+
+ /*
+ ** If an AGP device is present, only use half of the IOV space
+ ** for PCI DMA. Unfortunately we can't know ahead of time
+ ** whether GART support will actually be used, for now we
+ ** can just key on an AGP device found in the system.
+ ** We program the next pdir index after we stop w/ a key for
+ ** the GART code to handshake on.
+ */
+ if (SBA_GET_AGP(sba_dev)) {
+ DBG_INIT("%s() AGP Device found, reserving 512MB for GART support\n", __FUNCTION__);
+ ioc->pdir_size /= 2;
+ ((u64 *)pdir_base)[PDIR_INDEX(iova_space_size/2)] = 0x0000badbadc0ffeeULL;
+ }
+
+ DBG_INIT("%s() DONE\n", __FUNCTION__);
+}
+
+
+
+/**************************************************************************
+**
+** SBA initialization code (HW and SW)
+**
+** o identify SBA chip itself
+** o FIXME: initialize DMA hints for reasonable defaults
+**
+**************************************************************************/
+
+static void
+sba_hw_init(struct sba_device *sba_dev)
+{
+ int i;
+ int num_ioc;
+ u64 dma_mask;
+ u32 func_id;
+
+ /*
+ ** Identify the SBA so we can set the dma_mask. We can make a virtual
+ ** dma_mask of the memory subsystem such that devices not implmenting
+ ** a full 64bit mask might still be able to bypass efficiently.
+ */
+ func_id = READ_REG(sba_dev->sba_hpa + SBA_FUNC_ID);
+
+ if (func_id == ZX1_FUNC_ID_VALUE) {
+ dma_mask = 0xFFFFFFFFFFUL;
+ } else {
+ dma_mask = 0xFFFFFFFFFFFFFFFFUL;
+ }
+
+ DBG_INIT("%s(): ioc->dma_mask == 0x%lx\n", __FUNCTION__, dma_mask);
+
+ /*
+ ** Leaving in the multiple ioc code from parisc for the future,
+ ** currently there are no muli-ioc mckinley sbas
+ */
+ sba_dev->ioc[0].ioc_hpa = SBA_IOC_OFFSET;
+ num_ioc = 1;
+
+ sba_dev->num_ioc = num_ioc;
+ for (i = 0; i < num_ioc; i++) {
+ sba_dev->ioc[i].dma_mask = dma_mask;
+ sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa;
+ sba_ioc_init(sba_dev, &(sba_dev->ioc[i]), i);
+ }
+}
+
+static void
+sba_common_init(struct sba_device *sba_dev)
+{
+ int i;
+
+ /* add this one to the head of the list (order doesn't matter)
+ ** This will be useful for debugging - especially if we get coredumps
+ */
+ sba_dev->next = sba_list;
+ sba_list = sba_dev;
+ sba_count++;
+
+ for(i=0; i< sba_dev->num_ioc; i++) {
+ int res_size;
+
+ /* resource map size dictated by pdir_size */
+ res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
+ res_size >>= 3; /* convert bit count to byte count */
+ DBG_INIT("%s() res_size 0x%x\n",
+ __FUNCTION__, res_size);
+
+ sba_dev->ioc[i].res_size = res_size;
+ sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
+
+ if (NULL == sba_dev->ioc[i].res_map)
+ {
+ panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ );
+ }
+
+ memset(sba_dev->ioc[i].res_map, 0, res_size);
+ /* next available IOVP - circular search */
+ if ((sba_dev->hw_rev & 0xFF) >= 0x20) {
+ sba_dev->ioc[i].res_hint = (unsigned long *)
+ sba_dev->ioc[i].res_map;
+ } else {
+ u64 reserved_iov;
+
+ /* Yet another 1.x hack */
+ printk("zx1 1.x: Starting resource hint offset into IOV space to avoid initial zero value IOVA\n");
+ sba_dev->ioc[i].res_hint = (unsigned long *)
+ &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]);
+
+ sba_dev->ioc[i].res_map[0] = 0x1;
+ sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
+
+ for (reserved_iov = 0xA0000 ; reserved_iov < 0xC0000 ; reserved_iov += IOVP_SIZE) {
+ u64 *res_ptr = sba_dev->ioc[i].res_map;
+ int index = PDIR_INDEX(reserved_iov);
+ int res_word;
+ u64 mask;
+
+ res_word = (int)(index / BITS_PER_LONG);
+ mask = 0x1UL << (index - (res_word * BITS_PER_LONG));
+ res_ptr[res_word] |= mask;
+ sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (0x80000000000000FFULL | reserved_iov);
+
+ }
+ }
+
+#ifdef ASSERT_PDIR_SANITY
+ /* Mark first bit busy - ie no IOVA 0 */
+ sba_dev->ioc[i].res_map[0] = 0x1;
+ sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
+#endif
+
+ DBG_INIT("%s() %d res_map %x %p\n", __FUNCTION__,
+ i, res_size, (void *)sba_dev->ioc[i].res_map);
+ }
+
+ sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;
+}
+
+#ifdef CONFIG_PROC_FS
+static int sba_proc_info(char *buf, char **start, off_t offset, int len)
+{
+ struct sba_device *sba_dev = sba_list;
+ struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
+ int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
+ unsigned long i = 0, avg = 0, min, max;
+
+ sprintf(buf, "%s rev %d.%d\n",
+ "Hewlett Packard zx1 SBA",
+ ((sba_dev->hw_rev >> 4) & 0xF),
+ (sba_dev->hw_rev & 0xF)
+ );
+ sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n",
+ buf,
+ (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+ total_pages);
+
+ sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf,
+ total_pages - ioc->used_pages, ioc->used_pages,
+ (int) (ioc->used_pages * 100 / total_pages));
+
+ sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n",
+ buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
+
+ min = max = ioc->avg_search[0];
+ for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
+ avg += ioc->avg_search[i];
+ if (ioc->avg_search[i] > max) max = ioc->avg_search[i];
+ if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
+ }
+ avg /= SBA_SEARCH_SAMPLE;
+ sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+ buf, min, avg, max);
+
+ sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->msingle_calls, ioc->msingle_pages,
+ (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+#ifdef ALLOW_IOV_BYPASS
+ sprintf(buf, "%spci_map_single(): %12ld bypasses\n",
+ buf, ioc->msingle_bypass);
+#endif
+
+ sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->usingle_calls, ioc->usingle_pages,
+ (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls));
+#ifdef ALLOW_IOV_BYPASS
+ sprintf(buf, "%spci_unmap_single: %12ld bypasses\n",
+ buf, ioc->usingle_bypass);
+#endif
+
+ sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->msg_calls, ioc->msg_pages,
+ (int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
+#ifdef ALLOW_IOV_BYPASS
+ sprintf(buf, "%spci_map_sg() : %12ld bypasses\n",
+ buf, ioc->msg_bypass);
+#endif
+
+ sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ buf, ioc->usg_calls, ioc->usg_pages,
+ (int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+
+ return strlen(buf);
+}
+
+static int
+sba_resource_map(char *buf, char **start, off_t offset, int len)
+{
+ struct ioc *ioc = sba_list->ioc; /* FIXME: Multi-IOC support! */
+ unsigned int *res_ptr = (unsigned int *)ioc->res_map;
+ int i;
+
+ buf[0] = '\0';
+ for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
+ if ((i & 7) == 0)
+ strcat(buf,"\n ");
+ sprintf(buf, "%s %08x", buf, *res_ptr);
+ }
+ strcat(buf, "\n");
+
+ return strlen(buf);
+}
+#endif
+
+/*
+** Determine if sba should claim this chip (return 0) or not (return 1).
+** If so, initialize the chip and tell other partners in crime they
+** have work to do.
+*/
+void __init sba_init(void)
+{
+ struct sba_device *sba_dev;
+ u32 func_id, hw_rev;
+ u32 *func_offset = NULL;
+ int i, agp_found = 0;
+ static char sba_rev[6];
+ struct pci_dev *device = NULL;
+ u64 hpa = 0;
+
+ if (!(device = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_SBA, NULL)))
+ return;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (pci_resource_flags(device, i) == IORESOURCE_MEM) {
+ hpa = ioremap(pci_resource_start(device, i),
+ pci_resource_len(device, i));
+ break;
+ }
+ }
+
+ func_id = READ_REG(hpa + SBA_FUNC_ID);
+
+ if (func_id == ZX1_FUNC_ID_VALUE) {
+ (void)strcpy(sba_rev, "zx1");
+ func_offset = zx1_func_offsets;
+ } else {
+ return;
+ }
+
+ /* Read HW Rev First */
+ hw_rev = READ_REG(hpa + SBA_FCLASS) & 0xFFUL;
+
+ /*
+ * Not all revision registers of the chipset are updated on every
+ * turn. Must scan through all functions looking for the highest rev
+ */
+ if (func_offset) {
+ for (i = 0 ; func_offset[i] != -1 ; i++) {
+ u32 func_rev;
+
+ func_rev = READ_REG(hpa + SBA_FCLASS + func_offset[i]) & 0xFFUL;
+ DBG_INIT("%s() func offset: 0x%x rev: 0x%x\n",
+ __FUNCTION__, func_offset[i], func_rev);
+ if (func_rev > hw_rev)
+ hw_rev = func_rev;
+ }
+ }
+
+ printk(KERN_INFO "%s found %s %d.%d at %s, HPA 0x%lx\n", DRIVER_NAME,
+ sba_rev, ((hw_rev >> 4) & 0xF), (hw_rev & 0xF),
+ device->slot_name, hpa);
+
+ if ((hw_rev & 0xFF) < 0x20) {
+ printk(KERN_INFO "%s WARNING rev 2.0 or greater will be required for IO MMU support in the future\n", DRIVER_NAME);
+#ifndef CONFIG_IA64_HP_PROTO
+ panic("%s: CONFIG_IA64_HP_PROTO MUST be enabled to support SBA rev less than 2.0", DRIVER_NAME);
+#endif
+ }
+
+ sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
+ if (NULL == sba_dev) {
+ printk(KERN_ERR DRIVER_NAME " - couldn't alloc sba_device\n");
+ return;
+ }
+
+ memset(sba_dev, 0, sizeof(struct sba_device));
+
+ for(i=0; iioc[i].res_lock));
+
+ sba_dev->hw_rev = hw_rev;
+ sba_dev->sba_hpa = hpa;
+
+ /*
+ * We need to check for an AGP device, if we find one, then only
+ * use part of the IOVA space for PCI DMA, the rest is for GART.
+ * REVISIT for multiple IOC.
+ */
+ pci_for_each_dev(device)
+ agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);
+
+ if (agp_found && reserve_sba_gart)
+ SBA_SET_AGP(sba_dev);
+
+ sba_hw_init(sba_dev);
+ sba_common_init(sba_dev);
+
+#ifdef CONFIG_PROC_FS
+ {
+ struct proc_dir_entry * proc_mckinley_root;
+
+ proc_mckinley_root = proc_mkdir("bus/mckinley",0);
+ create_proc_info_entry(sba_rev, 0, proc_mckinley_root, sba_proc_info);
+ create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map);
+ }
+#endif
+}
+
+static int __init
+nosbagart (char *str)
+{
+ reserve_sba_gart = 0;
+ return 1;
+}
+
+__setup("nosbagart",nosbagart);
+
+EXPORT_SYMBOL(sba_init);
+EXPORT_SYMBOL(sba_map_single);
+EXPORT_SYMBOL(sba_unmap_single);
+EXPORT_SYMBOL(sba_map_sg);
+EXPORT_SYMBOL(sba_unmap_sg);
+EXPORT_SYMBOL(sba_dma_address);
+EXPORT_SYMBOL(sba_alloc_consistent);
+EXPORT_SYMBOL(sba_free_consistent);
diff -Nru a/arch/ia64/hp/hpsim_console.c b/arch/ia64/hp/hpsim_console.c
--- a/arch/ia64/hp/hpsim_console.c Mon Apr 22 15:32:19 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,64 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
- * David Mosberger-Tang
- * Copyright (C) 1999 Vijay Chander
- */
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "hpsim_ssc.h"
-
-static int simcons_init (struct console *, char *);
-static void simcons_write (struct console *, const char *, unsigned);
-static kdev_t simcons_console_device (struct console *);
-
-struct console hpsim_cons = {
- name: "simcons",
- write: simcons_write,
- device: simcons_console_device,
- setup: simcons_init,
- flags: CON_PRINTBUFFER,
- index: -1,
-};
-
-static int
-simcons_init (struct console *cons, char *options)
-{
- return 0;
-}
-
-static void
-simcons_write (struct console *cons, const char *buf, unsigned count)
-{
- unsigned long ch;
-
- while (count-- > 0) {
- ch = *buf++;
- ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR);
- if (ch == '\n')
- ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR);
- }
-}
-
-static kdev_t
-simcons_console_device (struct console *c)
-{
- return mk_kdev(TTY_MAJOR, 64 + c->index);
-}
diff -Nru a/arch/ia64/hp/hpsim_irq.c b/arch/ia64/hp/hpsim_irq.c
--- a/arch/ia64/hp/hpsim_irq.c Mon Apr 22 15:32:19 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,46 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang
- */
-
-#include
-#include
-#include
-#include
-
-static unsigned int
-hpsim_irq_startup (unsigned int irq)
-{
- return 0;
-}
-
-static void
-hpsim_irq_noop (unsigned int irq)
-{
-}
-
-static struct hw_interrupt_type irq_type_hp_sim = {
- typename: "hpsim",
- startup: hpsim_irq_startup,
- shutdown: hpsim_irq_noop,
- enable: hpsim_irq_noop,
- disable: hpsim_irq_noop,
- ack: hpsim_irq_noop,
- end: hpsim_irq_noop,
- set_affinity: (void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
-};
-
-void __init
-hpsim_irq_init (void)
-{
- irq_desc_t *idesc;
- int i;
-
- for (i = 0; i < NR_IRQS; ++i) {
- idesc = irq_desc(i);
- if (idesc->handler == &no_irq_type)
- idesc->handler = &irq_type_hp_sim;
- }
-}
diff -Nru a/arch/ia64/hp/hpsim_machvec.c b/arch/ia64/hp/hpsim_machvec.c
--- a/arch/ia64/hp/hpsim_machvec.c Mon Apr 22 15:32:19 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,2 +0,0 @@
-#define MACHVEC_PLATFORM_NAME hpsim
-#include
diff -Nru a/arch/ia64/hp/hpsim_setup.c b/arch/ia64/hp/hpsim_setup.c
--- a/arch/ia64/hp/hpsim_setup.c Mon Apr 22 15:32:19 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang
- * Copyright (C) 1999 Vijay Chander
- */
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "hpsim_ssc.h"
-
-extern struct console hpsim_cons;
-
-/*
- * Simulator system call.
- */
-asm (".text\n"
- ".align 32\n"
- ".global ia64_ssc\n"
- ".proc ia64_ssc\n"
- "ia64_ssc:\n"
- "mov r15=r36\n"
- "break 0x80001\n"
- "br.ret.sptk.many rp\n"
- ".endp\n");
-
-void
-ia64_ssc_connect_irq (long intr, long irq)
-{
- ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
-}
-
-void
-ia64_ctl_trace (long on)
-{
- ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE);
-}
-
-void __init
-hpsim_setup (char **cmdline_p)
-{
- ROOT_DEV = to_kdev_t(0x0801); /* default to first SCSI drive */
-
- register_console (&hpsim_cons);
-}
diff -Nru a/arch/ia64/hp/hpsim_ssc.h b/arch/ia64/hp/hpsim_ssc.h
--- a/arch/ia64/hp/hpsim_ssc.h Mon Apr 22 15:32:19 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/*
- * Platform dependent support for HP simulator.
- *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang
- * Copyright (C) 1999 Vijay Chander
- */
-#ifndef _IA64_PLATFORM_HPSIM_SSC_H
-#define _IA64_PLATFORM_HPSIM_SSC_H
-
-/* Simulator system calls: */
-
-#define SSC_CONSOLE_INIT 20
-#define SSC_GETCHAR 21
-#define SSC_PUTCHAR 31
-#define SSC_CONNECT_INTERRUPT 58
-#define SSC_GENERATE_INTERRUPT 59
-#define SSC_SET_PERIODIC_INTERRUPT 60
-#define SSC_GET_RTC 65
-#define SSC_EXIT 66
-#define SSC_LOAD_SYMBOLS 69
-#define SSC_GET_TOD 74
-#define SSC_CTL_TRACE 76
-
-#define SSC_NETDEV_PROBE 100
-#define SSC_NETDEV_SEND 101
-#define SSC_NETDEV_RECV 102
-#define SSC_NETDEV_ATTACH 103
-#define SSC_NETDEV_DETACH 104
-
-/*
- * Simulator system call.
- */
-extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
-
-#endif /* _IA64_PLATFORM_HPSIM_SSC_H */
diff -Nru a/arch/ia64/hp/sim/Makefile b/arch/ia64/hp/sim/Makefile
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/Makefile Mon Apr 22 15:32:19 2002
@@ -0,0 +1,19 @@
+#
+# ia64/platform/hp/sim/Makefile
+#
+# Copyright (C) 2002 Hewlett-Packard Co.
+# David Mosberger-Tang
+# Copyright (C) 1999 Silicon Graphics, Inc.
+# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+#
+
+O_TARGET := sim.o
+
+obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o
+obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o
+
+obj-$(CONFIG_HP_SIMETH) += simeth.o
+obj-$(CONFIG_HP_SIMSERIAL) += simserial.o
+obj-$(CONFIG_HP_SIMSCSI) += simscsi.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/ia64/hp/sim/hpsim_console.c b/arch/ia64/hp/sim/hpsim_console.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/hpsim_console.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,64 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
+ * David Mosberger-Tang
+ * Copyright (C) 1999 Vijay Chander
+ */
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "hpsim_ssc.h"
+
+static int simcons_init (struct console *, char *);
+static void simcons_write (struct console *, const char *, unsigned);
+static kdev_t simcons_console_device (struct console *);
+
+struct console hpsim_cons = {
+ name: "simcons",
+ write: simcons_write,
+ device: simcons_console_device,
+ setup: simcons_init,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+static int
+simcons_init (struct console *cons, char *options)
+{
+ return 0;
+}
+
+static void
+simcons_write (struct console *cons, const char *buf, unsigned count)
+{
+ unsigned long ch;
+
+ while (count-- > 0) {
+ ch = *buf++;
+ ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR);
+ if (ch == '\n')
+ ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR);
+ }
+}
+
+static kdev_t
+simcons_console_device (struct console *c)
+{
+ return mk_kdev(TTY_MAJOR, 64 + c->index);
+}
diff -Nru a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/hpsim_irq.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,46 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang
+ */
+
+#include
+#include
+#include
+#include
+
+static unsigned int
+hpsim_irq_startup (unsigned int irq)
+{
+ return 0;
+}
+
+static void
+hpsim_irq_noop (unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type irq_type_hp_sim = {
+ typename: "hpsim",
+ startup: hpsim_irq_startup,
+ shutdown: hpsim_irq_noop,
+ enable: hpsim_irq_noop,
+ disable: hpsim_irq_noop,
+ ack: hpsim_irq_noop,
+ end: hpsim_irq_noop,
+ set_affinity: (void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
+};
+
+void __init
+hpsim_irq_init (void)
+{
+ irq_desc_t *idesc;
+ int i;
+
+ for (i = 0; i < NR_IRQS; ++i) {
+ idesc = irq_desc(i);
+ if (idesc->handler == &no_irq_type)
+ idesc->handler = &irq_type_hp_sim;
+ }
+}
diff -Nru a/arch/ia64/hp/sim/hpsim_machvec.c b/arch/ia64/hp/sim/hpsim_machvec.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/hpsim_machvec.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,2 @@
+#define MACHVEC_PLATFORM_NAME hpsim
+#include
diff -Nru a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/hpsim_setup.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,58 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998, 1999 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999 David Mosberger-Tang
+ * Copyright (C) 1999 Vijay Chander
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "hpsim_ssc.h"
+
+extern struct console hpsim_cons;
+
+/*
+ * Simulator system call.
+ */
+asm (".text\n"
+ ".align 32\n"
+ ".global ia64_ssc\n"
+ ".proc ia64_ssc\n"
+ "ia64_ssc:\n"
+ "mov r15=r36\n"
+ "break 0x80001\n"
+ "br.ret.sptk.many rp\n"
+ ".endp\n");
+
+void
+ia64_ssc_connect_irq (long intr, long irq)
+{
+ ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
+}
+
+void
+ia64_ctl_trace (long on)
+{
+ ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE);
+}
+
+void __init
+hpsim_setup (char **cmdline_p)
+{
+ ROOT_DEV = to_kdev_t(0x0801); /* default to first SCSI drive */
+
+ register_console (&hpsim_cons);
+}
diff -Nru a/arch/ia64/hp/sim/hpsim_ssc.h b/arch/ia64/hp/sim/hpsim_ssc.h
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/hpsim_ssc.h Mon Apr 22 15:32:19 2002
@@ -0,0 +1,36 @@
+/*
+ * Platform dependent support for HP simulator.
+ *
+ * Copyright (C) 1998, 1999 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999 David Mosberger-Tang
+ * Copyright (C) 1999 Vijay Chander
+ */
+#ifndef _IA64_PLATFORM_HPSIM_SSC_H
+#define _IA64_PLATFORM_HPSIM_SSC_H
+
+/* Simulator system calls: */
+
+#define SSC_CONSOLE_INIT 20
+#define SSC_GETCHAR 21
+#define SSC_PUTCHAR 31
+#define SSC_CONNECT_INTERRUPT 58
+#define SSC_GENERATE_INTERRUPT 59
+#define SSC_SET_PERIODIC_INTERRUPT 60
+#define SSC_GET_RTC 65
+#define SSC_EXIT 66
+#define SSC_LOAD_SYMBOLS 69
+#define SSC_GET_TOD 74
+#define SSC_CTL_TRACE 76
+
+#define SSC_NETDEV_PROBE 100
+#define SSC_NETDEV_SEND 101
+#define SSC_NETDEV_RECV 102
+#define SSC_NETDEV_ATTACH 103
+#define SSC_NETDEV_DETACH 104
+
+/*
+ * Simulator system call.
+ */
+extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
+
+#endif /* _IA64_PLATFORM_HPSIM_SSC_H */
diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/simeth.c Mon Apr 22 15:32:18 2002
@@ -0,0 +1,533 @@
+/*
+ * Simulated Ethernet Driver
+ *
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Stephane Eranian
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define SIMETH_RECV_MAX 10
+
+/*
+ * Maximum possible received frame for Ethernet.
+ * We preallocate an sk_buff of that size to avoid costly
+ * memcpy for temporary buffer into sk_buff. We do basically
+ * what's done in other drivers, like eepro with a ring.
+ * The difference is, of course, that we don't have real DMA !!!
+ */
+#define SIMETH_FRAME_SIZE ETH_FRAME_LEN
+
+
+#define SSC_NETDEV_PROBE 100
+#define SSC_NETDEV_SEND 101
+#define SSC_NETDEV_RECV 102
+#define SSC_NETDEV_ATTACH 103
+#define SSC_NETDEV_DETACH 104
+
+#define NETWORK_INTR 8
+
+struct simeth_local {
+ struct net_device_stats stats;
+ int simfd; /* descriptor in the simulator */
+};
+
+static int simeth_probe1(void);
+static int simeth_open(struct net_device *dev);
+static int simeth_close(struct net_device *dev);
+static int simeth_tx(struct sk_buff *skb, struct net_device *dev);
+static int simeth_rx(struct net_device *dev);
+static struct net_device_stats *simeth_get_stats(struct net_device *dev);
+static void simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static void set_multicast_list(struct net_device *dev);
+static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr);
+
+static char *simeth_version="0.3";
+
+/*
+ * This variable is used to establish a mapping between the Linux/ia64 kernel
+ * and the host linux kernel.
+ *
+ * As of today, we support only one card, even though most of the code
+ * is ready for many more. The mapping is then:
+ * linux/ia64 -> linux/x86
+ * eth0 -> eth1
+ *
+ * In the future, we some string operations, we could easily support up
+ * to 10 cards (0-9).
+ *
+ * The default mapping can be changed on the kernel command line by
+ * specifying simeth=ethX (or whatever string you want).
+ */
+static char *simeth_device="eth0"; /* default host interface to use */
+
+
+
+static volatile unsigned int card_count; /* how many cards "found" so far */
+static int simeth_debug; /* set to 1 to get debug information */
+
+/*
+ * Used to catch IFF_UP & IFF_DOWN events
+ */
+static struct notifier_block simeth_dev_notifier = {
+ simeth_device_event,
+ 0
+};
+
+
+/*
+ * Function used when using a kernel command line option.
+ *
+ * Format: simeth=interface_name (like eth0)
+ */
+static int __init
+simeth_setup(char *str)
+{
+ simeth_device = str;
+ return 1;
+}
+
+__setup("simeth=", simeth_setup);
+
+/*
+ * Function used to probe for simeth devices when not installed
+ * as a loadable module
+ */
+
+int __init
+simeth_probe (void)
+{
+ int r;
+
+ printk("simeth: v%s\n", simeth_version);
+
+ r = simeth_probe1();
+
+ if (r == 0) register_netdevice_notifier(&simeth_dev_notifier);
+
+ return r;
+}
+
+extern long ia64_ssc (long, long, long, long, int);
+extern void ia64_ssc_connect_irq (long intr, long irq);
+
+static inline int
+netdev_probe(char *name, unsigned char *ether)
+{
+ return ia64_ssc(__pa(name), __pa(ether), 0,0, SSC_NETDEV_PROBE);
+}
+
+
+static inline int
+netdev_connect(int irq)
+{
+ /* XXX Fix me
+ * this does not support multiple cards
+ * also no return value
+ */
+ ia64_ssc_connect_irq(NETWORK_INTR, irq);
+ return 0;
+}
+
+static inline int
+netdev_attach(int fd, int irq, unsigned int ipaddr)
+{
+ /* this puts the host interface in the right mode (start interupting) */
+ return ia64_ssc(fd, ipaddr, 0,0, SSC_NETDEV_ATTACH);
+}
+
+
+static inline int
+netdev_detach(int fd)
+{
+ /*
+ * inactivate the host interface (don't interrupt anymore) */
+ return ia64_ssc(fd, 0,0,0, SSC_NETDEV_DETACH);
+}
+
+static inline int
+netdev_send(int fd, unsigned char *buf, unsigned int len)
+{
+ return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_SEND);
+}
+
+static inline int
+netdev_read(int fd, unsigned char *buf, unsigned int len)
+{
+ return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV);
+}
+
+/*
+ * Function shared with module code, so cannot be in init section
+ *
+ * So far this function "detects" only one card (test_&_set) but could
+ * be extended easily.
+ *
+ * Return:
+ * - -ENODEV is no device found
+ * - -ENOMEM is no more memory
+ * - 0 otherwise
+ */
+static int
+simeth_probe1(void)
+{
+ unsigned char mac_addr[ETH_ALEN];
+ struct simeth_local *local;
+ struct net_device *dev;
+ int fd, i;
+
+ /*
+ * XXX Fix me
+ * let's support just one card for now
+ */
+ if (test_and_set_bit(0, &card_count))
+ return -ENODEV;
+
+ /*
+ * check with the simulator for the device
+ */
+ fd = netdev_probe(simeth_device, mac_addr);
+ if (fd == -1)
+ return -ENODEV;
+
+ dev = init_etherdev(NULL, sizeof(struct simeth_local));
+ if (!dev)
+ return -ENOMEM;
+
+ memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr));
+
+ dev->irq = ia64_alloc_irq();
+
+ /*
+ * attach the interrupt in the simulator, this does enable interrupts
+ * until a netdev_attach() is called
+ */
+ netdev_connect(dev->irq);
+
+ memset(dev->priv, 0, sizeof(struct simeth_local));
+
+ local = dev->priv;
+ local->simfd = fd; /* keep track of underlying file descriptor */
+
+ dev->open = simeth_open;
+ dev->stop = simeth_close;
+ dev->hard_start_xmit = simeth_tx;
+ dev->get_stats = simeth_get_stats;
+ dev->set_multicast_list = set_multicast_list; /* no yet used */
+
+ /* Fill in the fields of the device structure with ethernet-generic values. */
+ ether_setup(dev);
+
+ printk("%s: hosteth=%s simfd=%d, HwAddr", dev->name, simeth_device, local->simfd);
+ for(i = 0; i < ETH_ALEN; i++) {
+ printk(" %2.2x", dev->dev_addr[i]);
+ }
+ printk(", IRQ %d\n", dev->irq);
+
+ return 0;
+}
+
+/*
+ * actually binds the device to an interrupt vector
+ */
+static int
+simeth_open(struct net_device *dev)
+{
+ if (request_irq(dev->irq, simeth_interrupt, 0, "simeth", dev)) {
+ printk ("simeth: unable to get IRQ %d.\n", dev->irq);
+ return -EAGAIN;
+ }
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+/* copied from lapbether.c */
+static __inline__ int dev_is_ethdev(struct net_device *dev)
+{
+ return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5));
+}
+
+
+/*
+ * Handler for IFF_UP or IFF_DOWN
+ *
+ * The reason for that is that we don't want to be interrupted when the
+ * interface is down. There is no way to unconnect in the simualtor. Instead
+ * we use this function to shutdown packet processing in the frame filter
+ * in the simulator. Thus no interrupts are generated
+ *
+ *
+ * That's also the place where we pass the IP address of this device to the
+ * simulator so that that we can start filtering packets for it
+ *
+ * There may be a better way of doing this, but I don't know which yet.
+ */
+static int
+simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
+{
+ struct net_device *dev = (struct net_device *)ptr;
+ struct simeth_local *local;
+ struct in_device *in_dev;
+ struct in_ifaddr **ifap = NULL;
+ struct in_ifaddr *ifa = NULL;
+ int r;
+
+
+ if ( ! dev ) {
+ printk(KERN_WARNING "simeth_device_event dev=0\n");
+ return NOTIFY_DONE;
+ }
+
+ if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE;
+
+ /*
+ * Check whether or not it's for an ethernet device
+ *
+ * XXX Fixme: This works only as long as we support one
+ * type of ethernet device.
+ */
+ if ( !dev_is_ethdev(dev) ) return NOTIFY_DONE;
+
+ if ((in_dev=dev->ip_ptr) != NULL) {
+ for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
+ if (strcmp(dev->name, ifa->ifa_label) == 0) break;
+ }
+ if ( ifa == NULL ) {
+ printk("simeth_open: can't find device %s's ifa\n", dev->name);
+ return NOTIFY_DONE;
+ }
+
+ printk("simeth_device_event: %s ipaddr=0x%x\n", dev->name, htonl(ifa->ifa_local));
+
+ /*
+ * XXX Fix me
+ * if the device was up, and we're simply reconfiguring it, not sure
+ * we get DOWN then UP.
+ */
+
+ local = dev->priv;
+ /* now do it for real */
+ r = event == NETDEV_UP ?
+ netdev_attach(local->simfd, dev->irq, htonl(ifa->ifa_local)):
+ netdev_detach(local->simfd);
+
+ printk("simeth: netdev_attach/detach: event=%s ->%d\n", event == NETDEV_UP ? "attach":"detach", r);
+
+ return NOTIFY_DONE;
+}
+
+static int
+simeth_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+
+ free_irq(dev->irq, dev);
+
+ return 0;
+}
+
+/*
+ * Only used for debug
+ */
+static void
+frame_print(unsigned char *from, unsigned char *frame, int len)
+{
+ int i;
+
+ printk("%s: (%d) %02x", from, len, frame[0] & 0xff);
+ for(i=1; i < 6; i++ ) {
+ printk(":%02x", frame[i] &0xff);
+ }
+ printk(" %2x", frame[6] &0xff);
+ for(i=7; i < 12; i++ ) {
+ printk(":%02x", frame[i] &0xff);
+ }
+ printk(" [%02x%02x]\n", frame[12], frame[13]);
+
+ for(i=14; i < len; i++ ) {
+ printk("%02x ", frame[i] &0xff);
+ if ( (i%10)==0) printk("\n");
+ }
+ printk("\n");
+}
+
+
+/*
+ * Function used to transmit of frame, very last one on the path before
+ * going to the simulator.
+ */
+static int
+simeth_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct simeth_local *local = (struct simeth_local *)dev->priv;
+
+#if 0
+ /* ensure we have at least ETH_ZLEN bytes (min frame size) */
+ unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ /* Where do the extra padding bytes comes from inthe skbuff ? */
+#else
+ /* the real driver in the host system is going to take care of that
+ * or maybe it's the NIC itself.
+ */
+ unsigned int length = skb->len;
+#endif
+
+ local->stats.tx_bytes += skb->len;
+ local->stats.tx_packets++;
+
+
+ if (simeth_debug > 5) frame_print("simeth_tx", skb->data, length);
+
+ netdev_send(local->simfd, skb->data, length);
+
+ /*
+ * we are synchronous on write, so we don't simulate a
+ * trasnmit complete interrupt, thus we don't need to arm a tx
+ */
+
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static inline struct sk_buff *
+make_new_skb(struct net_device *dev)
+{
+ struct sk_buff *nskb;
+
+ /*
+ * The +2 is used to make sure that the IP header is nicely
+ * aligned (on 4byte boundary I assume 14+2=16)
+ */
+ nskb = dev_alloc_skb(SIMETH_FRAME_SIZE + 2);
+ if ( nskb == NULL ) {
+ printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name);
+ return NULL;
+ }
+ nskb->dev = dev;
+
+ skb_reserve(nskb, 2); /* Align IP on 16 byte boundaries */
+
+ skb_put(nskb,SIMETH_FRAME_SIZE);
+
+ return nskb;
+}
+
+/*
+ * called from interrupt handler to process a received frame
+ */
+static int
+simeth_rx(struct net_device *dev)
+{
+ struct simeth_local *local;
+ struct sk_buff *skb;
+ int len;
+ int rcv_count = SIMETH_RECV_MAX;
+
+ local = (struct simeth_local *)dev->priv;
+ /*
+ * the loop concept has been borrowed from other drivers
+ * looks to me like it's a throttling thing to avoid pushing to many
+ * packets at one time into the stack. Making sure we can process them
+ * upstream and make forward progress overall
+ */
+ do {
+ if ( (skb=make_new_skb(dev)) == NULL ) {
+ printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name);
+ local->stats.rx_dropped++;
+ return 0;
+ }
+ /*
+ * Read only one frame at a time
+ */
+ len = netdev_read(local->simfd, skb->data, SIMETH_FRAME_SIZE);
+ if ( len == 0 ) {
+ if ( simeth_debug > 0 ) printk(KERN_WARNING "%s: count=%d netdev_read=0\n", dev->name, SIMETH_RECV_MAX-rcv_count);
+ break;
+ }
+#if 0
+ /*
+ * XXX Fix me
+ * Should really do a csum+copy here
+ */
+ memcpy(skb->data, frame, len);
+#endif
+ skb->protocol = eth_type_trans(skb, dev);
+
+ if ( simeth_debug > 6 ) frame_print("simeth_rx", skb->data, len);
+
+ /*
+ * push the packet up & trigger software interrupt
+ */
+ netif_rx(skb);
+
+ local->stats.rx_packets++;
+ local->stats.rx_bytes += len;
+
+ } while ( --rcv_count );
+
+ return len; /* 0 = nothing left to read, otherwise, we can try again */
+}
+
+/*
+ * Interrupt handler (Yes, we can do it too !!!)
+ */
+static void
+simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = dev_id;
+
+ if ( dev == NULL ) {
+ printk(KERN_WARNING "simeth: irq %d for unknown device\n", irq);
+ return;
+ }
+
+ /*
+ * very simple loop because we get interrupts only when receving
+ */
+ while (simeth_rx(dev));
+}
+
+static struct net_device_stats *
+simeth_get_stats(struct net_device *dev)
+{
+ struct simeth_local *local = (struct simeth_local *) dev->priv;
+
+ return &local->stats;
+}
+
+/* fake multicast ability */
+static void
+set_multicast_list(struct net_device *dev)
+{
+ printk(KERN_WARNING "%s: set_multicast_list called\n", dev->name);
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+static int
+simeth_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
+{
+ printk(KERN_WARNING "%s: simeth_accept_fastpath called\n", dev->name);
+ return -1;
+}
+#endif
+
+__initcall(simeth_probe);
diff -Nru a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/simscsi.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,368 @@
+/*
+ * Simulated SCSI driver.
+ *
+ * Copyright (C) 1999, 2001-2002 Hewlett-Packard Co
+ * David Mosberger-Tang
+ * Stephane Eranian
+ *
+ * 02/01/15 David Mosberger Updated for v2.5.1
+ * 99/12/18 David Mosberger Added support for READ10/WRITE10 needed by linux v2.3.33
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include "../drivers/scsi/scsi.h"
+#include "../drivers/scsi/sd.h"
+#include "../drivers/scsi/hosts.h"
+#include "simscsi.h"
+
+#define DEBUG_SIMSCSI 1
+
+/* Simulator system calls: */
+
+#define SSC_OPEN 50
+#define SSC_CLOSE 51
+#define SSC_READ 52
+#define SSC_WRITE 53
+#define SSC_GET_COMPLETION 54
+#define SSC_WAIT_COMPLETION 55
+
+#define SSC_WRITE_ACCESS 2
+#define SSC_READ_ACCESS 1
+
+#if DEBUG_SIMSCSI
+ int simscsi_debug;
+# define DBG simscsi_debug
+#else
+# define DBG 0
+#endif
+
+static struct Scsi_Host *host;
+
+static void simscsi_interrupt (unsigned long val);
+DECLARE_TASKLET(simscsi_tasklet, simscsi_interrupt, 0);
+
+struct disk_req {
+ unsigned long addr;
+ unsigned len;
+};
+
+struct disk_stat {
+ int fd;
+ unsigned count;
+};
+
+extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr);
+
+static int desc[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static struct queue_entry {
+ Scsi_Cmnd *sc;
+} queue[SIMSCSI_REQ_QUEUE_LEN];
+
+static int rd, wr;
+static atomic_t num_reqs = ATOMIC_INIT(0);
+
+/* base name for default disks */
+static char *simscsi_root = DEFAULT_SIMSCSI_ROOT;
+
+#define MAX_ROOT_LEN 128
+
+/*
+ * used to setup a new base for disk images
+ * to use /foo/bar/disk[a-z] as disk images
+ * you have to specify simscsi=/foo/bar/disk on the command line
+ */
+static int __init
+simscsi_setup (char *s)
+{
+ /* XXX Fix me we may need to strcpy() ? */
+ if (strlen(s) > MAX_ROOT_LEN) {
+ printk("simscsi_setup: prefix too long---using default %s\n", simscsi_root);
+ }
+ simscsi_root = s;
+ return 1;
+}
+
+__setup("simscsi=", simscsi_setup);
+
+static void
+simscsi_interrupt (unsigned long val)
+{
+ Scsi_Cmnd *sc;
+
+ while ((sc = queue[rd].sc) != 0) {
+ atomic_dec(&num_reqs);
+ queue[rd].sc = 0;
+ if (DBG)
+ printk("simscsi_interrupt: done with %ld\n", sc->serial_number);
+ (*sc->scsi_done)(sc);
+ rd = (rd + 1) % SIMSCSI_REQ_QUEUE_LEN;
+ }
+}
+
+int
+simscsi_detect (Scsi_Host_Template *templ)
+{
+ templ->proc_name = "simscsi";
+ host = scsi_register(templ, 0);
+ return 1; /* fake one SCSI host adapter */
+}
+
+int
+simscsi_release (struct Scsi_Host *host)
+{
+ return 0; /* this is easy... */
+}
+
+const char *
+simscsi_info (struct Scsi_Host *host)
+{
+ return "simulated SCSI host adapter";
+}
+
+int
+simscsi_abort (Scsi_Cmnd *cmd)
+{
+ printk ("simscsi_abort: unimplemented\n");
+ return SCSI_ABORT_SUCCESS;
+}
+
+int
+simscsi_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+ printk ("simscsi_reset: unimplemented\n");
+ return SCSI_RESET_SUCCESS;
+}
+
+int
+simscsi_biosparam (Disk *disk, kdev_t n, int ip[])
+{
+ int size = disk->capacity;
+
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = size >> 11;
+ return 0;
+}
+
+static void
+simscsi_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset, unsigned long len)
+{
+ struct disk_stat stat;
+ struct disk_req req;
+
+ req.addr = __pa(sc->request_buffer);
+ req.len = len; /* # of bytes to transfer */
+
+ if (sc->request_bufflen < req.len)
+ return;
+
+ stat.fd = desc[sc->target];
+ if (DBG)
+ printk("simscsi_%s @ %lx (off %lx)\n",
+ mode == SSC_READ ? "read":"write", req.addr, offset);
+ ia64_ssc(stat.fd, 1, __pa(&req), offset, mode);
+ ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION);
+
+ if (stat.count == req.len) {
+ sc->result = GOOD;
+ } else {
+ sc->result = DID_ERROR << 16;
+ }
+}
+
+static void
+simscsi_sg_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset)
+{
+ int list_len = sc->use_sg;
+ struct scatterlist *sl = (struct scatterlist *)sc->buffer;
+ struct disk_stat stat;
+ struct disk_req req;
+
+ stat.fd = desc[sc->target];
+
+ while (list_len) {
+ req.addr = __pa(page_address(sl->page) + sl->offset);
+ req.len = sl->length;
+ if (DBG)
+ printk("simscsi_sg_%s @ %lx (off %lx) use_sg=%d len=%d\n",
+ mode == SSC_READ ? "read":"write", req.addr, offset,
+ list_len, sl->length);
+ ia64_ssc(stat.fd, 1, __pa(&req), offset, mode);
+ ia64_ssc(__pa(&stat), 0, 0, 0, SSC_WAIT_COMPLETION);
+
+ /* should not happen in our case */
+ if (stat.count != req.len) {
+ sc->result = DID_ERROR << 16;
+ return;
+ }
+ offset += sl->length;
+ sl++;
+ list_len--;
+ }
+ sc->result = GOOD;
+}
+
+/*
+ * function handling both READ_6/WRITE_6 (non-scatter/gather mode)
+ * commands.
+ * Added 02/26/99 S.Eranian
+ */
+static void
+simscsi_readwrite6 (Scsi_Cmnd *sc, int mode)
+{
+ unsigned long offset;
+
+ offset = (((sc->cmnd[1] & 0x1f) << 16) | (sc->cmnd[2] << 8) | sc->cmnd[3])*512;
+ if (sc->use_sg > 0)
+ simscsi_sg_readwrite(sc, mode, offset);
+ else
+ simscsi_readwrite(sc, mode, offset, sc->cmnd[4]*512);
+}
+
+
+static void
+simscsi_readwrite10 (Scsi_Cmnd *sc, int mode)
+{
+ unsigned long offset;
+
+ offset = ( (sc->cmnd[2] << 24) | (sc->cmnd[3] << 16)
+ | (sc->cmnd[4] << 8) | (sc->cmnd[5] << 0))*512;
+ if (sc->use_sg > 0)
+ simscsi_sg_readwrite(sc, mode, offset);
+ else
+ simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512);
+}
+
+int
+simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *))
+{
+ char fname[MAX_ROOT_LEN+16];
+ char *buf;
+#if DEBUG_SIMSCSI
+ register long sp asm ("sp");
+
+ if (DBG)
+ printk("simscsi_queuecommand: target=%d,cmnd=%u,sc=%lu,sp=%lx,done=%p\n",
+ sc->target, sc->cmnd[0], sc->serial_number, sp, done);
+#endif
+
+ sc->result = DID_BAD_TARGET << 16;
+ sc->scsi_done = done;
+ if (sc->target <= 7 && sc->lun == 0) {
+ switch (sc->cmnd[0]) {
+ case INQUIRY:
+ if (sc->request_bufflen < 35) {
+ break;
+ }
+ sprintf (fname, "%s%c", simscsi_root, 'a' + sc->target);
+ desc[sc->target] = ia64_ssc (__pa(fname), SSC_READ_ACCESS|SSC_WRITE_ACCESS,
+ 0, 0, SSC_OPEN);
+ if (desc[sc->target] < 0) {
+ /* disk doesn't exist... */
+ break;
+ }
+ buf = sc->request_buffer;
+ buf[0] = 0; /* magnetic disk */
+ buf[1] = 0; /* not a removable medium */
+ buf[2] = 2; /* SCSI-2 compliant device */
+ buf[3] = 2; /* SCSI-2 response data format */
+ buf[4] = 31; /* additional length (bytes) */
+ buf[5] = 0; /* reserved */
+ buf[6] = 0; /* reserved */
+ buf[7] = 0; /* various flags */
+ memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28);
+ sc->result = GOOD;
+ break;
+
+ case TEST_UNIT_READY:
+ sc->result = GOOD;
+ break;
+
+ case READ_6:
+ if (desc[sc->target] < 0 )
+ break;
+ simscsi_readwrite6(sc, SSC_READ);
+ break;
+
+ case READ_10:
+ if (desc[sc->target] < 0 )
+ break;
+ simscsi_readwrite10(sc, SSC_READ);
+ break;
+
+ case WRITE_6:
+ if (desc[sc->target] < 0)
+ break;
+ simscsi_readwrite6(sc, SSC_WRITE);
+ break;
+
+ case WRITE_10:
+ if (desc[sc->target] < 0)
+ break;
+ simscsi_readwrite10(sc, SSC_WRITE);
+ break;
+
+
+ case READ_CAPACITY:
+ if (desc[sc->target] < 0 || sc->request_bufflen < 8) {
+ break;
+ }
+ buf = sc->request_buffer;
+
+ /* pretend to be a 1GB disk (partition table contains real stuff): */
+ buf[0] = 0x00;
+ buf[1] = 0x1f;
+ buf[2] = 0xff;
+ buf[3] = 0xff;
+ /* set block size of 512 bytes: */
+ buf[4] = 0;
+ buf[5] = 0;
+ buf[6] = 2;
+ buf[7] = 0;
+ sc->result = GOOD;
+ break;
+
+ case MODE_SENSE:
+ printk("MODE_SENSE\n");
+ break;
+
+ case START_STOP:
+ printk("START_STOP\n");
+ break;
+
+ default:
+ panic("simscsi: unknown SCSI command %u\n", sc->cmnd[0]);
+ }
+ }
+ if (sc->result == DID_BAD_TARGET) {
+ sc->result |= DRIVER_SENSE << 24;
+ sc->sense_buffer[0] = 0x70;
+ sc->sense_buffer[2] = 0x00;
+ }
+ if (atomic_read(&num_reqs) >= SIMSCSI_REQ_QUEUE_LEN) {
+ panic("Attempt to queue command while command is pending!!");
+ }
+ atomic_inc(&num_reqs);
+ queue[wr].sc = sc;
+ wr = (wr + 1) % SIMSCSI_REQ_QUEUE_LEN;
+
+ tasklet_schedule(&simscsi_tasklet);
+ return 0;
+}
+
+
+static Scsi_Host_Template driver_template = SIMSCSI;
+
+#define __initcall(fn) late_initcall(fn)
+
+#include "../drivers/scsi/scsi_module.c"
diff -Nru a/arch/ia64/hp/sim/simscsi.h b/arch/ia64/hp/sim/simscsi.h
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/simscsi.h Mon Apr 22 15:32:18 2002
@@ -0,0 +1,39 @@
+/*
+ * Simulated SCSI driver.
+ *
+ * Copyright (C) 1999 Hewlett-Packard Co
+ * David Mosberger-Tang
+ */
+#ifndef SIMSCSI_H
+#define SIMSCSI_H
+
+#define SIMSCSI_REQ_QUEUE_LEN 64
+
+#define DEFAULT_SIMSCSI_ROOT "/var/ski-disks/sd"
+
+extern int simscsi_detect (Scsi_Host_Template *);
+extern int simscsi_release (struct Scsi_Host *);
+extern const char *simscsi_info (struct Scsi_Host *);
+extern int simscsi_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int simscsi_abort (Scsi_Cmnd *);
+extern int simscsi_reset (Scsi_Cmnd *, unsigned int);
+extern int simscsi_biosparam (Disk *, kdev_t, int[]);
+
+#define SIMSCSI { \
+ detect: simscsi_detect, \
+ release: simscsi_release, \
+ info: simscsi_info, \
+ queuecommand: simscsi_queuecommand, \
+ abort: simscsi_abort, \
+ reset: simscsi_reset, \
+ bios_param: simscsi_biosparam, \
+ can_queue: SIMSCSI_REQ_QUEUE_LEN, \
+ this_id: -1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: SIMSCSI_REQ_QUEUE_LEN, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: DISABLE_CLUSTERING \
+}
+
+#endif /* SIMSCSI_H */
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/hp/sim/simserial.c Mon Apr 22 15:32:19 2002
@@ -0,0 +1,1104 @@
+/*
+ * Simulated Serial Driver (fake serial)
+ *
+ * This driver is mostly used for bringup purposes and will go away.
+ * It has a strong dependency on the system console. All outputs
+ * are rerouted to the same facility as the one used by printk which, in our
+ * case means sys_sim.c console (goes via the simulator). The code hereafter
+ * is completely leveraged from the serial.c driver.
+ *
+ * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999 Stephane Eranian
+ * Copyright (C) 2000 David Mosberger-Tang
+ *
+ * 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close().
+ * 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef CONFIG_KDB
+# include
+#endif
+
+#undef SIMSERIAL_DEBUG /* define this to get some debug information */
+
+#define KEYBOARD_INTR 3 /* must match with simulator! */
+
+#define NR_PORTS 1 /* only one port for now */
+#define SERIAL_INLINE 1
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define SSC_GETCHAR 21
+
+extern long ia64_ssc (long, long, long, long, int);
+extern void ia64_ssc_connect_irq (long intr, long irq);
+
+static char *serial_name = "SimSerial driver";
+static char *serial_version = "0.6";
+
+/*
+ * This has been extracted from asm/serial.h. We need one eventually but
+ * I don't know exactly what we're going to put in it so just fake one
+ * for now.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+/*
+ * Most of the values here are meaningless to this particular driver.
+ * However some values must be preserved for the code (leveraged from serial.c
+ * to work correctly).
+ * port must not be 0
+ * type must not be UNKNOWN
+ * So I picked arbitrary (guess from where?) values instead
+ */
+static struct serial_state rs_table[NR_PORTS]={
+ /* UART CLK PORT IRQ FLAGS */
+ { 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */
+};
+
+/*
+ * Just for the fun of it !
+ */
+static struct serial_uart_config uart_config[] = {
+ { "unknown", 1, 0 },
+ { "8250", 1, 0 },
+ { "16450", 1, 0 },
+ { "16550", 1, 0 },
+ { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
+ { "cirrus", 1, 0 },
+ { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
+ { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+ UART_STARTECH },
+ { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+ { 0, 0}
+};
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+static struct async_struct *IRQ_ports[NR_IRQS];
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+static struct console *console;
+
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
+
+extern struct console *console_drivers; /* from kernel/printk.c */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+#ifdef SIMSERIAL_DEBUG
+ printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
+ tty->stopped, tty->hw_stopped, tty->flow_stopped);
+#endif
+
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+#if SIMSERIAL_DEBUG
+ printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
+ tty->stopped, tty->hw_stopped, tty->flow_stopped);
+#endif
+}
+
+static void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
+{
+ unsigned char ch;
+ static unsigned char seen_esc = 0;
+
+ while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) {
+ if ( ch == 27 && seen_esc == 0 ) {
+ seen_esc = 1;
+ continue;
+ } else {
+ if ( seen_esc==1 && ch == 'O' ) {
+ seen_esc = 2;
+ continue;
+ } else if ( seen_esc == 2 ) {
+ if ( ch == 'P' ) show_state(); /* F1 key */
+ if ( ch == 'Q' ) show_buffers(); /* F2 key */
+#ifdef CONFIG_KDB
+ if ( ch == 'S' )
+ kdb(KDB_REASON_KEYBOARD, 0, (kdb_eframe_t) regs);
+#endif
+
+ seen_esc = 0;
+ continue;
+ }
+ }
+ seen_esc = 0;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
+
+ *tty->flip.char_buf_ptr = ch;
+
+ *tty->flip.flag_buf_ptr = 0;
+
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ tty_flip_buffer_push(tty);
+}
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct async_struct * info;
+
+ /*
+ * I don't know exactly why they don't use the dev_id opaque data
+ * pointer instead of this extra lookup table
+ */
+ info = IRQ_ports[irq];
+ if (!info || !info->tty) {
+ printk("simrs_interrupt_single: info|tty=0 info=%p problem\n", info);
+ return;
+ }
+ /*
+ * pretty simple in our case, because we only get interrupts
+ * on inbound traffic
+ */
+ receive_chars(info->tty, regs);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+#if 0
+/*
+ * not really used in our situation so keep them commented out for now
+ */
+static DECLARE_TASK_QUEUE(tq_serial); /* used to be at the top of the file */
+static void do_serial_bh(void)
+{
+ run_task_queue(&tq_serial);
+ printk("do_serial_bh: called\n");
+}
+#endif
+
+static void do_softint(void *private_)
+{
+ printk("simserial: do_softint called\n");
+}
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (!tty || !info->xmit.buf) return;
+
+ save_flags(flags); cli();
+ if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) {
+ restore_flags(flags);
+ return;
+ }
+ info->xmit.buf[info->xmit.head] = ch;
+ info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
+ restore_flags(flags);
+}
+
+static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
+{
+ int count;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ if (info->x_char) {
+ char c = info->x_char;
+
+ console->write(console, &c, 1);
+
+ info->state->icount.tx++;
+ info->x_char = 0;
+
+ goto out;
+ }
+
+ if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) {
+#ifdef SIMSERIAL_DEBUG
+ printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
+ info->xmit.head, info->xmit.tail, info->tty->stopped);
+#endif
+ goto out;
+ }
+ /*
+ * We removed the loop and try to do it in to chunks. We need
+ * 2 operations maximum because it's a ring buffer.
+ *
+ * First from current to tail if possible.
+ * Then from the beginning of the buffer until necessary
+ */
+
+ count = MIN(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE),
+ SERIAL_XMIT_SIZE - info->xmit.tail);
+ console->write(console, info->xmit.buf+info->xmit.tail, count);
+
+ info->xmit.tail = (info->xmit.tail+count) & (SERIAL_XMIT_SIZE-1);
+
+ /*
+ * We have more at the beginning of the buffer
+ */
+ count = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+ if (count) {
+ console->write(console, info->xmit.buf, count);
+ info->xmit.tail += count;
+ }
+out:
+ restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+ if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped ||
+ !info->xmit.buf)
+ return;
+
+ transmit_chars(info, NULL);
+}
+
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, ret = 0;
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (!tty || !info->xmit.buf || !tmp_buf) return 0;
+
+ save_flags(flags);
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ int c1;
+ c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ cli();
+ c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ cli();
+ while (1) {
+ c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0) {
+ break;
+ }
+ memcpy(info->xmit.buf + info->xmit.head, buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ restore_flags(flags);
+ }
+ /*
+ * Hey, we transmit directly from here in our case
+ */
+ if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE)
+ && !tty->stopped && !tty->hw_stopped) {
+ transmit_chars(info, NULL);
+ }
+ return ret;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ info->xmit.head = info->xmit.tail = 0;
+ restore_flags(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+ info->x_char = ch;
+ if (ch) {
+ /*
+ * I guess we could call console->write() directly but
+ * let's do that for now.
+ */
+ transmit_chars(info, NULL);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+ if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty));
+
+ printk("simrs_throttle called\n");
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+ struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ rs_send_xchar(tty, START_CHAR(tty));
+ }
+ printk("simrs_unthrottle called\n");
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TIOCMGET:
+ printk("rs_ioctl: TIOCMGET called\n");
+ return -EINVAL;
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ printk("rs_ioctl: TIOCMBIS/BIC/SET called\n");
+ return -EINVAL;
+ case TIOCGSERIAL:
+ printk("simrs_ioctl TIOCGSERIAL called\n");
+ return 0;
+ case TIOCSSERIAL:
+ printk("simrs_ioctl TIOCSSERIAL called\n");
+ return 0;
+ case TIOCSERCONFIG:
+ printk("rs_ioctl: TIOCSERCONFIG called\n");
+ return -EINVAL;
+
+ case TIOCSERGETLSR: /* Get line status register */
+ printk("rs_ioctl: TIOCSERGETLSR called\n");
+ return -EINVAL;
+
+ case TIOCSERGSTRUCT:
+ printk("rs_ioctl: TIOCSERGSTRUCT called\n");
+#if 0
+ if (copy_to_user((struct async_struct *) arg,
+ info, sizeof(struct async_struct)))
+ return -EFAULT;
+#endif
+ return 0;
+
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ printk("rs_ioctl: TIOCMIWAIT: called\n");
+ return 0;
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ printk("rs_ioctl: TIOCGICOUNT called\n");
+ return 0;
+
+ case TIOCSERGWILD:
+ case TIOCSERSWILD:
+ /* "setserial -W" is called in Debian boot */
+ printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ unsigned int cflag = tty->termios->c_cflag;
+
+ if ( (cflag == old_termios->c_cflag)
+ && ( RELEVANT_IFLAG(tty->termios->c_iflag)
+ == RELEVANT_IFLAG(old_termios->c_iflag)))
+ return;
+
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ rs_start(tty);
+ }
+}
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+ unsigned long flags;
+ struct serial_state *state;
+ int retval;
+
+ if (!(info->flags & ASYNC_INITIALIZED)) return;
+
+ state = info->state;
+
+#ifdef SIMSERIAL_DEBUG
+ printk("Shutting down serial port %d (irq %d)....", info->line,
+ state->irq);
+#endif
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ /*
+ * First unlink the serial port from the IRQ chain...
+ */
+ if (info->next_port)
+ info->next_port->prev_port = info->prev_port;
+ if (info->prev_port)
+ info->prev_port->next_port = info->next_port;
+ else
+ IRQ_ports[state->irq] = info->next_port;
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ if (state->irq && (!IRQ_ports[state->irq] ||
+ !IRQ_ports[state->irq]->next_port)) {
+ if (IRQ_ports[state->irq]) {
+ free_irq(state->irq, NULL);
+ retval = request_irq(state->irq, rs_interrupt_single,
+ IRQ_T(info), "serial", NULL);
+
+ if (retval)
+ printk("serial shutdown: request_irq: error %d"
+ " Couldn't reacquire IRQ.\n", retval);
+ } else
+ free_irq(state->irq, NULL);
+ }
+
+ if (info->xmit.buf) {
+ free_page((unsigned long) info->xmit.buf);
+ info->xmit.buf = 0;
+ }
+
+ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ struct serial_state *state;
+ unsigned long flags;
+
+ if (!info ) return;
+
+ state = info->state;
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+#ifdef SIMSERIAL_DEBUG
+ printk("rs_close: hung_up\n");
+#endif
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+#ifdef SIMSERIAL_DEBUG
+ printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+ if ((tty->count == 1) && (state->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. state->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "state->count is %d\n", state->count);
+ state->count = 1;
+ }
+ if (--state->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, state->count);
+ state->count = 0;
+ }
+ if (state->count) {
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ restore_flags(flags);
+
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ shutdown(info);
+ if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(info->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+}
+
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_hangup(struct tty_struct *tty)
+{
+ struct async_struct * info = (struct async_struct *)tty->driver_data;
+ struct serial_state *state = info->state;
+
+#ifdef SIMSERIAL_DEBUG
+ printk("rs_hangup: called\n");
+#endif
+
+ state = info->state;
+
+ rs_flush_buffer(tty);
+ if (info->flags & ASYNC_CLOSING)
+ return;
+ shutdown(info);
+
+ info->event = 0;
+ state->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+ struct async_struct *info;
+ struct serial_state *sstate;
+
+ sstate = rs_table + line;
+ sstate->count++;
+ if (sstate->info) {
+ *ret_info = sstate->info;
+ return 0;
+ }
+ info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+ if (!info) {
+ sstate->count--;
+ return -ENOMEM;
+ }
+ memset(info, 0, sizeof(struct async_struct));
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ info->magic = SERIAL_MAGIC;
+ info->port = sstate->port;
+ info->flags = sstate->flags;
+ info->xmit_fifo_size = sstate->xmit_fifo_size;
+ info->line = line;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->state = sstate;
+ if (sstate->info) {
+ kfree(info);
+ *ret_info = sstate->info;
+ return 0;
+ }
+ *ret_info = sstate->info = info;
+ return 0;
+}
+
+static int
+startup(struct async_struct *info)
+{
+ unsigned long flags;
+ int retval=0;
+ void (*handler)(int, void *, struct pt_regs *);
+ struct serial_state *state= info->state;
+ unsigned long page;
+
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ save_flags(flags); cli();
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
+
+ if (!state->port || !state->type) {
+ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ goto errout;
+ }
+ if (info->xmit.buf)
+ free_page(page);
+ else
+ info->xmit.buf = (unsigned char *) page;
+
+#ifdef SIMSERIAL_DEBUG
+ printk("startup: ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+ /*
+ * Allocate the IRQ if necessary
+ */
+ if (state->irq && (!IRQ_ports[state->irq] ||
+ !IRQ_ports[state->irq]->next_port)) {
+ if (IRQ_ports[state->irq]) {
+ retval = -EBUSY;
+ goto errout;
+ } else
+ handler = rs_interrupt_single;
+
+ retval = request_irq(state->irq, handler, IRQ_T(info),
+ "simserial", NULL);
+ if (retval) {
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR,
+ &info->tty->flags);
+ retval = 0;
+ }
+ goto errout;
+ }
+ }
+
+ /*
+ * Insert serial port into IRQ chain.
+ */
+ info->prev_port = 0;
+ info->next_port = IRQ_ports[state->irq];
+ if (info->next_port)
+ info->next_port->prev_port = info;
+ IRQ_ports[state->irq] = info;
+
+ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->xmit.head = info->xmit.tail = 0;
+
+#if 0
+ /*
+ * Set up serial timers...
+ */
+ timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
+ timer_active |= 1 << RS_TIMER;
+#endif
+
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ }
+
+ info->flags |= ASYNC_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+
+errout:
+ restore_flags(flags);
+ return retval;
+}
+
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+ struct async_struct *info;
+ int retval, line;
+ unsigned long page;
+
+ MOD_INC_USE_COUNT;
+ line = minor(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (line >= NR_PORTS)) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+ retval = get_async_struct(line, &info);
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ return retval;
+ }
+ tty->driver_data = info;
+ info->tty = tty;
+
+#ifdef SIMSERIAL_DEBUG
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->state->count);
+#endif
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ if (!tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+ return -ENOMEM;
+ }
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+ }
+
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval) {
+ /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
+ return retval;
+ }
+
+ if ((info->state->count == 1) &&
+ (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->state->normal_termios;
+ else
+ *tty->termios = info->state->callout_termios;
+ }
+
+ /*
+ * figure out which console to use (should be one already)
+ */
+ console = console_drivers;
+ while (console) {
+ if ((console->flags & CON_ENABLED) && console->write) break;
+ console = console->next;
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SIMSERIAL_DEBUG
+ printk("rs_open ttys%d successful\n", info->line);
+#endif
+ return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+ return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n",
+ state->line, uart_config[state->type].name,
+ state->port, state->irq);
+}
+
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int i, len = 0, l;
+ off_t begin = 0;
+
+ len += sprintf(page, "simserinfo:1.0 driver:%s\n", serial_version);
+ for (i = 0; i < NR_PORTS && len < 4000; i++) {
+ l = line_info(page + len, &rs_table[i]);
+ len += l;
+ if (len+begin > off+count)
+ goto done;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ *eof = 1;
+done:
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static inline void show_serial_version(void)
+{
+ printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+ printk(" no serial options enabled\n");
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+static int __init
+simrs_init (void)
+{
+ int i;
+ struct serial_state *state;
+
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.driver_name = "simserial";
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = 1;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+ serial_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_open;
+ serial_driver.close = rs_close;
+ serial_driver.write = rs_write;
+ serial_driver.put_char = rs_put_char;
+ serial_driver.flush_chars = rs_flush_chars;
+ serial_driver.write_room = rs_write_room;
+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
+ serial_driver.flush_buffer = rs_flush_buffer;
+ serial_driver.ioctl = rs_ioctl;
+ serial_driver.throttle = rs_throttle;
+ serial_driver.unthrottle = rs_unthrottle;
+ serial_driver.send_xchar = rs_send_xchar;
+ serial_driver.set_termios = rs_set_termios;
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+ serial_driver.break_ctl = rs_break;
+ serial_driver.wait_until_sent = rs_wait_until_sent;
+ serial_driver.read_proc = rs_read_proc;
+
+ /*
+ * Let's have a little bit of fun !
+ */
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+
+ if (state->type == PORT_UNKNOWN) continue;
+
+ if (!state->irq) {
+ state->irq = ia64_alloc_irq();
+ ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
+ }
+
+ printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n",
+ state->line,
+ state->port, state->irq,
+ uart_config[state->type].name);
+ }
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ callout_driver.read_proc = 0;
+ callout_driver.proc_entry = 0;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register simserial driver\n");
+
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ return 0;
+}
+
+#ifndef MODULE
+__initcall(simrs_init);
+#endif
diff -Nru a/arch/ia64/hp/simeth.c b/arch/ia64/hp/simeth.c
--- a/arch/ia64/hp/simeth.c Mon Apr 22 15:32:18 2002
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,533 +0,0 @@
-/*
- * Simulated Ethernet Driver
- *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
- * Stephane Eranian
- */
-#include
-#include
-#include
-#include
-#include