aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2002-01-30 01:39:55 +0000
committerdavem <davem>2002-01-30 01:39:55 +0000
commit740838cd7a21abebe650af413af6ded3bf5e7aad (patch)
tree9f579227eb9dedee3454bb9685d484447d66d4b3
parenta9e46fd6ff191750dd6f661f514e5687875b3a73 (diff)
downloadnetdev-vger-cvs-740838cd7a21abebe650af413af6ded3bf5e7aad.tar.gz
Merge mainline to 2.5.3-pre6
-rw-r--r--Documentation/DocBook/Makefile6
-rw-r--r--Documentation/DocBook/writing_usb_driver.tmpl469
-rw-r--r--Documentation/scsi-generic.txt870
-rw-r--r--Documentation/scsi.txt70
-rw-r--r--Makefile5
-rw-r--r--arch/alpha/Config.help154
-rw-r--r--arch/arm/Config.help69
-rw-r--r--arch/cris/Config.help63
-rw-r--r--arch/i386/Config.help86
-rw-r--r--arch/i386/defconfig4
-rw-r--r--arch/i386/kernel/apic.c28
-rw-r--r--arch/i386/kernel/entry.S2
-rw-r--r--arch/i386/kernel/mtrr.c85
-rw-r--r--arch/i386/kernel/process.c12
-rw-r--r--arch/i386/kernel/setup.c7
-rw-r--r--arch/i386/kernel/smpboot.c11
-rw-r--r--arch/ia64/Config.help39
-rw-r--r--arch/m68k/Config.help45
-rw-r--r--arch/ppc/8xx_io/Config.help10
-rw-r--r--arch/ppc/Config.help204
-rw-r--r--arch/sh/Config.help133
-rw-r--r--arch/sparc64/kernel/smp.c135
-rw-r--r--arch/sparc64/kernel/traps.c17
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/base/Makefile7
-rw-r--r--drivers/base/core.c213
-rw-r--r--drivers/base/fs.c131
-rw-r--r--drivers/base/interface.c174
-rw-r--r--drivers/char/Config.help22
-rw-r--r--drivers/char/console.c8
-rw-r--r--drivers/char/ftape/Config.help72
-rw-r--r--drivers/hotplug/pcihp_skeleton.c432
-rw-r--r--drivers/ide/Config.help15
-rw-r--r--drivers/ieee1394/video1394.c4
-rw-r--r--drivers/isdn/Config.help10
-rw-r--r--drivers/isdn/isdn_common.c5
-rw-r--r--drivers/mtd/chips/Config.help16
-rw-r--r--drivers/net/wireless/wavelan_cs.c14
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/pci-driver.c36
-rw-r--r--drivers/pci/pci.c3
-rw-r--r--drivers/usb/hcd.c2
-rw-r--r--drivers/usb/hcd/Config.help15
-rw-r--r--drivers/usb/hcd/ehci-hcd.c2
-rw-r--r--drivers/usb/uhci.c14
-rw-r--r--drivers/usb/usb-ohci.c2
-rw-r--r--drivers/usb/usb-uhci.c28
-rw-r--r--drivers/usb/usb.c53
-rw-r--r--fs/adfs/dir.c4
-rw-r--r--fs/adfs/inode.c46
-rw-r--r--fs/adfs/super.c57
-rw-r--r--fs/bfs/bfs_defs.h7
-rw-r--r--fs/bfs/dir.c14
-rw-r--r--fs/bfs/file.c25
-rw-r--r--fs/bfs/inode.c79
-rw-r--r--fs/buffer.c1
-rw-r--r--fs/fat/buffer.c9
-rw-r--r--fs/fat/cache.c5
-rw-r--r--fs/fat/cvf.c14
-rw-r--r--fs/fat/dir.c11
-rw-r--r--fs/fat/fatfs_syms.c5
-rw-r--r--fs/fat/file.c9
-rw-r--r--fs/fat/inode.c74
-rw-r--r--fs/fat/misc.c5
-rw-r--r--fs/hfs/inode.c16
-rw-r--r--fs/hfs/super.c58
-rw-r--r--fs/isofs/compress.c4
-rw-r--r--fs/isofs/inode.c98
-rw-r--r--fs/isofs/namei.c2
-rw-r--r--fs/isofs/rock.c10
-rw-r--r--fs/isofs/util.c1
-rw-r--r--fs/jffs/inode-v23.c2
-rw-r--r--fs/jffs/jffs_fm.c2
-rw-r--r--fs/jffs2/dir.c1
-rw-r--r--fs/jffs2/malloc.c35
-rw-r--r--fs/jffs2/readinode.c10
-rw-r--r--fs/jffs2/super.c14
-rw-r--r--fs/jffs2/write.c9
-rw-r--r--fs/msdos/namei.c4
-rw-r--r--fs/ntfs/fs.c110
-rw-r--r--fs/ntfs/macros.h15
-rw-r--r--fs/ntfs/unistr.c1
-rw-r--r--fs/reiserfs/super.c2
-rw-r--r--fs/smbfs/dir.c9
-rw-r--r--fs/smbfs/file.c10
-rw-r--r--fs/smbfs/inode.c82
-rw-r--r--fs/smbfs/proc.c46
-rw-r--r--fs/ufs/super.c12
-rw-r--r--fs/vfat/namei.c6
-rw-r--r--include/asm-i386/apic.h2
-rw-r--r--include/asm-i386/bitops.h77
-rw-r--r--include/asm-i386/mmu_context.h26
-rw-r--r--include/asm-sparc64/bitops.h127
-rw-r--r--include/asm-sparc64/mmu_context.h18
-rw-r--r--include/linux/adfs_fs.h6
-rw-r--r--include/linux/adfs_fs_i.h1
-rw-r--r--include/linux/bfs_fs.h7
-rw-r--r--include/linux/bfs_fs_i.h1
-rw-r--r--include/linux/fs.h16
-rw-r--r--include/linux/hfs_fs.h7
-rw-r--r--include/linux/hfs_fs_i.h1
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/isdn.h1
-rw-r--r--include/linux/iso_fs.h6
-rw-r--r--include/linux/iso_fs_i.h1
-rw-r--r--include/linux/jffs2_fs_i.h6
-rw-r--r--include/linux/msdos_fs.h9
-rw-r--r--include/linux/msdos_fs_i.h2
-rw-r--r--include/linux/ntfs_fs_i.h6
-rw-r--r--include/linux/sched.h21
-rw-r--r--include/linux/smb_fs.h7
-rw-r--r--include/linux/smb_fs_i.h2
-rw-r--r--include/linux/usb.h32
-rw-r--r--init/main.c15
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/device.c527
-rw-r--r--kernel/exit.c3
-rw-r--r--kernel/fork.c5
-rw-r--r--kernel/sched.c246
-rw-r--r--mm/page_alloc.c1
-rw-r--r--net/ipv4/icmp.c20
-rw-r--r--net/ipv4/tcp_ipv4.c21
122 files changed, 3997 insertions, 1959 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index fbd727042..a564b85dc 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -1,7 +1,8 @@
BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
- deviceiobook.sgml procfs-guide.sgml tulip-user.sgml
+ deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
+ writing_usb_driver.sgml
PS := $(patsubst %.sgml, %.ps, $(BOOKS))
PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -65,6 +66,9 @@ via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c
tulip-user.sgml: tulip-user.tmpl
$(TOPDIR)/scripts/docgen <$< >$@
+writing_usb_driver.sgml: writing_usb_driver.tmpl
+ $(TOPDIR)/scripts/docgen <$< >$@
+
sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \
<sis900.tmpl >sis900.sgml
diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl
new file mode 100644
index 000000000..98d689b33
--- /dev/null
+++ b/Documentation/DocBook/writing_usb_driver.tmpl
@@ -0,0 +1,469 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="USBDeviceDriver">
+ <bookinfo>
+ <title>Writing USB Device Drivers</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Greg</firstname>
+ <surname>Kroah-Hartman</surname>
+ <affiliation>
+ <address>
+ <email>greg@kroah.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2001-2002</year>
+ <holder>Greg Kroah-Hartman</holder>
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation 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.
+ </para>
+
+ <para>
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+ </para>
+
+ <para>
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+
+ <para>
+ This documentation is based on an article published in
+ Linux Journal Magazine, October 2001, Issue 90.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ The Linux USB subsystem has grown from supporting only two different
+ types of devices in the 2.2.7 kernel (mice and keyboards), to over 20
+ different types of devices in the 2.4 kernel. Linux currently supports
+ almost all USB class devices (standard types of devices like keyboards,
+ mice, modems, printers and speakers) and an ever-growing number of
+ vendor-specific devices (such as USB to serial converters, digital
+ cameras, Ethernet devices and MP3 players). For a full list of the
+ different USB devices currently supported, see Resources.
+ </para>
+ <para>
+ The remaining kinds of USB devices that do not have support on Linux are
+ almost all vendor-specific devices. Each vendor decides to implement a
+ custom protocol to talk to their device, so a custom driver usually needs
+ to be created. Some vendors are open with their USB protocols and help
+ with the creation of Linux drivers, while others do not publish them, and
+ developers are forced to reverse-engineer. See Resources for some links
+ to handy reverse-engineering tools.
+ </para>
+ <para>
+ Because each different protocol causes a new driver to be created, I have
+ written a generic USB driver skeleton, modeled after the pci-skeleton.c
+ file in the kernel source tree upon which many PCI network drivers have
+ been based. This USB skeleton can be found at drivers/usb/usb-skeleton.c
+ in the kernel source tree. In this article I will walk through the basics
+ of the skeleton driver, explaining the different pieces and what needs to
+ be done to customize it to your specific device.
+ </para>
+ </chapter>
+
+ <chapter id="basics">
+ <title>Linux USB Basics</title>
+ <para>
+ If you are going to write a Linux USB driver, please become familiar with
+ the USB protocol specification. It can be found, along with many other
+ useful documents, at the USB home page (see Resources). An excellent
+ introduction to the Linux USB subsystem can be found at the USB Working
+ Devices List (see Resources). It explains how the Linux USB subsystem is
+ structured and introduces the reader to the concept of USB urbs, which
+ are essential to USB drivers.
+ </para>
+ <para>
+ The first thing a Linux USB driver needs to do is register itself with
+ the Linux USB subsystem, giving it some information about which devices
+ the driver supports and which functions to call when a device supported
+ by the driver is inserted or removed from the system. All of this
+ information is passed to the USB subsystem in the usb_driver structure.
+ The skeleton driver declares a usb_driver as:
+ </para>
+ <programlisting>
+static struct usb_driver skel_driver = {
+ name: "skeleton",
+ probe: skel_probe,
+ disconnect: skel_disconnect,
+ fops: &amp;skel_fops,
+ minor: USB_SKEL_MINOR_BASE,
+ id_table: skel_table,
+};
+ </programlisting>
+ <para>
+ The variable name is a string that describes the driver. It is used in
+ informational messages printed to the system log. The probe and
+ disconnect function pointers are called when a device that matches the
+ information provided in the id_table variable is either seen or removed.
+ </para>
+ <para>
+ The fops and minor variables are optional. Most USB drivers hook into
+ another kernel subsystem, such as the SCSI, network or TTY subsystem.
+ These types of drivers register themselves with the other kernel
+ subsystem, and any user-space interactions are provided through that
+ interface. But for drivers that do not have a matching kernel subsystem,
+ such as MP3 players or scanners, a method of interacting with user space
+ is needed. The USB subsystem provides a way to register a minor device
+ number and a set of file_operations function pointers that enable this
+ user-space interaction. The skeleton driver needs this kind of interface,
+ so it provides a minor starting number and a pointer to its
+ file_operations functions.
+ </para>
+ <para>
+ The USB driver is then registered with a call to usb_register, usually in
+ the driver's init function, as shown here:
+ </para>
+ <programlisting>
+static int __init usb_skel_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&amp;skel_driver);
+ if (result &lt; 0) {
+ err(&quot;usb_register failed for the &quot;__FILE__ &quot;driver.&quot;
+ &quot;Error number %d&quot;, result);
+ return -1;
+ }
+
+ return 0;
+}
+module_init(usb_skel_init);
+ </programlisting>
+ <para>
+ When the driver is unloaded from the system, it needs to unregister
+ itself with the USB subsystem. This is done with the usb_unregister
+ function:
+ </para>
+ <programlisting>
+static void __exit usb_skel_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&amp;skel_driver);
+}
+module_exit(usb_skel_exit);
+ </programlisting>
+ <para>
+ To enable the linux-hotplug system to load the driver automatically when
+ the device is plugged in, you need to create a MODULE_DEVICE_TABLE. The
+ following code tells the hotplug scripts that this module supports a
+ single device with a specific vendor and product ID:
+ </para>
+ <programlisting>
+/* table of devices that work with this driver */
+static struct usb_device_id skel_table [] = {
+ { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, skel_table);
+ </programlisting>
+ <para>
+ There are other macros that can be used in describing a usb_device_id for
+ drivers that support a whole class of USB drivers. See usb.h for more
+ information on this.
+ </para>
+ </chapter>
+
+ <chapter id="device">
+ <title>Device operation</title>
+ <para>
+ When a device is plugged into the USB bus that matches the device ID
+ pattern that your driver registered with the USB core, the probe function
+ is called. The usb_device structure, interface number and the interface ID
+ are passed to the function:
+ </para>
+ <programlisting>
+static void * skel_probe(struct usb_device *dev,
+unsigned int ifnum, const struct usb_device_id *id)
+ </programlisting>
+ <para>
+ The driver now needs to verify that this device is actually one that it
+ can accept. If not, or if any error occurs during initialization, a NULL
+ value is returned from the probe function. Otherwise a pointer to a
+ private data structure containing the driver's state for this device is
+ returned. That pointer is stored in the usb_device structure, and all
+ callbacks to the driver pass that pointer.
+ </para>
+ <para>
+ In the skeleton driver, we determine what end points are marked as bulk-in
+ and bulk-out. We create buffers to hold the data that will be sent and
+ received from the device, and a USB urb to write data to the device is
+ initialized. Also, we register the device with the devfs subsystem,
+ allowing users of devfs to access our device. That registration looks like
+ the following:
+ </para>
+ <programlisting>
+/* initialize the devfs node for this device and register it */
+sprintf(name, &quot;skel%d&quot;, skel->minor);
+skel->devfs = devfs_register (usb_devfs_handle,
+ name,
+ DEVFS_FL_DEFAULT,
+ USB_MAJOR,
+ USB_SKEL_MINOR_BASE + skel->minor,
+ S_IFCHR | S_IRUSR | S_IWUSR |
+ S_IRGRP | S_IWGRP | S_IROTH,
+ &amp;skel_fops,
+ NULL);
+ </programlisting>
+ <para>
+ If the devfs_register function fails, we do not care, as the devfs
+ subsystem will report this to the user.
+ </para>
+ <para>
+ Conversely, when the device is removed from the USB bus, the disconnect
+ function is called with the device pointer. The driver needs to clean any
+ private data that has been allocated at this time and to shut down any
+ pending urbs that are in the USB system. The driver also unregisters
+ itself from the devfs subsystem with the call:
+ </para>
+ <programlisting>
+/* remove our devfs node */
+devfs_unregister(skel->devfs);
+ </programlisting>
+ <para>
+ Now that the device is plugged into the system and the driver is bound to
+ the device, any of the functions in the file_operations structure that
+ were passed to the USB subsystem will be called from a user program trying
+ to talk to the device. The first function called will be open, as the
+ program tries to open the device for I/O. Within the skeleton driver's
+ open function we increment the driver's usage count if it is a module with
+ a call to MODULE_INC_USE_COUNT. With this macro call, if the driver is
+ compiled as a module, the driver cannot be unloaded until a corresponding
+ MODULE_DEC_USE_COUNT macro is called. We also increment our private usage
+ count and save off a pointer to our internal structure in the file
+ structure. This is done so that future calls to file operations will
+ enable the driver to determine which device the user is addressing. All of
+ this is done with the following code:
+ </para>
+ <programlisting>
+/* increment our usage count for the module */
+MOD_INC_USE_COUNT;
+++skel->open_count;
+
+/* save our object in the file's private structure */
+file->private_data = skel;
+ </programlisting>
+ <para>
+ After the open function is called, the read and write functions are called
+ to receive and send data to the device. In the skel_write function, we
+ receive a pointer to some data that the user wants to send to the device
+ and the size of the data. The function determines how much data it can
+ send to the device based on the size of the write urb it has created (this
+ size depends on the size of the bulk out end point that the device has).
+ Then it copies the data from user space to kernel space, points the urb to
+ the data and submits the urb to the USB subsystem. This can be shown in
+ he following code:
+ </para>
+ <programlisting>
+/* we can only write as much as 1 urb will hold */
+bytes_written = (count > skel->bulk_out_size) ? skel->bulk_out_size : count;
+
+/* copy the data from user space into our urb */
+copy_from_user(skel->write_urb->transfer_buffer, buffer, bytes_written);
+
+/* set up our urb */
+usb_fill_bulk_urb(skel->write_urb,
+ skel->dev,
+ usb_sndbulkpipe(skel->dev, skel->bulk_out_endpointAddr),
+ skel->write_urb->transfer_buffer,
+ bytes_written,
+ skel_write_bulk_callback,
+ skel);
+
+/* send the data out the bulk port */
+result = usb_submit_urb(skel->write_urb);
+if (result) {
+ err(&quot;Failed submitting write urb, error %d&quot;, result);
+}
+ </programlisting>
+ <para>
+ When the write urb is filled up with the proper information using the
+ FILL_BULK_URB function, we point the urb's completion callback to call our
+ own skel_write_bulk_callback function. This function is called when the
+ urb is finished by the USB subsystem. The callback function is called in
+ interrupt context, so caution must be taken not to do very much processing
+ at that time. Our implementation of skel_write_bulk_callback merely
+ reports if the urb was completed successfully or not and then returns.
+ </para>
+ <para>
+ The read function works a bit differently from the write function in that
+ we do not use an urb to transfer data from the device to the driver.
+ Instead we call the usb_bulk_msg function, which can be used to send or
+ receive data from a device without having to create urbs and handle
+ urb completion callback functions. We call the usb_bulk_msg function,
+ giving it a buffer into which to place any data received from the device
+ and a timeout value. If the timeout period expires without receiving any
+ data from the device, the function will fail and return an error message.
+ This can be shown with the following code:
+ </para>
+ <programlisting>
+/* do an immediate bulk read to get data from the device */
+retval = usb_bulk_msg (skel->dev,
+ usb_rcvbulkpipe (skel->dev,
+ skel->bulk_in_endpointAddr),
+ skel->bulk_in_buffer,
+ skel->bulk_in_size,
+ &amp;count, HZ*10);
+/* if the read was successful, copy the data to user space */
+if (!retval) {
+ if (copy_to_user (buffer, skel->bulk_in_buffer, count))
+ retval = -EFAULT;
+ else
+ retval = count;
+}
+ </programlisting>
+ <para>
+ The usb_bulk_msg function can be very useful for doing single reads or
+ writes to a device; however, if you need to read or write constantly to a
+ device, it is recommended to set up your own urbs and submit them to the
+ USB subsystem.
+ </para>
+ <para>
+ When the user program releases the file handle that it has been using to
+ talk to the device, the release function in the driver is called. In this
+ function we decrement the module usage count with a call to
+ MOD_DEC_USE_COUNT (to match our previous call to MOD_INC_USE_COUNT). We
+ also determine if there are any other programs that are currently talking
+ to the device (a device may be opened by more than one program at one
+ time). If this is the last user of the device, then we shut down any
+ possible pending writes that might be currently occurring. This is all
+ done with:
+ </para>
+ <programlisting>
+/* decrement our usage count for the device */
+--skel->open_count;
+if (skel->open_count &lt;= 0) {
+ /* shutdown any bulk writes that might be going on */
+ usb_unlink_urb (skel->write_urb);
+ skel->open_count = 0;
+}
+/* decrement our usage count for the module */
+MOD_DEC_USE_COUNT;
+ </programlisting>
+ <para>
+ One of the more difficult problems that USB drivers must be able to handle
+ smoothly is the fact that the USB device may be removed from the system at
+ any point in time, even if a program is currently talking to it. It needs
+ to be able to shut down any current reads and writes and notify the
+ user-space programs that the device is no longer there. The following
+ code is an example of how to do this: </para>
+ <programlisting>
+/* if the device is not opened, then we clean right now */
+if (skel->open_count) {
+ minor_table[skel->minor] = NULL;
+ if (skel->bulk_in_buffer != NULL)
+ kfree (skel->bulk_in_buffer);
+ if (skel->bulk_out_buffer != NULL)
+ kfree (skel->bulk_out_buffer);
+ if (skel->write_urb != NULL)
+ usb_free_urb (skel->write_urb);
+ kfree (skel);
+} else {
+ skel->dev = NULL;
+ up (&amp;skel->sem);
+}
+ </programlisting>
+ <para>
+ If a program currently has an open handle to the device, we only null the
+ usb_device structure in our local structure, as it has now gone away. For
+ every read, write, release and other functions that expect a device to be
+ present, the driver first checks to see if this usb_device structure is
+ still present. If not, it releases that the device has disappeared, and a
+ -ENODEV error is returned to the user-space program. When the release
+ function is eventually called, it determines if there is no usb_device
+ structure and if not, it does the cleanup that the skel_disconnect
+ function normally does if there are no open files on the device (see
+ Listing 5).
+ </para>
+ <programlisting>
+if (skel->dev == NULL) {
+ /* the device was unplugged before the file was released */
+ minor_table[skel->minor] = NULL;
+ if (skel->bulk_in_buffer != NULL)
+ kfree (skel->bulk_in_buffer);
+ if (skel->bulk_out_buffer != NULL)
+ kfree (skel->bulk_out_buffer);
+ if (skel->write_urb != NULL)
+ usb_free_urb (skel->write_urb);
+ kfree (skel);
+ goto exit;
+}
+ </programlisting>
+ </chapter>
+
+ <chapter id="iso">
+ <title>Isochronous Data</title>
+ <para>
+ This usb-skeleton driver does not have any examples of interrupt or
+ isochronous data being sent to or from the device. Interrupt data is sent
+ almost exactly as bulk data is, with a few minor exceptions. Isochronous
+ data works differently with continuous streams of data being sent to or
+ from the device. The audio and video camera drivers are very good examples
+ of drivers that handle isochronous data and will be useful if you also
+ need to do this.
+ </para>
+ </chapter>
+
+ <chapter id="Conclusion">
+ <title>Conclusion</title>
+ <para>
+ Writing Linux USB device drivers is not a difficult task as the
+ usb-skeleton driver shows. This driver, combined with the other current
+ USB drivers, should provide enough examples to help a beginning author
+ create a working driver in a minimal amount of time. The linux-usb-devel
+ mailing list archives also contain a lot of helpful information.
+ </para>
+ </chapter>
+
+ <chapter id="resources">
+ <title>Resources</title>
+ <para>
+ The Linux USB Project: <ulink url="http://www.linux-usb.org">http://www.linux-usb.org/</ulink>
+ </para>
+ <para>
+ Linux Hotplug Project: <ulink url="http://linux-hotplug.sourceforge.net">http://linux-hotplug.sourceforge.net/</ulink>
+ </para>
+ <para>
+ Linux USB Working Devices List: <ulink url="http://www.qbik.ch/usb/devices">http://www.qbik.ch/usb/devices/</ulink>
+ </para>
+ <para>
+ linux-usb-devel Mailing List Archives: <ulink url="http://marc.theaimsgroup.com/?l=linux-usb-devel">http://marc.theaimsgroup.com/?l=linux-usb-devel</ulink>
+ </para>
+ <para>
+ Programming Guide for Linux USB Device Drivers: <ulink url="http://usb.cs.tum.edu/usbdoc">http://usb.cs.tum.edu/usbdoc</ulink>
+ </para>
+ <para>
+ USB Home Page: <ulink url="http://www.usb.org">http://www.usb.org</ulink>
+ </para>
+ </chapter>
+
+</book>
diff --git a/Documentation/scsi-generic.txt b/Documentation/scsi-generic.txt
index 220957462..88da90139 100644
--- a/Documentation/scsi-generic.txt
+++ b/Documentation/scsi-generic.txt
@@ -1,793 +1,101 @@
- Notes on Linux's SG driver version 2.1.39
- -----------------------------------------
- 20010329
-
+ Notes on Linux SCSI Generic (sg) driver
+ ---------------------------------------
+ 20020126
Introduction
============
The SCSI Generic driver (sg) is one of the four "high level" SCSI device
drivers along with sd, st and sr (disk, tape and CDROM respectively). Sg
is more generalized (but lower level) than its siblings and tends to be
used on SCSI devices that don't fit into the already serviced categories.
-Thus sg is used for scanners, cd writers and reading audio cds digitally
+Thus sg is used for scanners, CD writers and reading audio CDs digitally
amongst other things.
-These are notes on the Linux SCSI generic packet device driver (sg)
-describing version 2.1.39 . The original driver was written by Lawrence
-Foard and remained in place with minimal changes since circa 1992.
-Version 2 of this driver remains backward compatible (binary and
-source **) with the original. It adds scatter gather, command queuing,
-per file descriptor sequencing, asynchronous notification and better
-error reporting.
-
-This is an abridged version of the sg documentation that is targeted
-at the linux/Documentation directory. The full document can be found
-at http://www.torque.net/sg/p/scsi-generic_long.txt .
-
-The Linux 2.4 series kernels have now been released. Lk 2.4 contains
-an upgraded "version 3" sg driver which is described in a supplementary
-document at http://www.torque.net/sg/p/scsi-generic_v3.txt .
-
-The interface and usage of the original sg driver have been documented
-by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
-of the document is version 1.5 dated 7th May 1996. It can found at
-ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO .
-A copy of this document can be found at:
-http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO.txt .
-
-** It is possible to write applications that perform differently
-depending on whether they are using the original or this version of
-the sg device driver. The author is not aware of any useful
-pre-existing applications that have problems with version 2.
-
-
-Architecture
-============
-The SCSI generic packet device driver (sg) is a character based device.
-It is one of the four high level device driver in the SCSI sub-system;
-the others are sd (for direct-access devices - disks), st (for tapes)
-and sr (for data cdroms). Sd and sr are block devices while st (like sg)
-is a character device.
-
-The unifying layer of the SCSI sub-system is the so-called mid-level.
-Below that are the "low level" drivers which are the drivers for the
-various adapters supported by Linux. Also at this level are pseudo
-adapter drivers such as ide-scsi which converts the SCSI protocol to
-ATAPI (which are similar to one another) for use by IDE devices.
-
-Since sg is a character device it supports the traditional Unix
-system calls of open(), close(), read(), write() and ioctl(). Two other
-related system calls: poll() and fcntl() are added to this list and
-how they interact with the sg device driver is documented later.
-
-An SG device is accessed by write()ing SCSI commands plus any associated
-outgoing data to it; the resulting status codes and any incoming data are
-then obtained by a read() call. The device can be opened O_NONBLOCK
-(non-blocking) and poll() used to monitor its progress. The device may be
-opened O_EXCL which excludes other "sg" users from this device (but not
-"sd", "st" or "sr" users). The buffer given to the write() call is made
-up as follows:
- - struct sg_header image (see below)
- - scsi command (6, 10 or 12 bytes long)
- - data to be written to the device (if any)
-
-The buffer received from the corresponding read() call contains:
- - struct sg_header image (check status/errors + sense_buffer)
- - data read back from device (if any)
-
-The given SCSI command has its LUN field overwritten by the LUN value of
-the associated sg device that has been open()ed.
-
-SCSI commands are only attempted once (i.e. there are no internal
-retries). If appropriate (e.g. a SCSI READ) the data buffer is copied back
-to user space irrespective of the values of the various SCSI related
-error/status codes. [Some adapters that use an old error interface in
-the SCSI mid level ignore the retry count and retry certain errors.]
-
-
-sg_header
-=========
-This is the name of the control structure that conveys information
-about the length of data to be read/written by the associated SCSI
-command. It also conveys error and status information from the
-read() call. An instance of this structure is the first thing that
-is placed in the data buffers of both write() and read().
-
-In its original form it looked like this:
-struct sg_header {
- int pack_len;
- int reply_len;
- int pack_id;
- int result;
- unsigned int twelve_byte:1;
- unsigned int other_flags:31;
- unsigned char sense_buffer[16];
-}; /* this structure is 36 bytes long */
-
-The 'pack_len' is bizarre and ends up having the 'reply_len' put in it
-(perhaps it had a use at some stage). Even though it looks like an
-input variable, it is not read by sg internally (only written).
-
-The 'reply_len' is the length of the data the corresponding read()
-will/should request (including the sg_header).
-
-The 'pack_id' is not acted upon by the sg device driver but is conveyed
-back to the corresponding read() so it can be used for sequencing by an
-application.
-
-The 'result' is also bizarre, turning certain types of host codes to 0 (no
-error), EBUSY or EIO. With better error reporting now available, the
-'result' is best ignored.
-
-The 'twelve_byte' field overrides the internal SCSI command length detection
-algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
-a command length of 12 bytes.
-The command length detection algorithm is as follows:
-Group: 0 1 2 3 4 5 6 7
-Length: 6 10 10 12 12 12 10 10
-
-'other_flags' was originally documented as "not used" but some current
-applications assume it has 0 placed in it.
-
-The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is
-returned when the target returns a SCSI status code of CHECK_CONDITION
-or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This
-buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
-this is unlikely to happen in the 2.2.x series of kernels.
-
-
-The new sg_header offered in this driver is:
-#define SG_MAX_SENSE 16
-struct sg_header
-{
- int pack_len; /* [o] reply_len (ie useless) ignored as input */
- int reply_len; /* [i] max length of expected reply (inc. sg_header) */
- int pack_id; /* [io] id number of packet (use ints >= 0) */
- int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
- unsigned int twelve_byte:1;
- /* [i] Force 12 byte command length for group 6 & 7 commands */
- unsigned int target_status:5; /* [o] scsi status from target */
- unsigned int host_status:8; /* [o] host status (see "DID" codes) */
- unsigned int driver_status:8; /* [o] driver status+suggestion */
- unsigned int other_flags:10; /* unused */
- unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
- when target_status is CHECK_CONDITION or
- when target_status is COMMAND_TERMINATED or
- when (driver_status & DRIVER_SENSE) is true. */
-}; /* This structure is 36 bytes long on i386 */
-
-Firstly the new header is binary compatible with the original. This is
-important for keeping existing apps working without recompilation.
-
-Only those elements (or fields) that are new or in some way different
-from the original are documented below.
-
-'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID,
-&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest
-waiting packet; any other value will cause the read() to wait (or yield
-EAGAIN) until a packet with that 'pack_id' becomes available. In all cases
-the value of 'pack_id' available after a read() is the value given to that
-variable in the prior, corresponding write().
-
-The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN
-ioctl().
-
-The 'target_status' field is always output and is the (masked and shifted
-1 bit right) SCSI status code from the target device. The allowable
-values are (found in <scsi/scsi.h>):
-/* N.B. 1 bit offset from usual SCSI status values */
-#define GOOD 0x00
-#define CHECK_CONDITION 0x01
-#define CONDITION_GOOD 0x02
-#define BUSY 0x04
-#define INTERMEDIATE_GOOD 0x08
-#define INTERMEDIATE_C_GOOD 0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define COMMAND_TERMINATED 0x11
-#define QUEUE_FULL 0x14
-When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
-'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
-is true then the 'sense_buffer' is also output (this seems to occur when
-the ide-scsi emulation is used). When the 'sense_buffer' is output the
-SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
-
-The 'host_status' field is always output and has the following values
-whose "defines" are not visible outside the kernel. A copy of these
-defines can be found in sg_err.h (see the utilities section):
-#define DID_OK 0x00 /* NO error */
-#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */
-#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */
-#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */
-#define DID_BAD_TARGET 0x04 /* BAD target, device not responding? */
-#define DID_ABORT 0x05 /* Told to abort for some other reason */
-#define DID_PARITY 0x06 /* Parity error */
-#define DID_ERROR 0x07 /* Internal error [DMA underrun on aic7xxx]*/
-#define DID_RESET 0x08 /* Reset by somebody. */
-#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */
-#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */
-#define DID_SOFT_ERROR 0x0b /* The low level driver wants a retry */
-
-The 'driver_status' field is always output. When ('driver_status' &
-DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these
-defines can be found in sg_err.h (see the utilities section):
-#define DRIVER_OK 0x00 /* Typically no suggestion */
-#define DRIVER_BUSY 0x01
-#define DRIVER_SOFT 0x02
-#define DRIVER_MEDIA 0x03
-#define DRIVER_ERROR 0x04
-#define DRIVER_INVALID 0x05
-#define DRIVER_TIMEOUT 0x06
-#define DRIVER_HARD 0x07
-#define DRIVER_SENSE 0x08 /* Implies sense_buffer output */
-/* above status 'or'ed with one of the following suggestions */
-#define SUGGEST_RETRY 0x10
-#define SUGGEST_ABORT 0x20
-#define SUGGEST_REMAP 0x30
-#define SUGGEST_DIE 0x40
-#define SUGGEST_SENSE 0x80
-
-'other_flags' still remains as a 10 bit field (reduced from 31 bits), so
-code that places 0 in it will still be happy. It is not used.
-
-
-System Calls
-============
-What follows are descriptions of the characteristics of the standard
-Unix operating system calls when applied to a SCSI generic device
-using this version of the device driver.
-
-open(const char * filename, int flags)
---------------------------------------
-The filename should be an 'sg' device such as
-/dev/sg[0,1,2,...]
-/dev/sg[a-z] <<< now deprecated >>>
-or a symbolic link to one of these. [Devfs has its own sub-directory for
-sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .]
-It seems as though SCSI devices are allocated to sg minor numbers in the
-same order as they appear in 'cat /proc/scsi/scsi'. Sg is a "character"
-based Linux device driver. This means it has an open/close/read/write/ioctl
-type interface.
-
-Flags can be either O_RDONLY or O_RDWR or-ed with either
-O_EXCL waits for other opens on sg device to be closed before
- proceeding. If O_NONBLOCK is set then yields EBUSY when
- someone else has the sg device open. The combination of
- O_RDONLY and O_EXCL is disallowed.
-O_NONBLOCK Sets non-blocking mode. Calls that would otherwise block
- yield EAGAIN (eg read() ) or EBUSY (eg open() ).
-
-The original version of sg did not allow the O_RDONLY (yielding a EACCES
-error). This version allows it for accessing ioctls (e.g. doing an sg
-device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
-allowed. These flags are found in <fcntl.h> .
-
-By default, sequencing is per file descriptor in this version of sg. This
-means, for example that 2 processes can independently manipulate the same
-sg device at the same time. This may or may not make sense depending on
-the application: 2 processes (logically) reading from the same direct access
-device (ie a disk) is ok while running 2 instances of cd writing software
-on the same device at the same time probably wouldn't be a good idea. The
-previous version of sg supported only per device sequencing and this can
-still be selected with the SG_SET_MERGE_FD,1 ioctl().
-
-The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in
-the current sg.h) on open(). The size of this reserved buffer can
-subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both
-cases these are requests subject to various dynamic constraints. The actual
-amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl().
-The reserved buffer will be used if:
- - it is not already in use (eg when command queuing is in use)
- - a write() does not call for a buffer size larger than the
- reserved size.
-
-Returns a file descriptor if >= 0 , otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-EACCES Either the user doesn't have appropriate permissions on
- 'filename' or attempted to use both O_RDONLY and O_EXCL
-EBUSY O_NONBLOCK set and some user of this sg device has O_EXCL
- set while someone is already using this device
-EINTR while waiting for an "exclusive" lock to clear, a signal
- is received, just try again ...
-ENODEV sg not compiled into kernel or the kernel cannot find the
- sg module (or it can't initialize itself (low memory??))
-ENOENT given filename not found
-ENOMEM An attempt to get memory to store this open's context
- failed (this was _not_ a request to reserve DMA memory)
-ENXIO either there is no attached device corresponding to given
- filename or scsi sub-system is currently processing some
- error (eg doing a device reset) or the sg driver/module
- removed or corrupted
-
-
-write(int sg_fd, const void * buffer, size_t count)
----------------------------------------------------
-Even though sg is a character-based device driver it sends and receives
-packets to/from the associated scsi device. Write() is used to send a
-packet containing 2 mandatory parts and 1 optional part. The mandatory
-parts are:
- - a control block (an instance of struct sg_header)
- - a SCSI command (6, 10 or 12 bytes long)
-The optional part is:
- - outgoing data (eg if a SCSI write command is being sent)
-These should appear as one contiguous string in the buffer given to
-write() in the above order with no pad characters.
-
-If a write() accepts this packet then at some later time the user should
-call a read() to get the result of the SCSI command. The previous sg
-driver enforced a strict write()/read()/write()/read() regime so that a
-second write() would block until first read() was finished. This sg
-driver relaxes that condition and thereby allows command queuing
-(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor).
-However, for backward compatibility, command queuing is turned off
-by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed
-via the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing
-the above define to 1].
-
-In this sg driver a write() should return more or less immediately.
-
-Returns number of bytes written if > 0 , otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-EACCES opened with RD_ONLY flag
-EAGAIN SCSI mid-level out of command blocks (rare), try again.
- This is more likely to happen when queuing commands,
- so wait a bit (eg usleep(10000) ) before trying again
-EDOM a) command queuing off: a packet is already queued
- b) command queuing on: too many packets queued
- (SG_MAX_QUEUE exceeded)
-EFAULT 'buffer' for 'count' bytes is an invalid memory range
-EIO a) incoming buffer too short. It should be at least
- (6 + sizeof(struct sg_header))==42 bytes long
- b) SCSI command length given in SG_NEXT_CMD_LEN too long
- c) reply_len negative
-ENOMEM can't get memory for DMA. Take evasive action ...
-ENXIO either scsi sub-system is currently processing some error
- (eg doing a device reset) or the sg driver/module removed
- or corrupted
-
-
-read(int sg_fd, void * buffer, size_t count)
---------------------------------------------
-Read() is used to receive a packet containing 1 mandatory part and 1
-optional part. The mandatory part is:
- - a control block (an instance of struct sg_header)
-The optional part is:
- - incoming data (eg if a SCSI read command was sent by earlier write() )
-The buffer given to a read() and its corresponding count should be
-sufficient to accommodate this packet to avoid truncation. Truncation occurs
-if count < sg_header::replylen .
-
-By default, read() will return the oldest packet queued up. If the
-SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
-fetch the packet whose pack_id (given earlier to write()) matches the
-sg_header::pack_id given to this read(). If not available it will either
-wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
-to read() will match the oldest packet.
-
-Returns number of bytes read if > 0 , otherwise -1 implies an error.
-Unfortunately the return value in the non-error case is simply the
-same as the count argument. It is not the actual number of bytes
-DMA-ed by the SCSI device. This driver is currently unable to provide
-such an underrun indication.
-
-If the SCSI device reports an error then a REQUEST SENSE is automatically
-done and the output is placed in the sense_buffer array which is in the
-control block. This action is sometimes called "auto-sense".
-
-Error codes (value in 'errno' after -1 returned):
-EAGAIN either no waiting packet or requested packet is not
- available while O_NONBLOCK flag was set
-EFAULT 'buffer' for 'count' bytes is an invalid memory range
-EINTR while waiting for a packet, a signal is received, just
- try again ...
-EIO if the 'count' given to read() is < sizeof(struct sg_header)
- and the 'result' element in sg_header is non-zero. Not a
- recommended error reporting technique
-ENXIO either scsi sub-system is currently processing some error
- (eg doing a device reset) or the sg driver/module removed
- or corrupted
-
-
-close(int sg_fd)
-----------------
-Preferably a close() should be done after all issued write()s have had
-their corresponding read() calls completed. Unfortunately this is not
-always possible. The semantics of close() in Unix are to return more
-or less immediately (ie not wait on any event) so the driver needs to
-arrange for an orderly cleanup of those packets that are still "in
-flight".
-
-A process that has an open file descriptor to an sg device may be aborted
-(eg by a kill signal). In this case, the kernel automatically calls close
-(which is called 'sg_release()' in the version 2 driver) to facilitate
-the cleanup mentioned above.
-
-A problem persists in version 2.1.39 if the sg driver is a module and is
-removed while packets are still "in flight".
-
-Returns 0 if successful, otherwise -1 implies an error.
-
-Error codes (value in 'errno' after -1 returned):
-ENXIO sg driver/module removed or corrupted
-
-ioctl(int sg_fd, int command, ...) [sg specific]
--------------------------------------------------
-Ken Thompson (or perhaps some other Unix luminary) described ioctl() as
-the "garbage bin of Unix". This driver compounds the situation by adding
-more ...
-If a ioctl command is not recognized by sg (and the various lower levels
-that it may pass the command on to) then the error EINVAL occurs. If an
-invalid address is given (in the 3rd argument) then the error EFAULT occurs.
-
-Those commands with an appended "+" are new in version 2.
-
-Those commands with an appended "W" are only accessible from file
-descriptors opened with O_RDWR. They will yield EACCES otherwise.
-
-SG_GET_TIMEOUT:
-Ignores its 3rd argument and _returns_ the timeout value (which will be
->= 0 ). The unit of this timeout is "jiffies" which are currently 10
-millisecond intervals on i386 (less on an alpha). Linux supplies
-a manifest constant HZ which is the number of "jiffies" in 1 second.
-
-SG_SET_TIMEOUT:
-Assumes 3rd argument points to an int containing the new timeout value
-for this file descriptor. The unit is a "jiffy". Packets that are
-already "in flight" will not be affected. The default value is set
-on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is
-currently 1 minute and may not be long enough for formats. Negative
-values will yield an EIO error.
-
-SG_EMULATED_HOST:
-Assumes 3rd argument points to an int and outputs a flag indicating
-whether the host (adapter) is connected to a real SCSI bus or is an
-emulated one (eg ide-scsi device driver). A value of 1 means emulated
-while 0 is not.
-
-SG_SET_TRANSFORM W:
-Only is meaningful when SG_EMULATED host has yielded 1 (i.e. the low-level
-is the ide-scsi device driver); otherwise an EINVAL error occurs. The
-default state is to _not_ transform SCSI commands to the corresponding
-ATAPI commands but pass them straight through as is. [Only certain classes
-of SCSI commands need to be transformed to their ATAPI equivalents.]
-The third argument is interpreted as an integer. When it is non-zero then
-a flag is set inside the ide-scsi driver that transforms subsequent
-commands sent to this driver. When zero is passed as the 3rd argument to
-this ioctl then the flag within the ide-scsi driver is cleared and
-subsequent commands are not transformed. Beware, this state will affect
-all devices (and hence all related sg file descriptors) associated with
-this ide-scsi "bus".
-
-SG_GET_TRANSFORM:
-Third argument is ignored. Only is meaningful when SG_EMULATED host has
-yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
-an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI
-to ATAPI commands (default). Returns 1 when it is transforming them.
-
-SG_SET_FORCE_LOW_DMA +:
-Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
-means sg decides whether to use memory above 16 Mbyte level (on i386)
-based on the host adapter being used by this SCSI device. Typically
-PCI SCSI adapters will indicate they can DMA to the whole 32 bit address
-space.
-If 1 is given then the host adapter is overridden and only memory below
-the 16MB level is used for DMA. A requirement for this should be
-extremely rare. If the "reserved" buffer allocated on open() is not in
-use then it will be de-allocated and re-allocated under the 16MB level
-(and the latter operation could fail yielding ENOMEM).
-Only the current file descriptor is affected.
-
-SG_GET_LOW_DMA +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0
-indicates the whole 32 bit address space is being used for DMA transfers
-on this file descriptor. 1 indicates the memory below the 16MB level
-(on i386) is being used (and this may be the case because the host
-adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
-
-SG_GET_SCSI_ID +:
-Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see
-sg.h) and populates it. That structure contains ints for host_no,
-channel, scsi_id, lun, scsi_type, allowable commands per lun and
-queue_depth. Most of this information is available from other sources
-(eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) but tends to be
-awkward to collect.
-Allowable commands per lun and queue_depth give an insight to the
-command queuing capabilities of the adapters and the device. The latter
-overrides the former (logically) and the former is only of interest
-if it is equal to queue_depth which probably indicates the device
-does not support queueing commands (e.g. most scanners).
-
-SG_SET_FORCE_PACK_ID +:
-Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
-to return the oldest (written) packet if multiple packets are
-waiting to be read (when command queuing is being used).
-1 instructs read() to view the sg_header::pack_id as input and return the
-oldest packet matching that pack_id or wait until it arrives (or yield
-EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
-given to read() in the mode will match the oldest packet.
-Only the current file descriptor is affected by this command.
-
-SG_GET_PACK_ID +:
-Assumes 3rd argument points to an int and places the pack_id of the
-oldest (written) packet in it. If no packet is waiting to be read then
-yields -1.
-
-SG_GET_NUM_WAITING +:
-Assumes 3rd argument points to an int and places the number of packets
-waiting to be read in it.
-
-SG_GET_SG_TABLESIZE +:
-Assumes 3rd argument points to an int and places the maximum number of
-scatter gather elements supported by the host adapter. 0 indicates that
-the adapter does support scatter gather.
-
-SG_SET_RESERVED_SIZE +W:
-Assumes 3rd argument is pointing to an int. That value will be used to
-request a new reserved buffer of that size. The previous reserved buffer
-is freed (if it is not in use; if it was in use -EBUSY is returned).
-A new reserved buffer is then allocated and its actual size can be found by
-calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used
-for DMA purposes by subsequent write() commands if it is not already in
-use and if the write() is not calling for a buffer size larger than that
-reserved. The reserved buffer may well be a series of kernel buffers if the
-adapter supports scatter-gather. Large buffers can be requested (eg 1 MB).
-
-SG_GET_RESERVED_SIZE +:
-Assumes 3rd argument points to an int and places the size in bytes of
-the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE
-ioctl() call on this fd. The result can be 0 if memory is very tight. In
-this case it may not be wise to attempt something like burning a CD on
-this file descriptor.
-
-SG_SET_MERGE_FD +W:
-Assumes 3rd argument is pointing to an int. 0 (the default) causes all
-subsequent sequencing to be per file descriptor. 1 causes all subsequent
-sequencing to be per device. If this command tries to change the current
-state and there is one or more _other_ file descriptors using this sg
-device then an EBUSY error occurs. Per device sequencing was the original
-semantics and allowed, for example different processes to "share" the
-device, one perhaps write()ing with the other one read()ing. This command
-is supplied if anyone needs those semantics. Per file descriptor
-sequencing, perhaps with the use of the O_EXCL flag, seems more sensible.
-
-SG_GET_MERGE_FD +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-sequencing is per file descriptor. 1 implies sequencing is per device
-(original sg driver's semantics).
-
-SG_SET_COMMAND_Q +:
-Assumes 3rd argument is pointing to an int. 0 (current default, set by
-SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
-a packet while one is already queued will result in a EDOM error.
-1 turns command queuing on.
-Changing the queuing state only affects write()s done after the change.
-Only the current file descriptor is affected by this command.
-
-SG_GET_COMMAND_Q +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-that command queuing is off on this file descriptor. 1 implies command
-queuing is on.
-
-SG_SET_UNDERRUN_FLAG +:
-Assumes 3rd argument is pointing to an int. 0 (current default, set by
-SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests
-that underruns be flagged. [The only low level driver that acts on this
-at the moment is the aic7xxx which yields a DID_ERROR error on underrun.]
-Only the current file descriptor is affected by this command (unless
-"per device" sequencing has been selected).
-
-SG_GET_UNDERRUN_FLAG +:
-Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
-that underruns are not being reported. 1 implies that underruns are being
-reported (see SG_SET_UNDERRUN_FLAG for more details).
-
-SG_NEXT_CMD_LEN +:
-Assumes 3rd argument is pointing to an int. The value of the int (if > 0)
-will be used as the SCSI command length of the next SCSI command sent to
-a write() on this fd. After that write() the SCSI command length logic is
-reset to use automatic length detection (ie depending on SCSI command group
-and the 'twelve_byte' field). If the current SCSI command length maximum of
-12 is exceeded then the affected write() will yield an EDOM error.
-Giving this ioctl() a value of 0 will set automatic length detection for
-the next write(). N.B. Only the following write() on this fd is affected by
-this ioctl().
-
-SG_GET_VERSION_NUM +:
-Assumes 3rd argument points to an int. The version number is then placed
-in that int. A sg version such as 2.1.36 will yield "20136" from this ioctl.
-
-SG_SCSI_RESET +:
-Assumes 3rd argument points to an int. Unfortunately doesn't currently
-do much (may in the future after other issues are resolved). Yields an
-EBUSY error if the SCSI bus or the associated device is being reset
-when this ioctl() is called, otherwise returns 0.
-N.B. In some recent distributions there is a patch to the SCSI mid level
-code that activates this ioctl. Check your distribution.
-
-SG_SET_DEBUG +:
-Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
-off. Values > 0 cause the SCSI sense buffer to be decoded and output
-to the console/log when a SCSI device error occurs. Values > 8 cause
-the current sg device driver's state to be output to the console/log
-(this is a "one off" effect).
-If you need a _lot_ of the SCSI sub-system debug information (mainly from
-the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
-debug will appear in your console/log.
-
-
-poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms)
---------------------------------------------------------------
-This is a native call in Linux 2.2 but most of its capabilities are available
-through the older select() call. Given a choice poll() should probably be
-used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
-for polling; and optionally with asynchronous notification as well using
-the fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
-Only if something drastically is wrong (eg file handle gone stale) will
-POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
-POLLIN is set when there is one or more packets waiting to be read.
-When POLLIN is set it implies that a read() will not block (nor yield
-EAGAIN in non-blocking mode) but return a packet immediately.
-POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
-(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected
-by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
-set until the number of queued packets reaches SG_MAX_QUEUE, if the
-state is off then POLLOUT is only set when no packets are queued.
-Note that a packet can be queued after write()ing but not available to be
-read(); this typically happens when a SCSI read command is issued while
-the data is being retrieved.
-Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
-it is per device.
-
-
-fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg)
-----------------------------------------------------------------
-There are several uses for this system call in association with a sg
-file descriptor. The following pseudo code shows code that is useful for
-scanning the sg devices, taking care not to be caught in a wait for
-an O_EXCL lock by another process, and when the appropriate device is
-found, switching to normal blocked io. A working example of this logic
-is in the sg_scan utility program.
-
-open("/dev/sg0", O_RDONLY | O_NONBLOCK)
-/* check device, EBUSY means some other process has O_EXCL lock on it */
-/* when the device you want is found then ... */
-flags = fcntl(sg_fd, F_GETFL)
-fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
-/* since, for simple apps, it is easier to use normal blocked io */
-
-
-Some work has to be done in Linux to set up for asynchronous notification.
-This is a non-blocking mode of operation in which, when the driver receives
-data back from a device so that a read() can be done, it sends a SIGPOLL
-(aka SIGIO) signal to the owning process. A working example of this logic
-is in the sg_poll test program.
-
-sigemptyset(&sig_set)
-sigaddset(&sig_set, SIGPOLL)
-sigaction(SIGPOLL, &s_action, 0)
-fcntl(sg_fd, F_SETOWN, getpid())
-flags = fcntl(sg_fd, F_GETFL);
-fcntl(sg_fd, F_SETFL, flags | O_ASYNC)
-
-
-Utility and Test Programs
-=========================
-See the README file in the sg_utils<date>.tgz tarball. Look on the
-http://www.torque.net/sg website for the latest version.
-
-Briefly, that tarball contains the following utilities:
-sg_dd512 'dd' like program that assumes 512 byte blocks size
-sg_dd2048 'dd' like program that assumes 2048 byte blocks size
-sg_dd2352 'dd' like program that assumes 2352 byte blocks size
-sgq_dd512 like 'sg_dd512' but does command queuing on "if"
-sgp_dd probably the most flexible 'dd' variant. It uses POSIX
- threads, block size set by "bs=..." plus other options.
-sg_scan outputs information (optionally Inquiry) on SCSI devices
-sg_rbuf tests SCSI bus transfer speed (without physical IO)
-sg_whoami outputs info (optionally capacity) of given SCSI device
-sginfo outputs "mode" information about SCSI devices (it is a
- re-port of the scsiinfo program onto the sg interface)
-
-It also contains the following test programs:
-sg_debug outputs sg driver state to console/log file
-sg_poll tests asynchronous notification
-sg_runt_ex example run time selection program for application authors
-sg_simple1 example program first time users
-sg_simple2 like sg_simple1 but with more primitive error processing
-sg_inquiry does a SCSI Inquiry command (from original HOWTO)
-sg_tst_med checks presence of media (from original HOWTO)
-
-There are also 2 source files (sg_err.[hc]) for outputting and categorizing
-SCSI 2 errors and warnings. This code is used by most of the above
-utility and test programs.
-
-The following programs: sg_dd512, sg_dd2048, sg_dd2352, sg_scan, sg_runt_ex,
-sg_rbuf, sg_tst_med, sg_inquiry and sginfo, can be compiled either for this
-new sg driver _or_ the original sg driver (in 2.0 or 2.2 series kernels).
-sg_runt_ex can be run on 2.0, 2.2 or 2.3 series kernels even if it is
-compiled on a different series (eg compiled on 2.0, run on 2.2).
-
-
-Header files
-============
-User applications need to find the correct "sg.h" header file matching
-their kernel in order to write code using the sg device driver. This is
-sometimes more difficult than it should be. The correct "sg.h" will usually
-be found at /usr/src/linux/include/scsi/sg.h . Another important header
-file is "scsi.h" which will be in the same directory.
-
-When "#include <scsi/sg.h>" is written in an application then this refers
-to the file /usr/include/scsi/sg.h . A problem sometimes arises because
-the files in the /usr/include/scsi directory are controlled by the GNU
-library people who maintain glibc. Unfortunately these 2 versions of
-the sg.h header file are not always in sync. [This was the case in Redhat
-6.0 and 6.1 .] Glibc 2.1.3 and later versions should get this right.
-
-If this is a problem, the user may need to copy sg.h (and scsi.h) from
-the kernel source includes to /usr/include scsi. If the user can change
-the effected source code then another approach is to rely on the fact that
-/usr/src/linux is a symbolic link to /usr/src/linux/include/linux and
-change the sg.h include to look like:
- #include <linux/../scsi/sg.h>
-This solution is used by the author of cdparanoia (Monty) in his application.
-
-[Former scsi generic documents suggested adding a symbolic link to
-bypass this problem but that is not popular with the glibc maintainers.
-I would like to thank Andreas Jaeger <aj@suse.de> for his contributions
-on this subject.]
-
-
-Extra information in scsi-generic_long.txt
-==========================================
-This document is an abridged form of a more comprehensive document called
-scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt).
-
-The longer document contains additional sections on:
- - memory issues
- - ioctl()s in common with sd, st + sr
- - distinguishing the original from the new driver
- - SG_BIG_BUFF and friends
- - shortcomings
- - future directions
- - an appendix with some SCSI 2 information in it
-
-
-References
-==========
-http://www.t10.org Very important site for SCSI related information.
- Contains SCSI 2 and 3 draft standards.
-http://www.andante.org/scsi.html
- This is Eric Youngdale's site. Eric is primarily
- responsible for the Linux SCSI architecture and
- its mid-level implementation.
-http://www.kernel.dk Jens Axboe's site for Linux cdrom matters including
- the SCSI "sr" driver.
-http://www.torque.net/sg
- My site with sg related information.
-newsgroup:linux-scsi@vger.kernel.org
- Newsgroup for Linux related SCSI matters
-/usr/src/linux/MAINTAINERS
- This is a file in the Linux kernel source that
- contains up to date information about who maintains
- what and where information can be found. Links to
- SCSI adapter information are also here.
-
-
-Conclusion
-==========
-The SCSI generic packet device driver attempts to make as few assumptions
-as possible about the device it is connected to while giving applications
-using it as much flexibility as possible on the SCSI command level. Sg
-needs to hide the "messy" kernel related details while protecting
-the integrity of the kernel against sg "abuse". Some of these aims are
-contradictory and some compromises need to be made. For example: should
-a sg based application be able to reset a SCSI bus when that could cause
-collateral damage to a disk holding the root file system? There is no
-easy answer to this and many other related questions.
-
-If you have any suggestion about sg (or improving (the accuracy of) this
-document) please contact me.
+Rather than document the driver's interface here, version information
+is provided plus pointers (i.e. URLs) where to find documentation
+and examples.
+
+
+Major versions of the sg driver
+===============================
+There are three major versions of sg found in the linux kernel (lk):
+ - sg version 1 (original) from 1992 to early 1999 (lk 2.2.5) .
+ It is based in the sg_header interface structure.
+ - sg version 2 from lk 2.2.6 in the 2.2 series. It is based on
+ an extended version of the sg_header interface structure.
+ - sg version 3 found in the lk 2.4 series (and the lk 2.5 series).
+ It adds the sg_io_hdr interface structure.
+
+
+Sg driver documentation
+=======================
+The most recent documentation of the sg driver is kept at the Linux
+Documentation Project's (LDP) site:
+http://www.linuxdoc.org/HOWTO/SCSI-Generic-HOWTO
+This describes the sg version 3 driver found in the lk 2.4 series.
+The LDP renders documents in single and multiple page HTML, postscript
+and pdf. This document can also be found at:
+http://www.torque.net/sg/p/sg_v3_ho.html
+
+Documentation for the version 2 sg driver found in the lk 2.2 series can
+be found at http://www.torque.net/sg/p/scsi-generic.txt . A larger version
+is at: http://www.torque.net/sg/p/scsi-generic_long.txt .
+
+The original documentation for the sg driver (prior to lk 2.2.6) can be
+found at http://www.torque.net/sg/p/original/SCSI-Programming-HOWTO.txt
+and in the LDP archives.
+
+A changelog with brief notes can be found in the
+/usr/src/linux/include/scsi/sg.h file. Note that the glibc maintainers copy
+and edit this file (removing its changelog for example) before placing it
+in /usr/include/scsi/sg.h . Driver debugging information and other notes
+can be found at the top of the /usr/src/linux/drivers/scsi/sg.c file.
+
+A more general description of the Linux SCSI subsystem of which sg is a
+part can be found at http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO .
+
+
+Example code and utilities
+==========================
+There are two packages of sg utilities:
+ - sg3_utils for the sg version 3 driver found in lk 2.4
+ - sg_utils for the sg version 2 (and original) driver found in lk 2.2
+ and earlier
+Both packages will work in the lk 2.4 series however sg3_utils offers more
+capabilities. They can be found at: http://www.torque.net/sg and
+freshmeat.net
+
+Another approach is to look at the applications that use the sg driver.
+These include cdrecord, cdparanoia, SANE and cdrdao.
+
+
+Mapping of Linux kernel versions to sg driver versions
+======================================================
+Here is a list of linux kernels in the 2.4 series that had new version
+of the sg driver:
+ lk 2.4.0 : sg version 3.1.17
+ lk 2.4.7 : sg version 3.1.19
+ lk 2.4.10 : sg version 3.1.20 **
+ lk 2.4.17 : sg version 3.1.22
+
+** There were 3 changes to sg version 3.1.20 by third parties in the
+ next six linux kernel versions.
+
+For reference here is a list of linux kernels in the 2.2 series that had
+new version of the sg driver:
+ lk 2.2.0 : original sg version [with no version number]
+ lk 2.2.6 : sg version 2.1.31
+ lk 2.2.8 : sg version 2.1.32
+ lk 2.2.10 : sg version 2.1.34 [SG_GET_VERSION_NUM ioctl first appeared]
+ lk 2.2.14 : sg version 2.1.36
+ lk 2.2.16 : sg version 2.1.38
+ lk 2.2.17 : sg version 2.1.39
+ lk 2.2.20 : sg version 2.1.40
+
+The lk 2.5 development series has recently commenced and it currently
+contains sg version 3.5.23 which is functionally equivalent to sg
+version 3.1.22 found in lk 2.4.17 .
Douglas Gilbert
+26th January 2002
dgilbert@interlog.com
diff --git a/Documentation/scsi.txt b/Documentation/scsi.txt
index 69d8388c7..934fe73e7 100644
--- a/Documentation/scsi.txt
+++ b/Documentation/scsi.txt
@@ -1,30 +1,44 @@
+SCSI subsystem documentation
+============================
+The Linux Documentation Project (LDP) maintains a document describing
+the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
+http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
+and multiple page HTML renderings as well as postscript and pdf.
+It can also be found at http://www.torque.net/scsi/SCSI-2.4-HOWTO .
- The scsi support in the linux kernel can be modularized in a
-number of different ways depending upon the needs of the end user. To
-understand your options, we should first define a few terms.
-
- The scsi-core contains the core of scsi support. Without it
-you can do nothing with any of the other scsi drivers. The scsi core
-support can be a module (scsi_mod.o), or it can be built into the kernel.
-If the core is a module, it must be the first scsi module loaded, and
-if you unload the modules, it will have to be the last one unloaded.
-
- The individual upper and lower level drivers can be loaded in any
-order once the scsi core is present in the kernel (either compiled in
-or loaded as a module). The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
-tape driver (st.o) and scsi generics driver (sg.o) represent the upper level
-drivers to support the various assorted devices which can be controlled.
-You can for example load the tape driver to use the tape drive, and then
-unload it once you have no further need for the driver (and release the
-associated memory).
-
- The lower level drivers are the ones that support the
-individual cards that are supported for the hardware platform that you
-are running under. Examples are aha1542.o to drive Adaptec 1542
-cards. Rather than list the drivers which *can* be modularized, it is
-easier to list the ones which cannot, since the list only contains a
-few entries. The drivers which have NOT been modularized are:
-
- NCR5380 boards of one kind or another including PAS16,
- Trantor T128/128F/228,
+
+Notes on using modules in the SCSI subsystem
+============================================
+The scsi support in the linux kernel can be modularized in a number of
+different ways depending upon the needs of the end user. To understand
+your options, we should first define a few terms.
+
+The scsi-core (also known as the "mid level") contains the core of scsi
+support. Without it you can do nothing with any of the other scsi drivers.
+The scsi core support can be a module (scsi_mod.o), or it can be built into
+the kernel. If the core is a module, it must be the first scsi module
+loaded, and if you unload the modules, it will have to be the last one
+unloaded. In practice the modprobe and rmmod commands (and "autoclean")
+will enforce the correct ordering of loading and unloading modules in
+the SCSI subsystem.
+
+The individual upper and lower level drivers can be loaded in any order
+once the scsi core is present in the kernel (either compiled in or loaded
+as a module). The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
+tape driver ** (st.o) and scsi generics driver (sg.o) represent the upper
+level drivers to support the various assorted devices which can be
+controlled. You can for example load the tape driver to use the tape drive,
+and then unload it once you have no further need for the driver (and release
+the associated memory).
+
+The lower level drivers are the ones that support the individual cards that
+are supported for the hardware platform that you are running under. Those
+individual cards are often called Host Bus Adapters (HBAs). For example the
+aic7xxx.o driver is used to control all recent SCSI controller cards from
+Adaptec. Almost all lower level drivers can be built either as modules or
+built into the kernel.
+
+
+** There is a variant of the st driver for controlling OnStream tape
+ devices. Its module name is osst.o .
diff --git a/Makefile b/Makefile
index 588d45f8b..825c3e655 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 3
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -131,7 +131,8 @@ DRIVERS- :=
DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
-DRIVERS-y += drivers/char/char.o \
+DRIVERS-y += drivers/base/base.o \
+ drivers/char/char.o \
drivers/block/block.o \
drivers/misc/misc.o \
drivers/net/net.o \
diff --git a/arch/alpha/Config.help b/arch/alpha/Config.help
index 367fee6c6..4a5b50343 100644
--- a/arch/alpha/Config.help
+++ b/arch/alpha/Config.help
@@ -92,11 +92,83 @@ CONFIG_NUMA
Access). This option is for configuring high-end multiprocessor
server machines. If in doubt, say N.
+CONFIG_ALPHA_GENERIC
+ This is the system type of your hardware. A "generic" kernel will
+ run on any supported Alpha system. However, if you configure a
+ kernel for your specific system, it will be faster and smaller.
+
+ To find out what type of Alpha system you have, you may want to
+ check out the Linux/Alpha FAQ, accessible on the WWW from
+ <http://www.alphalinux.org/>. In summary:
+
+ Alcor/Alpha-XLT AS 600
+ Alpha-XL XL-233, XL-266
+ AlphaBook1 Alpha laptop
+ Avanti AS 200, AS 205, AS 250, AS 255, AS 300, AS 400
+ Cabriolet AlphaPC64, AlphaPCI64
+ DP264 DP264
+ EB164 EB164 21164 evaluation board
+ EB64+ EB64+ 21064 evaluation board
+ EB66 EB66 21066 evaluation board
+ EB66+ EB66+ 21066 evaluation board
+ Jensen DECpc 150, DEC 2000 model 300,
+ DEC 2000 model 500
+ LX164 AlphaPC164-LX
+ Miata Personal Workstation 433a, 433au, 500a,
+ 500au, 600a, or 600au
+ Mikasa AS 1000
+ Noname AXPpci33, UDB (Multia)
+ Noritake AS 1000A, AS 600A, AS 800
+ PC164 AlphaPC164
+ Rawhide AS 1200, AS 4000, AS 4100
+ Ruffian RPX164-2, AlphaPC164-UX, AlphaPC164-BX
+ SX164 AlphaPC164-SX
+ Sable AS 2000, AS 2100
+ Shark DS 20L
+ Takara Takara
+ Titan Privateer
+ Wildfire AlphaServer GS 40/80/160/320
+
+ If you don't know what to do, choose "generic".
+
+CONFIG_ALPHA_ALCOR
+ For systems using the Digital ALCOR chipset: 5 chips (4, 64-bit data
+ slices (Data Switch, DSW) - 208-pin PQFP and 1 control (Control, I/O
+ Address, CIA) - a 383 pin plastic PGA). It provides a DRAM
+ controller (256-bit memory bus) and a PCI interface. It also does
+ all the work required to support an external Bcache and to maintain
+ memory coherence when a PCI device DMAs into (or out of) memory.
+
+CONFIG_ALPHA_XL
+ XL-233 and XL-266-based Alpha systems.
+
+CONFIG_ALPHA_BOOK1
+ Dec AlphaBook1/Burns Alpha-based laptops.
+
CONFIG_ALPHA_AVANTI
Avanti AS 200, AS 205, AS 250, AS 255, AS 300, and AS 400-based
Alphas. Info at
<http://www.unix-ag.org/Linux-Alpha/Architectures/Avanti.html>.
+CONFIG_ALPHA_CABRIOLET
+ Cabriolet AlphaPC64, AlphaPCI64 systems. Derived from EB64+ but now
+ baby-AT with Flash boot ROM, no on-board SCSI or Ethernet. 3 ISA
+ slots, 4 PCI slots (one pair are on a shared slot), uses plug-in
+ Bcache SIMMs. Requires power supply with 3.3V output.
+
+CONFIG_ALPHA_DP264
+ Various 21264 systems with the tsunami core logic chipset.
+ API Networks: 264DP, UP2000(+), CS20;
+ Compaq: DS10(E,L), XP900, XP1000, DS20(E), ES40.
+
+CONFIG_ALPHA_EB164
+ EB164 21164 evaluation board from DEC. Uses 21164 and ALCOR. Has
+ ISA and PCI expansion (3 ISA slots, 2 64-bit PCI slots (one is
+ shared with an ISA slot) and 2 32-bit PCI slots. Uses plus-in
+ Bcache SIMMs. I/O sub-system provides SuperI/O (2S, 1P, FD), KBD,
+ MOUSE (PS2 style), RTC/NVRAM. Boot ROM is Flash. PC-AT-sized
+ motherboard. Requires power supply with 3.3V output.
+
CONFIG_ALPHA_EB64P
Uses 21064 or 21064A and APECs. Has ISA and PCI expansion (3 ISA,
2 PCI, one pair are on a shared slot). Supports 36-bit DRAM SIMs.
@@ -105,6 +177,43 @@ CONFIG_ALPHA_EB64P
SuperI/O (2S, 1P, FD), RTC/NVRAM. Boot ROM is EPROM. PC-AT size.
Runs from standard PC power supply.
+CONFIG_ALPHA_EB66
+ A Digital DS group board. Uses 21066 or 21066A. I/O sub-system is
+ identical to EB64+. Baby PC-AT size. Runs from standard PC power
+ supply. The EB66 schematic was published as a marketing poster
+ advertising the 21066 as "the first microprocessor in the world with
+ embedded PCI".
+
+CONFIG_ALPHA_EB66P
+ Later variant of the EB66 board.
+
+CONFIG_ALPHA_EIGER
+ Apparently an obscure OEM single-board computer based on the
+ Typhoon/Tsunami chipset family. Information on it is scanty.
+
+CONFIG_ALPHA_JENSEN
+ DEC PC 150 AXP (aka Jensen): This is a very old Digital system - one
+ of the first-generation Alpha systems. A number of these systems
+ seem to be available on the second- hand market. The Jensen is a
+ floor-standing tower system which originally used a 150MHz 21064 It
+ used programmable logic to interface a 486 EISA I/O bridge to the
+ CPU.
+
+CONFIG_ALPHA_LX164
+ A technical overview of this board is available at
+ <http://www.unix-ag.org/Linux-Alpha/Architectures/LX164.html>.
+
+CONFIG_ALPHA_MIATA
+ The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
+ or 600au). There is an Installation HOWTO for this hardware at
+ <http://members.brabant.chello.nl/~s.vandereijk/miata.html>.
+
+CONFIG_ALPHA_MIKASA
+ AlphaServer 1000-based Alpha systems.
+
+CONFIG_ALPHA_NAUTILUS
+ Alpha systems based on the AMD 751 & ALI 1543C chipsets.
+
CONFIG_ALPHA_NONAME
The AXPpci33 (aka NoName), is based on the EB66 (includes the Multia
UDB). This design was produced by Digital's Technical OEM (TOEM)
@@ -114,6 +223,28 @@ CONFIG_ALPHA_NONAME
2 versions, with either PS/2 or large DIN connectors for the
keyboard.
+CONFIG_ALPHA_NORITAKE
+ AlphaServer 1000A, AlphaServer 600A, and AlphaServer 800-based
+ systems.
+
+CONFIG_ALPHA_RAWHIDE
+ AlphaServer 1200, AlphaServer 4000 and AlphaServer 4100 machines.
+ See HOWTO at
+ <http://www.alphalinux.org/docs/rawhide/4100_install.shtml>.
+
+CONFIG_ALPHA_RUFFIAN
+ Samsung APC164UX. There is a page on known problems and workarounds
+ at <http://www.alphalinux.org/faq/FAQ-11.html>.
+
+CONFIG_ALPHA_SABLE
+ Digital AlphaServer 2000 and 2100-based systems.
+
+CONFIG_ALPHA_TAKARA
+ Alpha 11164-based OEM single-board computer.
+
+CONFIG_ALPHA_WILDFIRE
+ AlphaServer GS 40/80/160/320 SMP based on the EV67 core.
+
CONFIG_ALPHA_PRIMO
Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx.
@@ -237,6 +368,29 @@ CONFIG_PCMCIA
and ds.o. If you want to compile it as a module, say M here and
read <file:Documentation/modules.txt>.
+CONFIG_KCORE_ELF
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image. This can be used
+ in gdb:
+
+ $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+ You have two choices here: ELF and A.OUT. Selecting ELF will make
+ /proc/kcore appear in ELF core format as defined by the Executable
+ and Linking Format specification. Selecting A.OUT will choose the
+ old "a.out" format which may be necessary for some old versions
+ of binutils or on some architectures.
+
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel so if you
+ don't understand what this means or are not a kernel hacker, just
+ leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+ Not necessary unless you're using a very out-of-date binutils
+ version. You probably want KCORE_ELF.
+
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
executables used across different architectures and operating
diff --git a/arch/arm/Config.help b/arch/arm/Config.help
index 06cd31773..ff4735b21 100644
--- a/arch/arm/Config.help
+++ b/arch/arm/Config.help
@@ -170,6 +170,29 @@ CONFIG_PCMCIA
and ds.o. If you want to compile it as a module, say M here and
read <file:Documentation/modules.txt>.
+CONFIG_KCORE_ELF
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image. This can be used
+ in gdb:
+
+ $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+ You have two choices here: ELF and A.OUT. Selecting ELF will make
+ /proc/kcore appear in ELF core format as defined by the Executable
+ and Linking Format specification. Selecting A.OUT will choose the
+ old "a.out" format which may be necessary for some old versions
+ of binutils or on some architectures.
+
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel so if you
+ don't understand what this means or are not a kernel hacker, just
+ leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+ Not necessary unless you're using a very out-of-date binutils
+ version. You probably want KCORE_ELF.
+
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
executables used across different architectures and operating
@@ -251,6 +274,26 @@ CONFIG_VGA_CONSOLE
Say Y.
+CONFIG_ARCH_ANAKIN
+ The Anakin is a StrongArm based SA110 - 2 DIN Vehicle Telematics Platform.
+ 64MB SDRAM - 4 Mb Flash - Compact Flash Interface - 1 MB VRAM
+
+ On board peripherals:
+ * Front display: 400x234 16 bit TFT touchscreen
+ * External independent second screen interface
+ * CAN controller SJA1000
+ * USB host controller
+ * 6 channel video codec with hardware overlay
+ * Smartcard reader
+ * IrDa
+
+ Modules interfaced over the Multi Media Extension slots:
+ * A communication card
+ Wavecom GPRS modem
+ uBlock GPS
+ Bosch DAB module
+ * An audio card ( 4 * 40W, AC97 Codec, I2S)
+
CONFIG_ARCH_CAMELOT
This enables support for Altera's Excalibur XA10 development board.
If you would like to build your kernel to run on one of these boards
@@ -453,6 +496,12 @@ CONFIG_ISDN
want), say M here and read <file:Documentation/modules.txt>. The
module will be called isdn.o. If unsure, say N.
+CONFIG_ARCH_ARCA5K
+ This selects what ARM system you wish to build the kernel for. It
+ also selects to some extent the CPU type. If you are unsure what
+ to set this option to, please consult any information supplied with
+ your system.
+
CONFIG_ARCH_A5K
Say Y here to to support the Acorn A5000. Linux can support the
internal IDE disk and CD-ROM interface, serial and parallel port,
@@ -465,6 +514,16 @@ CONFIG_ARCH_ARC
floppy disks. Picture and more detailed specifications at
<http://www.computingmuseum.com/museum/archi.htm>.
+CONFIG_ARCH_EBSA110
+ This is an evaluation board for the StrongARM processor available
+ from Digital. It has limited hardware on-board, including an onboard
+ Ethernet interface, two PCMCIA sockets, two serial ports and a
+ parallel port.
+
+CONFIG_ARCH_RPC
+ On the Acorn Risc-PC, Linux can support the internal IDE disk and
+ CD-ROM interface, serial and parallel port, and the floppy drive.
+
CONFIG_PAGESIZE_16
Say Y here if your Archimedes or A5000 system has only 2MB of
memory, otherwise say N. The resulting kernel will not run on a
@@ -487,6 +546,16 @@ CONFIG_ARCH_EBSA285_HOST
Saying N will reduce the size of the Footbridge kernel.
+CONFIG_ARCH_L7200
+ Say Y here if you intend to run this kernel on a LinkUp Systems
+ L7200 Software Development Board which uses an ARM720T processor.
+ Information on this board can be obtained at:
+
+ <http://www.linkupsys.com/>
+
+ If you have any questions or comments about the Linux kernel port
+ to this board, send e-mail to sjhill@cotw.com.
+
CONFIG_ARCH_NETWINDER
Say Y here if you intend to run this kernel on the Rebel.COM
NetWinder. Information about this machine can be found at:
diff --git a/arch/cris/Config.help b/arch/cris/Config.help
index c4e25ff79..6dc300a70 100644
--- a/arch/cris/Config.help
+++ b/arch/cris/Config.help
@@ -196,6 +196,12 @@ CONFIG_ISDN
want), say M here and read <file:Documentation/modules.txt>. The
module will be called isdn.o. If unsure, say N.
+CONFIG_ETRAX100LX
+ Support version 1 of the Etrax 100LX.
+
+CONFIG_ETRAX100LX_V2
+ Support version 2 of the Etrax 100LX.
+
CONFIG_SVINTO_SIM
Support the xsim ETRAX Simulator.
@@ -205,6 +211,34 @@ CONFIG_ETRAX_DRAM_SIZE
CONFIG_ETRAX_FLASH_BUSWIDTH
Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
+CONFIG_ETRAX_PA_LEDS
+ The Etrax network driver is responsible for flashing LED's when
+ packets arrive and are sent. It uses macros defined in
+ <file:include/asm-cris/io.h>, and those macros are defined after what
+ YOU choose in this option. The actual bits used are configured
+ separately. Select this if the LEDs are on port PA. Some products
+ put the leds on PB or a memory-mapped latch (CSP0) instead.
+
+CONFIG_ETRAX_PB_LEDS
+ The Etrax network driver is responsible for flashing LED's when
+ packets arrive and are sent. It uses macros defined in
+ <file:include/asm-cris/io.h>, and those macros are defined after what
+ YOU choose in this option. The actual bits used are configured
+ separately. Select this if the LEDs are on port PB. Some products
+ put the leds on PA or a memory-mapped latch (CSP0) instead.
+
+CONFIG_ETRAX_CSP0_LEDS
+ The Etrax network driver is responsible for flashing LED's when
+ packets arrive and are sent. It uses macros defined in
+ <file:include/asm-cris/io.h>, and those macros are defined after what
+ YOU choose in this option. The actual bits used are configured
+ separately. Select this if the LEDs are on a memory-mapped latch
+ using chip select CSP0, this is mapped at 0x90000000.
+ Some products put the leds on PA or PB instead.
+
+CONFIG_ETRAX_NO_LEDS
+ Select this option if you don't have any LED at all.
+
CONFIG_ETRAX_LED1G
Bit to use for the first green LED.
Most Axis products use bit 2 here.
@@ -382,3 +416,32 @@ CONFIG_ETRAX_WATCHDOG
Enable the built-in watchdog timer support on Etrax100 embedded
network computers.
+CONFIG_ETRAX_DEBUG_PORT0
+ Choose a serial port for the ETRAX debug console. Default to
+ port 0.
+
+CONFIG_ETRAX_DEBUG_PORT1
+ Use serial port 1 for the console.
+
+CONFIG_ETRAX_DEBUG_PORT2
+ Use serial port 2 for the console.
+
+CONFIG_ETRAX_DEBUG_PORT3
+ Use serial port 3 for the console.
+
+CONFIG_ETRAX_DEBUG_PORT_NULL
+ Disable serial-port debugging.
+
+CONFIG_ETRAX_RESCUE_SER0
+ Select one of the four serial ports as a rescue port. The default
+ is port 0.
+
+CONFIG_ETRAX_RESCUE_SER1
+ Use serial port 1 as the rescue port.
+
+CONFIG_ETRAX_RESCUE_SER2
+ Use serial port 2 as the rescue port.
+
+CONFIG_ETRAX_RESCUE_SER3
+ Use serial port 3 as the rescue port.
+
diff --git a/arch/i386/Config.help b/arch/i386/Config.help
index e5ca97747..9b5b72e11 100644
--- a/arch/i386/Config.help
+++ b/arch/i386/Config.help
@@ -188,6 +188,20 @@ CONFIG_PCI
information about which PCI hardware does work under Linux and which
doesn't.
+CONFIG_PCI_GOBIOS
+ On PCI systems, the BIOS can be used to detect the PCI devices and
+ determine their configuration. However, some old PCI motherboards
+ have BIOS bugs and may crash if this is done. Also, some embedded
+ PCI-based systems don't have any BIOS at all. Linux can also try to
+ detect the PCI hardware directly without using the BIOS.
+
+ With this option, you can specify how Linux should detect the PCI
+ devices. If you choose "BIOS", the BIOS will be used, if you choose
+ "Direct", the BIOS won't be used, and if you choose "Any", the
+ kernel will try the direct access method and falls back to the BIOS
+ if that doesn't work. If unsure, go with the default, which is
+ "Any".
+
CONFIG_HOTPLUG_PCI
Say Y here if you have a motherboard with a PCI Hotplug controller.
This allows you to add and remove PCI cards while the machine is
@@ -263,6 +277,29 @@ CONFIG_PCMCIA
and ds.o. If you want to compile it as a module, say M here and
read <file:Documentation/modules.txt>.
+CONFIG_KCORE_ELF
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image. This can be used
+ in gdb:
+
+ $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+ You have two choices here: ELF and A.OUT. Selecting ELF will make
+ /proc/kcore appear in ELF core format as defined by the Executable
+ and Linking Format specification. Selecting A.OUT will choose the
+ old "a.out" format which may be necessary for some old versions
+ of binutils or on some architectures.
+
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel so if you
+ don't understand what this means or are not a kernel hacker, just
+ leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+ Not necessary unless you're using a very out-of-date binutils
+ version. You probably want KCORE_ELF.
+
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
executables used across different architectures and operating
@@ -333,6 +370,55 @@ CONFIG_BINFMT_MISC
you have use for it; the module is called binfmt_misc.o. If you
don't know what to answer at this point, say Y.
+CONFIG_M386
+ This is the processor type of your CPU. This information is used for
+ optimizing purposes. In order to compile a kernel that can run on
+ all x86 CPU types (albeit not optimally fast), you can specify
+ "386" here.
+
+ The kernel will not necessarily run on earlier architectures than
+ the one you have chosen, e.g. a Pentium optimized kernel will run on
+ a PPro, but not necessarily on a i486.
+
+ Here are the settings recommended for greatest speed:
+ - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
+ 486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels
+ will run on a 386 class machine.
+ - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
+ SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S.
+ - "586" for generic Pentium CPUs, possibly lacking the TSC
+ (time stamp counter) register.
+ - "Pentium-Classic" for the Intel Pentium.
+ - "Pentium-MMX" for the Intel Pentium MMX.
+ - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II.
+ - "Pentium-III" for the Intel Pentium III
+ and Celerons based on the Coppermine core.
+ - "Pentium-4" for the Intel Pentium 4.
+ - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
+ - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
+ - "Crusoe" for the Transmeta Crusoe series.
+ - "Winchip-C6" for original IDT Winchip.
+ - "Winchip-2" for IDT Winchip 2.
+ - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
+ - "CyrixIII" for VIA Cyrix III or VIA C3.
+
+ If you don't know what to do, choose "386".
+
+CONFIG_M486
+ Select this for a x486 processor, ether Intel or one of the
+ compatible processors from AMD, Cyrix, IBM, or Intel. Includes DX,
+ DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or
+ U5S.
+
+CONFIG_M586
+ Select this for an x586 or x686 processor such as the AMD K5, the
+ Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not
+ assume the RDTSC instruction.
+
+CONFIG_M586TSC
+ Select this for a Pentium Classic processor with the RDTSC (Read
+ Time Stamp Counter) instruction for benchmarking.
+
CONFIG_VGA_CONSOLE
Saying Y here will allow you to use Linux in text mode through a
display that complies with the generic VGA standard. Virtually
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 78e1716f6..d045155c8 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -70,6 +70,10 @@ CONFIG_NOHIGHMEM=y
CONFIG_SMP=y
# CONFIG_MULTIQUAD is not set
CONFIG_HAVE_DEC_LOCK=y
+
+#
+# General options
+#
CONFIG_X86_IO_APIC=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_PCI=y
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 22ee8aceb..254f0e572 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -88,8 +88,12 @@ void clear_local_APIC(void)
apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
if (maxlvt >= 4)
apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
- apic_write(APIC_ESR, 0);
- v = apic_read(APIC_ESR);
+ v = GET_APIC_VERSION(apic_read(APIC_LVR));
+ if (APIC_INTEGRATED(v)) { /* !82489DX */
+ if (maxlvt > 3)
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ }
}
void __init connect_bsp_APIC(void)
@@ -918,6 +922,26 @@ void __init setup_APIC_clocks (void)
smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1);
}
+void __init disable_APIC_timer(void)
+{
+ if (using_apic_timer) {
+ unsigned long v;
+
+ v = apic_read(APIC_LVTT);
+ apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+ }
+}
+
+void enable_APIC_timer(void)
+{
+ if (using_apic_timer) {
+ unsigned long v;
+
+ v = apic_read(APIC_LVTT);
+ apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED);
+ }
+}
+
/*
* the frequency of the profiling timer can be changed
* by writing a multiplier value into /proc/profile.
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 0eb76e8e9..ead91fcb6 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -77,7 +77,7 @@ addr_limit = 12
exec_domain = 16
need_resched = 20
tsk_ptrace = 24
-processor = 52
+cpu = 32
ENOSYS = 38
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 0a85edcc9..d93e7a710 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -378,10 +378,8 @@ struct set_mtrr_context
static int arr3_protected;
/* Put the processor into a state where MTRRs can be safely set */
-static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
+static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt)
{
- unsigned long tmp;
-
/* Disable interrupts locally */
__save_flags (ctxt->flags); __cli ();
@@ -404,16 +402,27 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
}
if ( mtrr_if == MTRR_IF_INTEL ) {
- /* Disable MTRRs, and set the default type to uncached */
+ /* Save MTRR state */
rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+ } else {
+ /* Cyrix ARRs - everything else were excluded at the top */
+ ctxt->ccr3 = getCx86 (CX86_CCR3);
+ }
+} /* End Function set_mtrr_prepare_save */
+
+static void set_mtrr_cache_disable (struct set_mtrr_context *ctxt)
+{
+ if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
+ return;
+
+ if ( mtrr_if == MTRR_IF_INTEL ) {
+ /* Disable MTRRs, and set the default type to uncached */
wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
} else {
/* Cyrix ARRs - everything else were excluded at the top */
- tmp = getCx86 (CX86_CCR3);
- setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
- ctxt->ccr3 = tmp;
+ setCx86 (CX86_CCR3, (ctxt->ccr3 & 0x0f) | 0x10);
}
-} /* End Function set_mtrr_prepare */
+} /* End Function set_mtrr_cache_disable */
/* Restore the processor after a set_mtrr_prepare */
static void set_mtrr_done (struct set_mtrr_context *ctxt)
@@ -674,7 +683,10 @@ static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
{
struct set_mtrr_context ctxt;
- if (do_safe) set_mtrr_prepare (&ctxt);
+ if (do_safe) {
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
+ }
if (size == 0)
{
/* The invalid bit is kept in the mask, so we simply clear the
@@ -726,7 +738,10 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
}
}
- if (do_safe) set_mtrr_prepare (&ctxt);
+ if (do_safe) {
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
+ }
base <<= PAGE_SHIFT;
setCx86(arr, ((unsigned char *) &base)[3]);
setCx86(arr+1, ((unsigned char *) &base)[2]);
@@ -750,7 +765,10 @@ static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
u32 regs[2];
struct set_mtrr_context ctxt;
- if (do_safe) set_mtrr_prepare (&ctxt);
+ if (do_safe) {
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
+ }
/*
* Low is MTRR0 , High MTRR 1
*/
@@ -788,7 +806,10 @@ static void centaur_set_mcr_up (unsigned int reg, unsigned long base,
struct set_mtrr_context ctxt;
unsigned long low, high;
- if (do_safe) set_mtrr_prepare( &ctxt );
+ if (do_safe) {
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
+ }
if (size == 0)
{
/* Disable */
@@ -985,6 +1006,7 @@ static unsigned long __init set_mtrr_state (struct mtrr_state *state,
static atomic_t undone_count;
+static volatile int wait_barrier_cache_disable = FALSE;
static volatile int wait_barrier_execute = FALSE;
static volatile int wait_barrier_cache_enable = FALSE;
@@ -1003,18 +1025,21 @@ static void ipi_handler (void *info)
{
struct set_mtrr_data *data = info;
struct set_mtrr_context ctxt;
-
- set_mtrr_prepare (&ctxt);
+ set_mtrr_prepare_save (&ctxt);
/* Notify master that I've flushed and disabled my cache */
atomic_dec (&undone_count);
- while (wait_barrier_execute) barrier ();
+ while (wait_barrier_cache_disable) { rep_nop(); barrier(); }
+ set_mtrr_cache_disable (&ctxt);
+ /* Notify master that I've flushed and disabled my cache */
+ atomic_dec (&undone_count);
+ while (wait_barrier_execute) { rep_nop(); barrier(); }
/* The master has cleared me to execute */
(*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
data->smp_type, FALSE);
/* Notify master CPU that I've executed the function */
atomic_dec (&undone_count);
/* Wait for master to clear me to enable cache and return */
- while (wait_barrier_cache_enable) barrier ();
+ while (wait_barrier_cache_enable) { rep_nop(); barrier(); }
set_mtrr_done (&ctxt);
} /* End Function ipi_handler */
@@ -1028,6 +1053,7 @@ static void set_mtrr_smp (unsigned int reg, unsigned long base,
data.smp_base = base;
data.smp_size = size;
data.smp_type = type;
+ wait_barrier_cache_disable = TRUE;
wait_barrier_execute = TRUE;
wait_barrier_cache_enable = TRUE;
atomic_set (&undone_count, smp_num_cpus - 1);
@@ -1035,15 +1061,22 @@ static void set_mtrr_smp (unsigned int reg, unsigned long base,
if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
panic ("mtrr: timed out waiting for other CPUs\n");
/* Flush and disable the local CPU's cache */
- set_mtrr_prepare (&ctxt);
+ set_mtrr_prepare_save (&ctxt);
+ /* Wait for all other CPUs to flush and disable their caches */
+ while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
+ /* Set up for completion wait and then release other CPUs to change MTRRs*/
+ atomic_set (&undone_count, smp_num_cpus - 1);
+ wait_barrier_cache_disable = FALSE;
+ set_mtrr_cache_disable (&ctxt);
+
/* Wait for all other CPUs to flush and disable their caches */
- while (atomic_read (&undone_count) > 0) barrier ();
+ while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
/* Set up for completion wait and then release other CPUs to change MTRRs*/
atomic_set (&undone_count, smp_num_cpus - 1);
wait_barrier_execute = FALSE;
(*set_mtrr_up) (reg, base, size, type, FALSE);
/* Now wait for other CPUs to complete the function */
- while (atomic_read (&undone_count) > 0) barrier ();
+ while (atomic_read (&undone_count) > 0) { rep_nop(); barrier(); }
/* Now all CPUs should have finished the function. Release the barrier to
allow them to re-enable their caches and return from their interrupt,
then enable the local cache and return */
@@ -1887,7 +1920,9 @@ static void __init cyrix_arr_init_secondary(void)
struct set_mtrr_context ctxt;
int i;
- set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+ /* flush cache and enable MAPEN */
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
/* the CCRs are not contiguous */
for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
@@ -1924,7 +1959,9 @@ static void __init cyrix_arr_init(void)
int i;
#endif
- set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+ /* flush cache and enable MAPEN */
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
/* Save all CCRs locally */
ccr[0] = getCx86 (CX86_CCR0);
@@ -2073,7 +2110,8 @@ static void __init centaur_mcr_init(void)
{
struct set_mtrr_context ctxt;
- set_mtrr_prepare (&ctxt);
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
if(boot_cpu_data.x86_model==4)
centaur_mcr0_init();
@@ -2190,7 +2228,8 @@ static void __init intel_mtrr_init_secondary_cpu(void)
/* Note that this is not ideal, since the cache is only flushed/disabled
for this CPU while the MTRRs are changed, but changing this requires
more invasive changes to the way the kernel boots */
- set_mtrr_prepare (&ctxt);
+ set_mtrr_prepare_save (&ctxt);
+ set_mtrr_cache_disable (&ctxt);
mask = set_mtrr_state (&smp_mtrr_state, &ctxt);
set_mtrr_done (&ctxt);
/* Use the atomic bitops to update the global mask */
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 0f0b20014..558c9d603 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -689,15 +689,17 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
/*
- * Restore %fs and %gs.
+ * Restore %fs and %gs if needed.
*/
- loadsegment(fs, next->fs);
- loadsegment(gs, next->gs);
+ if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) {
+ loadsegment(fs, next->fs);
+ loadsegment(gs, next->gs);
+ }
/*
* Now maybe reload the debug registers
*/
- if (next->debugreg[7]){
+ if (unlikely(next->debugreg[7])) {
loaddebug(next, 0);
loaddebug(next, 1);
loaddebug(next, 2);
@@ -707,7 +709,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
loaddebug(next, 7);
}
- if (prev->ioperm || next->ioperm) {
+ if (unlikely(prev->ioperm || next->ioperm)) {
if (next->ioperm) {
/*
* 4 cachelines copy ... not good, but not that
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index fd3493f87..66871bc40 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -2803,9 +2803,10 @@ void __init cpu_init (void)
load_TR(nr);
load_LDT(&init_mm);
- /*
- * Clear all 6 debug registers:
- */
+ /* Clear %fs and %gs. */
+ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
+
+ /* Clear all 6 debug registers: */
#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 0f5521b3f..e8afcadb7 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -435,6 +435,7 @@ void __init smp_callin(void)
*/
smp_store_cpu_info(cpuid);
+ disable_APIC_timer();
/*
* Allow the master to continue.
*/
@@ -462,16 +463,15 @@ int __init start_secondary(void *unused)
* things done here to the most necessary things.
*/
cpu_init();
- init_idle();
smp_callin();
while (!atomic_read(&smp_commenced))
rep_nop();
+ enable_APIC_timer();
/*
* low-memory mappings have been cleared, flush them from
* the local TLBs too.
*/
local_flush_tlb();
- idle_startup_done();
return cpu_idle();
}
@@ -805,7 +805,7 @@ static void __init do_boot_cpu (int apicid)
if (!idle)
panic("No idle process for CPU %d", cpu);
- idle->cpu = cpu;
+ init_idle(idle, cpu);
map_cpu_to_boot_apicid(cpu, apicid);
@@ -924,6 +924,7 @@ static void __init do_boot_cpu (int apicid)
}
cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
static void smp_tune_scheduling (void)
{
@@ -957,9 +958,13 @@ static void smp_tune_scheduling (void)
cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
}
+ cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000;
+
printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
(long)cacheflush_time/(cpu_khz/1000),
((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
+ printk("task migration cache decay timeout: %ld msecs.\n",
+ (cache_decay_ticks + 1) * 1000 / HZ);
}
/*
diff --git a/arch/ia64/Config.help b/arch/ia64/Config.help
index 70d715a46..23ae7ec73 100644
--- a/arch/ia64/Config.help
+++ b/arch/ia64/Config.help
@@ -449,6 +449,45 @@ CONFIG_ISDN
want), say M here and read <file:Documentation/modules.txt>. The
module will be called isdn.o. If unsure, say N.
+CONFIG_ITANIUM
+ Select your IA64 processor type. The default is Intel Itanium.
+
+CONFIG_MCKINLEY
+ Select this to configure for a McKinley processor.
+
+CONFIG_IA64_GENERIC
+ This selects the system type of your hardware. A "generic" kernel
+ will run on any supported IA-64 system. However, if you configure
+ a kernel for your specific system, it will be faster and smaller.
+
+ To find out what type of IA-64 system you have, you may want to
+ check the IA-64 Linux web site at <http://www.linux-ia64.org/>.
+ As of the time of this writing, most hardware is DIG compliant,
+ so the "DIG-compliant" option is usually the right choice.
+
+ HP-simulator For the HP simulator
+ (<http://software.hp.com/ia64linux/>).
+ SN1-simulator For the SGI SN1 simulator.
+ DIG-compliant For DIG ("Developer's Interface Guide") compliant
+ system.
+
+ If you don't know what to do, choose "generic".
+
+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
+ IA-32 compatibility, a page size of 4KB should be selected (the vast
+ majority of IA-32 binaries work perfectly fine with a larger page
+ size). For Itanium systems, do NOT chose a page size larger than
+ 16KB.
+
+ 4KB For best IA-32 compatibility
+ 8KB For best IA-64 performance
+ 16KB For best IA-64 performance
+ 64KB Not for Itanium.
+
+ If you don't know what to do, choose 8KB.
+
CONFIG_ITANIUM_BSTEP_SPECIFIC
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
diff --git a/arch/m68k/Config.help b/arch/m68k/Config.help
index 6d8aab048..105f13bd4 100644
--- a/arch/m68k/Config.help
+++ b/arch/m68k/Config.help
@@ -143,6 +143,29 @@ CONFIG_PCMCIA
and ds.o. If you want to compile it as a module, say M here and
read <file:Documentation/modules.txt>.
+CONFIG_KCORE_ELF
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image. This can be used
+ in gdb:
+
+ $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+ You have two choices here: ELF and A.OUT. Selecting ELF will make
+ /proc/kcore appear in ELF core format as defined by the Executable
+ and Linking Format specification. Selecting A.OUT will choose the
+ old "a.out" format which may be necessary for some old versions
+ of binutils or on some architectures.
+
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel so if you
+ don't understand what this means or are not a kernel hacker, just
+ leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+ Not necessary unless you're using a very out-of-date binutils
+ version. You probably want KCORE_ELF.
+
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
executables used across different architectures and operating
@@ -981,6 +1004,28 @@ CONFIG_BUSMOUSE
The module will be called busmouse.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_WATCHDOG
+ If you say Y here (and to one of the following options) and create a
+ character special file /dev/watchdog with major number 10 and minor
+ number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
+ subsequently opening the file and then failing to write to it for
+ longer than 1 minute will result in rebooting the machine. This
+ could be useful for a networked machine that needs to come back
+ online as fast as possible after a lock-up. There's both a watchdog
+ implementation entirely in software (which can sometimes fail to
+ reboot the machine) and a driver for hardware watchdog boards, which
+ are more robust and can also keep track of the temperature inside
+ your computer. For details, read <file:Documentation/watchdog.txt>
+ in the kernel source.
+
+ The watchdog is usually used together with the watchdog daemon
+ which is available from
+ <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
+ also monitor NFS connections and can reboot the machine when the process
+ table is full.
+
+ If unsure, say N.
+
CONFIG_WATCHDOG_NOWAYOUT
The default watchdog behaviour (which you get if you say N here) is
to stop the timer if the process managing it closes the file
diff --git a/arch/ppc/8xx_io/Config.help b/arch/ppc/8xx_io/Config.help
index 00ac76eb1..f6cf9de80 100644
--- a/arch/ppc/8xx_io/Config.help
+++ b/arch/ppc/8xx_io/Config.help
@@ -12,6 +12,16 @@ CONFIG_SCC_ENET
Enable Ethernet support via the Motorola MPC8xx serial
commmunications controller.
+CONFIG_SCC1_ENET
+ Use MPC8xx serial communications controller 1 to drive Ethernet
+ (default).
+
+CONFIG_SCC2_ENET
+ Use MPC8xx serial communications controller 2 to drive Ethernet.
+
+CONFIG_SCC3_ENET
+ Use MPC8xx serial communications controller 3 to drive Ethernet.
+
CONFIG_ENET_BIG_BUFFERS
Allocate large buffers for MPC8xx Etherenet. Increases throughput
and decreases the likelihood of dropped packets, but costs memory.
diff --git a/arch/ppc/Config.help b/arch/ppc/Config.help
index 00954858e..5786797a8 100644
--- a/arch/ppc/Config.help
+++ b/arch/ppc/Config.help
@@ -668,6 +668,17 @@ CONFIG_MULTIFACE_III_TTY
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>.
+CONFIG_6xx
+ There are four types of PowerPC chips supported. The more common
+ types (601, 603, 604, 740, 750, 7400), the Motorola embedded
+ versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions
+ (403 and 405) and the high end 64 bit Power processors (Power 3,
+ Power 4). Unless you are building a kernel for one of the embedded
+ processor systems, or a 64 bit IBM RS/6000, choose 6xx. Note that
+ the kernel runs in 32-bit mode even on 64-bit chips. Also note that
+ because the 82xx family has a 603e core, specific support for that
+ chipset is asked later on.
+
CONFIG_8260
The MPC8260 CPM (Communications Processor Module) is a typical
embedded CPU made by Motorola. Selecting this option means that
@@ -676,6 +687,17 @@ CONFIG_8260
If in doubt, say N.
+CONFIG_OAK
+ Select Oak if you have an IBM 403GCX "Oak" Evaluation Board.
+
+ Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board.
+
+ More information on these boards is available at:
+ <http://www.chips.ibm.com/products/powerpc/tools/evk_pn.html#GCX>.
+
+CONFIG_WALNUT
+ Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board.
+
CONFIG_PPC601_SYNC_FIX
Some versions of the PPC601 (the first PowerPC chip) have bugs which
mean that extra synchronization instructions are required near
@@ -706,6 +728,16 @@ CONFIG_ALL_PPC
Select APUS if configuring for a PowerUP Amiga. More information is
available at: <http://linux-apus.sourceforge.net/>.
+CONFIG_GEMINI
+ Select Gemini if configuring for a Synergy Microsystems' Gemini
+ series Single Board Computer. More information is available at:
+ <http://www.synergymicro.com/PressRel/97_10_15.html>.
+
+CONFIG_APUS
+ Select APUS if configuring for a PowerUP Amiga.
+ More information is available at:
+ <http://linux-apus.sourceforge.net/>.
+
CONFIG_ALTIVEC
This option enables kernel support for the Altivec extensions to the
PowerPC processor. The kernel currently supports saving and restoring
@@ -771,6 +803,178 @@ CONFIG_PMAC_BACKLIGHT
events; also, the PowerBook button device will be enabled so you can
change the screen brightness.
+CONFIG_RPXLITE
+ Single-board computers based around the PowerPC MPC8xx chips and
+ intended for embedded applications. The following types are
+ supported:
+
+ RPX-Lite:
+ Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823.
+
+ RPX-Classic:
+ Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on
+ the MPC 860
+
+ BSE-IP:
+ Bright Star Engineering ip-Engine.
+
+ TQM823L:
+ TQM850L:
+ TQM855L:
+ TQM860L:
+ MPC8xx based family of mini modules, half credit card size,
+ up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports,
+ 2 x CAN bus interface, ...
+ Manufacturer: TQ Components, www.tq-group.de
+ Date of Release: October (?) 1999
+ End of Life: not yet :-)
+ URL:
+ - module: <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>
+ - starter kit: <http://www.denx.de/PDF/STK8xxLHWM201.pdf>
+ - images: <http://www.denx.de/embedded-ppc-en.html>
+
+ FPS850L:
+ FingerPrint Sensor System (based on TQM850L)
+ Manufacturer: IKENDI AG, <http://www.ikendi.com/>
+ Date of Release: November 1999
+ End of life: end 2000 ?
+ URL: see TQM850L
+
+ SPD823TS:
+ MPC823 based board used in the "Tele Server" product
+ Manufacturer: Speech Design, <http://www.speech-design.de/>
+ Date of Release: Mid 2000 (?)
+ End of life: -
+ URL: <http://www.speech-design.de/>
+ select "English", then "Teleteam Solutions", then "TeleServer"
+
+ IVMS8:
+ MPC860 based board used in the "Integrated Voice Mail System",
+ Small Version (8 voice channels)
+ Manufacturer: Speech Design, <http://www.speech-design.de/>
+ Date of Release: December 2000 (?)
+ End of life: -
+ URL: <http://www.speech-design.de/>
+
+ IVML24:
+ MPC860 based board used in the "Integrated Voice Mail System",
+ Large Version (24 voice channels)
+ Manufacturer: Speech Design, <http://www.speech-design.de/>
+ Date of Release: March 2001 (?)
+ End of life: -
+ URL: <http://www.speech-design.de/>
+
+ SM850:
+ Service Module (based on TQM850L)
+ Manufacturer: Dependable Computer Systems, <http://www.decomsys.com/>
+ Date of Release: end 2000 (?)
+ End of life: mid 2001 (?)
+ URL: <http://www.tz-mikroelektronik.de/ServiceModule/index.html>
+
+ HERMES:
+ Hermes-Pro ISDN/LAN router with integrated 8 x hub
+ Manufacturer: Multidata Gesellschaft für Datentechnik und Informatik
+ <http://www.multidata.de/>
+ Date of Release: 2000 (?)
+ End of life: -
+ URL: <http://www.multidata.de/english/products/hpro.htm>
+
+ IP860:
+ VMEBus IP (Industry Pack) carrier board with MPC860
+ Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
+ Date of Release: ?
+ End of life: -
+ URL: <http://www.microsys.de/html/ip860.html>
+
+ PCU_E:
+ PCU = Peripheral Controller Unit, Extended
+ Manufacturer: Siemens AG, ICN (Information and Communication Networks)
+ <http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html>
+ Date of Release: April 2001
+ End of life: August 2001
+ URL: n. a.
+
+CONFIG_RPXCLASSIC
+ The RPX-Classic is a single-board computer based on the Motorola
+ MPC860. It features 16MB of DRAM and a variable amount of flash,
+ I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two
+ LEDs. Variants with Ethernet ports exist. Say Y here to support it
+ directly.
+
+CONFIG_BSEIP
+ Say Y here to support the Bright Star Engineering ipEngine SBC.
+ This is a credit-card-sized device featuring a MPC823 processor,
+ 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
+ controller, and two RS232 ports.
+
+CONFIG_TQM823L
+ Say Y here to support the TQM823L, one of an MPC8xx-based family of
+ mini SBCs (half credit-card size) from TQ Components first released
+ in late 1999. Technical references are at
+ <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+ <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+ <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM850L
+ Say Y here to support the TQM850L, one of an MPC8xx-based family of
+ mini SBCs (half credit-card size) from TQ Components first released
+ in late 1999. Technical references are at
+ <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+ <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+ <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM855L
+ Say Y here to support the TQM855L, one of an MPC8xx-based family of
+ mini SBCs (half credit-card size) from TQ Components first released
+ in late 1999. Technical references are at
+ <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+ <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+ <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM860L
+ Say Y here to support the TQM860L, one of an MPC8xx-based family of
+ mini SBCs (half credit-card size) from TQ Components first released
+ in late 1999. Technical references are at
+ <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
+ <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
+ <http://www.denx.de/embedded-ppc-en.html>.
+
+CONFIG_TQM860
+ Say Y here to support the TQM860, one of an MPC8xx-based family of
+ SBCs (credit-card size) from TQ Components first released in
+ mid-1999 and discontinued mid-2000.
+
+CONFIG_SM850
+ Say Y here to support the Service Module 850 from Dependable
+ Computer Systems, an SBC based on the TQM850L module by TQ
+ Components. This board is no longer in production. The
+ manufacturer's website is at <http://www.decomsys.com/>.
+
+CONFIG_SPD823TS
+ Say Y here to support the Speech Design 823 Tele-Server from Speech
+ Design, released in 2000. The manufacturer's website is at
+ <http://www.speech-design.de/>.
+
+CONFIG_IVMS8
+ Say Y here to support the Integrated Voice-Mail Small 8-channel SBC
+ from Speech Design, released March 2001. The manufacturer's website
+ is at <http://www.speech-design.de/>.
+
+CONFIG_IVML24
+ Say Y here to support the Integrated Voice-Mail Large 24-channel SBC
+ from Speech Design, released March 2001. The manufacturer's website
+ is at <http://www.speech-design.de/>.
+
+CONFIG_MBX
+ MBX is a line of Motorola single-board computer based around the
+ MPC821 and MPC860 processors, and intended for embedded-controller
+ applications. Say Y here to support these boards directly.
+
+CONFIG_WINCEPT
+ The Wincept 100/110 is a Motorola single-board computer based on the
+ MPC821 PowerPC, introduced in 1998 and designed to be used in
+ thin-client machines. Say Y to support it directly.
+
CONFIG_EST8260
EST8260:
The EST8260 is a single-board computer manufactured by Wind River
diff --git a/arch/sh/Config.help b/arch/sh/Config.help
index f09d4e6af..90d188800 100644
--- a/arch/sh/Config.help
+++ b/arch/sh/Config.help
@@ -82,6 +82,20 @@ CONFIG_PCI
information about which PCI hardware does work under Linux and which
doesn't.
+CONFIG_PCI_GOBIOS
+ On PCI systems, the BIOS can be used to detect the PCI devices and
+ determine their configuration. However, some old PCI motherboards
+ have BIOS bugs and may crash if this is done. Also, some embedded
+ PCI-based systems don't have any BIOS at all. Linux can also try to
+ detect the PCI hardware directly without using the BIOS.
+
+ With this option, you can specify how Linux should detect the PCI
+ devices. If you choose "BIOS", the BIOS will be used, if you choose
+ "Direct", the BIOS won't be used, and if you choose "Any", the
+ kernel will try the direct access method and falls back to the BIOS
+ if that doesn't work. If unsure, go with the default, which is
+ "Any".
+
CONFIG_MCA
MicroChannel Architecture is found in some IBM PS/2 machines and
laptops. It is a bus system similar to PCI or ISA. See
@@ -136,6 +150,29 @@ CONFIG_PCMCIA
and ds.o. If you want to compile it as a module, say M here and
read <file:Documentation/modules.txt>.
+CONFIG_KCORE_ELF
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image. This can be used
+ in gdb:
+
+ $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+ You have two choices here: ELF and A.OUT. Selecting ELF will make
+ /proc/kcore appear in ELF core format as defined by the Executable
+ and Linking Format specification. Selecting A.OUT will choose the
+ old "a.out" format which may be necessary for some old versions
+ of binutils or on some architectures.
+
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel so if you
+ don't understand what this means or are not a kernel hacker, just
+ leave it at its default value ELF.
+
+CONFIG_KCORE_AOUT
+ Not necessary unless you're using a very out-of-date binutils
+ version. You probably want KCORE_ELF.
+
CONFIG_BINFMT_ELF
ELF (Executable and Linkable Format) is a format for libraries and
executables used across different architectures and operating
@@ -659,6 +696,102 @@ CONFIG_CF_ENABLER
If in doubt, select 'N'.
+CONFIG_SH_GENERIC
+ Select Generic if configuring for a generic SuperH system.
+ The "generic" option compiles in *all* the possible hardware
+ support and relies on the sh_mv= kernel commandline option to choose
+ at runtime which routines to use. "MV" stands for "machine vector";
+ each of the machines below is described by a machine vector.
+
+ Select SolutionEngine if configuring for a Hitachi SH7709
+ or SH7750/7750S evalutation board.
+
+ Select Overdrive if configuring for a ST407750 Overdrive board.
+ More information at
+ <http://linuxsh.sourceforge.net/docs/7750overdrive.php3>.
+
+ Select HP620 if configuring for a HP Jornada HP620.
+ More information (hardware only) at
+ <http://www.hp.com/jornada/>.
+
+ Select HP680 if configuring for a HP Jornada HP680.
+ More information (hardware only) at
+ <http://www.hp.com/jornada/products/680/>.
+
+ Select HP690 if configuring for a HP Jornada HP690.
+ More information (hardware only) at
+ <http://www.hp.com/jornada/products/680/>.
+
+ Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
+ More information at
+ <http://sources.redhat.com/ecos/hardware.html#SuperH>.
+
+ Select DMIDA if configuring for a DataMyte 4000 Industrial
+ Digital Assistant. More information at <http://www.dmida.com/>.
+
+ Select EC3104 if configuring for a system with an Eclipse
+ International EC3104 chip, e.g. the Harris AD2000 or Compaq Aero 8000.
+
+ Select Dreamcast if configuring for a SEGA Dreamcast.
+ More information at
+ <http://www.m17n.org/linux-sh/dreamcast/>. There is a
+ Dreamcast project is at <http://linuxdc.sourceforge.net/>.
+
+ Select BareCPU if you know what this means, and it applies
+ to your system.
+
+CONFIG_SH_SOLUTION_ENGINE
+ Select SolutionEngine if configuring for a Hitachi SH7709
+ or SH7750 evalutation board.
+
+CONFIG_SH_7751_SOLUTION_ENGINE
+ Select 7751 SolutionEngine if configuring for a Hitachi SH7751
+ evalutation board.
+
+CONFIG_SH_HP620
+ Select HP620 if configuring for a HP jornada HP620.
+ More information (hardware only) at
+ <http://www.hp.com/jornada/>.
+
+CONFIG_SH_HP680
+ Select HP680 if configuring for a HP Jornada HP680.
+ More information (hardware only) at
+ <http://www.hp.com/jornada/products/680/>.
+
+CONFIG_SH_HP690
+ Select HP690 if configuring for a HP Jornada HP690.
+ More information (hardware only)
+ at <http://www.hp.com/jornada/products/680/>.
+
+CONFIG_SH_CQREEK
+ Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
+ More information at
+ <http://sources.redhat.com/ecos/hardware.html#SuperH>.
+
+CONFIG_SH_DMIDA
+ Select DMIDA if configuring for a DataMyte 4000 Industrial
+ Digital Assistant. More information at <http://www.dmida.com/>.
+
+CONFIG_SH_EC3104
+ Select EC3104 if configuring for a system with an Eclipse
+ International EC3104 chip, e.g. the Harris AD2000.
+
+CONFIG_SH_DREAMCAST
+ Select Dreamcast if configuring for a SEGA Dreamcast.
+ More information at
+ <http://www.m17n.org/linux-sh/dreamcast/>. There is a
+ Dreamcast project is at <http://linuxdc.sourceforge.net/>.
+
+CONFIG_SH_UNKNOWN
+ "Bare CPU" aka "unknown" means an SH-based system which is not one
+ of the specific ones mentioned above, which means you need to enter
+ all sorts of stuff like CONFIG_MEMORY_START because the config
+ system doesn't already know what it is. You get a machine vector
+ without any platform-specific code in it, so things like the RTC may
+ not work.
+
+ This option is for the early stages of porting to a new machine.
+
CONFIG_CPU_SUBTYPE_SH7707
Select the type of SuperH processor you have. This information is
used for optimizing and configuration purposes.
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 7ea6ee240..a14989388 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -218,12 +218,8 @@ void __init smp_callin(void)
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- init_idle();
-
while (!smp_threads_ready)
membar("#LoadLoad");
-
- idle_startup_done();
}
void cpu_panic(void)
@@ -242,6 +238,8 @@ extern unsigned long sparc64_cpu_startup;
*/
static struct task_struct *cpu_new_task = NULL;
+static void smp_tune_scheduling(void);
+
void __init smp_boot_cpus(void)
{
int cpucount = 0, i;
@@ -250,8 +248,10 @@ void __init smp_boot_cpus(void)
__sti();
smp_store_cpu_info(boot_cpu_id);
- if (linux_num_cpus == 1)
+ if (linux_num_cpus == 1) {
+ smp_tune_scheduling();
return;
+ }
for (i = 0; i < NR_CPUS; i++) {
if (i == boot_cpu_id)
@@ -272,7 +272,7 @@ void __init smp_boot_cpus(void)
p = init_task.prev_task;
- p->cpu = i;
+ init_idle(p, i);
unhash_process(p);
@@ -324,6 +324,12 @@ ignorecpu:
smp_activated = 1;
smp_num_cpus = cpucount + 1;
}
+
+ /* We want to run this with all the other cpus spinning
+ * in the kernel.
+ */
+ smp_tune_scheduling();
+
smp_processors_ready = 1;
membar("#StoreStore | #StoreLoad");
}
@@ -1172,27 +1178,106 @@ void __init smp_tick_init(void)
prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
}
-static inline unsigned long find_flush_base(unsigned long size)
+cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
+
+extern unsigned long cheetah_tune_scheduling(void);
+extern unsigned long timer_ticks_per_usec_quotient;
+
+static void __init smp_tune_scheduling(void)
{
- struct page *p = mem_map;
- unsigned long found, base;
-
- size = PAGE_ALIGN(size);
- found = size;
- base = (unsigned long) page_address(p);
- while (found != 0) {
- /* Failure. */
- if (p >= (mem_map + max_mapnr))
- return 0UL;
- if (PageReserved(p)) {
- found = size;
- base = (unsigned long) page_address(p);
- } else {
- found -= PAGE_SIZE;
- }
- p++;
+ unsigned long orig_flush_base, flush_base, flags, *p;
+ unsigned int ecache_size, order;
+ cycles_t tick1, tick2, raw;
+
+ /* Approximate heuristic for SMP scheduling. It is an
+ * estimation of the time it takes to flush the L2 cache
+ * on the local processor.
+ *
+ * The ia32 chooses to use the L1 cache flush time instead,
+ * and I consider this complete nonsense. The Ultra can service
+ * a miss to the L1 with a hit to the L2 in 7 or 8 cycles, and
+ * L2 misses are what create extra bus traffic (ie. the "cost"
+ * of moving a process from one cpu to another).
+ */
+ printk("SMP: Calibrating ecache flush... ");
+ if (tlb_type == cheetah) {
+ cacheflush_time = cheetah_tune_scheduling();
+ goto report;
}
- return base;
+
+ ecache_size = prom_getintdefault(linux_cpus[0].prom_node,
+ "ecache-size", (512 * 1024));
+ if (ecache_size > (4 * 1024 * 1024))
+ ecache_size = (4 * 1024 * 1024);
+ orig_flush_base = flush_base =
+ __get_free_pages(GFP_KERNEL, order = get_order(ecache_size));
+
+ if (flush_base != 0UL) {
+ __save_and_cli(flags);
+
+ /* Scan twice the size once just to get the TLB entries
+ * loaded and make sure the second scan measures pure misses.
+ */
+ for (p = (unsigned long *)flush_base;
+ ((unsigned long)p) < (flush_base + (ecache_size<<1));
+ p += (64 / sizeof(unsigned long)))
+ *((volatile unsigned long *)p);
+
+ /* Now the real measurement. */
+ __asm__ __volatile__("
+ b,pt %%xcc, 1f
+ rd %%tick, %0
+
+ .align 64
+1: ldx [%2 + 0x000], %%g1
+ ldx [%2 + 0x040], %%g2
+ ldx [%2 + 0x080], %%g3
+ ldx [%2 + 0x0c0], %%g5
+ add %2, 0x100, %2
+ cmp %2, %4
+ bne,pt %%xcc, 1b
+ nop
+
+ rd %%tick, %1"
+ : "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base)
+ : "2" (flush_base), "r" (flush_base + ecache_size)
+ : "g1", "g2", "g3", "g5");
+
+ __restore_flags(flags);
+
+ raw = (tick2 - tick1);
+
+ /* Dampen it a little, considering two processes
+ * sharing the cache and fitting.
+ */
+ cacheflush_time = (raw - (raw >> 2));
+
+ free_pages(orig_flush_base, order);
+ } else {
+ cacheflush_time = ((ecache_size << 2) +
+ (ecache_size << 1));
+ }
+report:
+ /* Convert cpu ticks to jiffie ticks. */
+#if 1
+ printk("timer_ticks_per_usec_quotient %lx\n", timer_ticks_per_usec_quotient);
+#endif
+ cache_decay_ticks = ((long)cacheflush_time * timer_ticks_per_usec_quotient);
+#if 1
+ printk("cache_decay_ticks step 1: %lx\n", cache_decay_ticks);
+#endif
+ cache_decay_ticks >>= 32UL;
+#if 1
+ printk("cache_decay_ticks step 2: %lx\n", cache_decay_ticks);
+#endif
+ cache_decay_ticks = (cache_decay_ticks * HZ) / 1000;
+#if 1
+ printk("cache_decay_ticks step 3: %lx\n", cache_decay_ticks);
+#endif
+
+ printk("Using heuristic of %ld cycles, %ld ticks.\n",
+ cacheflush_time, cache_decay_ticks);
}
/* /proc/profile writes can call this, don't __init it please. */
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 7d61a0fba..a89fcd43b 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.83 2002-01-11 08:45:38 davem Exp $
+/* $Id: traps.c,v 1.84 2002-01-30 01:39:56 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -527,6 +527,21 @@ static void cheetah_flush_ecache_line(unsigned long physaddr)
"i" (ASI_PHYS_USE_EC));
}
+#ifdef CONFIG_SMP
+unsigned long cheetah_tune_scheduling(void)
+{
+ unsigned long tick1, tick2, raw;
+
+ __asm__ __volatile__("rd %%tick, %0" : "=r" (tick1));
+ cheetah_flush_ecache();
+ __asm__ __volatile__("rd %%tick, %0" : "=r" (tick2));
+
+ raw = (tick2 - tick1);
+
+ return (raw - (raw >> 2));
+}
+#endif
+
/* Unfortunately, the diagnostic access to the I-cache tags we need to
* use to clear the thing interferes with I-cache coherency transactions.
*
diff --git a/drivers/Makefile b/drivers/Makefile
index ca56bf34b..4d2f078d6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -10,7 +10,7 @@ mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi ide \
message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
fc4 net/hamradio i2c acpi bluetooth
-subdir-y := parport char block net sound misc media cdrom hotplug
+subdir-y := base parport char block net sound misc media cdrom hotplug
subdir-m := $(subdir-y)
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
new file mode 100644
index 000000000..d206ad374
--- /dev/null
+++ b/drivers/base/Makefile
@@ -0,0 +1,7 @@
+O_TARGET := base.o
+
+obj-y := core.o interface.o fs.o
+
+export-objs := core.o interface.o fs.o
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/base/core.c b/drivers/base/core.c
new file mode 100644
index 000000000..c60ba9e87
--- /dev/null
+++ b/drivers/base/core.c
@@ -0,0 +1,213 @@
+/*
+ * drivers/base/core.c - core driver model code (device registration, etc)
+ *
+ * Copyright (c) 2002 Patrick Mochel
+ * 2002 Open Source Development Lab
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DBG(x...) printk(x)
+#else
+# define DBG(x...)
+#endif
+
+static struct iobus device_root = {
+ bus_id: "root",
+ name: "Logical System Root",
+};
+
+int (*platform_notify)(struct device * dev) = NULL;
+int (*platform_notify_remove)(struct device * dev) = NULL;
+
+extern int device_make_dir(struct device * dev);
+extern void device_remove_dir(struct device * dev);
+
+extern int iobus_make_dir(struct iobus * iobus);
+extern void iobus_remove_dir(struct iobus * iobus);
+
+static spinlock_t device_lock;
+
+/**
+ * device_register - register a device
+ * @dev: pointer to the device structure
+ *
+ * First, make sure that the device has a parent, create
+ * a directory for it, then add it to the parent's list of
+ * children.
+ */
+int device_register(struct device *dev)
+{
+ int error;
+
+ if (!dev || !strlen(dev->bus_id))
+ return -EINVAL;
+ BUG_ON(!dev->parent);
+
+ spin_lock(&device_lock);
+ INIT_LIST_HEAD(&dev->node);
+ spin_lock_init(&dev->lock);
+ atomic_set(&dev->refcount,2);
+
+ get_iobus(dev->parent);
+ list_add_tail(&dev->node,&dev->parent->devices);
+ spin_unlock(&device_lock);
+
+ DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
+ dev->bus_id, dev->name, parent->bus_id);
+
+ if ((error = device_make_dir(dev)))
+ goto register_done;
+
+ /* notify platform of device entry */
+ if (platform_notify)
+ platform_notify(dev);
+
+ register_done:
+ put_device(dev);
+ if (error)
+ put_iobus(dev->parent);
+ return error;
+}
+
+/**
+ * put_device - clean up device
+ * @dev: device in question
+ *
+ * Decrement reference count for device.
+ * If it hits 0, we need to clean it up.
+ * However, we may be here in interrupt context, and it may
+ * take some time to do proper clean up (removing files, calling
+ * back down to device to clean up everything it has).
+ * So, we remove it from its parent's list and add it to the list of
+ * devices to be cleaned up.
+ */
+void put_device(struct device * dev)
+{
+ if (!atomic_dec_and_lock(&dev->refcount,&device_lock))
+ return;
+ list_del_init(&dev->node);
+ spin_unlock(&device_lock);
+
+ DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
+ dev->bus_id,dev->name);
+
+ /* remove the driverfs directory */
+ device_remove_dir(dev);
+
+ if (dev->subordinate)
+ iobus_remove_dir(dev->subordinate);
+
+ /* Notify the platform of the removal, in case they
+ * need to do anything...
+ */
+ if (platform_notify_remove)
+ platform_notify_remove(dev);
+
+ /* Tell the driver to clean up after itself.
+ * Note that we likely didn't allocate the device,
+ * so this is the driver's chance to free that up...
+ */
+ if (dev->driver && dev->driver->remove)
+ dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
+
+ put_iobus(dev->parent);
+}
+
+int iobus_register(struct iobus *bus)
+{
+ int error;
+
+ if (!bus || !strlen(bus->bus_id))
+ return -EINVAL;
+
+ spin_lock(&device_lock);
+ atomic_set(&bus->refcount,2);
+ spin_lock_init(&bus->lock);
+ INIT_LIST_HEAD(&bus->node);
+ INIT_LIST_HEAD(&bus->devices);
+ INIT_LIST_HEAD(&bus->children);
+
+ if (bus != &device_root) {
+ if (!bus->parent)
+ bus->parent = &device_root;
+ get_iobus(bus->parent);
+ list_add_tail(&bus->node,&bus->parent->children);
+ }
+ spin_unlock(&device_lock);
+
+ DBG("DEV: registering bus. ID = '%s' name = '%s' parent = %p\n",
+ bus->bus_id,bus->name,bus->parent);
+
+ error = iobus_make_dir(bus);
+
+ put_iobus(bus);
+ if (error && bus->parent)
+ put_iobus(bus->parent);
+ return error;
+}
+
+/**
+ * iobus_unregister - remove bus and children from device tree
+ * @bus: pointer to bus structure
+ *
+ * Remove device from parent's list of children and decrement
+ * reference count on controlling device. That should take care of
+ * the rest of the cleanup.
+ */
+void put_iobus(struct iobus * iobus)
+{
+ if (!atomic_dec_and_lock(&iobus->refcount,&device_lock))
+ return;
+ list_del_init(&iobus->node);
+ spin_unlock(&device_lock);
+
+ if (!list_empty(&iobus->devices) ||
+ !list_empty(&iobus->children))
+ BUG();
+
+ put_iobus(iobus->parent);
+ /* unregister itself */
+ put_device(iobus->self);
+}
+
+static int __init device_init_root(void)
+{
+ /* initialize parent bus lists */
+ return iobus_register(&device_root);
+}
+
+int __init device_driver_init(void)
+{
+ int error = 0;
+
+ DBG("DEV: Initialising Device Tree\n");
+
+ spin_lock_init(&device_lock);
+
+ error = init_driverfs_fs();
+
+ if (error) {
+ panic("DEV: could not initialise driverfs\n");
+ return error;
+ }
+
+ error = device_init_root();
+ if (error) {
+ printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
+ return error;
+ }
+
+ DBG("DEV: Done Initialising\n");
+ return error;
+}
+
+EXPORT_SYMBOL(device_register);
+EXPORT_SYMBOL(iobus_register);
+EXPORT_SYMBOL(device_driver_init);
diff --git a/drivers/base/fs.c b/drivers/base/fs.c
new file mode 100644
index 000000000..c6d5f1872
--- /dev/null
+++ b/drivers/base/fs.c
@@ -0,0 +1,131 @@
+/*
+ * drivers/base/fs.c - driver model interface to driverfs
+ *
+ * Copyright (c) 2002 Patrick Mochel
+ * 2002 Open Source Development Lab
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+
+extern struct driver_file_entry * device_default_files[];
+
+/**
+ * device_create_file - create a driverfs file for a device
+ * @dev: device requesting file
+ * @entry: entry describing file
+ *
+ * Allocate space for file entry, copy descriptor, and create.
+ */
+int device_create_file(struct device * dev, struct driver_file_entry * entry)
+{
+ struct driver_file_entry * new_entry;
+ int error = -ENOMEM;
+
+ if (!dev)
+ return -EINVAL;
+ get_device(dev);
+
+ new_entry = kmalloc(sizeof(*new_entry),GFP_KERNEL);
+ if (!new_entry)
+ goto done;
+
+ memcpy(new_entry,entry,sizeof(*entry));
+ error = driverfs_create_file(new_entry,&dev->dir);
+ if (error)
+ kfree(new_entry);
+ done:
+ put_device(dev);
+ return error;
+}
+
+/**
+ * device_remove_file - remove a device's file by name
+ * @dev: device requesting removal
+ * @name: name of the file
+ *
+ */
+void device_remove_file(struct device * dev, const char * name)
+{
+ if (dev) {
+ get_device(dev);
+ driverfs_remove_file(&dev->dir,name);
+ put_device(dev);
+ }
+}
+
+/**
+ * device_remove_dir - remove a device's directory
+ * @dev: device in question
+ */
+void device_remove_dir(struct device * dev)
+{
+ if (dev)
+ driverfs_remove_dir(&dev->dir);
+}
+
+/**
+ * device_make_dir - create a driverfs directory
+ * @name: name of directory
+ * @parent: dentry for the parent directory
+ *
+ * Do the initial creation of the device's driverfs directory
+ * and populate it with the one default file.
+ *
+ * This is just a helper for device_register(), as we
+ * don't export this function. (Yes, that means we don't allow
+ * devices to create subdirectories).
+ */
+int device_make_dir(struct device * dev)
+{
+ struct driver_dir_entry * parent = NULL;
+ struct driver_file_entry * entry;
+ int error;
+ int i;
+
+ INIT_LIST_HEAD(&dev->dir.files);
+ dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+ dev->dir.name = dev->bus_id;
+
+ if (dev->parent)
+ parent = &dev->parent->dir;
+
+ if ((error = driverfs_create_dir(&dev->dir,parent)))
+ return error;
+
+ for (i = 0; (entry = *(device_default_files + i)); i++) {
+ if ((error = device_create_file(dev,entry))) {
+ device_remove_dir(dev);
+ return error;
+ }
+ }
+ return 0;
+}
+
+void iobus_remove_dir(struct iobus * iobus)
+{
+ if (iobus)
+ driverfs_remove_dir(&iobus->dir);
+}
+
+int iobus_make_dir(struct iobus * iobus)
+{
+ struct driver_dir_entry * parent = NULL;
+ int error;
+
+ INIT_LIST_HEAD(&iobus->dir.files);
+ iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+ iobus->dir.name = iobus->bus_id;
+
+ if (iobus->parent)
+ parent = &iobus->parent->dir;
+
+ error = driverfs_create_dir(&iobus->dir,parent);
+ return error;
+}
+
+EXPORT_SYMBOL(device_create_file);
+EXPORT_SYMBOL(device_remove_file);
+
diff --git a/drivers/base/interface.c b/drivers/base/interface.c
new file mode 100644
index 000000000..28813db26
--- /dev/null
+++ b/drivers/base/interface.c
@@ -0,0 +1,174 @@
+/*
+ * drivers/base/interface.c - common driverfs interface that's exported to
+ * the world for all devices.
+ * Copyright (c) 2002 Patrick Mochel
+ * 2002 Open Source Development Lab
+ */
+
+#include <linux/device.h>
+
+/**
+ * device_read_status - report some device information
+ * @page: page-sized buffer to write into
+ * @count: number of bytes requested
+ * @off: offset into buffer
+ * @data: device-specific data
+ *
+ * Report some human-readable information about the device.
+ * This includes the name, the bus id, and the current power state.
+ */
+static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
+{
+ char *str = page;
+
+ if (off)
+ return 0;
+
+ str += sprintf(str,"Name: %s\n",dev->name);
+ str += sprintf(str,"Bus ID: %s\n",dev->bus_id);
+
+ return (str - page);
+}
+
+/**
+ * device_write_status - forward a command to a driver
+ * @buf: encoded command
+ * @count: number of bytes in buffer
+ * @off: offset into buffer to start with
+ * @data: device-specific data
+ *
+ * Send a comamnd to a device driver.
+ * The following actions are supported:
+ * probe - scan slot for device
+ * remove - detach driver from slot
+ * suspend <state> <stage> - perform <stage> for entering <state>
+ * resume <stage> - perform <stage> for waking device up.
+ * (See Documentation/driver-model.txt for the theory of an n-stage
+ * suspend sequence).
+ */
+static ssize_t device_write_status(struct device * dev, const char* buf, size_t count, loff_t off)
+{
+ char command[20];
+ int num;
+ int arg = 0;
+ int error = 0;
+
+ if (off)
+ return 0;
+
+ /* everything involves dealing with the driver. */
+ if (!dev->driver)
+ return 0;
+
+ num = sscanf(buf,"%10s %d",command,&arg);
+
+ if (!num)
+ return 0;
+
+ if (!strcmp(command,"probe")) {
+ if (dev->driver->probe)
+ error = dev->driver->probe(dev);
+
+ } else if (!strcmp(command,"remove")) {
+ if (dev->driver->remove)
+ error = dev->driver->remove(dev,REMOVE_NOTIFY);
+ } else
+ error = -EFAULT;
+ return error < 0 ? error : count;
+}
+
+static struct driver_file_entry device_status_entry = {
+ name: "status",
+ mode: S_IWUSR | S_IRUGO,
+ show: device_read_status,
+ store: device_write_status,
+};
+
+static ssize_t
+device_read_power(struct device * dev, char * page, size_t count, loff_t off)
+{
+ char * str = page;
+
+ if (off)
+ return 0;
+
+ str += sprintf(str,"State: %d\n",dev->current_state);
+
+ return (str - page);
+}
+
+static ssize_t
+device_write_power(struct device * dev, const char * buf, size_t count, loff_t off)
+{
+ char str_command[20];
+ char str_stage[20];
+ int num_args;
+ u32 state;
+ u32 int_stage;
+ int error = 0;
+
+ if (off)
+ return 0;
+
+ if (!dev->driver)
+ goto done;
+
+ num_args = sscanf(buf,"%s %s %u",str_command,str_stage,&state);
+
+ error = -EINVAL;
+
+ if (!num_args)
+ goto done;
+
+ if (!strnicmp(str_command,"suspend",7)) {
+ if (num_args != 3)
+ goto done;
+ if (!strnicmp(str_stage,"notify",6))
+ int_stage = SUSPEND_NOTIFY;
+ else if (!strnicmp(str_stage,"save",4))
+ int_stage = SUSPEND_SAVE_STATE;
+ else if (!strnicmp(str_stage,"disable",7))
+ int_stage = SUSPEND_DISABLE;
+ else if (!strnicmp(str_stage,"powerdown",8))
+ int_stage = SUSPEND_POWER_DOWN;
+ else
+ goto done;
+
+ if (dev->driver->suspend)
+ error = dev->driver->suspend(dev,state,int_stage);
+ else
+ error = 0;
+ } else if (!strnicmp(str_command,"resume",6)) {
+ if (num_args != 2)
+ goto done;
+
+ if (!strnicmp(str_stage,"poweron",7))
+ int_stage = RESUME_POWER_ON;
+ else if (!strnicmp(str_stage,"restore",7))
+ int_stage = RESUME_RESTORE_STATE;
+ else if (!strnicmp(str_stage,"enable",6))
+ int_stage = RESUME_ENABLE;
+ else
+ goto done;
+
+ if (dev->driver->resume)
+ error = dev->driver->resume(dev,int_stage);
+ else
+ error = 0;
+ }
+ done:
+ return error < 0 ? error : count;
+}
+
+static struct driver_file_entry device_power_entry = {
+ name: "power",
+ mode: S_IWUSR | S_IRUGO,
+ show: device_read_power,
+ store: device_write_power,
+};
+
+struct driver_file_entry * device_default_files[] = {
+ &device_status_entry,
+ &device_power_entry,
+ NULL,
+};
diff --git a/drivers/char/Config.help b/drivers/char/Config.help
index eac875817..9ff014a4f 100644
--- a/drivers/char/Config.help
+++ b/drivers/char/Config.help
@@ -818,6 +818,28 @@ CONFIG_INTEL_RNG
If unsure, say N.
+CONFIG_WATCHDOG
+ If you say Y here (and to one of the following options) and create a
+ character special file /dev/watchdog with major number 10 and minor
+ number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
+ subsequently opening the file and then failing to write to it for
+ longer than 1 minute will result in rebooting the machine. This
+ could be useful for a networked machine that needs to come back
+ online as fast as possible after a lock-up. There's both a watchdog
+ implementation entirely in software (which can sometimes fail to
+ reboot the machine) and a driver for hardware watchdog boards, which
+ are more robust and can also keep track of the temperature inside
+ your computer. For details, read <file:Documentation/watchdog.txt>
+ in the kernel source.
+
+ The watchdog is usually used together with the watchdog daemon
+ which is available from
+ <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
+ also monitor NFS connections and can reboot the machine when the process
+ table is full.
+
+ If unsure, say N.
+
CONFIG_WATCHDOG_NOWAYOUT
The default watchdog behaviour (which you get if you say N here) is
to stop the timer if the process managing it closes the file
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 6565004c8..aa6bfa254 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -2349,14 +2349,18 @@ static void con_start(struct tty_struct *tty)
static void con_flush_chars(struct tty_struct *tty)
{
- struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+ struct vt_struct *vt;
if (in_interrupt()) /* from flush_to_ldisc */
return;
pm_access(pm_con);
+
+ /* if we race with con_close(), vt may be null */
acquire_console_sem();
- set_cursor(vt->vc_num);
+ vt = (struct vt_struct *)tty->driver_data;
+ if (vt)
+ set_cursor(vt->vc_num);
release_console_sem();
}
diff --git a/drivers/char/ftape/Config.help b/drivers/char/ftape/Config.help
index ab20dca8d..ed0b6b4ba 100644
--- a/drivers/char/ftape/Config.help
+++ b/drivers/char/ftape/Config.help
@@ -79,6 +79,78 @@ CONFIG_FT_PROC_FS
interface. Accessing `/proc/ftape' while the module is unloaded will
result in a kernel Oops. This cannot be fixed from inside ftape.
+CONFIG_FT_NORMAL_DEBUG
+ This option controls the amount of debugging output the ftape driver
+ is ABLE to produce; it does not increase or diminish the debugging
+ level itself. If unsure, leave this at its default setting,
+ i.e. choose "Normal".
+
+ Ftape can print lots of debugging messages to the system console
+ resp. kernel log files. Reducing the amount of possible debugging
+ output reduces the size of the kernel module by some KB, so it might
+ be a good idea to use "None" for emergency boot floppies.
+
+ If you want to save memory then the following strategy is
+ recommended: leave this option at its default setting "Normal" until
+ you know that the driver works as expected, afterwards reconfigure
+ the kernel, this time specifying "Reduced" or "None" and recompile
+ and install the kernel as usual. Note that choosing "Excessive"
+ debugging output does not increase the amount of debugging output
+ printed to the console but only makes it possible to produce
+ "Excessive" debugging output.
+
+ Please read <file:Documentation/ftape.txt> for a short description
+ how to control the amount of debugging output.
+
+CONFIG_FT_FULL_DEBUG
+ Extremely verbose output for driver debugging purposes.
+
+CONFIG_FT_NO_TRACE
+ Reduced tape driver debugging output.
+
+CONFIG_FT_NO_TRACE_AT_ALL
+ Suppress all debugging output from the tape drive.
+
+CONFIG_FT_STD_FDC
+ Only change this setting if you have a special controller. If you
+ didn't plug any add-on card into your computer system but just
+ plugged the floppy tape cable into the already existing floppy drive
+ controller then you don't want to change the default setting,
+ i.e. choose "Standard".
+
+ Choose "MACH-2" if you have a Mountain Mach-2 controller.
+ Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20
+ controller.
+ Choose "Alt/82078" if you have another controller that is located at
+ an IO base address different from the standard floppy drive
+ controller's base address of `0x3f0', or uses an IRQ (interrupt)
+ channel different from `6', or a DMA channel different from
+ `2'. This is necessary for any controller card that is based on
+ Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high
+ speed" controllers.
+
+ If you choose something other than "Standard" then please make
+ sure that the settings for the IO base address and the IRQ and DMA
+ channel in the configuration menus below are correct. Use the manual
+ of your tape drive to determine the correct settings!
+
+ If you are already successfully using your tape drive with another
+ operating system then you definitely should use the same settings
+ for the IO base, the IRQ and DMA channel that have proven to work
+ with that other OS.
+
+ Note that this menu lets you specify only the default setting for
+ the hardware setup. The hardware configuration can be changed at
+ boot time (when ftape is compiled into the kernel, i.e. if you
+ have said Y to "Floppy tape drive") or module load time (i.e. if you
+ have said M to "Floppy tape drive").
+
+ Please read also the file <file:Documentation/ftape.txt> which
+ contains a short description of the parameters that can be set at
+ boot or load time. If you want to use your floppy tape drive on a
+ PCI-bus based system, please read the file
+ <file:drivers/char/ftape/README.PCI>.
+
CONFIG_FT_FDC_BASE
You don't need to specify a value if the following default
settings for the base IO address are correct:
diff --git a/drivers/hotplug/pcihp_skeleton.c b/drivers/hotplug/pcihp_skeleton.c
new file mode 100644
index 000000000..3a7bc21f5
--- /dev/null
+++ b/drivers/hotplug/pcihp_skeleton.c
@@ -0,0 +1,432 @@
+/*
+ * PCI Hot Plug Controller Skeleton Driver - 0.1
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * 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 program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is to be used as a skeleton driver to be show how to interface
+ * with the pci hotplug core easily.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+
+
+#define SLOT_MAGIC 0x67267322
+struct slot {
+ u32 magic;
+ u8 number;
+ struct hotplug_slot *hotplug_slot;
+ struct list_head slot_list;
+};
+
+static LIST_HEAD(slot_list);
+
+#if !defined(CONFIG_HOTPLUG_PCI_SKELETON_MODULE)
+ #define MY_NAME "pcihp_skeleton"
+#else
+ #define MY_NAME THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...) \
+ do { \
+ if (debug) \
+ printk (KERN_DEBUG "%s: " format "\n", \
+ MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+
+
+/* local variables */
+static int debug;
+static int num_slots;
+
+#define DRIVER_VERSION "0.1"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
+#define DRIVER_DESC "Hot Plug PCI Controller Skeleton Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot (struct hotplug_slot *slot);
+static int disable_slot (struct hotplug_slot *slot);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int hardware_test (struct hotplug_slot *slot, u32 value);
+static int get_power_status (struct hotplug_slot *slot, u8 *value);
+static int get_attention_status (struct hotplug_slot *slot, u8 *value);
+static int get_latch_status (struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops skel_hotplug_slot_ops = {
+ owner: THIS_MODULE,
+ enable_slot: enable_slot,
+ disable_slot: disable_slot,
+ set_attention_status: set_attention_status,
+ hardware_test: hardware_test,
+ get_power_status: get_power_status,
+ get_attention_status: get_attention_status,
+ get_latch_status: get_latch_status,
+ get_adapter_status: get_adapter_status,
+};
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+ if (!slot) {
+ dbg("%s - slot == NULL", function);
+ return -1;
+ }
+ if (slot->magic != SLOT_MAGIC) {
+ dbg("%s - bad magic number for slot", function);
+ return -1;
+ }
+ if (!slot->hotplug_slot) {
+ dbg("%s - slot->hotplug_slot == NULL!", function);
+ return -1;
+ }
+ return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{
+ struct slot *slot;
+
+ if (!hotplug_slot) {
+ dbg("%s - hotplug_slot == NULL\n", function);
+ return NULL;
+ }
+
+ slot = (struct slot *)hotplug_slot->private;
+ if (slot_paranoia_check (slot, function))
+ return NULL;
+ return slot;
+}
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ /*
+ * Fill in code here to enable the specified slot
+ */
+
+ return retval;
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ /*
+ * Fill in code here to disable the specified slot
+ */
+
+ return retval;
+}
+
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ switch (status) {
+ case 0:
+ /*
+ * Fill in code here to turn light off
+ */
+ break;
+
+ case 1:
+ default:
+ /*
+ * Fill in code here to turn light on
+ */
+ break;
+ }
+
+ return retval;
+}
+
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ err ("No hardware tests are defined for this driver");
+ retval = -ENODEV;
+
+ /* Or you can specify a test if you want to */
+
+ return retval;
+}
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+ /*
+ * Fill in logic to get the current power status of the specific
+ * slot and store it in the *value location.
+ */
+
+ return retval;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+ /*
+ * Fill in logic to get the current attention status of the specific
+ * slot and store it in the *value location.
+ */
+
+ return retval;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+ /*
+ * Fill in logic to get the current latch status of the specific
+ * slot and store it in the *value location.
+ */
+
+ return retval;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+ int retval = 0;
+
+ if (slot == NULL)
+ return -ENODEV;
+
+ dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+ /*
+ * Fill in logic to get the current adapter status of the specific
+ * slot and store it in the *value location.
+ */
+
+ return retval;
+}
+
+#define SLOT_NAME_SIZE 10
+static void make_slot_name (struct slot *slot)
+{
+ /*
+ * Stupid way to make a filename out of the slot name.
+ * replace this if your hardware provides a better way to name slots.
+ */
+ snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number);
+}
+
+static int init_slots (void)
+{
+ struct slot *slot;
+ struct hotplug_slot *hotplug_slot;
+ struct hotplug_slot_info *info;
+ char *name;
+ int retval = 0;
+ int i;
+
+ /*
+ * Create a structure for each slot, and register that slot
+ * with the pci_hotplug subsystem.
+ */
+ for (i = 0; i < num_slots; ++i) {
+ slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+ if (!slot)
+ return -ENOMEM;
+ memset(slot, 0, sizeof(struct slot));
+
+ hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+ if (!hotplug_slot) {
+ kfree (slot);
+ return -ENOMEM;
+ }
+ memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
+ slot->hotplug_slot = hotplug_slot;
+
+ info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+ if (!info) {
+ kfree (hotplug_slot);
+ kfree (slot);
+ return -ENOMEM;
+ }
+ memset(info, 0, sizeof (struct hotplug_slot_info));
+ hotplug_slot->info = info;
+
+ name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+ if (!name) {
+ kfree (info);
+ kfree (hotplug_slot);
+ kfree (slot);
+ return -ENOMEM;
+ }
+ hotplug_slot->name = name;
+
+ slot->magic = SLOT_MAGIC;
+ slot->number = i;
+
+ hotplug_slot->private = slot;
+ make_slot_name (slot);
+ hotplug_slot->ops = &skel_hotplug_slot_ops;
+
+ /*
+ * Initilize the slot info structure with some known
+ * good values.
+ */
+ info->power_status = get_skel_power_status(slot);
+ info->attention_status = get_skel_attention_status(slot);
+ info->latch_status = get_skel_latch_status(slot);
+ info->adapter_status = get_skel_adapter_status(slot);
+
+ dbg ("registering slot %d\n", i);
+ retval = pci_hp_register (slot->hotplug_slot);
+ if (retval) {
+ err ("pci_hp_register failed with error %d\n", retval);
+ kfree (info);
+ kfree (name);
+ kfree (hotplug_slot);
+ kfree (slot);
+ return retval;
+ }
+
+ /* add slot to our internal list */
+ list_add (&slot->slot_list, &slot_list);
+ }
+
+ return retval;
+}
+
+static void cleanup_slots (void)
+{
+ struct list_head *tmp;
+ struct slot *slot;
+
+ /*
+ * Unregister all of our slots with the pci_hotplug subsystem,
+ * and free up all memory that we had allocated.
+ */
+ list_for_each (tmp, &slot_list) {
+ slot = list_entry (tmp, struct slot, slot_list);
+ list_del (&slot->slot_list);
+ pci_hp_deregister (slot->hotplug_slot);
+ kfree (slot->hotplug_slot->info);
+ kfree (slot->hotplug_slot->name);
+ kfree (slot->hotplug_slot);
+ kfree (slot);
+ }
+
+ return;
+}
+
+static int __init pcihp_skel_init(void)
+{
+ int retval;
+
+ /*
+ * Do specific initialization stuff for your driver here
+ * Like initilizing your controller hardware (if any) and
+ * determining the number of slots you have in the system
+ * right now.
+ */
+ num_slots = 5;
+
+ retval = init_slots();
+ if (retval)
+ return retval;
+
+ info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ return 0;
+}
+
+static void __exit pcihp_skel_exit(void)
+{
+ /*
+ * Clean everything up.
+ */
+ cleanup_slots();
+}
+
+module_init(pcihp_skel_init);
+module_exit(pcihp_skel_exit);
+
diff --git a/drivers/ide/Config.help b/drivers/ide/Config.help
index d87acd1ba..04eff0669 100644
--- a/drivers/ide/Config.help
+++ b/drivers/ide/Config.help
@@ -752,6 +752,21 @@ CONFIG_BLK_DEV_MPC8xx_IDE
If unsure, say N.
+CONFIG_IDE_8xx_PCCARD
+ Select how the IDE devices are connected to the MPC8xx system:
+
+ 8xx_PCCARD uses the 8xx internal PCMCIA interface in combination
+ with a PC Card (e.g. ARGOSY portable Hard Disk Adapter),
+ ATA PC Card HDDs or ATA PC Flash Cards (example: TQM8xxL
+ systems)
+
+ 8xx_DIRECT is used for directly connected IDE devices using the 8xx
+ internal PCMCIA interface (example: IVMS8 systems)
+
+ EXT_DIRECT is used for IDE devices directly connected to the 8xx
+ bus using some glue logic, but _not_ the 8xx internal
+ PCMCIA interface (example: IDIF860 systems)
+
CONFIG_BLK_DEV_IDEDISK_FUJITSU
Enable vendor-specific code for Fujitsu IDE disks. Unless you are
the IDE maintainer, you probably do not want to mess with this.
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index ead267c6d..285432040 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -844,7 +844,7 @@ static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
}
-static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
+static int do_iso_mmap(struct vm_area_struct *vma, struct ti_ohci *ohci, struct dma_iso_ctx *d,
const char *adr, unsigned long size)
{
unsigned long start=(unsigned long) adr;
@@ -865,7 +865,7 @@ static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
pos=(unsigned long) d->buf;
while (size > 0) {
page = kvirt_to_pa(pos);
- if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+ if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
start+=PAGE_SIZE;
pos+=PAGE_SIZE;
diff --git a/drivers/isdn/Config.help b/drivers/isdn/Config.help
index cf2cd3ddb..a2bb99bc1 100644
--- a/drivers/isdn/Config.help
+++ b/drivers/isdn/Config.help
@@ -363,6 +363,16 @@ CONFIG_HISAX_ST5481
This enables the driver for ST5481 based USB ISDN adapters,
e.g. the BeWan Gazel 128 USB
+CONFIG_HISAX_FRITZ_PCIPNP
+ This enables the driver for the AVM Fritz!Card PCI, Fritz!Card PCI v2
+ and Fritz!Card PnP.
+ (the latter also needs you to select "ISA Plug and Play support"
+ from the menu "Plug and Play configuration")
+
+CONFIG_HISAX_FRITZ_CLASSIC
+ This enables the driver for the AVM Fritz!Card classic, formerly
+ known as AVM A1.
+
CONFIG_ISDN_DRV_PCBIT
This enables support for the PCBIT ISDN-card. This card is
manufactured in Portugal by Octal. For running this card,
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index d6fa2e0ef..ae1f624f7 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -2169,11 +2169,6 @@ static void isdn_register_devfs(int k)
{
char buf[11];
- sprintf (buf, "isdn%d", k);
- dev->devfs_handle_isdnX[k] =
- devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
- ISDN_MAJOR, k,0600 | S_IFCHR,
- &isdn_fops, NULL);
sprintf (buf, "isdnctrl%d", k);
dev->devfs_handle_isdnctrlX[k] =
devfs_register (devfs_handle, buf, DEVFS_FL_DEFAULT,
diff --git a/drivers/mtd/chips/Config.help b/drivers/mtd/chips/Config.help
index 779a179a7..854560690 100644
--- a/drivers/mtd/chips/Config.help
+++ b/drivers/mtd/chips/Config.help
@@ -46,6 +46,22 @@ CONFIG_MTD_CFI_I4
If your flash chips are interleaved in fours - i.e. you have four
flash chips addressed by each bus cycle, then say 'Y'.
+CONFIG_MTD_CFI_NOSWAP
+ This option defines the way in which the CPU attempts to arrange
+ data bits when writing the 'magic' commands to the chips. Saying
+ 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't
+ enabled, means that the CPU will not do any swapping; the chips
+ are expected to be wired to the CPU in 'host-endian' form.
+ Specific arrangements are possible with the BIG_ENDIAN_BYTE and
+ LITTLE_ENDIAN_BYTE, if the bytes are reversed.
+
+ If you have a LART, on which the data (and address) lines were
+ connected in a fashion which ensured that the nets were as short
+ as possible, resulting in a bit-shuffling which seems utterly
+ random to the untrained eye, you need the LART_ENDIAN_BYTE option.
+
+ Yes, there really exists something sicker than PDP-endian :)
+
CONFIG_MTD_CFI_INTELEXT
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index b11332345..173f937c3 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -797,7 +797,7 @@ static inline void wl_roam_gather(device * dev,
wavepoint_history *wavepoint=NULL; /* WavePoint table entry */
net_local *lp=(net_local *)dev->priv; /* Device info */
-#if 0
+#ifdef I_NEED_THIS_FEATURE
/* Some people don't need this, some other may need it */
nwid=nwid^ntohs(beacon->domain_id);
#endif
@@ -1417,7 +1417,7 @@ wv_init_info(device * dev)
printk("2430.5");
break;
default:
- printk("???");
+ printk("unknown");
}
}
@@ -1732,7 +1732,7 @@ wv_set_frequency(u_long base, /* i/o port of the card */
memcmp(dac, dac_verify, 2 * 2))
{
#ifdef DEBUG_IOCTL_ERROR
- printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+ printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
#endif
return -EOPNOTSUPP;
}
@@ -1981,7 +1981,7 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
case SIOCGIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ??? - especially old cards...) */
+ * (does it work for everybody ? - especially old cards...) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
@@ -3163,7 +3163,7 @@ wv_mmc_init(device * dev)
*/
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ??? - especially old cards...) */
+ * (does it work for everybody ? - especially old cards...) */
/* Note : WFREQSEL verify that it is able to read from EEprom
* a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
* is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -4718,7 +4718,7 @@ wavelan_event(event_t event, /* The event received */
* obliged to close nicely the wavelan here. David, could you
* close the device before suspending them ? And, by the way,
* could you, on resume, add a "route add -net ..." after the
- * ifconfig up ??? Thanks... */
+ * ifconfig up ? Thanks... */
/* Stop receiving new messages and wait end of transmission */
wv_ru_stop(dev);
@@ -4745,7 +4745,7 @@ wavelan_event(event_t event, /* The event received */
if(link->state & DEV_CONFIG)
{
CardServices(RequestConfiguration, link->handle, &link->conf);
- if(link->open) /* If RESET -> True, If RESUME -> False ??? */
+ if(link->open) /* If RESET -> True, If RESUME -> False ? */
{
wv_hw_reset(dev);
netif_device_attach(dev);
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index c1f49dfd3..a83c36f0d 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -13,7 +13,7 @@ O_TARGET := driver.o
export-objs := pci.o
-obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o
+obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o pci-driver.o
obj-$(CONFIG_PROC_FS) += proc.o
ifndef CONFIG_SPARC64
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
new file mode 100644
index 000000000..cef707b70
--- /dev/null
+++ b/drivers/pci/pci-driver.c
@@ -0,0 +1,36 @@
+/*
+ * drivers/pci/pci-driver.c - default PCI driver.
+ *
+ */
+
+#include <linux/pci.h>
+
+static int pci_device_suspend(struct device * dev, u32 stage, u32 state)
+{
+ struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
+ int error = 0;
+
+ if (pci_dev->driver) {
+ if (stage == SUSPEND_SAVE_STATE && pci_dev->driver->save_state)
+ error = pci_dev->driver->save_state(pci_dev,state);
+ else if (stage == SUSPEND_POWER_DOWN && pci_dev->driver->suspend)
+ error = pci_dev->driver->suspend(pci_dev,state);
+ }
+ return error;
+}
+
+static int pci_device_resume(struct device * dev, u32 stage)
+{
+ struct pci_dev * pci_dev = (struct pci_dev *)list_entry(dev,struct pci_dev,dev);
+
+ if (pci_dev->driver) {
+ if (stage == RESUME_POWER_ON && pci_dev->driver->resume)
+ pci_dev->driver->resume(pci_dev);
+ }
+ return 0;
+}
+
+struct device_driver pci_device_driver = {
+ suspend: pci_device_suspend,
+ resume: pci_device_resume,
+};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c9bc732b4..685cb1f7b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -38,6 +38,8 @@
LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices);
+extern struct device_driver pci_device_driver;
+
/**
* pci_find_slot - locate PCI device from a given PCI slot
* @bus: number of PCI bus on which desired PCI device resides
@@ -1369,6 +1371,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
dev0.bus = bus;
dev0.sysdata = bus->sysdata;
dev0.dev.parent = &bus->iobus;
+ dev0.dev.driver = &pci_device_driver;
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8) {
diff --git a/drivers/usb/hcd.c b/drivers/usb/hcd.c
index 882b4d559..e8e3e840a 100644
--- a/drivers/usb/hcd.c
+++ b/drivers/usb/hcd.c
@@ -1175,6 +1175,8 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
dbg ("%s: wait for giveback urb %p",
hcd->bus_name, urb);
}
+ } else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
+ return -EINPROGRESS;
}
goto bye;
done:
diff --git a/drivers/usb/hcd/Config.help b/drivers/usb/hcd/Config.help
index 3cdfd6eeb..c25152b48 100644
--- a/drivers/usb/hcd/Config.help
+++ b/drivers/usb/hcd/Config.help
@@ -21,3 +21,18 @@ CONFIG_USB_EHCI_HCD
The module will be called ehci-hcd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+OHCI (most USB hosts except VIA, Intel PIIX) support
+CONFIG_USB_OHCI_HCD
+ The Open Host Controller Interface (OHCI) is a standard for accessing
+ USB 1.1 host controller hardware. It does more in hardware than Intel's
+ UHCI specification. If your USB host controller follows the OHCI spec,
+ say Y. On most non-x86 systems, and on x86 hardware that's not using a
+ USB controller from Intel or VIA, this is appropriate. If your host
+ controller doesn't use PCI, this is probably appropriate. For a PCI
+ based system where you're not sure, the "lspci -v" entry will list the
+ right "prog-if" for your USB controller(s): EHCI, OHCI, or UHCI.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ohci-hcd.o. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
index f48416cbb..6ee303aa0 100644
--- a/drivers/usb/hcd/ehci-hcd.c
+++ b/drivers/usb/hcd/ehci-hcd.c
@@ -86,7 +86,7 @@
// #define EHCI_VERBOSE_DEBUG
// #define have_iso
-#ifdef DEBUG
+#ifdef CONFIG_DEBUG_SLAB
# define EHCI_SLAB_FLAGS (SLAB_POISON)
#else
# define EHCI_SLAB_FLAGS 0
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 2ced4412d..f34ffcdd6 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -813,7 +813,9 @@ static int uhci_submit_control(struct urb *urb)
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
/* 3 errors */
- status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ status = TD_CTRL_ACTIVE | (3 << 27);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
/*
* Build the TD for the control request
@@ -892,7 +894,7 @@ static int uhci_submit_control(struct urb *urb)
qh->urbp = urbp;
/* Low speed or small transfers gets a different queue and treatment */
- if (urb->pipe & TD_CTRL_LS) {
+ if (urb->dev->speed == USB_SPEED_LOW) {
uhci_insert_tds_in_qh(qh, urb, 0);
uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
} else {
@@ -1059,7 +1061,7 @@ static int usb_control_retrigger_status(struct urb *urb)
uhci_insert_tds_in_qh(urbp->qh, urb, 0);
/* Low speed or small transfers gets a different queue and treatment */
- if (urb->pipe & TD_CTRL_LS)
+ if (urb->dev->speed == USB_SPEED_LOW)
uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
else
uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
@@ -1083,7 +1085,9 @@ static int uhci_submit_interrupt(struct urb *urb)
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
- status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+ status = TD_CTRL_ACTIVE | TD_CTRL_IOC;
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
@@ -1218,7 +1222,7 @@ static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
return -EINVAL;
/* Can't have low speed bulk transfers */
- if (urb->pipe & TD_CTRL_LS)
+ if (urb->dev->speed == USB_SPEED_LOW)
return -EINVAL;
/* The "pipe" thing contains the destination in bits 8--18 */
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 6720ddfda..a33ffebb6 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -1234,7 +1234,7 @@ static ed_t * ep_add_ed (
| usb_pipeendpoint (pipe) << 7
| (usb_pipeisoc (pipe)? 0x8000: 0)
| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
- | usb_pipeslow (pipe) << 13
+ | (usb_dev->speed == USB_SPEED_LOW) << 13
| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 228051285..3c89ed982 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -722,8 +722,11 @@ _static int uhci_submit_control_urb (struct urb *urb)
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
/* 3 errors */
- status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
- (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+ status = TD_CTRL_ACTIVE
+ | (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
+ | (3 << 27);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
/* Build the TD for the control request, try forever, 8 bytes of data */
fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
@@ -797,7 +800,7 @@ _static int uhci_submit_control_urb (struct urb *urb)
qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
/* Start it up... put low speed first */
- if (urb->pipe & TD_CTRL_LS)
+ if (urb->dev->speed == USB_SPEED_LOW)
insert_qh (s, s->control_chain, qh, 0);
else
insert_qh (s, s->bulk_chain, qh, 0);
@@ -874,8 +877,11 @@ _static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
/* 3 errors */
- status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
- ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
+ status = TD_CTRL_ACTIVE
+ | ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD)
+ | (3 << 27);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
/* Build the TDs for the bulk request */
len = urb->transfer_buffer_length;
@@ -1469,8 +1475,11 @@ _static int uhci_submit_int_urb (struct urb *urb)
if (alloc_td (s, &td, UHCI_PTR_DEPTH))
return -ENOMEM;
- status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
- (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+ status = TD_CTRL_ACTIVE | TD_CTRL_IOC
+ | (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD)
+ | (3 << 27);
+ if (urb->dev->speed == USB_SPEED_LOW)
+ status |= TD_CTRL_LS;
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
@@ -2503,8 +2512,11 @@ _static int process_interrupt (uhci_t *s, struct urb *urb)
desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
}
- desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+ desc->hw.td.status= cpu_to_le32(TD_CTRL_ACTIVE | TD_CTRL_IOC |
(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
+ if (urb->dev->speed == USB_SPEED_LOW)
+ desc->hw.td.status |=
+ __constant_cpu_to_le32 (TD_CTRL_LS);
mb();
}
else {
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 0dff0a587..8464a085a 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -324,8 +324,9 @@ int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
unsigned int pipe = urb->pipe;
long bustime;
- bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe),
- usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+ bustime = usb_calc_bus_time (dev->speed == USB_SPEED_LOW,
+ usb_pipein(pipe), usb_pipeisoc(pipe),
+ usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
if (usb_pipeisoc(pipe))
bustime = NS_TO_US(bustime) / urb->number_of_packets;
else
@@ -2513,6 +2514,53 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
return err;
}
+/**
+ * usb_make_path - returns device path in the hub tree
+ * @dev: the device whose path is being constructed
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ *
+ * Returns length of the string (>= 0) or out of memory status (< 0).
+ */
+int usb_make_path(struct usb_device *dev, char *buf, size_t size)
+{
+ struct usb_device *pdev = dev->parent;
+ char *tmp;
+ char *port;
+ int i;
+
+ if (!(port = kmalloc(size, GFP_KERNEL)))
+ return -ENOMEM;
+ if (!(tmp = kmalloc(size, GFP_KERNEL))) {
+ kfree(port);
+ return -ENOMEM;
+ }
+
+ *port = 0;
+ while (pdev) {
+ for (i = 0; i < pdev->maxchild; i++)
+ if (pdev->children[i] == dev)
+ break;
+
+ if (pdev->children[i] != dev) {
+ kfree(port);
+ kfree(tmp);
+ return -ENODEV;
+ }
+
+ strcpy(tmp, port);
+ snprintf(port, size, strlen(port) ? "%d.%s" : "%d", i + 1, tmp);
+
+ dev = pdev;
+ pdev = dev->parent;
+ }
+
+ snprintf(buf, size, "usb%d:%s", dev->bus->busnum, port);
+ kfree(port);
+ kfree(tmp);
+ return strlen(buf);
+}
+
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
@@ -2762,5 +2810,6 @@ EXPORT_SYMBOL(usb_clear_halt);
EXPORT_SYMBOL(usb_set_configuration);
EXPORT_SYMBOL(usb_set_interface);
+EXPORT_SYMBOL(usb_make_path);
EXPORT_SYMBOL(usb_devfs_handle);
MODULE_LICENSE("GPL");
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 51828c605..cb6304a1d 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -146,9 +146,9 @@ adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_inf
if (ret)
goto out;
- if (inode->u.adfs_i.parent_id != dir.parent_id) {
+ if (ADFS_I(inode)->parent_id != dir.parent_id) {
adfs_error(sb, "parent directory changed under me! (%lx but got %lx)\n",
- inode->u.adfs_i.parent_id, dir.parent_id);
+ ADFS_I(inode)->parent_id, dir.parent_id);
ret = -EIO;
goto free_out;
}
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 5fefdd968..f757844eb 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -65,7 +65,7 @@ static int adfs_readpage(struct file *file, struct page *page)
static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
{
return cont_prepare_write(page, from, to, adfs_get_block,
- &page->mapping->host->u.adfs_i.mmu_private);
+ &ADFS_I(page->mapping->host)->mmu_private);
}
static int _adfs_bmap(struct address_space *mapping, long block)
@@ -87,8 +87,8 @@ adfs_filetype(struct inode *inode)
{
unsigned int type;
- if (inode->u.adfs_i.stamped)
- type = (inode->u.adfs_i.loadaddr >> 8) & 0xfff;
+ if (ADFS_I(inode)->stamped)
+ type = (ADFS_I(inode)->loadaddr >> 8) & 0xfff;
else
type = (unsigned int) -1;
@@ -101,7 +101,7 @@ adfs_filetype(struct inode *inode)
static umode_t
adfs_atts2mode(struct super_block *sb, struct inode *inode)
{
- unsigned int filetype, attr = inode->u.adfs_i.attr;
+ unsigned int filetype, attr = ADFS_I(inode)->attr;
umode_t mode, rmask;
if (attr & ADFS_NDA_DIRECTORY) {
@@ -151,7 +151,7 @@ adfs_mode2atts(struct super_block *sb, struct inode *inode)
/* FIXME: should we be able to alter a link? */
if (S_ISLNK(inode->i_mode))
- return inode->u.adfs_i.attr;
+ return ADFS_I(inode)->attr;
if (S_ISDIR(inode->i_mode))
attr = ADFS_NDA_DIRECTORY;
@@ -183,11 +183,11 @@ adfs_adfs2unix_time(struct inode *inode)
{
unsigned int high, low;
- if (inode->u.adfs_i.stamped == 0)
+ if (ADFS_I(inode)->stamped == 0)
return CURRENT_TIME;
- high = inode->u.adfs_i.loadaddr << 24;
- low = inode->u.adfs_i.execaddr;
+ high = ADFS_I(inode)->loadaddr << 24;
+ low = ADFS_I(inode)->execaddr;
high |= low >> 8;
low &= 255;
@@ -216,14 +216,14 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
{
unsigned int high, low;
- if (inode->u.adfs_i.stamped) {
+ if (ADFS_I(inode)->stamped) {
/* convert 32-bit seconds to 40-bit centi-seconds */
low = (secs & 255) * 100;
high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;
- inode->u.adfs_i.loadaddr = (high >> 24) |
- (inode->u.adfs_i.loadaddr & ~0xff);
- inode->u.adfs_i.execaddr = (low & 255) | (high << 8);
+ ADFS_I(inode)->loadaddr = (high >> 24) |
+ (ADFS_I(inode)->loadaddr & ~0xff);
+ ADFS_I(inode)->execaddr = (low & 255) | (high << 8);
}
}
@@ -263,11 +263,11 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
* for this file. This will need special handling
* for cross-directory renames.
*/
- inode->u.adfs_i.parent_id = obj->parent_id;
- inode->u.adfs_i.loadaddr = obj->loadaddr;
- inode->u.adfs_i.execaddr = obj->execaddr;
- inode->u.adfs_i.attr = obj->attr;
- inode->u.adfs_i.stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
+ ADFS_I(inode)->parent_id = obj->parent_id;
+ ADFS_I(inode)->loadaddr = obj->loadaddr;
+ ADFS_I(inode)->execaddr = obj->execaddr;
+ ADFS_I(inode)->attr = obj->attr;
+ ADFS_I(inode)->stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
inode->i_mode = adfs_atts2mode(sb, inode);
inode->i_mtime =
@@ -281,7 +281,7 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
inode->i_op = &adfs_file_inode_operations;
inode->i_fop = &adfs_file_operations;
inode->i_mapping->a_ops = &adfs_aops;
- inode->u.adfs_i.mmu_private = inode->i_size;
+ ADFS_I(inode)->mmu_private = inode->i_size;
}
insert_inode_hash(inode);
@@ -335,7 +335,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
if (ia_valid & ATTR_CTIME)
inode->i_ctime = attr->ia_ctime;
if (ia_valid & ATTR_MODE) {
- inode->u.adfs_i.attr = adfs_mode2atts(sb, inode);
+ ADFS_I(inode)->attr = adfs_mode2atts(sb, inode);
inode->i_mode = adfs_atts2mode(sb, inode);
}
@@ -362,10 +362,10 @@ void adfs_write_inode(struct inode *inode, int unused)
lock_kernel();
obj.file_id = inode->i_ino;
obj.name_len = 0;
- obj.parent_id = inode->u.adfs_i.parent_id;
- obj.loadaddr = inode->u.adfs_i.loadaddr;
- obj.execaddr = inode->u.adfs_i.execaddr;
- obj.attr = inode->u.adfs_i.attr;
+ obj.parent_id = ADFS_I(inode)->parent_id;
+ obj.loadaddr = ADFS_I(inode)->loadaddr;
+ obj.execaddr = ADFS_I(inode)->execaddr;
+ obj.attr = ADFS_I(inode)->attr;
obj.size = inode->i_size;
adfs_dir_update(sb, &obj);
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 1b695e5d1..adce0851c 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -232,7 +232,51 @@ static int adfs_statfs(struct super_block *sb, struct statfs *buf)
return 0;
}
+static kmem_cache_t *adfs_inode_cachep;
+
+static struct inode *adfs_alloc_inode(struct super_block *sb)
+{
+ struct adfs_inode_info *ei;
+ ei = (struct adfs_inode_info *)kmem_cache_alloc(adfs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void adfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
+ sizeof(struct adfs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (adfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(adfs_inode_cachep))
+ printk(KERN_INFO "adfs_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations adfs_sops = {
+ alloc_inode: adfs_alloc_inode,
+ destroy_inode: adfs_destroy_inode,
write_inode: adfs_write_inode,
put_super: adfs_put_super,
statfs: adfs_statfs,
@@ -435,12 +479,23 @@ static DECLARE_FSTYPE_DEV(adfs_fs_type, "adfs", adfs_read_super);
static int __init init_adfs_fs(void)
{
- return register_filesystem(&adfs_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&adfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_adfs_fs(void)
{
unregister_filesystem(&adfs_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/bfs/bfs_defs.h b/fs/bfs/bfs_defs.h
index c2756cdb9..4642f6707 100644
--- a/fs/bfs/bfs_defs.h
+++ b/fs/bfs/bfs_defs.h
@@ -9,9 +9,6 @@
#define su_sbh u.bfs_sb.si_sbh
#define su_bfs_sb u.bfs_sb.si_bfs_sb
-#define iu_dsk_ino u.bfs_i.i_dsk_ino
-#define iu_sblock u.bfs_i.i_sblock
-#define iu_eblock u.bfs_i.i_eblock
-
#define printf(format, args...) \
- printk(KERN_ERR "BFS-fs: " __FUNCTION__ "(): " format, ## args)
+ printk(KERN_ERR "BFS-fs: %s(): " format, __FUNCTION__, ## args)
+
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 266186cc3..cc46c9170 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -39,7 +39,7 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
while (f->f_pos < dir->i_size) {
offset = f->f_pos & (BFS_BSIZE-1);
- block = dir->iu_sblock + (f->f_pos >> BFS_BSIZE_BITS);
+ block = BFS_I(dir)->i_sblock + (f->f_pos >> BFS_BSIZE_BITS);
bh = sb_bread(dir->i_sb, block);
if (!bh) {
f->f_pos += BFS_BSIZE - offset;
@@ -97,8 +97,10 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
inode->i_fop = &bfs_file_operations;
inode->i_mapping->a_ops = &bfs_aops;
inode->i_mode = mode;
- inode->i_ino = inode->iu_dsk_ino = ino;
- inode->iu_sblock = inode->iu_eblock = 0;
+ inode->i_ino = ino;
+ BFS_I(inode)->i_dsk_ino = ino;
+ BFS_I(inode)->i_sblock = 0;
+ BFS_I(inode)->i_eblock = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
dump_imap("create",s);
@@ -262,8 +264,8 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
if (namelen > BFS_NAMELEN)
return -ENAMETOOLONG;
- sblock = dir->iu_sblock;
- eblock = dir->iu_eblock;
+ sblock = BFS_I(dir)->i_sblock;
+ eblock = BFS_I(dir)->i_eblock;
for (block=sblock; block<=eblock; block++) {
bh = sb_bread(dir->i_sb, block);
if(!bh)
@@ -313,7 +315,7 @@ static struct buffer_head * bfs_find_entry(struct inode * dir,
block = offset = 0;
while (block * BFS_BSIZE + offset < dir->i_size) {
if (!bh) {
- bh = sb_bread(dir->i_sb, dir->iu_sblock + block);
+ bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block);
if (!bh) {
block++;
continue;
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 4dbd8d694..428afd4a1 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -60,14 +60,15 @@ static int bfs_get_block(struct inode * inode, sector_t block,
long phys;
int err;
struct super_block *sb = inode->i_sb;
+ struct bfs_inode_info *bi = BFS_I(inode);
struct buffer_head *sbh = sb->su_sbh;
if (block < 0 || block > sb->su_blocks)
return -EIO;
- phys = inode->iu_sblock + block;
+ phys = bi->i_sblock + block;
if (!create) {
- if (phys <= inode->iu_eblock) {
+ if (phys <= bi->i_eblock) {
dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys);
map_bh(bh_result, sb, phys);
}
@@ -76,7 +77,7 @@ static int bfs_get_block(struct inode * inode, sector_t block,
/* if the file is not empty and the requested block is within the range
of blocks allocated for this file, we can grant it */
- if (inode->i_size && phys <= inode->iu_eblock) {
+ if (inode->i_size && phys <= bi->i_eblock) {
dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n",
create, block, phys);
map_bh(bh_result, sb, phys);
@@ -88,12 +89,12 @@ static int bfs_get_block(struct inode * inode, sector_t block,
/* if the last data block for this file is the last allocated block, we can
extend the file trivially, without moving it anywhere */
- if (inode->iu_eblock == sb->su_lf_eblk) {
+ if (bi->i_eblock == sb->su_lf_eblk) {
dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n",
create, block, phys);
map_bh(bh_result, sb, phys);
- sb->su_freeb -= phys - inode->iu_eblock;
- sb->su_lf_eblk = inode->iu_eblock = phys;
+ sb->su_freeb -= phys - bi->i_eblock;
+ sb->su_lf_eblk = bi->i_eblock = phys;
mark_inode_dirty(inode);
mark_buffer_dirty(sbh);
err = 0;
@@ -102,9 +103,9 @@ static int bfs_get_block(struct inode * inode, sector_t block,
/* Ok, we have to move this entire file to the next free block */
phys = sb->su_lf_eblk + 1;
- if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */
- err = bfs_move_blocks(inode->i_sb, inode->iu_sblock,
- inode->iu_eblock, phys);
+ if (bi->i_sblock) { /* if data starts on block 0 then there is no data */
+ err = bfs_move_blocks(inode->i_sb, bi->i_sblock,
+ bi->i_eblock, phys);
if (err) {
dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino);
goto out;
@@ -113,13 +114,13 @@ static int bfs_get_block(struct inode * inode, sector_t block,
err = 0;
dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", create, block, phys);
- inode->iu_sblock = phys;
+ bi->i_sblock = phys;
phys += block;
- sb->su_lf_eblk = inode->iu_eblock = phys;
+ sb->su_lf_eblk = bi->i_eblock = phys;
/* this assumes nothing can write the inode back while we are here
* and thus update inode->i_blocks! (XXX)*/
- sb->su_freeb -= inode->iu_eblock - inode->iu_sblock + 1 - inode->i_blocks;
+ sb->su_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
mark_inode_dirty(inode);
mark_buffer_dirty(sbh);
map_bh(bh_result, sb, phys);
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 402b936da..ee3a64beb 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -77,9 +77,9 @@ static void bfs_read_inode(struct inode * inode)
inode->i_atime = di->i_atime;
inode->i_mtime = di->i_mtime;
inode->i_ctime = di->i_ctime;
- inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
- inode->iu_sblock = di->i_sblock;
- inode->iu_eblock = di->i_eblock;
+ BFS_I(inode)->i_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
+ BFS_I(inode)->i_sblock = di->i_sblock;
+ BFS_I(inode)->i_eblock = di->i_eblock;
brelse(bh);
}
@@ -121,8 +121,8 @@ static void bfs_write_inode(struct inode * inode, int unused)
di->i_atime = inode->i_atime;
di->i_mtime = inode->i_mtime;
di->i_ctime = inode->i_ctime;
- di->i_sblock = inode->iu_sblock;
- di->i_eblock = inode->iu_eblock;
+ di->i_sblock = BFS_I(inode)->i_sblock;
+ di->i_eblock = BFS_I(inode)->i_eblock;
di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
mark_buffer_dirty(bh);
@@ -172,8 +172,8 @@ static void bfs_delete_inode(struct inode * inode)
/* if this was the last file, make the previous
block "last files last block" even if there is no real file there,
saves us 1 gap */
- if (s->su_lf_eblk == inode->iu_eblock) {
- s->su_lf_eblk = inode->iu_sblock - 1;
+ if (s->su_lf_eblk == BFS_I(inode)->i_eblock) {
+ s->su_lf_eblk = BFS_I(inode)->i_sblock - 1;
mark_buffer_dirty(s->su_sbh);
}
unlock_kernel();
@@ -206,7 +206,51 @@ static void bfs_write_super(struct super_block *s)
s->s_dirt = 0;
}
+static kmem_cache_t * bfs_inode_cachep;
+
+static struct inode *bfs_alloc_inode(struct super_block *sb)
+{
+ struct bfs_inode_info *bi;
+ bi = kmem_cache_alloc(bfs_inode_cachep, SLAB_KERNEL);
+ if (!bi)
+ return NULL;
+ return &bi->vfs_inode;
+}
+
+static void bfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(bfs_inode_cachep, BFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct bfs_inode_info *bi = foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&bi->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
+ sizeof(struct bfs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (bfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(bfs_inode_cachep))
+ printk(KERN_INFO "bfs_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations bfs_sops = {
+ alloc_inode: bfs_alloc_inode,
+ destroy_inode: bfs_destroy_inode,
read_inode: bfs_read_inode,
write_inode: bfs_write_inode,
delete_inode: bfs_delete_inode,
@@ -293,14 +337,14 @@ static struct super_block * bfs_read_super(struct super_block * s,
s->su_lf_ioff = 0;
for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) {
inode = iget(s,i);
- if (inode->iu_dsk_ino == 0)
+ if (BFS_I(inode)->i_dsk_ino == 0)
s->su_freei++;
else {
set_bit(i, s->su_imap);
s->su_freeb -= inode->i_blocks;
- if (inode->iu_eblock > s->su_lf_eblk) {
- s->su_lf_eblk = inode->iu_eblock;
- s->su_lf_sblk = inode->iu_sblock;
+ if (BFS_I(inode)->i_eblock > s->su_lf_eblk) {
+ s->su_lf_eblk = BFS_I(inode)->i_eblock;
+ s->su_lf_sblk = BFS_I(inode)->i_sblock;
s->su_lf_ioff = BFS_INO2OFF(i);
}
}
@@ -322,12 +366,23 @@ static DECLARE_FSTYPE_DEV(bfs_fs_type, "bfs", bfs_read_super);
static int __init init_bfs_fs(void)
{
- return register_filesystem(&bfs_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&bfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_bfs_fs(void)
{
unregister_filesystem(&bfs_fs_type);
+ destroy_inodecache();
}
module_init(init_bfs_fs)
diff --git a/fs/buffer.c b/fs/buffer.c
index baaf40a16..b3d7fdc72 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -724,6 +724,7 @@ static void free_more_memory(void)
wakeup_bdflush();
try_to_free_pages(zone, GFP_NOFS, 0);
run_task_queue(&tq_disk);
+ __set_current_state(TASK_RUNNING);
yield();
}
diff --git a/fs/fat/buffer.c b/fs/fat/buffer.c
index 117d85b33..fc65c2225 100644
--- a/fs/fat/buffer.c
+++ b/fs/fat/buffer.c
@@ -4,20 +4,11 @@
*
*/
-#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/blkdev.h>
#include <linux/msdos_fs.h>
#include <linux/fat_cvf.h>
-#if 0
-# define PRINTK(x) printk x
-#else
-# define PRINTK(x)
-#endif
-
struct buffer_head *fat_bread(struct super_block *sb, int block)
{
return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index a37623906..928999f24 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -8,11 +8,8 @@
* May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
*/
+#include <linux/fs.h>
#include <linux/msdos_fs.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
#include <linux/fat_cvf.h>
#if 0
diff --git a/fs/fat/cvf.c b/fs/fat/cvf.c
index 37dd78c57..5ce6244c1 100644
--- a/fs/fat/cvf.c
+++ b/fs/fat/cvf.c
@@ -8,15 +8,13 @@
*
*/
-#include<linux/sched.h>
-#include<linux/fs.h>
-#include<linux/msdos_fs.h>
-#include<linux/msdos_fs_sb.h>
-#include<linux/string.h>
-#include<linux/fat_cvf.h>
-#include<linux/config.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+#include <linux/msdos_fs_sb.h>
+#include <linux/fat_cvf.h>
+#include <linux/config.h>
#ifdef CONFIG_KMOD
-#include<linux/kmod.h>
+#include <linux/kmod.h>
#endif
#define MAX_CVF_FORMATS 3
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 29bb6bf79..a1ee11a74 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -13,17 +13,10 @@
* Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
*/
-#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
#include <linux/msdos_fs.h>
-#include <linux/nls.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/ioctl.h>
#include <linux/dirent.h>
-#include <linux/mm.h>
-#include <linux/ctype.h>
#include <asm/uaccess.h>
diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
index 343727a42..1ebb2731f 100644
--- a/fs/fat/fatfs_syms.c
+++ b/fs/fat/fatfs_syms.c
@@ -39,10 +39,13 @@ EXPORT_SYMBOL(fat_dir_empty);
EXPORT_SYMBOL(fat_truncate);
EXPORT_SYMBOL(fat_brelse);
+int __init fat_init_inodecache(void);
+void __exit fat_destroy_inodecache(void);
static int __init init_fat_fs(void)
{
fat_hash_init();
- return 0;
+ return fat_init_inodecache();
}
module_init(init_fat_fs)
+module_exit(fat_destroy_inodecache)
diff --git a/fs/fat/file.c b/fs/fat/file.c
index e18c537d0..27911fbd9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -8,18 +8,9 @@
#include <linux/sched.h>
#include <linux/locks.h>
-#include <linux/fs.h>
#include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/pagemap.h>
#include <linux/fat_cvf.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
#define PRINTK(x)
#define Printk(x) printk x
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index f769ee09e..8755a715a 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -11,23 +11,14 @@
*/
#include <linux/module.h>
-#include <linux/msdos_fs.h>
-#include <linux/nls.h>
-#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <linux/major.h>
-#include <linux/blkdev.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
#include <linux/locks.h>
-#include <linux/fat_cvf.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
+#include <linux/msdos_fs.h>
+#include <linux/fat_cvf.h>
-#include <asm/uaccess.h>
+//#include <asm/uaccess.h>
#include <asm/unaligned.h>
extern struct cvf_format default_cvf;
@@ -103,8 +94,7 @@ void fat_detach(struct inode *inode)
{
spin_lock(&fat_inode_lock);
MSDOS_I(inode)->i_location = 0;
- list_del(&MSDOS_I(inode)->i_fat_hash);
- INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
+ list_del_init(&MSDOS_I(inode)->i_fat_hash);
spin_unlock(&fat_inode_lock);
}
@@ -118,11 +108,11 @@ struct inode *fat_iget(struct super_block *sb, int i_pos)
spin_lock(&fat_inode_lock);
list_for_each(walk, p) {
i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
- if (i->i_fat_inode->i_sb != sb)
+ if (i->vfs_inode.i_sb != sb)
continue;
if (i->i_location != i_pos)
continue;
- inode = igrab(i->i_fat_inode);
+ inode = igrab(&i->vfs_inode);
if (inode)
break;
}
@@ -172,7 +162,7 @@ void fat_clear_inode(struct inode *inode)
lock_kernel();
spin_lock(&fat_inode_lock);
fat_cache_inval_inode(inode);
- list_del(&MSDOS_I(inode)->i_fat_hash);
+ list_del_init(&MSDOS_I(inode)->i_fat_hash);
spin_unlock(&fat_inode_lock);
unlock_kernel();
}
@@ -397,9 +387,7 @@ static void fat_read_root(struct inode *inode)
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
- MSDOS_I(inode)->i_fat_inode = inode;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode->i_version++;
@@ -533,7 +521,53 @@ int fat_dentry_to_fh(struct dentry *de, __u32 *fh, int *lenp, int needparent)
return 3;
}
+static kmem_cache_t *fat_inode_cachep;
+
+static struct inode *fat_alloc_inode(struct super_block *sb)
+{
+ struct msdos_inode_info *ei;
+ ei = (struct msdos_inode_info *)kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void fat_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct msdos_inode_info *ei = (struct msdos_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ INIT_LIST_HEAD(&ei->i_fat_hash);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+int __init fat_init_inodecache(void)
+{
+ fat_inode_cachep = kmem_cache_create("fat_inode_cache",
+ sizeof(struct msdos_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (fat_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+void __exit fat_destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(fat_inode_cachep))
+ printk(KERN_INFO "fat_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations fat_sops = {
+ alloc_inode: fat_alloc_inode,
+ destroy_inode: fat_destroy_inode,
write_inode: fat_write_inode,
delete_inode: fat_delete_inode,
put_super: fat_put_super,
@@ -872,9 +906,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
- MSDOS_I(inode)->i_fat_inode = inode;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode->i_version++;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 87b913b03..092f50adf 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -8,11 +8,6 @@
#include <linux/fs.h>
#include <linux/msdos_fs.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
#if 0
# define PRINTK(x) printk x
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 00e882a15..d4a78d006 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -233,7 +233,7 @@ static int hfs_readpage(struct file *file, struct page *page)
static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,hfs_get_block,
- &page->mapping->host->u.hfs_i.mmu_private);
+ &HFS_I(page->mapping->host)->mmu_private);
}
static int hfs_bmap(struct address_space *mapping, long block)
{
@@ -322,7 +322,13 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type,
inode->i_uid = hsb->s_uid;
inode->i_gid = hsb->s_gid;
- memset(HFS_I(inode), 0, sizeof(struct hfs_inode_info));
+ HFS_I(inode)->mmu_private = 0;
+ HFS_I(inode)->fork = NULL;
+ HFS_I(inode)->convert = 0;
+ HFS_I(inode)->file_type = 0;
+ HFS_I(inode)->dir_size = 0;
+ HFS_I(inode)->default_layout = NULL;
+ HFS_I(inode)->layout = NULL;
HFS_I(inode)->magic = HFS_INO_MAGIC;
HFS_I(inode)->entry = entry;
HFS_I(inode)->tz_secondswest = hfs_to_utc(0);
@@ -372,7 +378,7 @@ void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
inode->i_op = &hfs_file_inode_operations;
inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
- inode->u.hfs_i.mmu_private = inode->i_size;
+ HFS_I(inode)->mmu_private = inode->i_size;
} else { /* Directory */
struct hfs_dir *hdir = &entry->u.dir;
@@ -432,7 +438,7 @@ void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
inode->i_op = &hfs_file_inode_operations;
inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
- inode->u.hfs_i.mmu_private = inode->i_size;
+ HFS_I(inode)->mmu_private = inode->i_size;
} else { /* Directory */
struct hfs_dir *hdir = &entry->u.dir;
@@ -478,7 +484,7 @@ void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
inode->i_op = &hfs_file_inode_operations;
inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
- inode->u.hfs_i.mmu_private = inode->i_size;
+ HFS_I(inode)->mmu_private = inode->i_size;
} else { /* Directory */
struct hfs_dir *hdir = &entry->u.dir;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 90244a916..9ac627bb1 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -39,9 +39,53 @@ static void hfs_put_super(struct super_block *);
static int hfs_statfs(struct super_block *, struct statfs *);
static void hfs_write_super(struct super_block *);
+static kmem_cache_t * hfs_inode_cachep;
+
+static struct inode *hfs_alloc_inode(struct super_block *sb)
+{
+ struct hfs_inode_info *ei;
+ ei = (struct hfs_inode_info *)kmem_cache_alloc(hfs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void hfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(hfs_inode_cachep, HFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct hfs_inode_info *ei = (struct hfs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
+ sizeof(struct hfs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (hfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(hfs_inode_cachep))
+ printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n");
+}
+
/*================ Global variables ================*/
static struct super_operations hfs_super_operations = {
+ alloc_inode: hfs_alloc_inode,
+ destroy_inode: hfs_destroy_inode,
read_inode: hfs_read_inode,
put_inode: hfs_put_inode,
put_super: hfs_put_super,
@@ -472,13 +516,25 @@ bail3:
static int __init init_hfs_fs(void)
{
+ int err = init_inodecache();
+ if (err)
+ goto out1;
hfs_cat_init();
- return register_filesystem(&hfs_fs);
+ err = register_filesystem(&hfs_fs);
+ if (err)
+ goto out;
+ return 0;
+out:
+ hfs_cat_free();
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_hfs_fs(void) {
hfs_cat_free();
unregister_filesystem(&hfs_fs);
+ destroy_inodecache();
}
module_init(init_hfs_fs)
diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
index dd4662b7f..595599161 100644
--- a/fs/isofs/compress.c
+++ b/fs/isofs/compress.c
@@ -72,8 +72,8 @@ static int zisofs_readpage(struct file *file, struct page *page)
unsigned long bufmask = bufsize - 1;
int err = -EIO;
int i;
- unsigned int header_size = inode->u.isofs_i.i_format_parm[0];
- unsigned int zisofs_block_shift = inode->u.isofs_i.i_format_parm[1];
+ unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
+ unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
/* unsigned long zisofs_block_size = 1UL << zisofs_block_shift; */
unsigned int zisofs_block_page_shift = zisofs_block_shift-PAGE_CACHE_SHIFT;
unsigned long zisofs_block_pages = 1UL << zisofs_block_page_shift;
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index b1164e3b1..939748cf7 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -78,7 +78,51 @@ static void isofs_put_super(struct super_block *sb)
static void isofs_read_inode(struct inode *);
static int isofs_statfs (struct super_block *, struct statfs *);
+static kmem_cache_t *isofs_inode_cachep;
+
+static struct inode *isofs_alloc_inode(struct super_block *sb)
+{
+ struct iso_inode_info *ei;
+ ei = (struct iso_inode_info *)kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void isofs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct iso_inode_info *ei = (struct iso_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
+ sizeof(struct iso_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (isofs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(isofs_inode_cachep))
+ printk(KERN_INFO "iso_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations isofs_sops = {
+ alloc_inode: isofs_alloc_inode,
+ destroy_inode: isofs_destroy_inode,
read_inode: isofs_read_inode,
put_super: isofs_put_super,
statfs: isofs_statfs,
@@ -871,6 +915,7 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock,
unsigned int firstext;
unsigned long nextino;
int section, rv;
+ struct iso_inode_info *ei = ISOFS_I(inode);
lock_kernel();
@@ -883,9 +928,9 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock,
b_off = iblock;
offset = 0;
- firstext = inode->u.isofs_i.i_first_extent;
- sect_size = inode->u.isofs_i.i_section_size >> ISOFS_BUFFER_BITS(inode);
- nextino = inode->u.isofs_i.i_next_section_ino;
+ firstext = ei->i_first_extent;
+ sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
+ nextino = ei->i_next_section_ino;
section = 0;
while ( nblocks ) {
@@ -912,9 +957,9 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock,
ninode = iget(inode->i_sb, nextino);
if (!ninode)
goto abort;
- firstext = ninode->u.isofs_i.i_first_extent;
- sect_size = ninode->u.isofs_i.i_section_size;
- nextino = ninode->u.isofs_i.i_next_section_ino;
+ firstext = ISOFS_I(ninode)->i_first_extent;
+ sect_size = ISOFS_I(ninode)->i_section_size;
+ nextino = ISOFS_I(ninode)->i_next_section_ino;
iput(ninode);
if (++section > 100) {
@@ -1020,9 +1065,10 @@ static int isofs_read_level3_size(struct inode * inode)
int i = 0;
int more_entries = 0;
struct iso_directory_record * tmpde = NULL;
+ struct iso_inode_info *ei = ISOFS_I(inode);
inode->i_size = 0;
- inode->u.isofs_i.i_next_section_ino = 0;
+ ei->i_next_section_ino = 0;
block = f_pos >> ISOFS_BUFFER_BITS(inode);
offset = f_pos & (bufsize-1);
@@ -1074,7 +1120,7 @@ static int isofs_read_level3_size(struct inode * inode)
inode->i_size += isonum_733(de->size);
if (i == 1)
- inode->u.isofs_i.i_next_section_ino = f_pos;
+ ei->i_next_section_ino = f_pos;
more_entries = de->flags[-high_sierra] & 0x80;
@@ -1121,6 +1167,7 @@ static void isofs_read_inode(struct inode * inode)
unsigned int de_len;
unsigned long offset;
int volume_seq_no, i;
+ struct iso_inode_info *ei = ISOFS_I(inode);
bh = sb_bread(inode->i_sb, block);
if (!bh)
@@ -1148,7 +1195,7 @@ static void isofs_read_inode(struct inode * inode)
}
/* Assume it is a normal-format file unless told otherwise */
- inode->u.isofs_i.i_file_format = isofs_file_normal;
+ ei->i_file_format = isofs_file_normal;
if (de->flags[-high_sierra] & 2) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
@@ -1175,11 +1222,15 @@ static void isofs_read_inode(struct inode * inode)
inode->i_gid = inode->i_sb->u.isofs_sb.s_gid;
inode->i_blocks = inode->i_blksize = 0;
+ ei->i_format_parm[0] = 0;
+ ei->i_format_parm[1] = 0;
+ ei->i_format_parm[2] = 0;
- inode->u.isofs_i.i_section_size = isonum_733 (de->size);
+ ei->i_section_size = isonum_733 (de->size);
if(de->flags[-high_sierra] & 0x80) {
if(isofs_read_level3_size(inode)) goto fail;
} else {
+ ei->i_next_section_ino = 0;
inode->i_size = isonum_733 (de->size);
}
@@ -1233,7 +1284,7 @@ static void isofs_read_inode(struct inode * inode)
inode->i_mtime = inode->i_atime = inode->i_ctime =
iso_date(de->date, high_sierra);
- inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) +
+ ei->i_first_extent = (isonum_733 (de->extent) +
isonum_711 (de->ext_attr_length));
/* Set the number of blocks for stat() - should be done before RR */
@@ -1279,7 +1330,7 @@ static void isofs_read_inode(struct inode * inode)
{
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
- switch ( inode->u.isofs_i.i_file_format ) {
+ switch ( ei->i_file_format ) {
#ifdef CONFIG_ZISOFS
case isofs_file_compressed:
inode->i_data.a_ops = &zisofs_aops;
@@ -1348,14 +1399,26 @@ static DECLARE_FSTYPE_DEV(iso9660_fs_type, "iso9660", isofs_read_super);
static int __init init_iso9660_fs(void)
{
+ int err = init_inodecache();
+ if (err)
+ goto out;
#ifdef CONFIG_ZISOFS
- int err;
-
err = zisofs_init();
- if ( err )
- return err;
+ if (err)
+ goto out1;
+#endif
+ err = register_filesystem(&iso9660_fs_type);
+ if (err)
+ goto out2;
+ return 0;
+out2:
+#ifdef CONFIG_ZISOFS
+ zisofs_cleanup();
+out1:
#endif
- return register_filesystem(&iso9660_fs_type);
+ destroy_inodecache();
+out:
+ return err;
}
static void __exit exit_iso9660_fs(void)
@@ -1364,6 +1427,7 @@ static void __exit exit_iso9660_fs(void)
#ifdef CONFIG_ZISOFS
zisofs_cleanup();
#endif
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 2ee717c63..a9aa14892 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -65,7 +65,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
unsigned int block, f_pos, offset;
struct buffer_head * bh = NULL;
- if (!dir->u.isofs_i.i_first_extent)
+ if (!ISOFS_I(dir)->i_first_extent)
return 0;
f_pos = 0;
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index f5a2e2e67..08a6c8a3e 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -365,9 +365,9 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
printk(KERN_WARNING "Attempt to read inode for relocated directory\n");
goto out;
case SIG('C','L'):
- inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
+ ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location);
reloc = iget(inode->i_sb,
- (inode->u.isofs_i.i_first_extent <<
+ (ISOFS_I(inode)->i_first_extent <<
inode -> i_sb -> u.isofs_sb.s_log_zone_size));
if (!reloc)
goto out;
@@ -394,10 +394,10 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de,
printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift);
} else {
/* Note: we don't change i_blocks here */
- inode->u.isofs_i.i_file_format = isofs_file_compressed;
+ ISOFS_I(inode)->i_file_format = isofs_file_compressed;
/* Parameters to compression algorithm (header size, block size) */
- inode->u.isofs_i.i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]);
- inode->u.isofs_i.i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]);
+ ISOFS_I(inode)->i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]);
+ ISOFS_I(inode)->i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]);
inode->i_size = isonum_733(rr->u.ZF.real_size);
}
} else {
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index 69a58cb02..3f6d9c1ac 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -3,6 +3,7 @@
*/
#include <linux/time.h>
+#include <linux/fs.h>
#include <linux/iso_fs.h>
/*
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 67342dc52..db71f741b 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -357,7 +357,7 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
inode->i_nlink = raw_inode->nlink;
inode->i_uid = raw_inode->uid;
inode->i_gid = raw_inode->gid;
- inode->i_rdev = 0;
+ inode->i_rdev = NODEV;
inode->i_size = raw_inode->dsize;
inode->i_atime = raw_inode->atime;
inode->i_mtime = raw_inode->mtime;
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
index 47655fd33..004a3fd0c 100644
--- a/fs/jffs/jffs_fm.c
+++ b/fs/jffs/jffs_fm.c
@@ -46,7 +46,7 @@ jffs_build_begin(struct jffs_control *c, kdev_t dev)
}
DJM(no_jffs_fmcontrol++);
- mtd = get_mtd_device(NULL, MINOR(dev));
+ mtd = get_mtd_device(NULL, minor(dev));
if (!mtd) {
kfree(fmc);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c1e9143f6..4712eb7fd 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -42,6 +42,7 @@
#include <linux/jffs2.h>
#include <linux/jffs2_fs_i.h>
#include <linux/jffs2_fs_sb.h>
+#include <linux/sched.h>
#include "nodelist.h"
static int jffs2_readdir (struct file *, void *, filldir_t);
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 6ce14c9e5..18874665d 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -49,6 +49,7 @@
/* These are initialised to NULL in the kernel startup code.
If you're porting to other operating systems, beware */
+static kmem_cache_t *jffs2_inode_cachep;
static kmem_cache_t *full_dnode_slab;
static kmem_cache_t *raw_dirent_slab;
static kmem_cache_t *raw_inode_slab;
@@ -80,6 +81,31 @@ void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
}
}
+struct inode *jffs2_alloc_inode(struct super_block *sb)
+{
+ struct jffs2_inode_info *ei;
+ ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+void jffs2_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ init_MUTEX(&ei->sem);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
int __init jffs2_create_slab_caches(void)
{
full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL);
@@ -106,6 +132,13 @@ int __init jffs2_create_slab_caches(void)
if (!node_frag_slab)
goto err;
+ jffs2_inode_cachep = kmem_cache_create("jffs2_inode_cache",
+ sizeof(struct jffs2_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (!jffs2_inode_cachep)
+ goto err;
+
inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
if (inode_cache_slab)
@@ -131,6 +164,8 @@ void jffs2_destroy_slab_caches(void)
kmem_cache_destroy(node_frag_slab);
if(inode_cache_slab)
kmem_cache_destroy(inode_cache_slab);
+ if(jffs2_inode_cachep)
+ kmem_cache_destroy(jffs2_inode_cachep);
}
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index f72affe1a..1824be09f 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -259,9 +259,13 @@ void jffs2_read_inode (struct inode *inode)
f = JFFS2_INODE_INFO(inode);
c = JFFS2_SB_INFO(inode->i_sb);
- memset(f, 0, sizeof(*f));
+ f->highest_version = 0;
+ f->fraglist = NULL;
+ f->metadata = NULL;
+ f->dents = NULL;
+ f->flags = 0;
+ f->usercompr = 0;
D2(printk(KERN_DEBUG "getting inocache\n"));
- init_MUTEX(&f->sem);
f->inocache = jffs2_get_ino_cache(c, inode->i_ino);
D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache));
@@ -437,7 +441,7 @@ void jffs2_read_inode (struct inode *inode)
case S_IFSOCK:
case S_IFIFO:
inode->i_op = &jffs2_file_inode_operations;
- init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff)));
+ init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(rdev>>8, rdev&0xff)));
break;
default:
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 7e9e7bcbc..884bc8a30 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -59,9 +59,13 @@ void jffs2_write_super (struct super_block *);
static int jffs2_statfs (struct super_block *, struct statfs *);
int jffs2_remount_fs (struct super_block *, int *, char *);
extern void jffs2_clear_inode (struct inode *);
-
+extern void jffs2_destroy_inode (struct inode *);
+extern struct inode *jffs2_alloc_inode (struct super_block *);
+
static struct super_operations jffs2_super_operations =
{
+ alloc_inode: jffs2_alloc_inode,
+ destroy_inode: jffs2_destroy_inode,
read_inode: jffs2_read_inode,
// delete_inode: jffs2_delete_inode,
put_super: jffs2_put_super,
@@ -208,7 +212,7 @@ static struct super_block *jffs2_read_super(struct super_block *sb, void *data,
c = JFFS2_SB_INFO(sb);
memset(c, 0, sizeof(*c));
- c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+ c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
if (!c->mtd) {
D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
return NULL;
@@ -352,12 +356,6 @@ static int __init init_jffs2_fs(void)
sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u));
return -EIO;
}
-
- if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) {
- printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n",
- sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u));
- return -EIO;
- }
#endif
ret = jffs2_create_slab_caches();
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 32c11f954..301a02aab 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -73,8 +73,13 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
/* Alloc jffs2_inode_info when that's split in 2.5 */
f = JFFS2_INODE_INFO(inode);
- memset(f, 0, sizeof(*f));
- init_MUTEX_LOCKED(&f->sem);
+ down(&f->sem);
+ f->highest_version = 0;
+ f->fraglist = NULL;
+ f->metadata = NULL;
+ f->dents = NULL;
+ f->flags = 0;
+ f->usercompr = 0;
f->inocache = ic;
inode->i_nlink = f->inocache->nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index e431184b7..28d0caac9 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -12,10 +12,6 @@
#include <linux/sched.h>
#include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-
-#include <asm/uaccess.h>
#define MSDOS_DEBUG 0
#define PRINTK(x)
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 4783aaf1e..4fa8e2f01 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -68,7 +68,7 @@ static ssize_t ntfs_read(struct file *filp, char *buf, size_t count,loff_t *off)
int error;
ntfs_io io;
ntfs_attribute *attr;
- ntfs_inode *ino = NTFS_LINO2NINO(filp->f_dentry->d_inode);
+ ntfs_inode *ino = NTFS_I(filp->f_dentry->d_inode);
/* Inode is not properly initialized. */
if (!ino)
@@ -107,7 +107,7 @@ static ssize_t ntfs_write(struct file *filp, const char *buf, size_t count,
{
int err;
struct inode *vfs_ino = filp->f_dentry->d_inode;
- ntfs_inode *ntfs_ino = NTFS_LINO2NINO(vfs_ino);
+ ntfs_inode *ntfs_ino = NTFS_I(vfs_ino);
ntfs_attribute *data;
ntfs_io io;
struct ntfs_getuser_update_vm_s param;
@@ -296,7 +296,7 @@ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir)
ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Looking for next "
"file using ntfs_getdir_unsorted(), f_pos "
"0x%Lx.\n", (loff_t)(cb.ph << 16) | cb.pl);
- err = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, &cb.pl,
+ err = ntfs_getdir_unsorted(NTFS_I(dir), &cb.ph, &cb.pl,
ntfs_printcb, &cb);
} while (!err && !cb.ret_code && cb.ph < 0x7fff);
filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
@@ -541,7 +541,7 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
/* ntfs_getdir will place the directory entry into item, and the first
* long long is the MFT record number. */
walk.type = BY_NAME;
- walk.dir = NTFS_LINO2NINO(dir);
+ walk.dir = NTFS_I(dir);
walk.result = item;
if (ntfs_getdir_byname(&walk))
res = iget(dir->i_sb, NTFS_GETU32(item));
@@ -582,8 +582,10 @@ static int ntfs_create(struct inode* dir, struct dentry *d, int mode)
}
ntfs_debug(DEBUG_OTHER, "ntfs_create %s\n", d->d_name.name);
vol = NTFS_INO2VOL(dir);
- ino = NTFS_LINO2NINO(r);
- error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name,
+ ino = NTFS_I(r);
+ ino->u.index.recordsize = 0;
+ ino->u.index.clusters_per_record = 0;
+ error = ntfs_alloc_file(NTFS_I(dir), ino, (char*)d->d_name.name,
d->d_name.len);
if (error) {
ntfs_error("ntfs_alloc_file FAILED: error = %i", error);
@@ -595,7 +597,7 @@ static int ntfs_create(struct inode* dir, struct dentry *d, int mode)
error = ntfs_update_inode(ino);
if (error)
goto fail;
- error = ntfs_update_inode(NTFS_LINO2NINO(dir));
+ error = ntfs_update_inode(NTFS_I(dir));
if (error)
goto fail;
r->i_uid = vol->uid;
@@ -643,8 +645,8 @@ static int _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
if (!r)
goto out;
vol = NTFS_INO2VOL(dir);
- ino = NTFS_LINO2NINO(r);
- error = ntfs_mkdir(NTFS_LINO2NINO(dir), d->d_name.name, d->d_name.len,
+ ino = NTFS_I(r);
+ error = ntfs_mkdir(NTFS_I(dir), d->d_name.name, d->d_name.len,
ino);
if (error)
goto out;
@@ -710,9 +712,9 @@ static void ntfs_read_inode(struct inode* inode)
case FILE_Mft:
if (!vol->mft_ino || ((vol->ino_flags & 1) == 0))
goto sys_file_error;
- ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode));
+ ntfs_memcpy(NTFS_I(inode), vol->mft_ino, sizeof(ntfs_inode));
ino = vol->mft_ino;
- vol->mft_ino = &inode->u.ntfs_i;
+ vol->mft_ino = NTFS_I(inode);
vol->ino_flags &= ~1;
ntfs_free(ino);
ino = vol->mft_ino;
@@ -721,9 +723,9 @@ static void ntfs_read_inode(struct inode* inode)
case FILE_MftMirr:
if (!vol->mftmirr || ((vol->ino_flags & 2) == 0))
goto sys_file_error;
- ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode));
+ ntfs_memcpy(NTFS_I(inode), vol->mftmirr, sizeof(ntfs_inode));
ino = vol->mftmirr;
- vol->mftmirr = &inode->u.ntfs_i;
+ vol->mftmirr = NTFS_I(inode);
vol->ino_flags &= ~2;
ntfs_free(ino);
ino = vol->mftmirr;
@@ -732,9 +734,9 @@ static void ntfs_read_inode(struct inode* inode)
case FILE_BitMap:
if (!vol->bitmap || ((vol->ino_flags & 4) == 0))
goto sys_file_error;
- ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode));
+ ntfs_memcpy(NTFS_I(inode), vol->bitmap, sizeof(ntfs_inode));
ino = vol->bitmap;
- vol->bitmap = &inode->u.ntfs_i;
+ vol->bitmap = NTFS_I(inode);
vol->ino_flags &= ~4;
ntfs_free(ino);
ino = vol->bitmap;
@@ -746,10 +748,10 @@ static void ntfs_read_inode(struct inode* inode)
ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n",
inode->i_ino);
default:
- ino = &inode->u.ntfs_i;
- if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),
- inode->i_ino))
- {
+ ino = NTFS_I(inode);
+ ino->u.index.recordsize = 0;
+ ino->u.index.clusters_per_record = 0;
+ if (ntfs_init_inode(ino, NTFS_INO2VOL(inode), inode->i_ino)) {
ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode "
"0x%x\n", (unsigned int)inode->i_ino);
return;
@@ -803,7 +805,7 @@ static void ntfs_write_inode(struct inode *ino, int unused)
{
lock_kernel();
ntfs_debug(DEBUG_LINUX, "ntfs_write_inode 0x%x\n", ino->i_ino);
- ntfs_update_inode(NTFS_LINO2NINO(ino));
+ ntfs_update_inode(NTFS_I(ino));
unlock_kernel();
}
#endif
@@ -823,7 +825,7 @@ static void _ntfs_clear_inode(struct inode *inode)
case FILE_Mft:
if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) {
ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
- ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
+ ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
vol->mft_ino = ino;
vol->ino_flags |= 1;
goto unl_out;
@@ -832,7 +834,7 @@ static void _ntfs_clear_inode(struct inode *inode)
case FILE_MftMirr:
if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) {
ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
- ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
+ ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
vol->mftmirr = ino;
vol->ino_flags |= 2;
goto unl_out;
@@ -841,7 +843,7 @@ static void _ntfs_clear_inode(struct inode *inode)
case FILE_BitMap:
if (vol->bitmap && ((vol->ino_flags & 4) == 0)) {
ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
- ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
+ ntfs_memcpy(ino, NTFS_I(inode), sizeof(ntfs_inode));
vol->bitmap = ino;
vol->ino_flags |= 4;
goto unl_out;
@@ -850,7 +852,7 @@ static void _ntfs_clear_inode(struct inode *inode)
default:
/* Nothing. Just clear the inode and exit. */
}
- ntfs_clear_inode(&inode->u.ntfs_i);
+ ntfs_clear_inode(NTFS_I(inode));
unl_out:
unlock_kernel();
return;
@@ -914,7 +916,51 @@ static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options)
}
/* Define the super block operation that are implemented */
+
+static kmem_cache_t * ntfs_inode_cachep;
+
+static struct inode *__ntfs_alloc_inode(struct super_block *sb)
+{
+ struct ntfs_i *ei;
+ ei = (struct ntfs_i *)kmem_cache_alloc(ntfs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void ntfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(ntfs_inode_cachep, ntfs_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct ntfs_i *ei = (struct ntfs_i *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ ntfs_inode_cachep = kmem_cache_create("ntfs_inode_cache",
+ sizeof(struct ntfs_i),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (ntfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(ntfs_inode_cachep))
+ printk(KERN_INFO "ntfs_inode_cache: not all structures were freed\n");
+}
static struct super_operations ntfs_super_operations = {
+ alloc_inode: __ntfs_alloc_inode,
+ destroy_inode: ntfs_destroy_inode,
read_inode: ntfs_read_inode,
#ifdef CONFIG_NTFS_RW
write_inode: ntfs_write_inode,
@@ -1112,6 +1158,7 @@ static DECLARE_FSTYPE_DEV(ntfs_fs_type, "ntfs", ntfs_read_super);
static int __init init_ntfs_fs(void)
{
+ int err;
/* Comment this if you trust klogd. There are reasons not to trust it */
#if defined(DEBUG) && !defined(MODULE)
console_verbose();
@@ -1131,8 +1178,18 @@ static int __init init_ntfs_fs(void)
"]\n");
SYSCTL(1);
ntfs_debug(DEBUG_OTHER, "registering %s\n", ntfs_fs_type.name);
- /* Add this filesystem to the kernel table of filesystems. */
- return register_filesystem(&ntfs_fs_type);
+ err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&ntfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ SYSCTL(0);
+ return err;
}
static void __exit exit_ntfs_fs(void)
@@ -1140,6 +1197,7 @@ static void __exit exit_ntfs_fs(void)
SYSCTL(0);
ntfs_debug(DEBUG_OTHER, "unregistering %s\n", ntfs_fs_type.name);
unregister_filesystem(&ntfs_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
diff --git a/fs/ntfs/macros.h b/fs/ntfs/macros.h
index 708730950..cb65cd12d 100644
--- a/fs/ntfs/macros.h
+++ b/fs/ntfs/macros.h
@@ -14,17 +14,14 @@
#define NTFS_SB(vol) ((struct super_block*)(vol)->sb)
#define NTFS_SB2VOL(sb) (&(sb)->u.ntfs_sb)
#define NTFS_INO2VOL(ino) (&((ino)->i_sb->u.ntfs_sb))
-#define NTFS_LINO2NINO(ino) ((struct ntfs_inode_info*)(&((ino)->u.ntfs_i)))
+static inline struct ntfs_i *ntfs_i(struct inode *inode)
+{
+ return list_entry(inode, struct ntfs_i, vfs_inode);
+}
+#define NTFS_I(ino) (&ntfs_i(ino)->n)
static inline struct inode *VFS_I(struct ntfs_inode_info *ntfs_ino)
{
- struct inode *i = (struct inode*)((char*)ntfs_ino -
- ((char*)&(((struct inode*)NULL)->u.ntfs_i) -
- (char*)NULL));
-#ifdef DEBUG
- if ((char*)NTFS_LINO2NINO(i) != (char*)ntfs_ino)
- BUG();
-#endif
- return i;
+ return &list_entry(ntfs_ino, struct ntfs_i, n)->vfs_inode;
}
#define IS_MAGIC(a,b) (*(int*)(a) == *(int*)(b))
diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c
index 2f32a419b..c86d9b062 100644
--- a/fs/ntfs/unistr.c
+++ b/fs/ntfs/unistr.c
@@ -20,6 +20,7 @@
*/
#include <linux/string.h>
+#include <linux/fs.h>
#include <asm/byteorder.h>
#include "unistr.h"
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 65d6d90d8..854ed6d04 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -153,7 +153,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
static int init_inodecache(void)
{
- reiserfs_inode_cachep = kmem_cache_create("reiserfs_inode_cache",
+ reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
sizeof(struct reiserfs_inode_info),
0, SLAB_HWCACHE_ALIGN,
init_once, NULL);
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 5696c8e2f..53bedfd86 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -228,7 +228,7 @@ smb_dir_open(struct inode *dir, struct file *file)
lock_kernel();
server = server_from_dentry(dentry);
if (server->opt.protocol < SMB_PROTOCOL_LANMAN2) {
- unsigned long age = jiffies - dir->u.smbfs_i.oldmtime;
+ unsigned long age = jiffies - SMB_I(dir)->oldmtime;
if (age > 2*HZ)
smb_invalid_dir_cache(dir);
}
@@ -454,9 +454,10 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
goto out_no_inode;
if (have_id) {
- inode->u.smbfs_i.fileid = fileid;
- inode->u.smbfs_i.access = SMB_O_RDWR;
- inode->u.smbfs_i.open = server->generation;
+ struct smb_inode_info *ei = SMB_I(inode);
+ ei->fileid = fileid;
+ ei->access = SMB_O_RDWR;
+ ei->open = server->generation;
}
d_instantiate(dentry, inode);
out:
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 6f1214176..b3feaa569 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -43,7 +43,7 @@ smb_fsync(struct file *file, struct dentry * dentry, int datasync)
* (should be ok with writepage_sync)
*/
smb_lock_server(server);
- result = smb_proc_flush(server, dentry->d_inode->u.smbfs_i.fileid);
+ result = smb_proc_flush(server, SMB_I(dentry->d_inode)->fileid);
smb_unlock_server(server);
return result;
}
@@ -126,7 +126,7 @@ smb_writepage_sync(struct inode *inode, struct page *page,
offset += page->index << PAGE_CACHE_SHIFT;
VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
- inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
+ inode->i_ino, SMB_I(inode)->fileid, count, offset, wsize);
do {
if (count < wsize)
@@ -152,7 +152,7 @@ smb_writepage_sync(struct inode *inode, struct page *page,
* Update the inode now rather than waiting for a refresh.
*/
inode->i_mtime = inode->i_atime = CURRENT_TIME;
- inode->u.smbfs_i.flags |= SMB_F_LOCALWRITE;
+ SMB_I(inode)->flags |= SMB_F_LOCALWRITE;
if (offset > inode->i_size)
inode->i_size = offset;
} while (count);
@@ -337,7 +337,7 @@ smb_file_open(struct inode *inode, struct file * file)
result = smb_open(dentry, smb_mode);
if (result)
goto out;
- inode->u.smbfs_i.openers++;
+ SMB_I(inode)->openers++;
out:
unlock_kernel();
return 0;
@@ -347,7 +347,7 @@ static int
smb_file_release(struct inode *inode, struct file * file)
{
lock_kernel();
- if (!--inode->u.smbfs_i.openers) {
+ if (!--SMB_I(inode)->openers) {
/* We must flush any dirty pages now as we won't be able to
write anything after close. mmap can trigger this.
"openers" should perhaps include mmap'ers ... */
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 6b3648f89..61727bc89 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -49,8 +49,52 @@ static void smb_put_super(struct super_block *);
static int smb_statfs(struct super_block *, struct statfs *);
static int smb_show_options(struct seq_file *, struct vfsmount *);
+static kmem_cache_t *smb_inode_cachep;
+
+static struct inode *smb_alloc_inode(struct super_block *sb)
+{
+ struct smb_inode_info *ei;
+ ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void smb_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(smb_inode_cachep, SMB_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct smb_inode_info *ei = (struct smb_inode_info *) foo;
+ unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR;
+
+ if ((flags & flagmask) == SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ smb_inode_cachep = kmem_cache_create("smb_inode_cache",
+ sizeof(struct smb_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (smb_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(smb_inode_cachep))
+ printk(KERN_INFO "smb_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations smb_sops =
{
+ alloc_inode: smb_alloc_inode,
+ destroy_inode: smb_destroy_inode,
put_inode: force_delete,
delete_inode: smb_delete_inode,
put_super: smb_put_super,
@@ -71,7 +115,12 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
if (!result)
return result;
result->i_ino = fattr->f_ino;
- memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
+ SMB_I(result)->open = 0;
+ SMB_I(result)->fileid = 0;
+ SMB_I(result)->access = 0;
+ SMB_I(result)->flags = 0;
+ SMB_I(result)->closed = 0;
+ SMB_I(result)->openers = 0;
smb_set_inode_attr(result, fattr);
if (S_ISREG(result->i_mode)) {
result->i_op = &smb_file_inode_operations;
@@ -105,7 +154,7 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
fattr->f_blksize= inode->i_blksize;
fattr->f_blocks = inode->i_blocks;
- fattr->attr = inode->u.smbfs_i.attr;
+ fattr->attr = SMB_I(inode)->attr;
/*
* Keep the attributes in sync with the inode permissions.
*/
@@ -122,6 +171,8 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
void
smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
{
+ struct smb_inode_info *ei = SMB_I(inode);
+
/*
* A size change should have a different mtime, or same mtime
* but different size.
@@ -140,11 +191,12 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
inode->i_size = fattr->f_size;
inode->i_mtime = fattr->f_mtime;
inode->i_atime = fattr->f_atime;
- inode->u.smbfs_i.attr = fattr->attr;
+ ei->attr = fattr->attr;
+
/*
* Update the "last time refreshed" field for revalidation.
*/
- inode->u.smbfs_i.oldmtime = jiffies;
+ ei->oldmtime = jiffies;
if (inode->i_mtime != last_time || inode->i_size != last_sz) {
VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
@@ -237,9 +289,9 @@ smb_revalidate_inode(struct dentry *dentry)
/*
* Check whether we've recently refreshed the inode.
*/
- if (time_before(jiffies, inode->u.smbfs_i.oldmtime + SMB_MAX_AGE(s))) {
+ if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) {
VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
- inode->i_ino, jiffies, inode->u.smbfs_i.oldmtime);
+ inode->i_ino, jiffies, SMB_I(inode)->oldmtime);
goto out;
}
@@ -579,8 +631,8 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
error = smb_open(dentry, O_WRONLY);
if (error)
goto out;
- error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
- attr->ia_size);
+ error = smb_proc_trunc(server, SMB_I(inode)->fileid,
+ attr->ia_size);
if (error)
goto out;
error = vmtruncate(inode, attr->ia_size);
@@ -658,6 +710,7 @@ static DECLARE_FSTYPE( smb_fs_type, "smbfs", smb_read_super, 0);
static int __init init_smb_fs(void)
{
+ int err;
DEBUG1("registering ...\n");
#ifdef DEBUG_SMB_MALLOC
@@ -666,13 +719,24 @@ static int __init init_smb_fs(void)
smb_current_vmalloced = 0;
#endif
- return register_filesystem(&smb_fs_type);
+ err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&smb_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_smb_fs(void)
{
DEBUG1("unregistering ...\n");
unregister_filesystem(&smb_fs_type);
+ destroy_inodecache();
#ifdef DEBUG_SMB_MALLOC
printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced);
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 36b992c19..a24b1a905 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -940,6 +940,7 @@ static int
smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
{
struct inode *ino = dentry->d_inode;
+ struct smb_inode_info *ei = SMB_I(ino);
int mode, read_write = 0x42, read_only = 0x40;
int res;
char *p;
@@ -990,12 +991,12 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
}
/* We should now have data in vwv[0..6]. */
- ino->u.smbfs_i.fileid = WVAL(server->packet, smb_vwv0);
- ino->u.smbfs_i.attr = WVAL(server->packet, smb_vwv1);
+ ei->fileid = WVAL(server->packet, smb_vwv0);
+ ei->attr = WVAL(server->packet, smb_vwv1);
/* smb_vwv2 has mtime */
/* smb_vwv4 has size */
- ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
- ino->u.smbfs_i.open = server->generation;
+ ei->access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
+ ei->open = server->generation;
out:
return res;
@@ -1010,6 +1011,7 @@ smb_open(struct dentry *dentry, int wish)
{
struct inode *inode = dentry->d_inode;
int result;
+ __u16 access;
result = -ENOENT;
if (!inode) {
@@ -1040,11 +1042,10 @@ smb_open(struct dentry *dentry, int wish)
* Check whether the access is compatible with the desired mode.
*/
result = 0;
- if (inode->u.smbfs_i.access != wish &&
- inode->u.smbfs_i.access != SMB_O_RDWR)
- {
+ access = SMB_I(inode)->access;
+ if (access != wish && access != SMB_O_RDWR) {
PARANOIA("%s/%s access denied, access=%x, wish=%x\n",
- DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish);
+ DENTRY_PATH(dentry), access, wish);
result = -EACCES;
}
out:
@@ -1073,6 +1074,7 @@ smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime)
static int
smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
{
+ struct smb_inode_info *ei = SMB_I(ino);
int result = 0;
if (smb_is_open(ino))
{
@@ -1080,7 +1082,7 @@ smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
* We clear the open flag in advance, in case another
* process observes the value while we block below.
*/
- ino->u.smbfs_i.open = 0;
+ ei->open = 0;
/*
* Kludge alert: SMB timestamps are accurate only to
@@ -1096,22 +1098,21 @@ smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
* update the time stamps to sync mtime and atime.
*/
if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
- !(ino->u.smbfs_i.access == SMB_O_RDONLY))
+ !(ei->access == SMB_O_RDONLY))
{
struct smb_fattr fattr;
smb_get_inode_attr(ino, &fattr);
smb_proc_setattr_ext(server, ino, &fattr);
}
- result = smb_proc_close(server, ino->u.smbfs_i.fileid,
- ino->i_mtime);
+ result = smb_proc_close(server, ei->fileid, ino->i_mtime);
/*
* Force a revalidation after closing ... some servers
* don't post the size until the file has been closed.
*/
if (server->opt.protocol < SMB_PROTOCOL_NT1)
- ino->u.smbfs_i.oldmtime = 0;
- ino->u.smbfs_i.closed = jiffies;
+ ei->oldmtime = 0;
+ ei->closed = jiffies;
}
return result;
}
@@ -1160,7 +1161,7 @@ smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
smb_lock_server(server);
smb_setup_header(server, SMBread, 5, 0);
buf = server->packet;
- WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid);
+ WSET(buf, smb_vwv0, SMB_I(inode)->fileid);
WSET(buf, smb_vwv1, count);
DSET(buf, smb_vwv2, offset);
WSET(buf, smb_vwv4, 0);
@@ -1193,7 +1194,7 @@ smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
out:
VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
- inode->i_ino, inode->u.smbfs_i.fileid, count, result);
+ inode->i_ino, SMB_I(inode)->fileid, count, result);
smb_unlock_server(server);
return result;
}
@@ -1204,10 +1205,10 @@ smb_proc_write(struct inode *inode, off_t offset, int count, const char *data)
struct smb_sb_info *server = server_from_inode(inode);
int result;
__u8 *p;
- __u16 fileid = inode->u.smbfs_i.fileid;
+ __u16 fileid = SMB_I(inode)->fileid;
VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
- inode->i_ino, inode->u.smbfs_i.fileid, count, offset,
+ inode->i_ino, SMB_I(inode)->fileid, count, offset,
server->packet_size);
smb_lock_server(server);
@@ -2291,10 +2292,10 @@ smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
*/
if (server->mnt->flags & SMB_MOUNT_WIN95 &&
inode &&
- inode->u.smbfs_i.flags & SMB_F_LOCALWRITE &&
+ SMB_I(inode)->flags & SMB_F_LOCALWRITE &&
smb_is_open(inode))
{
- __u16 fileid = inode->u.smbfs_i.fileid;
+ __u16 fileid = SMB_I(inode)->fileid;
fattr->f_size = smb_proc_seek(server, fileid, 2, 0);
}
@@ -2395,7 +2396,7 @@ smb_proc_setattr_ext(struct smb_sb_info *server,
retry:
smb_setup_header(server, SMBsetattrE, 7, 0);
- WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
+ WSET(server->packet, smb_vwv0, SMB_I(inode)->fileid);
/* We don't change the creation time */
WSET(server->packet, smb_vwv1, 0);
WSET(server->packet, smb_vwv2, 0);
@@ -2511,8 +2512,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr)
/* setting the time on a Win95 server fails (tridge) */
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
!(server->mnt->flags & SMB_MOUNT_WIN95)) {
- if (smb_is_open(inode) &&
- inode->u.smbfs_i.access != SMB_O_RDONLY)
+ if (smb_is_open(inode) && SMB_I(inode)->access != SMB_O_RDONLY)
result = smb_proc_setattr_ext(server, inode, fattr);
else
result = smb_proc_setattr_trans2(server, dentry, fattr);
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 8d57fb9d6..f62f97114 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -652,13 +652,15 @@ magic_found:
uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
- if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192
- && uspi->s_bsize != 32768) {
- printk("ufs_read_super: fs_bsize %u != {4096, 8192, 32768}\n", uspi->s_bsize);
+ /* block size must be a power-of-two between 4k and 32k */
+ if ((uspi->s_bsize & (uspi->s_bsize-1)) ||
+ (uspi->s_bsize < 4096 || uspi->s_bsize > 32768)) {
+ printk("ufs_read_super: fs_bsize %u != {4096, 8192, 16384, 32768}\n", uspi->s_bsize);
goto failed;
}
- if (uspi->s_fsize != 512 && uspi->s_fsize != 1024
- && uspi->s_fsize != 2048 && uspi->s_fsize != 4096) {
+ /* fragment size must be a power-of-two between 512 and 4096 bytes */
+ if ((uspi->s_fsize & (uspi->s_fsize-1)) ||
+ (uspi->s_fsize < 512 || uspi->s_fsize > 4096)) {
printk("ufs_read_super: fs_fsize %u != {512, 1024, 2048. 4096}\n", uspi->s_fsize);
goto failed;
}
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 2e1d0f3aa..86516399d 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -19,13 +19,7 @@
#include <linux/sched.h>
#include <linux/msdos_fs.h>
-#include <linux/nls.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
#include <linux/ctype.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
#include <linux/slab.h>
#define DEBUG_LEVEL 0
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index 5f682e955..89921f9d7 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -79,6 +79,8 @@ extern void setup_APIC_clocks (void);
extern void setup_apic_nmi_watchdog (void);
extern inline void nmi_watchdog_tick (struct pt_regs * regs);
extern int APIC_init_uniprocessor (void);
+extern void disable_APIC_timer(void);
+extern void enable_APIC_timer(void);
extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback);
extern void apic_pm_unregister(struct pm_dev*);
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index b3d1e3a3f..4853f6791 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -292,6 +292,34 @@ static __inline__ int find_first_zero_bit(void * addr, unsigned size)
}
/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+static __inline__ int find_first_bit(void * addr, unsigned size)
+{
+ int d0, d1;
+ int res;
+
+ /* This looks at memory. Mark it volatile to tell gcc not to move it around */
+ __asm__ __volatile__(
+ "xorl %%eax,%%eax\n\t"
+ "repe; scasl\n\t"
+ "jz 1f\n\t"
+ "leal -4(%%edi),%%edi\n\t"
+ "bsfl (%%edi),%%eax\n"
+ "1:\tsubl %%ebx,%%edi\n\t"
+ "shll $3,%%edi\n\t"
+ "addl %%edi,%%eax"
+ :"=a" (res), "=&c" (d0), "=&D" (d1)
+ :"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
+ return res;
+}
+
+/**
* find_next_zero_bit - find the first zero bit in a memory region
* @addr: The address to base the search on
* @offset: The bitnumber to start searching at
@@ -304,7 +332,7 @@ static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
if (bit) {
/*
- * Look for zero in first byte
+ * Look for zero in the first 32 bits.
*/
__asm__("bsfl %1,%0\n\t"
"jne 1f\n\t"
@@ -325,6 +353,39 @@ static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
}
/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ int find_next_bit (void * addr, int size, int offset)
+{
+ unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+ int set = 0, bit = offset & 31, res;
+
+ if (bit) {
+ /*
+ * Look for nonzero in the first 32 bits:
+ */
+ __asm__("bsfl %1,%0\n\t"
+ "jne 1f\n\t"
+ "movl $32, %0\n"
+ "1:"
+ : "=r" (set)
+ : "r" (*p >> bit));
+ if (set < (32 - bit))
+ return set + offset;
+ set = 32 - bit;
+ p++;
+ }
+ /*
+ * No set bit yet, search remaining full words for a bit
+ */
+ res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr));
+ return (offset + set + res);
+}
+
+/**
* ffz - find first zero in word.
* @word: The word to search
*
@@ -338,6 +399,20 @@ static __inline__ unsigned long ffz(unsigned long word)
return word;
}
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+ __asm__("bsfl %1,%0"
+ :"=r" (word)
+ :"rm" (word));
+ return word;
+}
+
#ifdef __KERNEL__
/**
diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
index 6525a4b66..c8bc24cd9 100644
--- a/include/asm-i386/mmu_context.h
+++ b/include/asm-i386/mmu_context.h
@@ -16,17 +16,19 @@
# error update this function.
#endif
-static inline int sched_find_first_zero_bit(unsigned long *b)
+static inline int sched_find_first_bit(unsigned long *b)
{
- unsigned int rt;
-
- rt = b[0] & b[1] & b[2] & b[3];
- if (unlikely(rt != 0xffffffff))
- return find_first_zero_bit(b, MAX_RT_PRIO);
-
- if (b[4] != ~0)
- return ffz(b[4]) + MAX_RT_PRIO;
- return ffz(b[5]) + 32 + MAX_RT_PRIO;
+ if (unlikely(b[0]))
+ return __ffs(b[0]);
+ if (unlikely(b[1]))
+ return __ffs(b[1]) + 32;
+ if (unlikely(b[2]))
+ return __ffs(b[2]) + 64;
+ if (unlikely(b[3]))
+ return __ffs(b[3]) + 96;
+ if (b[4])
+ return __ffs(b[4]) + 128;
+ return __ffs(b[5]) + 32 + 128;
}
/*
* possibly do the LDT unload here?
@@ -49,13 +51,13 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk,
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
{
- if (prev != next) {
+ if (likely(prev != next)) {
/* stop flush ipis for the previous mm */
clear_bit(cpu, &prev->cpu_vm_mask);
/*
* Re-load LDT if necessary
*/
- if (prev->context.segments != next->context.segments)
+ if (unlikely(prev->context.segments != next->context.segments))
load_LDT(next);
#ifdef CONFIG_SMP
cpu_tlbstate[cpu].state = TLBSTATE_OK;
diff --git a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
index e47113635..393c1b2ea 100644
--- a/include/asm-sparc64/bitops.h
+++ b/include/asm-sparc64/bitops.h
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.38 2001-11-19 18:36:34 davem Exp $
+/* $Id: bitops.h,v 1.39 2002-01-30 01:40:00 davem Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -64,54 +64,38 @@ do { unsigned long __nr = (X); \
#define smp_mb__before_clear_bit() do { } while(0)
#define smp_mb__after_clear_bit() do { } while(0)
-extern __inline__ int test_bit(int nr, __const__ void *addr)
+static __inline__ int test_bit(int nr, __const__ void *addr)
{
return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63))) != 0UL;
}
/* The easy/cheese version for now. */
-extern __inline__ unsigned long ffz(unsigned long word)
+static __inline__ unsigned long ffz(unsigned long word)
{
unsigned long result;
-#ifdef ULTRA_HAS_POPULATION_COUNT /* Thanks for nothing Sun... */
- __asm__ __volatile__(
-" brz,pn %0, 1f\n"
-" neg %0, %%g1\n"
-" xnor %0, %%g1, %%g2\n"
-" popc %%g2, %0\n"
-"1: " : "=&r" (result)
- : "0" (word)
- : "g1", "g2");
-#else
-#if 1 /* def EASY_CHEESE_VERSION */
result = 0;
while(word & 1) {
result++;
word >>= 1;
}
-#else
- unsigned long tmp;
+ return result;
+}
- result = 0;
- tmp = ~word & -~word;
- if (!(unsigned)tmp) {
- tmp >>= 32;
- result = 32;
- }
- if (!(unsigned short)tmp) {
- tmp >>= 16;
- result += 16;
- }
- if (!(unsigned char)tmp) {
- tmp >>= 8;
- result += 8;
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+ unsigned long result = 0;
+
+ while (!(word & 1UL)) {
+ result++;
+ word >>= 1;
}
- if (tmp & 0xf0) result += 4;
- if (tmp & 0xcc) result += 2;
- if (tmp & 0xaa) result ++;
-#endif
-#endif
return result;
}
@@ -122,8 +106,12 @@ extern __inline__ unsigned long ffz(unsigned long word)
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
-
-#define ffs(x) generic_ffs(x)
+static __inline__ int ffs(int x)
+{
+ if (!x)
+ return 0;
+ return __ffs((unsigned long)x);
+}
/*
* hweightN: returns the hamming weight (i.e. the number
@@ -132,7 +120,7 @@ extern __inline__ unsigned long ffz(unsigned long word)
#ifdef ULTRA_HAS_POPULATION_COUNT
-extern __inline__ unsigned int hweight32(unsigned int w)
+static __inline__ unsigned int hweight32(unsigned int w)
{
unsigned int res;
@@ -140,7 +128,7 @@ extern __inline__ unsigned int hweight32(unsigned int w)
return res;
}
-extern __inline__ unsigned int hweight16(unsigned int w)
+static __inline__ unsigned int hweight16(unsigned int w)
{
unsigned int res;
@@ -148,7 +136,7 @@ extern __inline__ unsigned int hweight16(unsigned int w)
return res;
}
-extern __inline__ unsigned int hweight8(unsigned int w)
+static __inline__ unsigned int hweight8(unsigned int w)
{
unsigned int res;
@@ -165,12 +153,67 @@ extern __inline__ unsigned int hweight8(unsigned int w)
#endif
#endif /* __KERNEL__ */
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ unsigned long find_next_bit(void *addr, unsigned long size, unsigned long offset)
+{
+ unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+ unsigned long result = offset & ~63UL;
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 63UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp &= (~0UL << offset);
+ if (size < 64)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= 64;
+ result += 64;
+ }
+ while (size & ~63UL) {
+ if ((tmp = *(p++)))
+ goto found_middle;
+ result += 64;
+ size -= 64;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp &= (~0UL >> (64 - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+#define find_first_bit(addr, size) \
+ find_next_bit((addr), (size), 0)
+
/* find_next_zero_bit() finds the first zero bit in a bit string of length
* 'size' bits, starting the search at bit 'offset'. This is largely based
* on Linus's ALPHA routines, which are pretty portable BTW.
*/
-extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+static __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
unsigned long result = offset & ~63UL;
@@ -219,7 +262,7 @@ extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
#define set_le_bit(nr,addr) ((void)___test_and_set_le_bit(nr,addr))
#define clear_le_bit(nr,addr) ((void)___test_and_clear_le_bit(nr,addr))
-extern __inline__ int test_le_bit(int nr, __const__ void * addr)
+static __inline__ int test_le_bit(int nr, __const__ void * addr)
{
int mask;
__const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
@@ -232,7 +275,7 @@ extern __inline__ int test_le_bit(int nr, __const__ void * addr)
#define find_first_zero_le_bit(addr, size) \
find_next_zero_le_bit((addr), (size), 0)
-extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
+static __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
unsigned long result = offset & ~63UL;
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index b65ab3291..e8103b759 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.52 2002-01-11 08:45:38 davem Exp $ */
+/* $Id: mmu_context.h,v 1.53 2002-01-30 01:40:00 davem Exp $ */
#ifndef __SPARC64_MMU_CONTEXT_H
#define __SPARC64_MMU_CONTEXT_H
@@ -30,22 +30,20 @@
/*
* Every architecture must define this function. It's the fastest
* way of searching a 168-bit bitmap where the first 128 bits are
- * unlikely to be clear. It's guaranteed that at least one of the 168
+ * unlikely to be set. It's guaranteed that at least one of the 168
* bits is cleared.
*/
#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
# error update this function.
#endif
-static inline int sched_find_first_zero_bit(unsigned long *b)
+static inline int sched_find_first_bit(unsigned long *b)
{
- unsigned long rt;
-
- rt = b[0] & b[1];
- if (unlikely(rt != 0xffffffffffffffff))
- return find_first_zero_bit(b, MAX_RT_PRIO);
-
- return ffz(b[2]) + MAX_RT_PRIO;
+ if (unlikely(b[0]))
+ return __ffs(b[0]);
+ if (unlikely(b[1]))
+ return __ffs(b[1]) + 64;
+ return __ffs(b[2]) + 128;
}
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
diff --git a/include/linux/adfs_fs.h b/include/linux/adfs_fs.h
index 43add21b5..5c29f4982 100644
--- a/include/linux/adfs_fs.h
+++ b/include/linux/adfs_fs.h
@@ -41,6 +41,7 @@ struct adfs_discrecord {
#define ADFS_SUPER_MAGIC 0xadf5
#ifdef __KERNEL__
+#include <linux/adfs_fs_i.h>
/*
* Calculate the boot block checksum on an ADFS drive. Note that this will
* appear to be correct if the sector contains all zeros, so also check that
@@ -59,6 +60,11 @@ static inline int adfs_checkbblk(unsigned char *ptr)
return (result & 0xff) != ptr[511];
}
+static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct adfs_inode_info, vfs_inode);
+}
+
#endif
#endif
diff --git a/include/linux/adfs_fs_i.h b/include/linux/adfs_fs_i.h
index 7da1ceda0..442282509 100644
--- a/include/linux/adfs_fs_i.h
+++ b/include/linux/adfs_fs_i.h
@@ -18,6 +18,7 @@ struct adfs_inode_info {
unsigned int filetype; /* RISC OS file type */
unsigned int attr; /* RISC OS permissions */
int stamped:1; /* RISC OS file has date/time */
+ struct inode vfs_inode;
};
#endif
diff --git a/include/linux/bfs_fs.h b/include/linux/bfs_fs.h
index a4ffcbb75..1360909fc 100644
--- a/include/linux/bfs_fs.h
+++ b/include/linux/bfs_fs.h
@@ -6,6 +6,8 @@
#ifndef _LINUX_BFS_FS_H
#define _LINUX_BFS_FS_H
+#include <linux/bfs_fs_i.h>
+
#define BFS_BSIZE_BITS 9
#define BFS_BSIZE (1<<BFS_BSIZE_BITS)
@@ -87,5 +89,10 @@ extern struct address_space_operations bfs_aops;
extern struct inode_operations bfs_dir_inops;
extern struct file_operations bfs_dir_operations;
+static inline struct bfs_inode_info *BFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct bfs_inode_info, vfs_inode);
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_BFS_FS_H */
diff --git a/include/linux/bfs_fs_i.h b/include/linux/bfs_fs_i.h
index e939b229e..ca1432a1e 100644
--- a/include/linux/bfs_fs_i.h
+++ b/include/linux/bfs_fs_i.h
@@ -13,6 +13,7 @@ struct bfs_inode_info {
unsigned long i_dsk_ino; /* inode number from the disk, can be 0 */
unsigned long i_sblock;
unsigned long i_eblock;
+ struct inode vfs_inode;
};
#endif /* _LINUX_BFS_FS_I */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c4d612367..711a1674e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -287,17 +287,9 @@ extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long
#include <linux/pipe_fs_i.h>
-#include <linux/ntfs_fs_i.h>
-#include <linux/msdos_fs_i.h>
/* #include <linux/umsdos_fs_i.h> */
-#include <linux/iso_fs_i.h>
#include <linux/romfs_fs_i.h>
-#include <linux/smb_fs_i.h>
-#include <linux/hfs_fs_i.h>
-#include <linux/adfs_fs_i.h>
-#include <linux/bfs_fs_i.h>
#include <linux/proc_fs_i.h>
-#include <linux/jffs2_fs_i.h>
#include <linux/cramfs_fs_sb.h>
/*
@@ -461,18 +453,10 @@ struct inode {
unsigned int i_attr_flags;
__u32 i_generation;
union {
- struct ntfs_inode_info ntfs_i;
- struct msdos_inode_info msdos_i;
/* struct umsdos_inode_info umsdos_i; */
- struct iso_inode_info isofs_i;
struct romfs_inode_info romfs_i;
- struct smb_inode_info smbfs_i;
- struct hfs_inode_info hfs_i;
- struct adfs_inode_info adfs_i;
- struct bfs_inode_info bfs_i;
struct proc_inode_info proc_i;
struct socket socket_i;
- struct jffs2_inode_info jffs2_i;
void *generic_ip;
} u;
};
diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h
index 05de50628..bd64f199b 100644
--- a/include/linux/hfs_fs.h
+++ b/include/linux/hfs_fs.h
@@ -317,7 +317,12 @@ extern int hfs_mac2alpha(char *, const struct hfs_name *);
extern int hfs_mac2triv(char *, const struct hfs_name *);
extern void hfs_tolower(unsigned char *, int);
-#define HFS_I(X) (&((X)->u.hfs_i))
+#include <linux/hfs_fs_i.h>
+
+static inline struct hfs_inode_info *HFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct hfs_inode_info, vfs_inode);
+}
#define HFS_SB(X) (&((X)->u.hfs_sb))
static inline void hfs_nameout(struct inode *dir, struct hfs_name *out,
diff --git a/include/linux/hfs_fs_i.h b/include/linux/hfs_fs_i.h
index 8ae2ef99c..39312c9b8 100644
--- a/include/linux/hfs_fs_i.h
+++ b/include/linux/hfs_fs_i.h
@@ -39,6 +39,7 @@ struct hfs_inode_info {
/* for dentry cleanup */
void (*d_drop_op)(struct dentry *, const ino_t);
+ struct inode vfs_inode;
};
#endif
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index b496169b6..7fa1243b7 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -53,7 +53,7 @@
mm: NULL, \
active_mm: &init_mm, \
run_list: LIST_HEAD_INIT(tsk.run_list), \
- time_slice: NICE_TO_TIMESLICE(DEF_USER_NICE), \
+ time_slice: HZ, \
next_task: &tsk, \
prev_task: &tsk, \
p_opptr: &tsk, \
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index b59350f01..7cd0ecdd1 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -631,7 +631,6 @@ typedef struct isdn_devt {
#ifdef CONFIG_DEVFS_FS
devfs_handle_t devfs_handle_isdninfo;
devfs_handle_t devfs_handle_isdnctrl;
- devfs_handle_t devfs_handle_isdnX[ISDN_MAX_CHANNELS];
devfs_handle_t devfs_handle_isdnctrlX[ISDN_MAX_CHANNELS];
#ifdef CONFIG_ISDN_PPP
devfs_handle_t devfs_handle_ipppX[ISDN_MAX_CHANNELS];
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
index 9cdfbaea4..b235c3ea9 100644
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -170,6 +170,12 @@ struct iso_directory_record {
#include <asm/byteorder.h>
#include <asm/unaligned.h>
+#include <linux/iso_fs_i.h>
+
+static inline struct iso_inode_info *ISOFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct iso_inode_info, vfs_inode);
+}
static inline int isonum_711(char *p)
{
diff --git a/include/linux/iso_fs_i.h b/include/linux/iso_fs_i.h
index 4759a5488..e4fc9d8e4 100644
--- a/include/linux/iso_fs_i.h
+++ b/include/linux/iso_fs_i.h
@@ -16,6 +16,7 @@ struct iso_inode_info {
unsigned char i_format_parm[3];
unsigned long i_next_section_ino;
off_t i_section_size;
+ struct inode vfs_inode;
};
#endif
diff --git a/include/linux/jffs2_fs_i.h b/include/linux/jffs2_fs_i.h
index 6121a882f..d2c33379e 100644
--- a/include/linux/jffs2_fs_i.h
+++ b/include/linux/jffs2_fs_i.h
@@ -50,12 +50,16 @@ struct jffs2_inode_info {
// struct jffs2_raw_node_ref *lastnode;
__u16 flags;
__u8 usercompr;
+ struct inode vfs_inode;
};
#ifdef JFFS2_OUT_OF_KERNEL
#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
#else
-#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
+static inline struct jffs2_inode_info *JFFS2_INODE_INFO(struct inode *inode)
+{
+ return list_entry(inode, struct jffs2_inode_info, vfs_inode);
+}
#endif
#endif /* _JFFS2_FS_I */
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 49d37edb8..eff3797d6 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -4,9 +4,7 @@
/*
* The MS-DOS filesystem constants/structures
*/
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/fd.h>
+#include <linux/msdos_fs_i.h>
#include <asm/byteorder.h>
@@ -56,7 +54,10 @@
/* valid file mode bits */
#define MSDOS_SB(s) (&((s)->u.msdos_sb))
-#define MSDOS_I(i) (&((i)->u.msdos_i))
+static inline struct msdos_inode_info *MSDOS_I(struct inode *inode)
+{
+ return list_entry(inode, struct msdos_inode_info, vfs_inode);
+}
#define MSDOS_NAME 11 /* maximum name length */
#define MSDOS_LONGNAME 256 /* maximum name length */
diff --git a/include/linux/msdos_fs_i.h b/include/linux/msdos_fs_i.h
index 8d66550d2..7b102ea2e 100644
--- a/include/linux/msdos_fs_i.h
+++ b/include/linux/msdos_fs_i.h
@@ -12,8 +12,8 @@ struct msdos_inode_info {
int i_attrs; /* unused attribute bits */
int i_ctime_ms; /* unused change time in milliseconds */
int i_location; /* on-disk position of directory entry or 0 */
- struct inode *i_fat_inode; /* struct inode of this one */
struct list_head i_fat_hash; /* hash by i_location */
+ struct inode vfs_inode;
};
#endif
diff --git a/include/linux/ntfs_fs_i.h b/include/linux/ntfs_fs_i.h
index 8789aaa5a..45420c042 100644
--- a/include/linux/ntfs_fs_i.h
+++ b/include/linux/ntfs_fs_i.h
@@ -88,4 +88,10 @@ struct ntfs_inode_info {
} u;
};
+/* this is a kludge */
+struct ntfs_i {
+ struct ntfs_inode_info n;
+ struct inode vfs_inode;
+};
+
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index b34544b83..bbb5dbbf9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -140,8 +140,7 @@ extern spinlock_t mmlist_lock;
typedef struct task_struct task_t;
extern void sched_init(void);
-extern void init_idle(void);
-extern void idle_startup_done(void);
+extern void init_idle(task_t *idle, int cpu);
extern void show_state(void);
extern void cpu_init (void);
extern void trap_init(void);
@@ -151,6 +150,8 @@ extern void update_one_process(struct task_struct *p, unsigned long user,
extern void scheduler_tick(struct task_struct *p);
extern void sched_task_migrated(struct task_struct *p);
extern void smp_migrate_task(int cpu, task_t *task);
+extern unsigned long cache_decay_ticks;
+
#define MAX_SCHEDULE_TIMEOUT LONG_MAX
extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -256,7 +257,6 @@ struct task_struct {
unsigned int time_slice;
- #define MAX_SLEEP_AVG (2*HZ)
unsigned long sleep_avg;
unsigned long sleep_timestamp;
@@ -418,11 +418,22 @@ struct task_struct {
#define DEF_USER_NICE 0
/*
- * Default timeslice is 90 msecs, maximum is 180 msecs.
+ * Default timeslice is 150 msecs, maximum is 300 msecs.
* Minimum timeslice is 10 msecs.
+ *
+ * These are the 'tuning knobs' of the scheduler:
*/
#define MIN_TIMESLICE ( 10 * HZ / 1000)
-#define MAX_TIMESLICE (180 * HZ / 1000)
+#define MAX_TIMESLICE (300 * HZ / 1000)
+#define CHILD_FORK_PENALTY 95
+#define PARENT_FORK_PENALTY 100
+#define EXIT_WEIGHT 3
+#define PRIO_INTERACTIVE_RATIO 20
+#define PRIO_CPU_HOG_RATIO 60
+#define PRIO_BONUS_RATIO 70
+#define INTERACTIVE_DELTA 3
+#define MAX_SLEEP_AVG (2*HZ)
+#define STARVATION_LIMIT (2*HZ)
#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index 220020988..fe3570789 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -10,6 +10,7 @@
#define _LINUX_SMB_FS_H
#include <linux/smb.h>
+#include <linux/smb_fs_i.h>
/*
* ioctl commands
@@ -28,6 +29,10 @@
#include <linux/smb_mount.h>
#include <asm/unaligned.h>
+static inline struct smb_inode_info *SMB_I(struct inode *inode)
+{
+ return list_entry(inode, struct smb_inode_info, vfs_inode);
+}
/* macro names are short for word, double-word, long value (?) */
#define WVAL(buf,pos) \
@@ -157,7 +162,7 @@ struct smb_cache_control {
static inline int
smb_is_open(struct inode *i)
{
- return (i->u.smbfs_i.open == server_from_inode(i)->generation);
+ return (SMB_I(i)->open == server_from_inode(i)->generation);
}
diff --git a/include/linux/smb_fs_i.h b/include/linux/smb_fs_i.h
index d04a4656e..309e8b973 100644
--- a/include/linux/smb_fs_i.h
+++ b/include/linux/smb_fs_i.h
@@ -30,6 +30,8 @@ struct smb_inode_info {
unsigned long oldmtime; /* last time refreshed */
unsigned long closed; /* timestamp when closed */
unsigned openers; /* number of fileid users */
+
+ struct inode vfs_inode; /* must be at the end */
};
#endif
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 5309034e5..91e8498f3 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -881,6 +881,7 @@ extern int usb_string(struct usb_device *dev, int index,
char *buf, size_t size);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+extern int usb_make_path(struct usb_device *dev, char *buf, size_t size);
/*
* timeouts, in seconds, used for sending/receiving control messages
@@ -1096,7 +1097,7 @@ const struct usb_device_id *usb_match_id(struct usb_device *dev,
* - endpoint number (4 bits)
* - current Data0/1 state (1 bit) [Historical; now gone]
* - direction (1 bit)
- * - speed (1 bit)
+ * - speed (1 bit) [Historical and specific to USB 1.1; now gone.]
* - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.]
* - pipe type (2 bits: control, interrupt, bulk, isochronous)
*
@@ -1107,25 +1108,22 @@ const struct usb_device_id *usb_match_id(struct usb_device *dev,
* Let's not fall in that trap. We'll just encode it as a simple
* unsigned int. The encoding is:
*
- * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) [Historical; now gone.]
- * - direction: bit 7 (0 = Host-to-Device [Out], 1 = Device-to-Host [In])
+ * - max size: bits 0-1 [Historical; now gone.]
+ * - direction: bit 7 (0 = Host-to-Device [Out],
+ * 1 = Device-to-Host [In])
* - device: bits 8-14
* - endpoint: bits 15-18
* - Data0/1: bit 19 [Historical; now gone. ]
- * - speed: bit 26 (0 = Full, 1 = Low Speed)
- * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
+ * - lowspeed: bit 26 [Historical; now gone. ]
+ * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
+ * 10 = control, 11 = bulk)
*
* Why? Because it's arbitrary, and whatever encoding we select is really
* up to us. This one happens to share a lot of bit positions with the UHCI
* specification, so that much of the uhci driver can just mask the bits
* appropriately.
- *
- * NOTE: there's no encoding (yet?) for a "high speed" endpoint; treat them
- * like full speed devices.
*/
-// FIXME 2.5 get rid of usb_pipeslow(), just use dev->speed
-
#define PIPE_ISOCHRONOUS 0
#define PIPE_INTERRUPT 1
#define PIPE_CONTROL 2
@@ -1139,9 +1137,7 @@ const struct usb_device_id *usb_match_id(struct usb_device *dev,
#define usb_pipeout(pipe) ((((pipe) >> 7) & 1) ^ 1)
#define usb_pipein(pipe) (((pipe) >> 7) & 1)
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f)
-#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
-#define usb_pipeslow(pipe) (((pipe) >> 26) & 1)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
@@ -1163,13 +1159,7 @@ const struct usb_device_id *usb_match_id(struct usb_device *dev,
static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
{
- return (dev->devnum << 8) | (endpoint << 15) |
- ((dev->speed == USB_SPEED_LOW) << 26);
-}
-
-static inline unsigned int __default_pipe(struct usb_device *dev)
-{
- return ((dev->speed == USB_SPEED_LOW) << 26);
+ return (dev->devnum << 8) | (endpoint << 15);
}
/* Create various pipes... */
@@ -1181,8 +1171,8 @@ static inline unsigned int __default_pipe(struct usb_device *dev)
#define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
-#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30) | __default_pipe(dev))
-#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | __default_pipe(dev) | USB_DIR_IN)
+#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30))
+#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | USB_DIR_IN)
/* -------------------------------------------------------------------------- */
diff --git a/init/main.c b/init/main.c
index 0a71a18bc..f4f7ccc42 100644
--- a/init/main.c
+++ b/init/main.c
@@ -274,27 +274,14 @@ static void __init smp_init(void)
#else
-static unsigned long __initdata wait_init_idle;
-
-void __init idle_startup_done(void)
-{
- clear_bit(smp_processor_id(), &wait_init_idle);
- while (wait_init_idle) {
- cpu_relax();
- barrier();
- }
-}
-
/* Called by boot processor to activate the rest. */
static void __init smp_init(void)
{
/* Get other processors into their bootup holding patterns. */
smp_boot_cpus();
- wait_init_idle = cpu_online_map;
smp_threads_ready=1;
smp_commence();
- idle_startup_done();
}
#endif
@@ -391,7 +378,7 @@ asmlinkage void __init start_kernel(void)
check_bugs();
printk("POSIX conformance testing by UNIFIX\n");
- init_idle();
+ init_idle(current, smp_processor_id());
/*
* We count on the initial thread going ok
* Like idlers init is an unlocked kernel thread, which will
diff --git a/kernel/Makefile b/kernel/Makefile
index c118fff17..34fdbca17 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -10,12 +10,12 @@
O_TARGET := kernel.o
export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
- printk.o device.o
+ printk.o
obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
sysctl.o acct.o capability.o ptrace.o timer.o user.o \
- signal.o sys.o kmod.o context.o device.o
+ signal.o sys.o kmod.o context.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += ksyms.o
diff --git a/kernel/device.c b/kernel/device.c
deleted file mode 100644
index b74a17242..000000000
--- a/kernel/device.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * device.c
- *
- * Copyright (c) Patrick Mochel <mochel@osdl.org>
- *
- * 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 program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Please see Documentation/driver-model.txt for more explanation.
- */
-
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/module.h>
-#include <linux/stat.h>
-#include <linux/driverfs_fs.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-# define DBG(x...) printk(x)
-#else
-# define DBG(x...)
-#endif
-
-static struct iobus device_root = {
- bus_id: "root",
- name: "Logical System Root",
-};
-
-int (*platform_notify)(struct device * dev) = NULL;
-int (*platform_notify_remove)(struct device * dev) = NULL;
-
-static spinlock_t device_lock;
-
-static ssize_t device_read_status(struct device *, char *, size_t, loff_t);
-static ssize_t device_write_status(struct device *,const char *, size_t, loff_t);
-
-static struct driver_file_entry device_status_entry = {
- name: "status",
- mode: S_IWUSR | S_IRUGO,
- show: device_read_status,
- store: device_write_status,
-};
-
-static ssize_t device_read_power(struct device *, char *, size_t, loff_t);
-static ssize_t device_write_power(struct device *, const char *, size_t, loff_t);
-
-static struct driver_file_entry device_power_entry = {
- name: "power",
- mode: S_IWUSR | S_IRUGO,
- show: device_read_power,
- store: device_write_power,
-};
-
-/**
- * device_create_file - create a driverfs file for a device
- * @dev: device requesting file
- * @entry: entry describing file
- *
- * Allocate space for file entry, copy descriptor, and create.
- */
-int device_create_file(struct device * dev, struct driver_file_entry * entry)
-{
- struct driver_file_entry * new_entry;
- int error = -ENOMEM;
-
- if (!dev)
- return -EINVAL;
- get_device(dev);
-
- new_entry = kmalloc(sizeof(*new_entry),GFP_KERNEL);
- if (!new_entry)
- goto done;
-
- memcpy(new_entry,entry,sizeof(*entry));
- error = driverfs_create_file(new_entry,&dev->dir);
- if (error)
- kfree(new_entry);
- done:
- put_device(dev);
- return error;
-}
-
-/**
- * device_remove_file - remove a device's file by name
- * @dev: device requesting removal
- * @name: name of the file
- *
- */
-void device_remove_file(struct device * dev, const char * name)
-{
- if (dev) {
- get_device(dev);
- driverfs_remove_file(&dev->dir,name);
- put_device(dev);
- }
-}
-
-/**
- * device_remove_dir - remove a device's directory
- * @dev: device in question
- */
-void device_remove_dir(struct device * dev)
-{
- if (dev)
- driverfs_remove_dir(&dev->dir);
-}
-
-/**
- * device_make_dir - create a driverfs directory
- * @name: name of directory
- * @parent: dentry for the parent directory
- *
- * Do the initial creation of the device's driverfs directory
- * and populate it with the one default file.
- *
- * This is just a helper for device_register(), as we
- * don't export this function. (Yes, that means we don't allow
- * devices to create subdirectories).
- */
-static int device_make_dir(struct device * dev)
-{
- struct driver_dir_entry * parent = NULL;
- int error;
-
- INIT_LIST_HEAD(&dev->dir.files);
- dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
- dev->dir.name = dev->bus_id;
-
- if (dev->parent)
- parent = &dev->parent->dir;
-
- error = driverfs_create_dir(&dev->dir,parent);
-
- if (error)
- return error;
-
- error = device_create_file(dev,&device_status_entry);
- if (error) {
- device_remove_dir(dev);
- goto done;
- }
- error = device_create_file(dev,&device_power_entry);
- if (error)
- device_remove_dir(dev);
- done:
- return error;
-}
-
-void iobus_remove_dir(struct iobus * iobus)
-{
- if (iobus)
- driverfs_remove_dir(&iobus->dir);
-}
-
-static int iobus_make_dir(struct iobus * iobus)
-{
- struct driver_dir_entry * parent = NULL;
- int error;
-
- INIT_LIST_HEAD(&iobus->dir.files);
- iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
- iobus->dir.name = iobus->bus_id;
-
- if (iobus->parent)
- parent = &iobus->parent->dir;
-
- error = driverfs_create_dir(&iobus->dir,parent);
- return error;
-}
-
-/**
- * device_register - register a device
- * @dev: pointer to the device structure
- *
- * First, make sure that the device has a parent, create
- * a directory for it, then add it to the parent's list of
- * children.
- */
-int device_register(struct device *dev)
-{
- int error;
-
- if (!dev || !strlen(dev->bus_id))
- return -EINVAL;
- BUG_ON(!dev->parent);
-
- spin_lock(&device_lock);
- INIT_LIST_HEAD(&dev->node);
- spin_lock_init(&dev->lock);
- atomic_set(&dev->refcount,2);
-
- get_iobus(dev->parent);
- list_add_tail(&dev->node,&dev->parent->devices);
- spin_unlock(&device_lock);
-
- DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
- dev->bus_id, dev->name, parent->bus_id);
-
- if ((error = device_make_dir(dev)))
- goto register_done;
-
- /* notify platform of device entry */
- if (platform_notify)
- platform_notify(dev);
-
- register_done:
- put_device(dev);
- if (error)
- put_iobus(dev->parent);
- return error;
-}
-
-/**
- * put_device - clean up device
- * @dev: device in question
- *
- * Decrement reference count for device.
- * If it hits 0, we need to clean it up.
- * However, we may be here in interrupt context, and it may
- * take some time to do proper clean up (removing files, calling
- * back down to device to clean up everything it has).
- * So, we remove it from its parent's list and add it to the list of
- * devices to be cleaned up.
- */
-void put_device(struct device * dev)
-{
- if (!atomic_dec_and_lock(&dev->refcount,&device_lock))
- return;
- list_del_init(&dev->node);
- spin_unlock(&device_lock);
-
- DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
- dev->bus_id,dev->name);
-
- /* remove the driverfs directory */
- device_remove_dir(dev);
-
- if (dev->subordinate)
- iobus_remove_dir(dev->subordinate);
-
- /* Notify the platform of the removal, in case they
- * need to do anything...
- */
- if (platform_notify_remove)
- platform_notify_remove(dev);
-
- /* Tell the driver to clean up after itself.
- * Note that we likely didn't allocate the device,
- * so this is the driver's chance to free that up...
- */
- if (dev->driver && dev->driver->remove)
- dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
-
- put_iobus(dev->parent);
-}
-
-int iobus_register(struct iobus *bus)
-{
- int error;
-
- if (!bus || !strlen(bus->bus_id))
- return -EINVAL;
-
- spin_lock(&device_lock);
- atomic_set(&bus->refcount,2);
- spin_lock_init(&bus->lock);
- INIT_LIST_HEAD(&bus->node);
- INIT_LIST_HEAD(&bus->devices);
- INIT_LIST_HEAD(&bus->children);
-
- if (bus != &device_root) {
- if (!bus->parent)
- bus->parent = &device_root;
- get_iobus(bus->parent);
- list_add_tail(&bus->node,&bus->parent->children);
- }
- spin_unlock(&device_lock);
-
- DBG("DEV: registering bus. ID = '%s' name = '%s' parent = %p\n",
- bus->bus_id,bus->name,bus->parent);
-
- error = iobus_make_dir(bus);
-
- put_iobus(bus);
- if (error && bus->parent)
- put_iobus(bus->parent);
- return error;
-}
-
-/**
- * iobus_unregister - remove bus and children from device tree
- * @bus: pointer to bus structure
- *
- * Remove device from parent's list of children and decrement
- * reference count on controlling device. That should take care of
- * the rest of the cleanup.
- */
-void put_iobus(struct iobus * iobus)
-{
- if (!atomic_dec_and_lock(&iobus->refcount,&device_lock))
- return;
- list_del_init(&iobus->node);
- spin_unlock(&device_lock);
-
- if (!list_empty(&iobus->devices) ||
- !list_empty(&iobus->children))
- BUG();
-
- put_iobus(iobus->parent);
- /* unregister itself */
- put_device(iobus->self);
-}
-
-/**
- * device_read_status - report some device information
- * @page: page-sized buffer to write into
- * @count: number of bytes requested
- * @off: offset into buffer
- * @data: device-specific data
- *
- * Report some human-readable information about the device.
- * This includes the name, the bus id, and the current power state.
- */
-static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
-{
- char *str = page;
-
- if (off)
- return 0;
-
- str += sprintf(str,"Name: %s\n",dev->name);
- str += sprintf(str,"Bus ID: %s\n",dev->bus_id);
-
- return (str - page);
-}
-
-/**
- * device_write_status - forward a command to a driver
- * @buf: encoded command
- * @count: number of bytes in buffer
- * @off: offset into buffer to start with
- * @data: device-specific data
- *
- * Send a comamnd to a device driver.
- * The following actions are supported:
- * probe - scan slot for device
- * remove - detach driver from slot
- * suspend <state> <stage> - perform <stage> for entering <state>
- * resume <stage> - perform <stage> for waking device up.
- * (See Documentation/driver-model.txt for the theory of an n-stage
- * suspend sequence).
- */
-static ssize_t device_write_status(struct device * dev, const char* buf, size_t count, loff_t off)
-{
- char command[20];
- int num;
- int arg = 0;
- int error = 0;
-
- if (off)
- return 0;
-
- /* everything involves dealing with the driver. */
- if (!dev->driver)
- return 0;
-
- num = sscanf(buf,"%10s %d",command,&arg);
-
- if (!num)
- return 0;
-
- if (!strcmp(command,"probe")) {
- if (dev->driver->probe)
- error = dev->driver->probe(dev);
-
- } else if (!strcmp(command,"remove")) {
- if (dev->driver->remove)
- error = dev->driver->remove(dev,REMOVE_NOTIFY);
- } else
- error = -EFAULT;
- return error < 0 ? error : count;
-}
-
-static ssize_t
-device_read_power(struct device * dev, char * page, size_t count, loff_t off)
-{
- char * str = page;
-
- if (off)
- return 0;
-
- str += sprintf(str,"State: %d\n",dev->current_state);
-
- return (str - page);
-}
-
-static ssize_t
-device_write_power(struct device * dev, const char * buf, size_t count, loff_t off)
-{
- char str_command[20];
- char str_stage[20];
- int num_args;
- u32 state;
- u32 int_stage;
- int error = 0;
-
- if (off)
- return 0;
-
- if (!dev->driver)
- goto done;
-
- num_args = sscanf(buf,"%s %s %u",str_command,str_stage,&state);
-
- error = -EINVAL;
-
- if (!num_args)
- goto done;
-
- if (!strnicmp(str_command,"suspend",7)) {
- if (num_args != 3)
- goto done;
- if (!strnicmp(str_stage,"notify",6))
- int_stage = SUSPEND_NOTIFY;
- else if (!strnicmp(str_stage,"save",4))
- int_stage = SUSPEND_SAVE_STATE;
- else if (!strnicmp(str_stage,"disable",7))
- int_stage = SUSPEND_DISABLE;
- else if (!strnicmp(str_stage,"powerdown",8))
- int_stage = SUSPEND_POWER_DOWN;
- else
- goto done;
-
- if (dev->driver->suspend)
- error = dev->driver->suspend(dev,state,int_stage);
- else
- error = 0;
- } else if (!strnicmp(str_command,"resume",6)) {
- if (num_args != 2)
- goto done;
-
- if (!strnicmp(str_stage,"poweron",7))
- int_stage = RESUME_POWER_ON;
- else if (!strnicmp(str_stage,"restore",7))
- int_stage = RESUME_RESTORE_STATE;
- else if (!strnicmp(str_stage,"enable",6))
- int_stage = RESUME_ENABLE;
- else
- goto done;
-
- if (dev->driver->resume)
- error = dev->driver->resume(dev,int_stage);
- else
- error = 0;
- }
- done:
- return error < 0 ? error : count;
-}
-
-static int __init device_init_root(void)
-{
- /* initialize parent bus lists */
- return iobus_register(&device_root);
-}
-
-int __init device_driver_init(void)
-{
- int error = 0;
-
- DBG("DEV: Initialising Device Tree\n");
-
- spin_lock_init(&device_lock);
-
- error = init_driverfs_fs();
-
- if (error) {
- panic("DEV: could not initialise driverfs\n");
- return error;
- }
-
- error = device_init_root();
- if (error) {
- printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
- return error;
- }
-
- DBG("DEV: Done Initialising\n");
- return error;
-}
-
-void __exit device_driver_exit(void)
-{
-
-}
-
-static int __init device_setup(char *str)
-{
- return 0;
-}
-
-__setup("device=",device_setup);
-
-EXPORT_SYMBOL(device_register);
-EXPORT_SYMBOL(device_create_file);
-EXPORT_SYMBOL(device_remove_file);
-EXPORT_SYMBOL(iobus_register);
-EXPORT_SYMBOL(device_driver_init);
diff --git a/kernel/exit.c b/kernel/exit.c
index 850d3b7ef..429fd2908 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -59,6 +59,9 @@ static void release_task(struct task_struct * p)
current->time_slice += p->time_slice;
if (current->time_slice > MAX_TIMESLICE)
current->time_slice = MAX_TIMESLICE;
+ if (p->sleep_avg < current->sleep_avg)
+ current->sleep_avg = (current->sleep_avg * EXIT_WEIGHT +
+ p->sleep_avg) / (EXIT_WEIGHT + 1);
__restore_flags(flags);
p->pid = 0;
diff --git a/kernel/fork.c b/kernel/fork.c
index 661f650e6..592405a97 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -647,11 +647,10 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
{
int i;
- p->cpu = smp_processor_id();
-
/* ?? should we just memset this ?? */
for(i = 0; i < smp_num_cpus; i++)
- p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0;
+ p->per_cpu_utime[cpu_logical_map(i)] =
+ p->per_cpu_stime[cpu_logical_map(i)] = 0;
spin_lock_init(&p->sigmask_lock);
}
#endif
diff --git a/kernel/sched.c b/kernel/sched.c
index 4c7755127..0f632fcdd 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -41,7 +41,7 @@ struct prio_array {
*/
struct runqueue {
spinlock_t lock;
- unsigned long nr_running, nr_switches;
+ unsigned long nr_running, nr_switches, expired_timestamp;
task_t *curr, *idle;
prio_array_t *active, *expired, arrays[2];
int prev_nr_running[NR_CPUS];
@@ -70,8 +70,7 @@ repeat_lock_task:
return __rq;
}
-static inline void unlock_task_rq(runqueue_t *rq, task_t *p,
- unsigned long *flags)
+static inline void unlock_task_rq(runqueue_t *rq, unsigned long *flags)
{
spin_unlock_irqrestore(&rq->lock, *flags);
}
@@ -83,13 +82,13 @@ static inline void dequeue_task(struct task_struct *p, prio_array_t *array)
array->nr_active--;
list_del_init(&p->run_list);
if (list_empty(array->queue + p->prio))
- __set_bit(p->prio, array->bitmap);
+ __clear_bit(p->prio, array->bitmap);
}
static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
{
list_add_tail(&p->run_list, array->queue + p->prio);
- __clear_bit(p->prio, array->bitmap);
+ __set_bit(p->prio, array->bitmap);
array->nr_active++;
p->array = array;
}
@@ -109,12 +108,30 @@ static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
* being a CPU hog.
*
*/
-#define PRIO_INTERACTIVE (MAX_RT_PRIO + MAX_USER_PRIO/4)
-#define PRIO_CPU_HOG (MAX_RT_PRIO + MAX_USER_PRIO*3/4)
-#define TASK_INTERACTIVE(p) (((p)->prio <= PRIO_INTERACTIVE) || \
- (((p)->prio < PRIO_CPU_HOG) && \
- ((p)->prio <= NICE_TO_PRIO((p)->__nice)-3)))
+#define PRIO_INTERACTIVE \
+ (MAX_RT_PRIO + MAX_USER_PRIO*PRIO_INTERACTIVE_RATIO/100)
+#define PRIO_CPU_HOG \
+ (MAX_RT_PRIO + MAX_USER_PRIO*PRIO_CPU_HOG_RATIO/100)
+
+#define TASK_INTERACTIVE(p) \
+ (((p)->prio <= PRIO_INTERACTIVE) || \
+ (((p)->prio < PRIO_CPU_HOG) && \
+ ((p)->prio <= NICE_TO_PRIO((p)->__nice) - INTERACTIVE_DELTA)))
+
+/*
+ * We place interactive tasks back into the active array, if possible.
+ *
+ * To guarantee that this does not starve expired tasks we ignore the
+ * interactivity of a task if the first expired task had to wait more
+ * than a 'reasonable' amount of time. This deadline timeout is
+ * load-dependent, as the frequency of array switched decreases with
+ * increasing number of running tasks:
+ */
+#define EXPIRED_STARVING(rq) \
+ ((rq)->expired_timestamp && \
+ (jiffies - (rq)->expired_timestamp >= \
+ STARVATION_LIMIT * ((rq)->nr_running) + 1))
static inline int effective_prio(task_t *p)
{
@@ -122,18 +139,19 @@ static inline int effective_prio(task_t *p)
/*
* Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG]
- * into the 19 ... -18 bonus/penalty range.
+ * into the -14 ... +14 bonus/penalty range.
*
- * We take off the 10% from the full 0...39 priority range so that:
+ * We use 70% of the full 0...39 priority range so that:
*
- * 1) nice +19 CPU hogs do not preempt nice 0 CPU hogs just yet.
+ * 1) nice +19 CPU hogs do not preempt nice 0 CPU hogs.
* 2) nice -20 interactive tasks do not get preempted by
* nice 0 interactive tasks.
*
- * Both properties are important to certain applications.
+ * Both properties are important to certain workloads.
*/
- bonus = MAX_USER_PRIO*9/10 * p->sleep_avg / MAX_SLEEP_AVG -
- MAX_USER_PRIO*9/10/2;
+ bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 -
+ MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2;
+
prio = NICE_TO_PRIO(p->__nice) - bonus;
if (prio < MAX_RT_PRIO)
prio = MAX_RT_PRIO;
@@ -202,10 +220,10 @@ repeat:
}
rq = lock_task_rq(p, &flags);
if (unlikely(rq->curr == p)) {
- unlock_task_rq(rq, p, &flags);
+ unlock_task_rq(rq, &flags);
goto repeat;
}
- unlock_task_rq(rq, p, &flags);
+ unlock_task_rq(rq, &flags);
}
/*
@@ -260,7 +278,7 @@ static int try_to_wake_up(task_t * p, int synchronous)
resched_task(rq->curr);
success = 1;
}
- unlock_task_rq(rq, p, &flags);
+ unlock_task_rq(rq, &flags);
return success;
}
@@ -275,8 +293,10 @@ void wake_up_forked_process(task_t * p)
p->state = TASK_RUNNING;
if (!rt_task(p)) {
- p->sleep_avg = (p->sleep_avg * 4) / 5;
+ p->sleep_avg = p->sleep_avg * CHILD_FORK_PENALTY / 100;
p->prio = effective_prio(p);
+
+ current->sleep_avg = current->sleep_avg * PARENT_FORK_PENALTY / 100;
}
spin_lock_irq(&rq->lock);
p->cpu = smp_processor_id();
@@ -296,14 +316,14 @@ static inline void context_switch(task_t *prev, task_t *next)
prepare_to_switch();
- if (!mm) {
+ if (unlikely(!mm)) {
next->active_mm = oldmm;
atomic_inc(&oldmm->mm_count);
enter_lazy_tlb(oldmm, next, smp_processor_id());
} else
switch_mm(oldmm, mm, next, smp_processor_id());
- if (!prev->mm) {
+ if (unlikely(!prev->mm)) {
prev->active_mm = NULL;
mmdrop(oldmm);
}
@@ -326,7 +346,7 @@ unsigned long nr_running(void)
unsigned long i, sum = 0;
for (i = 0; i < smp_num_cpus; i++)
- sum += cpu_rq(i)->nr_running;
+ sum += cpu_rq(cpu_logical_map(i))->nr_running;
return sum;
}
@@ -336,11 +356,34 @@ unsigned long nr_context_switches(void)
unsigned long i, sum = 0;
for (i = 0; i < smp_num_cpus; i++)
- sum += cpu_rq(i)->nr_switches;
+ sum += cpu_rq(cpu_logical_map(i))->nr_switches;
return sum;
}
+#if CONFIG_SMP
+/*
+ * Lock the busiest runqueue as well, this_rq is locked already.
+ * Recalculate nr_running if we have to drop the runqueue lock.
+ */
+static inline unsigned int double_lock_balance(runqueue_t *this_rq,
+ runqueue_t *busiest, int this_cpu, int idle, unsigned int nr_running)
+{
+ if (unlikely(!spin_trylock(&busiest->lock))) {
+ if (busiest < this_rq) {
+ spin_unlock(&this_rq->lock);
+ spin_lock(&busiest->lock);
+ spin_lock(&this_rq->lock);
+ /* Need to recalculate nr_running */
+ if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+ nr_running = this_rq->nr_running;
+ else
+ nr_running = this_rq->prev_nr_running[this_cpu];
+ } else
+ spin_lock(&busiest->lock);
+ }
+ return nr_running;
+}
/*
* Current runqueue is empty, or rebalance tick: if there is an
* inbalance (current runqueue is too short) then pull from
@@ -351,8 +394,8 @@ unsigned long nr_context_switches(void)
*/
static void load_balance(runqueue_t *this_rq, int idle)
{
- int imbalance, nr_running, load, prev_max_load,
- max_load, idx, i, this_cpu = smp_processor_id();
+ int imbalance, nr_running, load, max_load,
+ idx, i, this_cpu = smp_processor_id();
task_t *next = this_rq->idle, *tmp;
runqueue_t *busiest, *rq_src;
prio_array_t *array;
@@ -384,20 +427,18 @@ static void load_balance(runqueue_t *this_rq, int idle)
nr_running = this_rq->nr_running;
else
nr_running = this_rq->prev_nr_running[this_cpu];
- prev_max_load = 1000000000;
busiest = NULL;
- max_load = 0;
+ max_load = 1;
for (i = 0; i < smp_num_cpus; i++) {
- rq_src = cpu_rq(i);
+ rq_src = cpu_rq(cpu_logical_map(i));
if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
load = rq_src->nr_running;
else
load = this_rq->prev_nr_running[i];
this_rq->prev_nr_running[i] = rq_src->nr_running;
- if ((load > max_load) && (load < prev_max_load) &&
- (rq_src != this_rq)) {
+ if ((load > max_load) && (rq_src != this_rq)) {
busiest = rq_src;
max_load = load;
}
@@ -408,37 +449,22 @@ static void load_balance(runqueue_t *this_rq, int idle)
imbalance = (max_load - nr_running) / 2;
- /*
- * It needs an at least ~25% imbalance to trigger balancing.
- *
- * prev_max_load makes sure that we do not try to balance
- * ad infinitum - certain tasks might be impossible to be
- * pulled into this runqueue.
- */
+ /* It needs an at least ~25% imbalance to trigger balancing. */
if (!idle && (imbalance < (max_load + 3)/4))
return;
- prev_max_load = max_load;
- /*
- * Ok, lets do some actual balancing:
- */
-
- if (busiest < this_rq) {
- spin_unlock(&this_rq->lock);
- spin_lock(&busiest->lock);
- spin_lock(&this_rq->lock);
- } else
- spin_lock(&busiest->lock);
+ nr_running = double_lock_balance(this_rq, busiest, this_cpu, idle, nr_running);
/*
* Make sure nothing changed since we checked the
* runqueue length.
*/
- if (busiest->nr_running <= nr_running + 1)
+ if (busiest->nr_running <= this_rq->nr_running + 1)
goto out_unlock;
/*
- * We first consider expired tasks. Those will likely not run
- * in the near future, thus switching CPUs has the least effect
+ * We first consider expired tasks. Those will likely not be
+ * executed in the near future, and they are most likely to
+ * be cache-cold, thus switching CPUs has the least effect
* on them.
*/
if (busiest->expired->nr_active)
@@ -453,7 +479,7 @@ new_array:
*/
idx = MAX_RT_PRIO;
skip_bitmap:
- idx = find_next_zero_bit(array->bitmap, MAX_PRIO, idx);
+ idx = find_next_bit(array->bitmap, MAX_PRIO, idx);
if (idx == MAX_PRIO) {
if (array == busiest->expired) {
array = busiest->active;
@@ -463,10 +489,23 @@ skip_bitmap:
}
head = array->queue + idx;
- curr = head->next;
+ curr = head->prev;
skip_queue:
tmp = list_entry(curr, task_t, run_list);
- if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) {
+
+ /*
+ * We do not migrate tasks that are:
+ * 1) running (obviously), or
+ * 2) cannot be migrated to this CPU due to cpus_allowed, or
+ * 3) are cache-hot on their current CPU.
+ */
+
+#define CAN_MIGRATE_TASK(p,rq,this_cpu) \
+ ((jiffies - (p)->sleep_timestamp > cache_decay_ticks) && \
+ ((p) != (rq)->curr) && \
+ (tmp->cpus_allowed & (1 << (this_cpu))))
+
+ if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) {
curr = curr->next;
if (curr != head)
goto skip_queue;
@@ -516,17 +555,21 @@ static inline void idle_tick(void)
spin_unlock(&this_rq()->lock);
}
+#endif
+
/*
* This function gets called by the timer code, with HZ frequency.
* We call it with interrupts disabled.
*/
void scheduler_tick(task_t *p)
{
- unsigned long now = jiffies;
runqueue_t *rq = this_rq();
+#if CONFIG_SMP
+ unsigned long now = jiffies;
if (p == rq->idle)
return idle_tick();
+#endif
/* Task might have expired already, but not scheduled off yet */
if (p->array != rq->active) {
p->need_resched = 1;
@@ -563,11 +606,19 @@ void scheduler_tick(task_t *p)
p->need_resched = 1;
p->prio = effective_prio(p);
p->time_slice = NICE_TO_TIMESLICE(p->__nice);
- enqueue_task(p, TASK_INTERACTIVE(p) ? rq->active : rq->expired);
+
+ if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) {
+ if (!rq->expired_timestamp)
+ rq->expired_timestamp = jiffies;
+ enqueue_task(p, rq->expired);
+ } else
+ enqueue_task(p, rq->active);
}
out:
+#if CONFIG_SMP
if (!(now % BUSY_REBALANCE_TICK))
load_balance(rq, 0);
+#endif
spin_unlock(&rq->lock);
}
@@ -590,22 +641,29 @@ asmlinkage void schedule(void)
spin_lock_irq(&rq->lock);
switch (prev->state) {
+ case TASK_RUNNING:
+ prev->sleep_timestamp = jiffies;
+ break;
case TASK_INTERRUPTIBLE:
if (unlikely(signal_pending(prev))) {
prev->state = TASK_RUNNING;
+ prev->sleep_timestamp = jiffies;
break;
}
default:
deactivate_task(prev, rq);
- case TASK_RUNNING:
- ;
}
+#if CONFIG_SMP
pick_next_task:
+#endif
if (unlikely(!rq->nr_running)) {
+#if CONFIG_SMP
load_balance(rq, 1);
if (rq->nr_running)
goto pick_next_task;
+#endif
next = rq->idle;
+ rq->expired_timestamp = 0;
goto switch_tasks;
}
@@ -617,13 +675,15 @@ pick_next_task:
rq->active = rq->expired;
rq->expired = array;
array = rq->active;
+ rq->expired_timestamp = 0;
}
- idx = sched_find_first_zero_bit(array->bitmap);
+ idx = sched_find_first_bit(array->bitmap);
queue = array->queue + idx;
next = list_entry(queue->next, task_t, run_list);
switch_tasks:
+ prefetch(next);
prev->need_resched = 0;
if (likely(prev != next)) {
@@ -805,9 +865,9 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask)
if (new_mask & (1UL << smp_processor_id()))
return;
#if CONFIG_SMP
- smp_migrate_task(ffz(~new_mask), current);
-
current->state = TASK_UNINTERRUPTIBLE;
+ smp_migrate_task(__ffs(new_mask), current);
+
schedule();
#endif
}
@@ -832,9 +892,8 @@ void set_user_nice(task_t *p, long nice)
goto out_unlock;
}
array = p->array;
- if (array) {
+ if (array)
dequeue_task(p, array);
- }
p->__nice = nice;
p->prio = NICE_TO_PRIO(nice);
if (array) {
@@ -848,7 +907,7 @@ void set_user_nice(task_t *p, long nice)
resched_task(rq->curr);
}
out_unlock:
- unlock_task_rq(rq, p, &flags);
+ unlock_task_rq(rq, &flags);
}
#ifndef __alpha__
@@ -968,7 +1027,7 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param)
activate_task(p, task_rq(p));
out_unlock:
- unlock_task_rq(rq, p, &flags);
+ unlock_task_rq(rq, &flags);
out_unlock_tasklist:
read_unlock_irq(&tasklist_lock);
@@ -1053,12 +1112,22 @@ asmlinkage long sys_sched_yield(void)
*/
spin_lock_irq(&rq->lock);
array = current->array;
- dequeue_task(current, array);
- if (likely(!rt_task(current)))
- if (current->prio < MAX_PRIO-1)
- current->prio++;
- enqueue_task(current, array);
- spin_unlock_irq(&rq->lock);
+ /*
+ * If the task has reached maximum priority (or is a RT task)
+ * then just requeue the task to the end of the runqueue:
+ */
+ if (likely(current->prio == MAX_PRIO-1 || rt_task(current))) {
+ list_del(&current->run_list);
+ list_add_tail(&current->run_list, array->queue + current->prio);
+ } else {
+ list_del(&current->run_list);
+ if (list_empty(array->queue + current->prio))
+ __clear_bit(current->prio, array->bitmap);
+ current->prio++;
+ list_add_tail(&current->run_list, array->queue + current->prio);
+ __set_bit(current->prio, array->bitmap);
+ }
+ spin_unlock(&rq->lock);
schedule();
@@ -1110,7 +1179,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
p = find_process_by_pid(pid);
if (p)
jiffies_to_timespec(p->policy & SCHED_FIFO ?
- 0 : NICE_TO_TIMESLICE(p->prio), &t);
+ 0 : NICE_TO_TIMESLICE(p->__nice), &t);
read_unlock(&tasklist_lock);
if (p)
retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1125,7 +1194,7 @@ static void show_task(task_t * p)
static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
printk("%-13.13s ", p->comm);
- state = p->state ? ffz(~p->state) + 1 : 0;
+ state = p->state ? __ffs(p->state) + 1 : 0;
if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
printk(stat_nam[state]);
else
@@ -1233,22 +1302,23 @@ static inline void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2)
spin_unlock(&rq2->lock);
}
-void __init init_idle(void)
+void __init init_idle(task_t *idle, int cpu)
{
- runqueue_t *this_rq = this_rq(), *rq = current->array->rq;
+ runqueue_t *idle_rq = cpu_rq(cpu), *rq = idle->array->rq;
unsigned long flags;
__save_flags(flags);
__cli();
- double_rq_lock(this_rq, rq);
-
- this_rq->curr = this_rq->idle = current;
- deactivate_task(current, rq);
- current->array = NULL;
- current->prio = MAX_PRIO;
- current->state = TASK_RUNNING;
- double_rq_unlock(this_rq, rq);
- current->need_resched = 1;
+ double_rq_lock(idle_rq, rq);
+
+ idle_rq->curr = idle_rq->idle = idle;
+ deactivate_task(idle, rq);
+ idle->array = NULL;
+ idle->prio = MAX_PRIO;
+ idle->state = TASK_RUNNING;
+ idle->cpu = cpu;
+ double_rq_unlock(idle_rq, rq);
+ idle->need_resched = 1;
__restore_flags(flags);
}
@@ -1276,10 +1346,10 @@ void __init sched_init(void)
array->lock = &rq->lock;
for (k = 0; k < MAX_PRIO; k++) {
INIT_LIST_HEAD(array->queue + k);
- __set_bit(k, array->bitmap);
+ __clear_bit(k, array->bitmap);
}
- // zero delimiter for bitsearch
- __clear_bit(MAX_PRIO, array->bitmap);
+ // delimiter for bitsearch
+ __set_bit(MAX_PRIO, array->bitmap);
}
}
/*
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 76ef2fe75..87b604500 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -394,6 +394,7 @@ rebalance:
return NULL;
/* Yield for kswapd, and try again */
+ __set_current_state(TASK_RUNNING);
yield();
goto rebalance;
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 9b4696de8..6e7de5a31 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.83 2001-12-13 09:00:19 davem Exp $
+ * Version: $Id: icmp.c,v 1.84 2002-01-30 01:40:01 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -181,8 +181,7 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
* all layers. All Socketless IP sends will soon be gone.
*/
-struct inode icmp_inode;
-struct socket *icmp_socket = &icmp_inode.u.socket_i;
+struct socket *icmp_socket;
/* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
which is strongly non-reenterable). A bit later it will be made
@@ -979,20 +978,9 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
void __init icmp_init(struct net_proto_family *ops)
{
- int err;
+ int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP, &icmp_socket);
- icmp_inode.i_mode = S_IFSOCK;
- icmp_inode.i_sock = 1;
- icmp_inode.i_uid = 0;
- icmp_inode.i_gid = 0;
- init_waitqueue_head(&icmp_inode.i_wait);
- init_waitqueue_head(&icmp_inode.u.socket_i.wait);
-
- icmp_socket->inode = &icmp_inode;
- icmp_socket->state = SS_UNCONNECTED;
- icmp_socket->type=SOCK_RAW;
-
- if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
+ if (err < 0)
panic("Failed to create the ICMP control socket.\n");
icmp_socket->sk->allocation=GFP_ATOMIC;
icmp_socket->sk->sndbuf = SK_WMEM_MAX*2;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index acd4aacb9..4f8dcdd10 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.238 2002-01-15 08:49:21 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.239 2002-01-30 01:40:01 davem Exp $
*
* IPv4 specific functions
*
@@ -69,8 +69,7 @@ extern int sysctl_ip_dynaddr;
#define ICMP_MIN_LENGTH 8
/* Socket used for sending RSTs */
-static struct inode tcp_inode;
-static struct socket *tcp_socket=&tcp_inode.u.socket_i;
+static struct socket *tcp_socket;
void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
struct sk_buff *skb);
@@ -2194,20 +2193,8 @@ struct proto tcp_prot = {
void __init tcp_v4_init(struct net_proto_family *ops)
{
- int err;
-
- tcp_inode.i_mode = S_IFSOCK;
- tcp_inode.i_sock = 1;
- tcp_inode.i_uid = 0;
- tcp_inode.i_gid = 0;
- init_waitqueue_head(&tcp_inode.i_wait);
- init_waitqueue_head(&tcp_inode.u.socket_i.wait);
-
- tcp_socket->inode = &tcp_inode;
- tcp_socket->state = SS_UNCONNECTED;
- tcp_socket->type=SOCK_RAW;
-
- if ((err=ops->create(tcp_socket, IPPROTO_TCP))<0)
+ int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
+ if (err < 0)
panic("Failed to create the TCP control socket.\n");
tcp_socket->sk->allocation=GFP_ATOMIC;
tcp_socket->sk->protinfo.af_inet.ttl = MAXTTL;