diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS Fri Mar 21 22:39:54 2003
+++ b/CREDITS Tue Apr 8 02:31:12 2003
@@ -2750,6 +2750,10 @@
E: wsalamon@nai.com
D: portions of the Linux Security Module (LSM) framework and security modules
+N: Robert Sanders
+E: gt8134b@prism.gatech.edu
+D: Dosemu
+
N: Duncan Sands
E: duncan.sands@wanadoo.fr
W: http://topo.math.u-psud.fr/~sands
@@ -2757,10 +2761,6 @@
S: 69 rue Dunois
S: 75013 Paris
S: France
-
-N: Robert Sanders
-E: gt8134b@prism.gatech.edu
-D: Dosemu
N: Hannu Savolainen
E: hannu@opensound.com
diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes Sun Feb 9 17:29:37 2003
+++ b/Documentation/Changes Fri Apr 4 09:04:01 2003
@@ -62,6 +62,7 @@
o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
o procps 2.0.9 # ps --version
o oprofile 0.5 # oprofiled --version
+o nfs-utils 1.0.3 # showmount --version
Kernel compilation
==================
diff -Nru a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl
--- a/Documentation/DocBook/usb.tmpl Fri Feb 28 03:44:59 2003
+++ b/Documentation/DocBook/usb.tmpl Wed Apr 2 07:27:30 2003
@@ -100,7 +100,8 @@
USB Host-Side API Model
- Host-side drivers for USB devices talk to the "usbcore" APIs.
+ Within the kernel,
+ host-side drivers for USB devices talk to the "usbcore" APIs.
There are two types of public "usbcore" APIs, targetted at two different
layers of USB driver. Those are
general purpose drivers, exposed through
@@ -287,6 +288,684 @@
!Edrivers/usb/core/hcd.c
!Edrivers/usb/core/hcd-pci.c
!Edrivers/usb/core/buffer.c
+
+
+
+ The USB Filesystem (usbfs)
+
+ This chapter presents the Linux usbfs.
+ You may prefer to avoid avoid writing new kernel code for your
+ USB driver; that's the problem that usbfs set out to solve.
+ User mode device drivers are usually packaged as applications
+ or libraries, and may use usbfs through some programming library
+ that wraps it. Such libraries include
+ libusb
+ for C/C++, and
+ jUSB for Java.
+
+
+ Unfinished
+ This particular documentation is incomplete,
+ especially with respect to the asynchronous mode.
+ As of kernel 2.5.66 the code and this (new) documentation
+ need to be cross-reviewed.
+
+
+
+ Configure usbfs into Linux kernels by enabling the
+ USB filesystem option (CONFIG_USB_DEVICEFS),
+ and you get basic support for user mode USB device drivers.
+ Until relatively recently it was often (confusingly) called
+ usbdevfs although it wasn't solving what
+ devfs was.
+ Every USB device will appear in usbfs, regardless of whether or
+ not it has a kernel driver; but only devices with kernel drivers
+ show up in devfs.
+
+
+
+ What files are in "usbfs"?
+
+ Conventionally mounted at
+ /proc/bus/usb, usbfs
+ features include:
+
+ /proc/bus/usb/devices
+ ... a text file
+ showing each of the USB devices on known to the kernel,
+ and their configuration descriptors.
+ You can also poll() this to learn about new devices.
+
+ /proc/bus/usb/BBB/DDD
+ ... magic files
+ exposing the each device's configuration descriptors, and
+ supporting a series of ioctls for making device requests,
+ including I/O to devices. (Purely for access by programs.)
+
+
+
+
+ Each bus is given a number (BBB) based on when it was
+ enumerated; within each bus, each device is given a similar
+ number (DDD).
+ Those BBB/DDD paths are not "stable" identifiers;
+ expect them to change even if you always leave the devices
+ plugged in to the same hub port.
+ Don't even think of saving these in application
+ configuration files.
+ Stable identifiers are available, for user mode applications
+ that want to use them. HID and networking devices expose
+ these IDs.
+
+
+
+
+
+ Mounting and Access Control
+
+ There are a number of mount options for usbfs, which will
+ be of most interest to you if you need to override the default
+ access control policy.
+ That policy is that only root may read or write device files
+ (/proc/bus/BBB/DDD) although anyone may read
+ the devices
+ or drivers files.
+ I/O requests to the device also need the CAP_SYS_RAWIO capability,
+
+
+ The significance of that is that by default, all user mode
+ device drivers need super-user privileges.
+ You can change modes or ownership in a driver setup
+ when the device hotplugs, or maye just start the
+ driver right then, as a privileged server (or some activity
+ within one).
+ That's the most secure approach for multi-user systems,
+ but for single user systems ("trusted" by that user)
+ it's more convenient just to grant everyone all access
+ (using the devmode=0666 option)
+ so the driver can start whenever it's needed.
+
+
+ The mount options for usbfs, usable in /etc/fstab or
+ in command line invocations of mount, are:
+
+
+
+ busgid=NNNNN
+ Controls the GID used for the
+ /proc/bus/usb/BBB
+ directories. (Default: 0)
+ busmode=MMM
+ Controls the file mode used for the
+ /proc/bus/usb/BBB
+ directories. (Default: 0555)
+
+ busuid=NNNNN
+ Controls the UID used for the
+ /proc/bus/usb/BBB
+ directories. (Default: 0)
+
+ devgid=NNNNN
+ Controls the GID used for the
+ /proc/bus/usb/BBB/DDD
+ files. (Default: 0)
+ devmode=MMM
+ Controls the file mode used for the
+ /proc/bus/usb/BBB/DDD
+ files. (Default: 0644)
+ devuid=NNNNN
+ Controls the UID used for the
+ /proc/bus/usb/BBB/DDD
+ files. (Default: 0)
+
+ listgid=NNNNN
+ Controls the GID used for the
+ /proc/bus/usb/devices and drivers files.
+ (Default: 0)
+ listmode=MMM
+ Controls the file mode used for the
+ /proc/bus/usb/devices and drivers files.
+ (Default: 0444)
+ listuid=NNNNN
+ Controls the UID used for the
+ /proc/bus/usb/devices and drivers files.
+ (Default: 0)
+
+
+
+
+ Note that many Linux distributions hard-wire the mount options
+ for usbfs in their init scripts, such as
+ /etc/rc.d/rc.sysinit,
+ rather than making it easy to set this per-system
+ policy in /etc/fstab.
+
+
+
+
+
+ /proc/bus/usb/devices
+
+ This file is handy for status viewing tools in user
+ mode, which can scan the text format and ignore most of it.
+ More detailed device status (including class and vendor
+ status) is available from device-specific files.
+ For information about the current format of this file,
+ see the
+ Documentation/usb/proc_usb_info.txt
+ file in your Linux kernel sources.
+
+
+ Otherwise the main use for this file from programs
+ is to poll() it to get notifications of usb devices
+ as they're plugged or unplugged.
+ To see what changed, you'd need to read the file and
+ compare "before" and "after" contents, scan the filesystem,
+ or see its hotplug event.
+
+
+
+
+
+ /proc/bus/usb/BBB/DDD
+
+ Use these files in one of these basic ways:
+
+
+ They can be read,
+ producing first the device descriptor
+ (18 bytes) and then the descriptors for the current configuration.
+ See the USB 2.0 spec for details about those binary data formats.
+ You'll need to convert most multibyte values from little endian
+ format to your native host byte order, although a few of the
+ fields in the device descriptor (both of the BCD-encoded fields,
+ and the vendor and product IDs) will be byteswapped for you.
+ Note that configuration descriptors include descriptors for
+ interfaces, altsettings, endpoints, and maybe additional
+ class descriptors.
+
+
+ Perform USB operations using
+ ioctl() requests to make endpoint I/O
+ requests (synchronously or asynchronously) or manage
+ the device.
+ These requests need the CAP_SYS_RAWIO capability,
+ as well as filesystem access permissions.
+ Only one ioctl request can be made on one of these
+ device files at a time.
+ This means that if you are synchronously reading an endpoint
+ from one thread, you won't be able to write to a different
+ endpoint from another thread until the read completes.
+ This works for half duplex protocols,
+ but otherwise you'd use asynchronous i/o requests.
+
+
+
+
+
+
+ Life Cycle of User Mode Drivers
+
+ Such a driver first needs to find a device file
+ for a device it knows how to handle.
+ Maybe it was told about it because a
+ /sbin/hotplug event handling agent
+ chose that driver to handle the new device.
+ Or maybe it's an application that scans all the
+ /proc/bus/usb device files, and ignores most devices.
+ In either case, it should read() all
+ the descriptors from the device file,
+ and check them against what it knows how to handle.
+ It might just reject everything except a particular
+ vendor and product ID, or need a more complex policy.
+
+
+ Never assume there will only be one such device
+ on the system at a time!
+ If your code can't handle more than one device at
+ a time, at least detect when there's more than one, and
+ have your users choose which device to use.
+
+
+ Once your user mode driver knows what device to use,
+ it interacts with it in either of two styles.
+ The simple style is to make only control requests; some
+ devices don't need more complex interactions than those.
+ (An example might be software using vendor-specific control
+ requests for some initialization or configuration tasks,
+ with a kernel driver for the rest.)
+
+
+ More likely, you need a more complex style driver:
+ one using non-control endpoints, reading or writing data
+ and claiming exclusive use of an interface.
+ Bulk transfers are easiest to use,
+ but only their sibling interrupt transfers
+ work with low speed devices.
+ Both interrupt and isochronous transfers
+ offer service guarantees because their bandwidth is reserved.
+ Such "periodic" transfers are awkward to use through usbfs,
+ unless you're using the asynchronous calls. However, interrupt
+ transfers can also be used in a synchronous "one shot" style.
+
+
+ Your user-mode driver should never need to worry
+ about cleaning up request state when the device is
+ disconnected, although it should close its open file
+ descriptors as soon as it starts seeing the ENODEV
+ errors.
+
+
+
+
+ The ioctl() Requests
+
+ To use these ioctls, you need to include the following
+ headers in your userspace program:
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <asm/byteorder.h>
+ The standard USB device model requests, from "Chapter 9" of
+ the USB 2.0 specification, are automatically included from
+ the <linux/usb_ch9.h> header.
+
+
+ Unless noted otherwise, the ioctl requests
+ described here will
+ update the modification time on the usbfs file to which
+ they are applied (unless they fail).
+ A return of zero indicates success; otherwise, a
+ standard USB error code is returned. (These are
+ documented in
+ Documentation/usb/error-codes.txt
+ in your kernel sources.)
+
+
+ Each of these files multiplexes access to several
+ I/O streams, one per endpoint.
+ Each device has one control endpoint (endpoint zero)
+ which supports a limited RPC style RPC access.
+ Devices are configured
+ by khubd (in the kernel) setting a device-wide
+ configuration that affects things
+ like power consumption and basic functionality.
+ The endpoints are part of USB interfaces,
+ which may have altsettings
+ affecting things like which endpoints are available.
+ Many devices only have a single configuration and interface,
+ so drivers for them will ignore configurations and altsettings.
+
+
+
+
+ Management/Status Requests
+
+ A number of usbfs requests don't deal very directly
+ with device I/O.
+ They mostly relate to device management and status.
+ These are all synchronous requests.
+
+
+
+
+ USBDEVFS_CLAIMINTERFACE
+ This is used to force usbfs to
+ claim a specific interface,
+ which has not previously been claimed by usbfs or any other
+ kernel driver.
+ The ioctl parameter is an integer holding the number of
+ the interface (bInterfaceNumber from descriptor).
+
+ Note that if your driver doesn't claim an interface
+ before trying to use one of its endpoints, and no
+ other driver has bound to it, then the interface is
+ automatically claimed by usbfs.
+
+ This claim will be released by a RELEASEINTERFACE ioctl,
+ or by closing the file descriptor.
+ File modification time is not updated by this request.
+
+
+ USBDEVFS_CONNECTINFO
+ Says whether the device is lowspeed.
+ The ioctl parameter points to a structure like this:
+struct usbdevfs_connectinfo {
+ unsigned int devnum;
+ unsigned char slow;
+};
+ File modification time is not updated by this request.
+
+ You can't tell whether a "not slow"
+ device is connected at high speed (480 MBit/sec)
+ or just full speed (12 MBit/sec).
+ You should know the devnum value already,
+ it's the DDD value of the device file name.
+
+
+ USBDEVFS_GETDRIVER
+ Returns the name of the kernel driver
+ bound to a given interface (a string). Parameter
+ is a pointer to this structure, which is modified:
+struct usbdevfs_getdriver {
+ unsigned int interface;
+ char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+ File modification time is not updated by this request.
+
+
+ USBDEVFS_IOCTL
+ Passes a request from userspace through
+ to a kernel driver that has an ioctl entry in the
+ struct usb_driver it registered.
+struct usbdevfs_ioctl {
+ int ifno;
+ int ioctl_code;
+ void *data;
+};
+
+/* user mode call looks like this.
+ * 'request' becomes the driver->ioctl() 'code' parameter.
+ * the size of 'param' is encoded in 'request', and that data
+ * is copied to or from the driver->ioctl() 'buf' parameter.
+ */
+static int
+usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
+{
+ struct usbdevfs_ioctl wrapper;
+
+ wrapper.ifno = ifno;
+ wrapper.ioctl_code = request;
+ wrapper.data = param;
+
+ return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
+}
+ File modification time is not updated by this request.
+
+ This request lets kernel drivers talk to user mode code
+ through filesystem operations even when they don't create
+ a charactor or block special device.
+ It's also been used to do things like ask devices what
+ device special file should be used.
+ Two pre-defined ioctls are used
+ to disconnect and reconnect kernel drivers, so
+ that user mode code can completely manage binding
+ and configuration of devices.
+
+
+ USBDEVFS_RELEASEINTERFACE
+ This is used to release the claim usbfs
+ made on interface, either implicitly or because of a
+ USBDEVFS_CLAIMINTERFACE call, before the file
+ descriptor is closed.
+ The ioctl parameter is an integer holding the number of
+ the interface (bInterfaceNumber from descriptor);
+ File modification time is not updated by this request.
+
+ No security check is made to ensure
+ that the task which made the claim is the one
+ which is releasing it.
+ This means that user mode driver may interfere
+ other ones.
+
+
+ USBDEVFS_RESETEP
+ Resets the data toggle value for an endpoint
+ (bulk or interrupt) to DATA0.
+ The ioctl parameter is an integer endpoint number
+ (1 to 15, as identified in the endpoint descriptor),
+ with USB_DIR_IN added if the device's endpoint sends
+ data to the host.
+
+ Avoid using this request.
+ It should probably be removed.
+ Using it typically means the device and driver will lose
+ toggle synchronization. If you really lost synchronization,
+ you likely need to completely handshake with the device,
+ using a request like CLEAR_HALT
+ or SET_INTERFACE.
+
+
+
+
+
+
+
+ Synchronous I/O Support
+
+ Synchronous requests involve the kernel blocking
+ until until the user mode request completes, either by
+ finishing successfully or by reporting an error.
+ In most cases this is the simplest way to use usbfs,
+ although as noted above it does prevent performing I/O
+ to more than one endpoint at a time.
+
+
+
+
+ USBDEVFS_BULK
+ Issues a bulk read or write request to the
+ device.
+ The ioctl parameter is a pointer to this structure:
+struct usbdevfs_bulktransfer {
+ unsigned int ep;
+ unsigned int len;
+ unsigned int timeout; /* in milliseconds */
+ void *data;
+};
+ The "ep" value identifies a
+ bulk endpoint number (1 to 15, as identified in an endpoint
+ descriptor),
+ masked with USB_DIR_IN when referring to an endpoint which
+ sends data to the host from the device.
+ The length of the data buffer is identified by "len";
+ Recent kernels support requests up to about 128KBytes.
+ FIXME say how read length is returned,
+ and how short reads are handled..
+
+
+ USBDEVFS_CLEAR_HALT
+ Clears endpoint halt (stall) and
+ resets the endpoint toggle. This is only
+ meaningful for bulk or interrupt endpoints.
+ The ioctl parameter is an integer endpoint number
+ (1 to 15, as identified in an endpoint descriptor),
+ masked with USB_DIR_IN when referring to an endpoint which
+ sends data to the host from the device.
+
+ Use this on bulk or interrupt endpoints which have
+ stalled, returning -EPIPE status
+ to a data transfer request.
+ Do not issue the control request directly, since
+ that could invalidate the host's record of the
+ data toggle.
+
+
+ USBDEVFS_CONTROL
+ Issues a control request to the device.
+ The ioctl parameter points to a structure like this:
+struct usbdevfs_ctrltransfer {
+ __u8 bRequestType;
+ __u8 bRequest;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+ __u32 timeout; /* in milliseconds */
+ void *data;
+};
+
+ The first eight bytes of this structure are the contents
+ of the SETUP packet to be sent to the device; see the
+ USB 2.0 specification for details.
+ The bRequestType value is composed by combining a
+ USB_TYPE_* value, a USB_DIR_* value, and a
+ USB_RECIP_* value (from
+ <linux/usb.h>).
+ If wLength is nonzero, it describes the length of the data
+ buffer, which is either written to the device
+ (USB_DIR_OUT) or read from the device (USB_DIR_IN).
+
+ At this writing, you can't transfer more than 4 KBytes
+ of data to or from a device; usbfs has a limit, and
+ some host controller drivers have a limit.
+ (That's not usually a problem.)
+ Also there's no way to say it's
+ not OK to get a short read back from the device.
+
+
+ USBDEVFS_RESET
+ Does a USB level device reset.
+ The ioctl parameter is ignored.
+ After the reset, this rebinds all device interfaces.
+ File modification time is not updated by this request.
+
+ Avoid using this call
+ until some usbcore bugs get fixed,
+ since it does not fully synchronize device, interface,
+ and driver (not just usbfs) state.
+
+
+ USBDEVFS_SETINTERFACE
+ Sets the alternate setting for an
+ interface. The ioctl parameter is a pointer to a
+ structure like this:
+struct usbdevfs_setinterface {
+ unsigned int interface;
+ unsigned int altsetting;
+};
+ File modification time is not updated by this request.
+
+ Those struct members are from some interface descriptor
+ applying to the the current configuration.
+ The interface number is the bInterfaceNumber value, and
+ the altsetting number is the bAlternateSetting value.
+ (This resets each endpoint in the interface.)
+
+
+ USBDEVFS_SETCONFIGURATION
+ Issues the
+ usb_set_configuration call
+ for the device.
+ The parameter is an integer holding the number of
+ a configuration (bConfigurationValue from descriptor).
+ File modification time is not updated by this request.
+
+ Avoid using this call
+ until some usbcore bugs get fixed,
+ since it does not fully synchronize device, interface,
+ and driver (not just usbfs) state.
+
+
+
+
+
+
+ Asynchronous I/O Support
+
+ As mentioned above, there are situations where it may be
+ important to initiate concurrent operations from user mode code.
+ This is particularly important for periodic transfers
+ (interrupt and isochronous), but it can be used for other
+ kinds of USB requests too.
+ In such cases, the asynchronous requests described here
+ are essential. Rather than submitting one request and having
+ the kernel block until it completes, the blocking is separate.
+
+
+ These requests are packaged into a structure that
+ resembles the URB used by kernel device drivers.
+ (No POSIX Async I/O support here, sorry.)
+ It identifies the endpoint type (USBDEVFS_URB_TYPE_*),
+ endpoint (number, masked with USB_DIR_IN as appropriate),
+ buffer and length, and a user "context" value serving to
+ uniquely identify each request.
+ (It's usually a pointer to per-request data.)
+ Flags can modify requests (not as many as supported for
+ kernel drivers).
+
+
+ Each request can specify a realtime signal number
+ (between SIGRTMIN and SIGRTMAX, inclusive) to request a
+ signal be sent when the request completes.
+
+
+ When usbfs returns these urbs, the status value
+ is updated, and the buffer may have been modified.
+ Except for isochronous transfers, the actual_length is
+ updated to say how many bytes were transferred; if the
+ USBDEVFS_URB_DISABLE_SPD flag is set
+ ("short packets are not OK"), if fewer bytes were read
+ than were requested then you get an error report.
+
+
+struct usbdevfs_iso_packet_desc {
+ unsigned int length;
+ unsigned int actual_length;
+ unsigned int status;
+};
+
+struct usbdevfs_urb {
+ unsigned char type;
+ unsigned char endpoint;
+ int status;
+ unsigned int flags;
+ void *buffer;
+ int buffer_length;
+ int actual_length;
+ int start_frame;
+ int number_of_packets;
+ int error_count;
+ unsigned int signr;
+ void *usercontext;
+ struct usbdevfs_iso_packet_desc iso_frame_desc[];
+};
+
+ For these asynchronous requests, the file modification
+ time reflects when the request was initiated.
+ This contrasts with their use with the synchronous requests,
+ where it reflects when requests complete.
+
+
+
+
+ USBDEVFS_DISCARDURB
+
+ TBS
+ File modification time is not updated by this request.
+
+
+
+ USBDEVFS_DISCSIGNAL
+
+ TBS
+ File modification time is not updated by this request.
+
+
+
+ USBDEVFS_REAPURB
+
+ TBS
+ File modification time is not updated by this request.
+
+
+
+ USBDEVFS_REAPURBNDELAY
+
+ TBS
+ File modification time is not updated by this request.
+
+
+
+ USBDEVFS_SUBMITURB
+
+ TBS
+
+
+
+
+
+
+
+
diff -Nru a/Documentation/io_ordering.txt b/Documentation/io_ordering.txt
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/Documentation/io_ordering.txt Tue Mar 18 02:02:11 2003
@@ -0,0 +1,47 @@
+On some platforms, so-called memory-mapped I/O is weakly ordered. On such
+platforms, driver writers are responsible for ensuring that I/O writes to
+memory-mapped addresses on their device arrive in the order intended. This is
+typically done by reading a 'safe' device or bridge register, causing the I/O
+chipset to flush pending writes to the device before any reads are posted. A
+driver would usually use this technique immediately prior to the exit of a
+critical section of code protected by spinlocks. This would ensure that
+subsequent writes to I/O space arrived only after all prior writes (much like a
+memory barrier op, mb(), only with respect to I/O).
+
+A more concrete example from a hypothetical device driver:
+
+ ...
+CPU A: spin_lock_irqsave(&dev_lock, flags)
+CPU A: val = readl(my_status);
+CPU A: ...
+CPU A: writel(newval, ring_ptr);
+CPU A: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+CPU B: spin_lock_irqsave(&dev_lock, flags)
+CPU B: val = readl(my_status);
+CPU B: ...
+CPU B: writel(newval2, ring_ptr);
+CPU B: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+
+In the case above, the device may receive newval2 before it receives newval,
+which could cause problems. Fixing it is easy enough though:
+
+ ...
+CPU A: spin_lock_irqsave(&dev_lock, flags)
+CPU A: val = readl(my_status);
+CPU A: ...
+CPU A: writel(newval, ring_ptr);
+CPU A: (void)readl(safe_register); /* maybe a config register? */
+CPU A: spin_unlock_irqrestore(&dev_lock, flags)
+ ...
+CPU B: spin_lock_irqsave(&dev_lock, flags)
+CPU B: val = readl(my_status);
+CPU B: ...
+CPU B: writel(newval2, ring_ptr);
+CPU B: (void)readl(safe_register); /* maybe a config register? */
+CPU B: spin_unlock_irqrestore(&dev_lock, flags)
+
+Here, the reads from safe_register will cause the I/O chipset to flush any
+pending writes before actually posting the read to the chipset, preventing
+possible data corruption.
diff -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Thu Mar 20 08:41:10 2003
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Thu Apr 10 03:28:09 2003
@@ -18,8 +18,8 @@
- Dec. 27, 2002
- 0.2 (reborn at Christmas)
+ Mar. 26, 2003
+ 0.3
@@ -30,7 +30,7 @@
- Copyright (c) 2002 Takashi Iwai tiwai@suse.de
+ Copyright (c) 2002, 2003 Takashi Iwai tiwai@suse.de
@@ -1425,11 +1425,11 @@
Resource Allocation
- The allocation of ports and irqs are done via standard kernel
+ The allocation of I/O ports and irqs are done via standard kernel
functions. Unlike ALSA ver.0.5.x., there are no helpers for
that. And these resources must be released in the destructor
- function (see below). Also, on ALSA 0.9.x, you don't need
- allocate (pseudo-)DMA for PCI like 0.5.x.
+ function (see below). Also, on ALSA 0.9.x, you don't need to
+ allocate (pseudo-)DMA for PCI like ALSA 0.5.x.
@@ -1461,7 +1461,7 @@
since irq 0 is valid. The port address and its resource pointer
can be initialized as null by
snd_magic_kcalloc() automatically, so you
- don't have to take care of it.
+ don't have to take care of resetting them.
@@ -2227,79 +2227,157 @@
-
- Operators
-
- OK, now let me explain the detail of each pcm callback
- (ops). In general, every callback must
- return 0 if successful, or a negative number with the error
- number such as -EINVAL at any
- error.
-
-
-
- The callback function takes at least the argument with
- snd_pcm_substream_t pointer. For retrieving the
- chip record from the given substream instance, you can use the
- following macro.
-
-
-
-
-
-
-
-
-
- It's expanded with a magic-cast, so the cast-error is
- automatically checked. You should define chip_t at
- the beginning of the code, since this will be referred in many
- places of pcm and control interfaces.
-
+
+ Runtime Pointer - The Chest of PCM Information
+
+ When the PCM substream is opened, a PCM runtime instance is
+ allocated and assigned to the substream. This pointer is
+ accessible via substream->runtime.
+ This runtime pointer holds the various information; it holds
+ the copy of hw_params and sw_params configurations, the buffer
+ pointers, mmap records, spinlocks, etc. Almost everyhing you
+ need for controlling the PCM can be found there.
+
-
- open callback
-
+
+ The definition of runtime instance is found in
+ <sound/pcm.h>. Here is the
+ copy from the file.
+
- This is called when a pcm substream is opened.
-
+
+ For the operators (callbacks) of each sound driver, most of
+ these records are supposed to be read-only. Only the PCM
+ middle-layer changes / updates these info. The excpetions are
+ the hardware description (hw), interrupt callbacks
+ (transfer_ack_xxx), DMA buffer information, and the private
+ data. Besides, if you use the standard buffer allocation
+ method via snd_pcm_lib_malloc_pages(),
+ you don't need to set the DMA buffer information by yourself.
+
-
- At least, here you have to initialize the runtime hardware
- record. Typically, this is done by like this:
+
+ In the sections below, important records are explained.
+
+
+ Hardware Description
+
+ The hardware descriptor (snd_pcm_hardware_t)
+ contains the definitions of the fundamental hardware
+ configuration. Above all, you'll need to define this in
+
+ the open callback.
+ Note that the runtime instance holds the copy of the
+ descriptor, not the pointer to the existing descriptor. That
+ is, in the open callback, you can modify the copied descriptor
+ (runtime->hw) as you need. For example, if the maximum
+ number of channels is 1 only on some chip models, you can
+ still use the same hardware descriptor and change the
+ channels_max later:
runtime;
-
- runtime->hw = snd_mychip_playback_hw;
- return 0;
- }
+ ...
+ runtime->hw = snd_mychip_playback_hw; // common definition
+ if (chip->model == VERY_OLD_ONE)
+ runtime->hw.channels_max = 1;
]]>
+
- where snd_mychip_playback_hw is the
- pre-defined hardware record.
-
+
+ Typically, you'll have a hardware descriptor like below:
- The similar struct exists on ALSA 0.5.x driver, so you can
- guess the values if you already wrote a driver.
-
-
-
+
+
The info field contains the type and
capabilities of this pcm. The bit flags are defined in
<sound/asound.h> as
@@ -2366,6 +2441,17 @@
must handle the corresponding commands.
+
+ When the PCM substreams can be synchronized (typically,
+ synchorinized start/stop of a playback and a capture streams),
+ you can give SNDRV_PCM_INFO_SYNC_START,
+ too. In this case, you'll need to check the linked-list of
+ PCM substreams in the trigger callback. This will be
+ described in the later section.
+
+
+
+ formats field contains the bit-flags
of supported formats (SNDRV_PCM_FMTBIT_XXX).
@@ -2373,38 +2459,181 @@
bits. In the example above, the signed 16bit little-endian
format is specified.
+
+ rates field contains the bit-flags of
supported rates (SNDRV_PCM_RATE_XXX).
When the chip supports continuous rates, pass
CONTINUOUS bit additionally.
- The pre-defined rate bits are only for typical rates. If your
- chip supports unconventional rates, you need to add
- KNOT bit and set up the
+ The pre-defined rate bits are provided only for typical
+ rates. If your chip supports unconventional rates, you need to add
+ KNOT bit and set up the hardware
constraint manually (explained later).
+
-
- There have been many changes of terminology between
- ALSA 0.5.x and 0.9.x.
- On the ALSA 0.9.x world, period means what is
- known as fragment in the OSS. It's the least
- size of (a part of) the buffer to generate an interrupt.
+
+
+ rate_min and
+ rate_max define the minimal and
+ maximal sample rate. This should correspond somehow to
+ rates bits.
+
+
+
+
+
+ channel_min and
+ channel_max
+ define, as you might already expected, the minimal and maximal
+ number of channels.
+
+
+
+
+
+ buffer_bytes_max defines the
+ maximal buffer size in bytes. There is no
+ buffer_bytes_min field, since
+ it can be calculated from the minimal period size and the
+ minimal number of periods.
+ Meanwhile, period_bytes_min and
+ define the minimal and maximal size of the period in bytes.
+ periods_max and
+ periods_min define the maximal and
+ minimal number of periods in the buffer.
-
- Now, taking the new terminology into account, the other fields
- are self-explanatory (I hope). Please note that here, both
- min/max buffer and period sizes are specified in bytes.
+
+ The period is a term, that corresponds to
+ fragment in the OSS world. The period defines the size at
+ which the PCM interrupt is generated. This size strongly
+ depends on the hardware.
+ Generally, the smaller period size will give you more
+ interrupts, that is, more controls.
+ In the case of capture, this size defines the input latency.
+ On the other hand, the whole buffer size defines the
+ output latency for the playback direction.
+
+
+
+
+
+ There is also a field fifo_size.
+ This specifies the size of the hardware FIFO, but it's not
+ used currently in the driver nor in the alsa-lib. So, you
+ can ignore this field.
+
+
+
+
+
+
+
+ PCM Configurations
+
+ Ok, let's go back again to the PCM runtime records.
+ The most frequently referred records in the runtime instance are
+ the PCM configurations.
+ The PCM configurations are stored on runtime instance
+ after the application sends hw_params data via
+ alsa-lib. There are many fields copied from hw_params and
+ sw_params structs. For example,
+ format holds the format type
+ chosen by the application. This field contains the enum value
+ SNDRV_PCM_FORMAT_XXX.
+
+
+
+ One thing to be noted is that the configured buffer and period
+ sizes are stored in frames in the runtime
+ In the ALSA world, 1 frame = channels * samples-size.
+ For conversion between frames and bytes, you can use the
+ helper functions, frames_to_bytes() and
+ bytes_to_frames().
+
+
+period_size);
+]]>
+
+
-
- Some drivers allocate the private instance for each pcm
- substream. It can be stored in
- substream->runtime->private_data.
- Since it's a void pointer, you
- should use magic-kmalloc and magic-cast for such an object.
+
+ Also, many software parameters (sw_params) are
+ stored in frames, too. Please check the type of the field.
+ snd_pcm_uframes_t is for the frames as unsigned
+ integer while snd_pcm_sframes_t is for the frames
+ as signed integer.
+
+
+
+
+ DMA Buffer Information
+
+ The DMA buffer is defined by the following four fields,
+ dma_area,
+ dma_addr,
+ dma_bytes and
+ dma_private.
+ The dma_area holds the buffer
+ pointer (the logical address). You can call
+ memcpy from/to
+ this pointer. Meanwhile, dma_addr
+ holds the physical address of the buffer. This field is
+ specified only when the buffer is a linear buffer.
+ dma_bytes holds the size of buffer
+ in bytes. dma_private is used for
+ the ALSA DMA allocator.
+
+
+
+ If you use a standard ALSA function,
+ snd_pcm_lib_malloc_pages(), for
+ allocating the buffer, these fields are set by the ALSA middle
+ layer, and you should not change them by
+ yourself. You can read them but not write them.
+ On the other hand, if you want to allocate the buffer by
+ yourself, you'll need to manage it in hw_params callback.
+ At least, dma_bytes is mandatory.
+ dma_area is necessary when the
+ buffer is mmapped. If your driver doesn't support mmap, this
+ field is not necessary. dma_addr
+ is also not mandatory. You can use
+ dma_private as you like, too.
+
+
+
+
+ Running Status
+
+ The running status can be referred via runtime->status.
+ This is the pointer to snd_pcm_mmap_status_t
+ record. For example, you can get the current DMA hardware
+ pointer via runtime->status->hw_ptr.
+
+
+
+ The DMA application pointer can be referred via
+ runtime->control, which points
+ snd_pcm_mmap_control_t record.
+ However, accessing directly to this value is not recommended.
+
+
+
+
+ Private Data
+
+ You can allocate a record for the substream and store it in
+ runtime->private_data. Usually, this
+ done in
+
+ the open callback.
+ Since it's a void pointer, you should use magic-kmalloc and
+ magic-cast for such an object.
@@ -2423,8 +2652,110 @@
- The allocated object must be released in the close callback below.
+ The allocated object must be released in
+
+ the close callback.
+
+
+
+ Interrupt Callbacks
+
+ The field transfer_ack_begin and
+ transfer_ack_end are called at
+ the beginning and the end of
+ snd_pcm_period_elapsed(), respectively.
+
+
+
+
+
+
+ Operators
+
+ OK, now let me explain the detail of each pcm callback
+ (ops). In general, every callback must
+ return 0 if successful, or a negative number with the error
+ number such as -EINVAL at any
+ error.
+
+
+
+ The callback function takes at least the argument with
+ snd_pcm_substream_t pointer. For retrieving the
+ chip record from the given substream instance, you can use the
+ following macro.
+
+
+
+
+
+
+
+
+
+ It's expanded with a magic-cast, so the cast-error is
+ automatically checked. You should define chip_t at
+ the beginning of the code, since this will be referred in many
+ places of pcm and control interfaces.
+
+
+
+ open callback
+
+
+
+
+
+
+
+ This is called when a pcm substream is opened.
+
+
+
+ At least, here you have to initialize the runtime->hw
+ record. Typically, this is done by like this:
+
+
+
+runtime;
+
+ runtime->hw = snd_mychip_playback_hw;
+ return 0;
+ }
+]]>
+
+
+
+ where snd_mychip_playback_hw is the
+ pre-defined hardware description.
+
+
+
+ You can allocate a private data in this callback, as described
+ in
+ Private Data section.
+
+
+
+ If the hardware configuration needs more constraints, set the
+ hardware constraints here, too.
+ See
+ Constraints for more details.
+
@@ -2622,23 +2953,6 @@
- Note that the period and the buffer sizes are stored in
- frames. In the ALSA world, 1 frame = channels
- * samples-size. For conversion between frames and bytes, you
- can use the helper functions,
- frames_to_bytes() and
- bytes_to_frames().
-
-
-
-period_size);
-]]>
-
-
-
-
-
Be careful that this callback will be called many times at
each set up, too.
@@ -5115,6 +5429,217 @@
+
+
+
+
+
+ How To Put Your Driver Into ALSA Tree
+
+ General
+
+ So far, you've learned how to write the driver codes.
+ And you might have a question now: how to put my own
+ driver into the ALSA driver tree?
+ Here (finally :) the standard procedure is described briefly.
+
+
+
+ Suppose that you'll create a new PCI driver for the card
+ xyz. The card module name would be
+ snd-xyz. The new driver is usually put into alsa-driver
+ tree. Then the driver is evaluated, audited and tested
+ by developers and users. After a certain time, the driver
+ will go to alsa-kernel tree and eventually integrated into
+ Linux 2.5 tree.
+
+
+
+ In the following sections, the driver code is supposed
+ to be put into alsa-driver tree. The two cases are assumed:
+ a driver consisting of a single source file and one consisting
+ of several source files.
+
+
+
+
+ Driver with A Single Source File
+
+
+
+
+ Modify alsa-driver/pci/Makefile
+
+
+
+ Suppose you have a file xyz.c. Add the following
+ two lines
+
+
+
+
+
+
+
+
+
+
+ Modify alsa-driver/acore/Makefile
+
+
+
+ Here define the dependent modules.
+
+
+
+
+
+
+ If the driver supports PCM, snd-pcm.o,
+ snd-timer.o and snd-page-alloc.o
+ will be needed.
+
+
+ For rawmidi, snd-rawmidi.o is needed in addition.
+ The MIDI stuff is also related to the sequencer.
+ You'll need to modify alsa-driver/acore/seq/Makefile.
+
+
+
+ For OPL3, snd-hwdep.o is needed, too.
+ It's involved with the sequencer, and as well as rawmidi,
+ you'll need to modify alsa-driver/acore/seq/Makefile
+ and acore/seq/instr/Makefile in addition.
+ Also, a new entry is necessary in
+ alsa-driver/drivers/opl3/Makefile.
+
+
+
+
+
+
+ Modify alsa-driver/utils/Modules.dep
+
+
+
+ Add the module definition for configure, here.
+ The beginning of the line must be a vertical bar, following
+ the card module name (snd-xyz) and the list of its all
+ dependent modules.
+
+
+
+
+
+
+
+
+
+
+
+ Run cvscompile script to re-generate the configure script and
+ build the whole stuff again.
+
+
+
+
+
+
+
+ Drivers with Several Source Files
+
+ Suppose that the driver snd-xyz have several source files.
+ They are located in the new subdirectory,
+ pci/xyz.
+
+
+
+
+ Add a new directory (xyz) to extra-subdir-y list in alsa-driver/pci/Makefile
+
+
+
+
+
+
+
+
+
+
+
+ Under the directory xyz, create a Makefile
+
+
+ Sample Makefile for a driver xyz
+
+
+
+
+
+
+
+
+
+ Modify alsa-driver/acore/Makefile
+
+
+
+ This procedure is as same as in the last section.
+
+
+
+
+
+ Modify alsa-driver/utils/Modules.dep
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Run cvscompile script to re-generate the configure script and
+ build the whole stuff again.
+
+
+
+
+
+
+
diff -Nru a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
--- a/Documentation/sysctl/kernel.txt Mon Feb 3 04:47:54 2003
+++ b/Documentation/sysctl/kernel.txt Wed Apr 9 01:01:38 2003
@@ -204,6 +204,18 @@
==============================================================
+panic_on_oops:
+
+Controls the kernel's behaviour when an oops or BUG is encountered.
+
+0: try to continue operation
+
+1: delay a few seconds (to give klogd time to record the oops output) and
+ then panic. If the `panic' sysctl is also non-zero then the machine will
+ be rebooted.
+
+==============================================================
+
pid_max:
PID allocation wrap value. When the kenrel's next PID value
diff -Nru a/Makefile b/Makefile
--- a/Makefile Mon Apr 7 09:42:21 2003
+++ b/Makefile Sat Apr 12 04:29:29 2003
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 67
-EXTRAVERSION =
+EXTRAVERSION = -bk4
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
@@ -342,17 +342,9 @@
echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
endef
-ifdef CONFIG_SMP
-# Final awk script makes sure per-cpu vars are in per-cpu section, as
-# old gcc (eg egcs 2.92.11) ignores section attribute if uninitialized.
-
-check_per_cpu = $(AWK) -f $(srctree)/scripts/per-cpu-check.awk < System.map
-endif
-
define rule_vmlinux
$(rule_vmlinux__)
$(NM) $@ | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
- $(check_per_cpu)
endef
LDFLAGS_vmlinux += -T arch/$(ARCH)/vmlinux.lds.s
diff -Nru a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
--- a/arch/alpha/kernel/core_cia.c Sun Dec 8 03:50:30 2002
+++ b/arch/alpha/kernel/core_cia.c Thu Apr 3 14:49:57 2003
@@ -610,7 +610,7 @@
*(vip)CIA_IOC_CIA_CNFG = temp;
}
- /* Syncronize with all previous changes. */
+ /* Synchronize with all previous changes. */
mb();
*(vip)CIA_IOC_CIA_REV;
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c Sun Mar 23 17:35:08 2003
+++ b/arch/alpha/kernel/pci.c Thu Apr 3 14:49:57 2003
@@ -230,7 +230,7 @@
void __init
pcibios_fixup_bus(struct pci_bus *bus)
{
- /* Propogate hose info into the subordinate devices. */
+ /* Propagate hose info into the subordinate devices. */
struct pci_controller *hose = bus->sysdata;
struct list_head *ln;
diff -Nru a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
--- a/arch/alpha/kernel/pci_iommu.c Tue Feb 25 09:17:06 2003
+++ b/arch/alpha/kernel/pci_iommu.c Thu Apr 3 14:49:57 2003
@@ -431,7 +431,7 @@
/* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must
be values that were returned from pci_alloc_consistent. SIZE must
be the same as what as passed into pci_alloc_consistent.
- References to the memory and mappings assosciated with CPU_ADDR or
+ References to the memory and mappings associated with CPU_ADDR or
DMA_ADDR past this call are illegal. */
void
diff -Nru a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c
--- a/arch/alpha/kernel/semaphore.c Thu Apr 18 16:23:15 2002
+++ b/arch/alpha/kernel/semaphore.c Thu Apr 3 14:49:57 2003
@@ -122,7 +122,7 @@
long tmp, tmp2, tmp3;
/* We must undo the sem->count down_interruptible decrement
- simultaneously and atomicly with the sem->waking
+ simultaneously and atomically with the sem->waking
adjustment, otherwise we can race with __up. This is
accomplished by doing a 64-bit ll/sc on two 32-bit words.
diff -Nru a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
--- a/arch/alpha/kernel/setup.c Sun Jan 19 01:30:58 2003
+++ b/arch/alpha/kernel/setup.c Thu Apr 3 14:49:57 2003
@@ -486,7 +486,7 @@
notifier_chain_register(&panic_notifier_list, &alpha_panic_block);
#ifdef CONFIG_ALPHA_GENERIC
- /* Assume that we've booted from SRM if we havn't booted from MILO.
+ /* Assume that we've booted from SRM if we haven't booted from MILO.
Detect the later by looking for "MILO" in the system serial nr. */
alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0;
#endif
@@ -569,7 +569,7 @@
#endif
/*
- * Indentify and reconfigure for the current system.
+ * Identify and reconfigure for the current system.
*/
cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
diff -Nru a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
--- a/arch/alpha/kernel/time.c Mon Feb 24 23:13:09 2003
+++ b/arch/alpha/kernel/time.c Thu Apr 3 14:49:57 2003
@@ -331,7 +331,7 @@
/* From John Bowman : allow the values
to settle, as the Update-In-Progress bit going low isn't good
- enough on some hardware. 2ms is our guess; we havn't found
+ enough on some hardware. 2ms is our guess; we haven't found
bogomips yet, but this is close on a 500Mhz box. */
__delay(1000000);
diff -Nru a/arch/alpha/lib/strrchr.S b/arch/alpha/lib/strrchr.S
--- a/arch/alpha/lib/strrchr.S Thu Aug 8 12:28:01 2002
+++ b/arch/alpha/lib/strrchr.S Thu Apr 3 14:49:57 2003
@@ -2,7 +2,7 @@
* arch/alpha/lib/strrchr.S
* Contributed by Richard Henderson (rth@tamu.edu)
*
- * Return the address of the last occurrance of a given character
+ * Return the address of the last occurrence of a given character
* within a null-terminated string, or null if it is not found.
*/
diff -Nru a/arch/alpha/math-emu/math.c b/arch/alpha/math-emu/math.c
--- a/arch/alpha/math-emu/math.c Mon Nov 4 17:29:05 2002
+++ b/arch/alpha/math-emu/math.c Thu Apr 3 14:49:57 2003
@@ -294,7 +294,7 @@
* the appropriate signal to the translated program.
*
* In addition, properly track the exception state in software
- * as described in the Alpha Architectre Handbook section 4.7.7.3.
+ * as described in the Alpha Architecture Handbook section 4.7.7.3.
*/
done:
if (_fex) {
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig Mon Mar 17 21:33:21 2003
+++ b/arch/i386/Kconfig Fri Apr 4 07:22:18 2003
@@ -142,7 +142,7 @@
config M486
bool "486"
help
- Select this for a x486 processor, ether Intel or one of the
+ Select this for a 486 series processor, either 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.
@@ -150,8 +150,8 @@
config M586
bool "586/K5/5x86/6x86/6x86MX"
help
- 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
+ Select this for an 586 or 686 series processor such as the AMD K5,
+ the Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not
assume the RDTSC (Read Time Stamp Counter) instruction.
config M586TSC
@@ -226,28 +226,28 @@
config MCRUSOE
bool "Crusoe"
help
- Select this for Transmeta Crusoe processor. Treats the processor
+ Select this for a Transmeta Crusoe processor. Treats the processor
like a 586 with TSC, and sets some GCC optimization flags (like a
Pentium Pro with no alignment requirements).
config MWINCHIPC6
bool "Winchip-C6"
help
- Select this for a IDT Winchip C6 chip. Linux and GCC
+ Select this for an IDT Winchip C6 chip. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment requirements.
config MWINCHIP2
bool "Winchip-2"
help
- Select this for a IDT Winchip-2. Linux and GCC
+ Select this for an IDT Winchip-2. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment requirements.
config MWINCHIP3D
bool "Winchip-2A/Winchip-3"
help
- Select this for a IDT Winchip-2A or 3. Linux and GCC
+ Select this for an IDT Winchip-2A or 3. Linux and GCC
treat this chip as a 586TSC with some extended instructions
and alignment reqirements. Development kernels also enable
out of order memory stores for this CPU, which can increase
@@ -260,15 +260,15 @@
treat this chip as a generic 586. Whilst the CPU is 686 class,
it lacks the cmov extension which gcc assumes is present when
generating 686 code.
- Note, that Nehemiah (Model 9) and above will not boot with this
- kernel due to them lacking the 3dnow instructions used in earlier
+ Note that Nehemiah (Model 9) and above will not boot with this
+ kernel due to them lacking the 3DNow! instructions used in earlier
incarnations of the CPU.
config MVIAC3_2
bool "VIA C3-2 (Nehemiah)"
help
- Select this for a VIA C3 "Nehemiah". Selecting this enables usage of SSE
- and tells gcc to treat the CPU as a 686.
+ Select this for a VIA C3 "Nehemiah". Selecting this enables usage
+ of SSE and tells gcc to treat the CPU as a 686.
Note, this kernel will not boot on older (pre model 9) C3s.
endchoice
@@ -435,7 +435,8 @@
enable and use it. If you say Y here even though your machine doesn't
have a local APIC, then the kernel will still run with no slowdown at
all. The local APIC supports CPU-generated self-interrupts (timer,
- performance counters), and the NMI watchdog which detects hard lockups.
+ performance counters), and the NMI watchdog which detects hard
+ lockups.
If you have a system with several CPUs, you do not need to say Y
here: the local APIC will be used automatically.
@@ -522,7 +523,7 @@
---help---
This adds a driver to safely access the System Management Mode of
the CPU on Toshiba portables with a genuine Toshiba BIOS. It does
- not work on models with a Pheonix BIOS. The System Management Mode
+ not work on models with a Phoenix BIOS. The System Management Mode
is used to set the BIOS and power saving options on Toshiba portables.
For information on utilities to make use of this driver see the
diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
--- a/arch/i386/boot/setup.S Mon Mar 31 14:29:08 2003
+++ b/arch/i386/boot/setup.S Thu Apr 3 07:46:29 2003
@@ -213,7 +213,7 @@
# Part of above routine, this one just prints ascii al
prtchr: pushw %ax
pushw %cx
- xorb %bh, %bh
+ movw $7,%bx
movw $0x01, %cx
movb $0x0e, %ah
int $0x10
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c Tue Apr 1 08:20:23 2003
+++ b/arch/i386/kernel/apm.c Thu Apr 3 16:12:19 2003
@@ -227,6 +227,8 @@
#include
#include
+#include "io_ports.h"
+
extern spinlock_t i8253_lock;
extern unsigned long get_cmos_time(void);
extern void machine_real_restart(unsigned char *, int);
@@ -295,6 +297,8 @@
*/
#define APM_ZERO_SEGS
+#include "apm.h"
+
/*
* Define to make all _set_limit calls use 64k limits. The APM 1.1 BIOS is
* supposed to provide limit information that it recognizes. Many machines
@@ -556,24 +560,11 @@
unsigned int saved_fs; unsigned int saved_gs;
# define APM_DO_SAVE_SEGS \
savesegment(fs, saved_fs); savesegment(gs, saved_gs)
-# define APM_DO_ZERO_SEGS \
- "pushl %%ds\n\t" \
- "pushl %%es\n\t" \
- "xorl %%edx, %%edx\n\t" \
- "mov %%dx, %%ds\n\t" \
- "mov %%dx, %%es\n\t" \
- "mov %%dx, %%fs\n\t" \
- "mov %%dx, %%gs\n\t"
-# define APM_DO_POP_SEGS \
- "popl %%es\n\t" \
- "popl %%ds\n\t"
# define APM_DO_RESTORE_SEGS \
loadsegment(fs, saved_fs); loadsegment(gs, saved_gs)
#else
# define APM_DECL_SEGS
# define APM_DO_SAVE_SEGS
-# define APM_DO_ZERO_SEGS
-# define APM_DO_POP_SEGS
# define APM_DO_RESTORE_SEGS
#endif
@@ -615,22 +606,7 @@
local_save_flags(flags);
APM_DO_CLI;
APM_DO_SAVE_SEGS;
- /*
- * N.B. We do NOT need a cld after the BIOS call
- * because we always save and restore the flags.
- */
- __asm__ __volatile__(APM_DO_ZERO_SEGS
- "pushl %%edi\n\t"
- "pushl %%ebp\n\t"
- "lcall *%%cs:apm_bios_entry\n\t"
- "setc %%al\n\t"
- "popl %%ebp\n\t"
- "popl %%edi\n\t"
- APM_DO_POP_SEGS
- : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
- "=S" (*esi)
- : "a" (func), "b" (ebx_in), "c" (ecx_in)
- : "memory", "cc");
+ apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi);
APM_DO_RESTORE_SEGS;
local_irq_restore(flags);
cpu_gdt_table[cpu][0x40 / 8] = save_desc_40;
@@ -673,26 +649,7 @@
local_save_flags(flags);
APM_DO_CLI;
APM_DO_SAVE_SEGS;
- {
- int cx, dx, si;
-
- /*
- * N.B. We do NOT need a cld after the BIOS call
- * because we always save and restore the flags.
- */
- __asm__ __volatile__(APM_DO_ZERO_SEGS
- "pushl %%edi\n\t"
- "pushl %%ebp\n\t"
- "lcall *%%cs:apm_bios_entry\n\t"
- "setc %%bl\n\t"
- "popl %%ebp\n\t"
- "popl %%edi\n\t"
- APM_DO_POP_SEGS
- : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
- "=S" (si)
- : "a" (func), "b" (ebx_in), "c" (ecx_in)
- : "memory", "cc");
- }
+ error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax);
APM_DO_RESTORE_SEGS;
local_irq_restore(flags);
cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40;
@@ -1212,11 +1169,11 @@
{
#ifdef INIT_TIMER_AFTER_SUSPEND
/* set the clock to 100 Hz */
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(0x34, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */
udelay(10);
- outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb_p(LATCH & 0xff, PIT_CH0); /* LSB */
udelay(10);
- outb(LATCH >> 8 , 0x40); /* MSB */
+ outb(LATCH >> 8, PIT_CH0); /* MSB */
udelay(10);
#endif
}
diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
--- a/arch/i386/kernel/cpu/common.c Thu Mar 13 15:47:14 2003
+++ b/arch/i386/kernel/cpu/common.c Sun Mar 23 07:55:48 2003
@@ -217,6 +217,10 @@
c->x86_capability[4] = excap;
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
+ if (c->x86 == 0xf) {
+ c->x86 += (tfms >> 20) & 0xff;
+ c->x86_model += ((tfms >> 16) & 0xF) << 4;
+ }
c->x86_mask = tfms & 15;
} else {
/* Have CPUID level 0 only - unheard of */
diff -Nru a/arch/i386/kernel/edd.c b/arch/i386/kernel/edd.c
--- a/arch/i386/kernel/edd.c Tue Jan 21 20:04:15 2003
+++ b/arch/i386/kernel/edd.c Fri Apr 4 17:08:17 2003
@@ -598,7 +598,7 @@
.default_attrs = def_attrs,
};
-static decl_subsys(edd,&ktype_edd);
+static decl_subsys(edd,&ktype_edd,NULL);
/**
diff -Nru a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
--- a/arch/i386/kernel/i387.c Mon Mar 10 10:20:30 2003
+++ b/arch/i386/kernel/i387.c Tue Apr 8 22:45:37 2003
@@ -40,10 +40,10 @@
tsk->thread.i387.fxsave.mxcsr = 0x1f80;
} else {
memset(&tsk->thread.i387.fsave, 0, sizeof(struct i387_fsave_struct));
- tsk->thread.i387.fsave.cwd = 0xffff037f;
- tsk->thread.i387.fsave.swd = 0xffff0000;
- tsk->thread.i387.fsave.twd = 0xffffffff;
- tsk->thread.i387.fsave.fos = 0xffff0000;
+ tsk->thread.i387.fsave.cwd = 0xffff037fu;
+ tsk->thread.i387.fsave.swd = 0xffff0000u;
+ tsk->thread.i387.fsave.twd = 0xffffffffu;
+ tsk->thread.i387.fsave.fos = 0xffff0000u;
}
tsk->used_math = 1;
}
@@ -98,7 +98,7 @@
struct _fpxreg *st = NULL;
unsigned long twd = (unsigned long) fxsave->twd;
unsigned long tag;
- unsigned long ret = 0xffff0000;
+ unsigned long ret = 0xffff0000u;
int i;
#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
@@ -183,7 +183,7 @@
if ( cpu_has_fxsr ) {
tsk->thread.i387.fxsave.cwd = cwd;
} else {
- tsk->thread.i387.fsave.cwd = ((long)cwd | 0xffff0000);
+ tsk->thread.i387.fsave.cwd = ((long)cwd | 0xffff0000u);
}
}
@@ -192,7 +192,7 @@
if ( cpu_has_fxsr ) {
tsk->thread.i387.fxsave.swd = swd;
} else {
- tsk->thread.i387.fsave.swd = ((long)swd | 0xffff0000);
+ tsk->thread.i387.fsave.swd = ((long)swd | 0xffff0000u);
}
}
@@ -201,7 +201,7 @@
if ( cpu_has_fxsr ) {
tsk->thread.i387.fxsave.twd = twd_i387_to_fxsr(twd);
} else {
- tsk->thread.i387.fsave.twd = ((long)twd | 0xffff0000);
+ tsk->thread.i387.fsave.twd = ((long)twd | 0xffff0000u);
}
}
@@ -216,16 +216,16 @@
* FXSR floating point environment conversions.
*/
-static int convert_fxsr_to_user( struct _fpstate *buf,
+static int convert_fxsr_to_user( struct _fpstate __user *buf,
struct i387_fxsave_struct *fxsave )
{
unsigned long env[7];
- struct _fpreg *to;
+ struct _fpreg __user *to;
struct _fpxreg *from;
int i;
- env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
- env[1] = (unsigned long)fxsave->swd | 0xffff0000;
+ env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
+ env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
env[2] = twd_fxsr_to_i387(fxsave);
env[3] = fxsave->fip;
env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
@@ -250,11 +250,11 @@
}
static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
- struct _fpstate *buf )
+ struct _fpstate __user *buf )
{
unsigned long env[7];
struct _fpxreg *to;
- struct _fpreg *from;
+ struct _fpreg __user *from;
int i;
if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
@@ -264,7 +264,7 @@
fxsave->swd = (unsigned short)(env[1] & 0xffff);
fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
fxsave->fip = env[3];
- fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
+ fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
fxsave->fcs = (env[4] & 0xffff);
fxsave->foo = env[5];
fxsave->fos = env[6];
@@ -275,9 +275,9 @@
unsigned long *t = (unsigned long *)to;
unsigned long *f = (unsigned long *)from;
- if (__get_user(*f, t) ||
- __get_user(*(f + 1), t + 1) ||
- __get_user(from->exponent, &to->exponent))
+ if (__get_user(*t, f) ||
+ __get_user(*(t + 1), f + 1) ||
+ __get_user(to->exponent, &from->exponent))
return 1;
}
return 0;
@@ -287,7 +287,7 @@
* Signal frame handlers.
*/
-static inline int save_i387_fsave( struct _fpstate *buf )
+static inline int save_i387_fsave( struct _fpstate __user *buf )
{
struct task_struct *tsk = current;
@@ -299,7 +299,7 @@
return 1;
}
-static int save_i387_fxsave( struct _fpstate *buf )
+static int save_i387_fxsave( struct _fpstate __user *buf )
{
struct task_struct *tsk = current;
int err = 0;
@@ -320,7 +320,7 @@
return 1;
}
-int save_i387( struct _fpstate *buf )
+int save_i387( struct _fpstate __user *buf )
{
if ( !current->used_math )
return 0;
@@ -341,7 +341,7 @@
}
}
-static inline int restore_i387_fsave( struct _fpstate *buf )
+static inline int restore_i387_fsave( struct _fpstate __user *buf )
{
struct task_struct *tsk = current;
clear_fpu( tsk );
@@ -349,7 +349,7 @@
sizeof(struct i387_fsave_struct) );
}
-static int restore_i387_fxsave( struct _fpstate *buf )
+static int restore_i387_fxsave( struct _fpstate __user *buf )
{
int err;
struct task_struct *tsk = current;
@@ -361,7 +361,7 @@
return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
}
-int restore_i387( struct _fpstate *buf )
+int restore_i387( struct _fpstate __user *buf )
{
int err;
@@ -382,21 +382,21 @@
* ptrace request handlers.
*/
-static inline int get_fpregs_fsave( struct user_i387_struct *buf,
+static inline int get_fpregs_fsave( struct user_i387_struct __user *buf,
struct task_struct *tsk )
{
return __copy_to_user( buf, &tsk->thread.i387.fsave,
sizeof(struct user_i387_struct) );
}
-static inline int get_fpregs_fxsave( struct user_i387_struct *buf,
+static inline int get_fpregs_fxsave( struct user_i387_struct __user *buf,
struct task_struct *tsk )
{
- return convert_fxsr_to_user( (struct _fpstate *)buf,
+ return convert_fxsr_to_user( (struct _fpstate __user *)buf,
&tsk->thread.i387.fxsave );
}
-int get_fpregs( struct user_i387_struct *buf, struct task_struct *tsk )
+int get_fpregs( struct user_i387_struct __user *buf, struct task_struct *tsk )
{
if ( HAVE_HWFP ) {
if ( cpu_has_fxsr ) {
@@ -406,25 +406,25 @@
}
} else {
return save_i387_soft( &tsk->thread.i387.soft,
- (struct _fpstate *)buf );
+ (struct _fpstate __user *)buf );
}
}
static inline int set_fpregs_fsave( struct task_struct *tsk,
- struct user_i387_struct *buf )
+ struct user_i387_struct __user *buf )
{
return __copy_from_user( &tsk->thread.i387.fsave, buf,
sizeof(struct user_i387_struct) );
}
static inline int set_fpregs_fxsave( struct task_struct *tsk,
- struct user_i387_struct *buf )
+ struct user_i387_struct __user *buf )
{
return convert_fxsr_from_user( &tsk->thread.i387.fxsave,
- (struct _fpstate *)buf );
+ (struct _fpstate __user *)buf );
}
-int set_fpregs( struct task_struct *tsk, struct user_i387_struct *buf )
+int set_fpregs( struct task_struct *tsk, struct user_i387_struct __user *buf )
{
if ( HAVE_HWFP ) {
if ( cpu_has_fxsr ) {
@@ -434,14 +434,14 @@
}
} else {
return restore_i387_soft( &tsk->thread.i387.soft,
- (struct _fpstate *)buf );
+ (struct _fpstate __user *)buf );
}
}
-int get_fpxregs( struct user_fxsr_struct *buf, struct task_struct *tsk )
+int get_fpxregs( struct user_fxsr_struct __user *buf, struct task_struct *tsk )
{
if ( cpu_has_fxsr ) {
- if (__copy_to_user( (void *)buf, &tsk->thread.i387.fxsave,
+ if (__copy_to_user( buf, &tsk->thread.i387.fxsave,
sizeof(struct user_fxsr_struct) ))
return -EFAULT;
return 0;
@@ -450,10 +450,10 @@
}
}
-int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct *buf )
+int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct __user *buf )
{
if ( cpu_has_fxsr ) {
- __copy_from_user( &tsk->thread.i387.fxsave, (void *)buf,
+ __copy_from_user( &tsk->thread.i387.fxsave, buf,
sizeof(struct user_fxsr_struct) );
/* mxcsr bit 6 and 31-16 must be zero for security reasons */
tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c Mon Apr 7 09:41:51 2003
+++ b/arch/i386/kernel/io_apic.c Mon Apr 7 16:40:21 2003
@@ -38,6 +38,8 @@
#include
+#include "io_ports.h"
+
#undef APIC_LOCKUP_DEBUG
#define APIC_LOCKUP_DEBUG
@@ -2135,7 +2137,7 @@
* Additionally, something is definitely wrong with irq9
* on PIIX4 boards.
*/
-#define PIC_IRQS (1<<2)
+#define PIC_IRQS (1 << PIC_CASCADE_IR)
void __init setup_IO_APIC(void)
{
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c Tue Feb 11 04:25:29 2003
+++ b/arch/i386/kernel/signal.c Tue Apr 8 21:33:40 2003
@@ -53,7 +53,7 @@
}
asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
{
struct pt_regs * regs = (struct pt_regs *) &unewset;
sigset_t saveset, newset;
@@ -82,8 +82,8 @@
}
asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction *act,
- struct old_sigaction *oact)
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+ struct old_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
int ret;
@@ -148,7 +148,7 @@
};
static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax)
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
{
unsigned int err = 0;
@@ -192,7 +192,7 @@
}
{
- struct _fpstate * buf;
+ struct _fpstate __user * buf;
err |= __get_user(buf, &sc->fpstate);
if (buf) {
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
@@ -211,7 +211,7 @@
asmlinkage int sys_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct pt_regs *) &__unused;
- struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
+ struct sigframe __user *frame = (struct sigframe __user *)(regs->esp - 8);
sigset_t set;
int eax;
@@ -241,7 +241,7 @@
asmlinkage int sys_rt_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct pt_regs *) &__unused;
- struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4);
+ struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs->esp - 4);
sigset_t set;
stack_t st;
int eax;
@@ -278,7 +278,7 @@
*/
static int
-setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate,
+setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
struct pt_regs *regs, unsigned long mask)
{
int tmp, err = 0;
@@ -323,7 +323,7 @@
/*
* Determine which stack to use..
*/
-static inline void *
+static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
{
unsigned long esp;
@@ -344,14 +344,14 @@
esp = (unsigned long) ka->sa.sa_restorer;
}
- return (void *)((esp - frame_size) & -8ul);
+ return (void __user *)((esp - frame_size) & -8ul);
}
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs)
{
void *restorer;
- struct sigframe *frame;
+ struct sigframe __user *frame;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
@@ -373,7 +373,7 @@
goto give_sigsegv;
if (_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
+ err |= __copy_to_user(&frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err)
@@ -428,7 +428,7 @@
sigset_t *set, struct pt_regs * regs)
{
void *restorer;
- struct rt_sigframe *frame;
+ struct rt_sigframe __user *frame;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c Thu Mar 27 21:15:25 2003
+++ b/arch/i386/kernel/smpboot.c Tue Apr 8 11:19:15 2003
@@ -49,10 +49,10 @@
#include
#include
#include
-#include "smpboot_hooks.h"
#include
#include
+#include
/* Set if we find a B stepping CPU */
static int __initdata smp_b_stepping;
@@ -823,13 +823,7 @@
store_NMI_vector(&nmi_high, &nmi_low);
- CMOS_WRITE(0xa, 0xf);
- local_flush_tlb();
- Dprintk("1.\n");
- *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
- Dprintk("2.\n");
- *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
- Dprintk("3.\n");
+ smpboot_setup_warm_reset_vector(start_eip);
/*
* Starting actual IPI sequence...
@@ -1045,7 +1039,7 @@
/*
* Cleanup possible dangling ends...
*/
- smpboot_setup_warm_reset_vector();
+ smpboot_restore_warm_reset_vector();
/*
* Allow the user to impress friends.
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- a/arch/i386/kernel/suspend.c Mon Feb 24 10:30:22 2003
+++ b/arch/i386/kernel/suspend.c Thu Apr 3 15:03:46 2003
@@ -16,7 +16,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c Mon Mar 17 21:33:07 2003
+++ b/arch/i386/kernel/traps.c Wed Apr 9 01:01:38 2003
@@ -257,6 +257,15 @@
show_registers(regs);
bust_spinlocks(0);
spin_unlock_irq(&die_lock);
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops) {
+ printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(5 * HZ);
+ panic("Fatal exception");
+ }
do_exit(SIGSEGV);
}
diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c Tue Apr 1 15:26:40 2003
+++ b/arch/i386/kernel/vm86.c Thu Apr 3 07:48:45 2003
@@ -30,6 +30,7 @@
*
*/
+#include
#include
#include
#include
@@ -725,7 +726,7 @@
void release_x86_irqs(struct task_struct *task)
{
int i;
- for (i=3; i<16; i++)
+ for (i = FIRST_VM86_IRQ ; i <= LAST_VM86_IRQ; i++)
if (vm86_irqs[i].tsk == task)
free_vm86_irq(i);
}
@@ -735,7 +736,7 @@
int bit;
unsigned long flags;
- if ( (irqnumber<3) || (irqnumber>15) ) return 0;
+ if (invalid_vm86_irq(irqnumber)) return 0;
if (vm86_irqs[irqnumber].tsk != current) return 0;
spin_lock_irqsave(&irqbits_lock, flags);
bit = irqbits & (1 << irqnumber);
@@ -760,7 +761,7 @@
int irq = irqnumber & 255;
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM;
- if ( (irq<3) || (irq>15) ) return -EPERM;
+ if (invalid_vm86_irq(irq)) return -EPERM;
if (vm86_irqs[irq].tsk) return -EPERM;
ret = request_irq(irq, &irq_handler, 0, VM86_IRQNAME, 0);
if (ret) return ret;
@@ -769,7 +770,7 @@
return irq;
}
case VM86_FREE_IRQ: {
- if ( (irqnumber<3) || (irqnumber>15) ) return -EPERM;
+ if (invalid_vm86_irq(irqnumber)) return -EPERM;
if (!vm86_irqs[irqnumber].tsk) return 0;
if (vm86_irqs[irqnumber].tsk != current) return -EPERM;
free_vm86_irq(irqnumber);
diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig
--- a/arch/ia64/Kconfig Sat Mar 8 14:50:37 2003
+++ b/arch/ia64/Kconfig Tue Apr 8 12:03:12 2003
@@ -401,6 +401,15 @@
endchoice
+config IA64_PAL_IDLE
+ bool "Use PAL_HALT_LIGHT in idle loop"
+ ---help---
+ Say Y here to enable use of PAL_HALT_LIGHT in the cpu_idle loop.
+ This allows the CPU to enter a low power state when idle. You
+ can enable CONFIG_IA64_PALINFO and check /proc/pal/cpu0/power_info
+ to see the power consumption and latency for this state. If you're
+ unsure your firmware supports it, answer N.
+
config SMP
bool "SMP support"
---help---
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile Mon Feb 24 05:40:16 2003
+++ b/arch/ia64/Makefile Wed Mar 26 08:30:43 2003
@@ -14,6 +14,7 @@
OBJCOPYFLAGS := --strip-all
LDFLAGS_vmlinux := -static
+LDFLAGS_MODULE += -T arch/ia64/module.lds
AFLAGS_KERNEL := -mconstant-gp
EXTRA :=
@@ -23,7 +24,7 @@
GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
-GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC))
+GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC) $(OBJDUMP))
ifeq ($(GAS_STATUS),buggy)
$(error Sorry, you need a newer version of the assember, one that is built from \
@@ -50,11 +51,8 @@
core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ arch/ia64/hp/common/ arch/ia64/hp/zx1/ \
arch/ia64/hp/sim/
core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
-core-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/kernel/ \
- arch/ia64/sn/io/ \
- arch/ia64/sn/io/sn2/ \
- arch/ia64/sn/io/sn2/pcibr/ \
- arch/ia64/sn/kernel/sn2/
+core-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/
+
drivers-$(CONFIG_PCI) += arch/ia64/pci/
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
diff -Nru a/arch/ia64/boot/Makefile b/arch/ia64/boot/Makefile
--- a/arch/ia64/boot/Makefile Sun Mar 9 13:47:41 2003
+++ b/arch/ia64/boot/Makefile Tue Apr 8 12:03:12 2003
@@ -9,7 +9,6 @@
#
targets-$(CONFIG_IA64_HP_SIM) += bootloader
-targets-$(CONFIG_IA64_GENERIC) += bootloader
targets := vmlinux.bin vmlinux.gz $(targets-y)
quiet_cmd_cptotop = LN $@
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c Tue Feb 4 17:06:01 2003
+++ b/arch/ia64/hp/common/sba_iommu.c Thu Apr 3 12:32:33 2003
@@ -1497,7 +1497,7 @@
ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
- sprintf(buf, "%s rev %d.%d\n", "Hewlett Packard zx1 SBA",
+ sprintf(buf, "%s rev %d.%d\n", "Hewlett-Packard zx1 SBA",
((sba_dev->hw_rev >> 4) & 0xF), (sba_dev->hw_rev & 0xF));
sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", buf,
(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ total_pages);
diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
--- a/arch/ia64/ia32/ia32_entry.S Sat Mar 8 11:30:11 2003
+++ b/arch/ia64/ia32/ia32_entry.S Sun Mar 9 01:34:44 2003
@@ -253,7 +253,7 @@
data8 sys_umount /* recycled never used phys( */
data8 sys32_ni_syscall /* old lock syscall holder */
data8 sys32_ioctl
- data8 sys32_fcntl /* 55 */
+ data8 compat_sys_fcntl /* 55 */
data8 sys32_ni_syscall /* old mpx syscall holder */
data8 sys_setpgid
data8 sys32_ni_syscall /* old ulimit syscall holder */
@@ -419,7 +419,7 @@
data8 sys_mincore
data8 sys_madvise
data8 sys_getdents64 /* 220 */
- data8 sys32_fcntl64
+ data8 compat_sys_fcntl64
data8 sys_ni_syscall /* reserved for TUX */
data8 sys_ni_syscall /* reserved for Security */
data8 sys_gettid
diff -Nru a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
--- a/arch/ia64/ia32/ia32_signal.c Tue Feb 25 02:41:21 2003
+++ b/arch/ia64/ia32/ia32_signal.c Wed Apr 9 11:51:33 2003
@@ -114,6 +114,7 @@
int
copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from)
{
+ unsigned int addr;
int err;
if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32)))
@@ -147,6 +148,12 @@
case __SI_POLL >> 16:
err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_TIMER >> 16:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ addr = (unsigned long) from->si_ptr;
+ err |= __put_user(addr, &to->si_ptr);
break;
/* case __SI_RT: This is not generated by the kernel as of now. */
}
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c Sun Mar 23 14:36:29 2003
+++ b/arch/ia64/ia32/sys_ia32.c Wed Apr 9 11:51:34 2003
@@ -119,10 +119,8 @@
asmlinkage long
sys32_execve (char *filename, unsigned int argv, unsigned int envp,
- int dummy3, int dummy4, int dummy5, int dummy6, int dummy7,
- int stack)
+ struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *)&stack;
unsigned long old_map_base, old_task_size, tssd;
char **av, **ae;
int na, ne, len;
@@ -1701,7 +1699,7 @@
return shmctl32(first, second, (void *)AA(ptr));
default:
- return -EINVAL;
+ return -ENOSYS;
}
return -EINVAL;
}
@@ -2156,26 +2154,23 @@
ret = -ESRCH;
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = -EPERM;
if (pid == 1) /* no messing around with init! */
- goto out;
+ goto out_tsk;
if (request == PTRACE_ATTACH) {
ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack);
- goto out;
- }
- ret = -ESRCH;
- if (!(child->ptrace & PT_PTRACED))
- goto out;
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
- goto out;
+ goto out_tsk;
}
- if (child->parent != current)
- goto out;
+
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0)
+ goto out_tsk;
switch (request) {
case PTRACE_PEEKTEXT:
@@ -2185,12 +2180,12 @@
ret = put_user(value, (unsigned int *) A(data));
else
ret = -EIO;
- goto out;
+ goto out_tsk;
case PTRACE_POKETEXT:
case PTRACE_POKEDATA: /* write the word at location addr */
ret = ia32_poke(regs, child, addr, data);
- goto out;
+ goto out_tsk;
case PTRACE_PEEKUSR: /* read word at addr in USER area */
ret = -EIO;
@@ -2265,43 +2260,13 @@
break;
}
+ out_tsk:
+ put_task_struct(child);
out:
unlock_kernel();
return ret;
}
-extern asmlinkage long sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg);
-
-asmlinkage long
-sys32_fcntl (unsigned int fd, unsigned int cmd, unsigned int arg)
-{
- mm_segment_t old_fs;
- struct flock f;
- long ret;
-
- switch (cmd) {
- case F_GETLK:
- case F_SETLK:
- case F_SETLKW:
- if (get_compat_flock(&f, (struct compat_flock *) A(arg)))
- return -EFAULT;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = sys_fcntl(fd, cmd, (unsigned long) &f);
- set_fs(old_fs);
- if (cmd == F_GETLK && put_compat_flock(&f, (struct compat_flock *) A(arg)))
- return -EFAULT;
- return ret;
-
- default:
- /*
- * `sys_fcntl' lies about arg, for the F_SETOWN
- * sub-function arg can have a negative value.
- */
- return sys_fcntl(fd, cmd, arg);
- }
-}
-
asmlinkage long sys_ni_syscall(void);
asmlinkage long
@@ -2593,66 +2558,6 @@
set_fs(KERNEL_DS);
ret = sys_setgroups(gidsetsize, gl);
set_fs(old_fs);
- return ret;
-}
-
-/*
- * Unfortunately, the x86 compiler aligns variables of type "long long" to a 4 byte boundary
- * only, which means that the x86 version of "struct flock64" doesn't match the ia64 version
- * of struct flock.
- */
-
-static inline long
-ia32_put_flock (struct flock *l, unsigned long addr)
-{
- return (put_user(l->l_type, (short *) addr)
- | put_user(l->l_whence, (short *) (addr + 2))
- | put_user(l->l_start, (long *) (addr + 4))
- | put_user(l->l_len, (long *) (addr + 12))
- | put_user(l->l_pid, (int *) (addr + 20)));
-}
-
-static inline long
-ia32_get_flock (struct flock *l, unsigned long addr)
-{
- unsigned int start_lo, start_hi, len_lo, len_hi;
- int err = (get_user(l->l_type, (short *) addr)
- | get_user(l->l_whence, (short *) (addr + 2))
- | get_user(start_lo, (int *) (addr + 4))
- | get_user(start_hi, (int *) (addr + 8))
- | get_user(len_lo, (int *) (addr + 12))
- | get_user(len_hi, (int *) (addr + 16))
- | get_user(l->l_pid, (int *) (addr + 20)));
- l->l_start = ((unsigned long) start_hi << 32) | start_lo;
- l->l_len = ((unsigned long) len_hi << 32) | len_lo;
- return err;
-}
-
-asmlinkage long
-sys32_fcntl64 (unsigned int fd, unsigned int cmd, unsigned int arg)
-{
- mm_segment_t old_fs;
- struct flock f;
- long ret;
-
- switch (cmd) {
- case F_GETLK64:
- case F_SETLK64:
- case F_SETLKW64:
- if (ia32_get_flock(&f, arg))
- return -EFAULT;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = sys_fcntl(fd, cmd, (unsigned long) &f);
- set_fs(old_fs);
- if (cmd == F_GETLK && ia32_put_flock(&f, arg))
- return -EFAULT;
- break;
-
- default:
- ret = sys32_fcntl(fd, cmd, arg);
- break;
- }
return ret;
}
diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
--- a/arch/ia64/kernel/Makefile Sun Mar 9 14:15:54 2003
+++ b/arch/ia64/kernel/Makefile Tue Apr 8 12:03:13 2003
@@ -4,16 +4,15 @@
extra-y := head.o init_task.o
-obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o \
- irq.o irq_ia64.o irq_lsapic.o ivt.o \
- machvec.o pal.o process.o perfmon.o ptrace.o sal.o \
- semaphore.o setup.o \
- signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
+obj-y := acpi.o entry.o efi.o efi_stub.o gate.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o \
+ ivt.o machvec.o pal.o perfmon.o process.o ptrace.o sal.o semaphore.o setup.o signal.o \
+ sys_ia64.o time.o traps.o unaligned.o unwind.o
-obj-$(CONFIG_FSYS) += fsys.o
-obj-$(CONFIG_IOSAPIC) += iosapic.o
-obj-$(CONFIG_IA64_PALINFO) += palinfo.o
-obj-$(CONFIG_EFI_VARS) += efivars.o
-obj-$(CONFIG_SMP) += smp.o smpboot.o
-obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o
-obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
+obj-$(CONFIG_EFI_VARS) += efivars.o
+obj-$(CONFIG_FSYS) += fsys.o
+obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
+obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o
+obj-$(CONFIG_IA64_PALINFO) += palinfo.o
+obj-$(CONFIG_IOSAPIC) += iosapic.o
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_SMP) += smp.o smpboot.o
diff -Nru a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/kernel/acpi-ext.c Thu Apr 3 12:32:33 2003
@@ -0,0 +1,71 @@
+/*
+ * arch/ia64/kernel/acpi-ext.c
+ *
+ * Copyright (C) 2003 Hewlett-Packard
+ * Copyright (C) Alex Williamson
+ *
+ * Vendor specific extensions to ACPI. These are used by both
+ * HP and NEC.
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+
+/*
+ * Note: Strictly speaking, this is only needed for HP and NEC machines.
+ * However, NEC machines identify themselves as DIG-compliant, so there is
+ * no easy way to #ifdef this out.
+ */
+acpi_status
+hp_acpi_csr_space (acpi_handle obj, u64 *csr_base, u64 *csr_length)
+{
+ int i, offset = 0;
+ acpi_status status;
+ struct acpi_buffer buf;
+ struct acpi_resource_vendor *res;
+ struct acpi_hp_vendor_long *hp_res;
+ efi_guid_t vendor_guid;
+
+ *csr_base = 0;
+ *csr_length = 0;
+
+ status = acpi_get_crs(obj, &buf);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
+ return status;
+ }
+
+ res = (struct acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
+ if (!res) {
+ printk(KERN_ERR PREFIX "Failed to find config space for device\n");
+ acpi_dispose_crs(&buf);
+ return AE_NOT_FOUND;
+ }
+
+ hp_res = (struct acpi_hp_vendor_long *)(res->reserved);
+
+ if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
+ printk(KERN_ERR PREFIX "Unknown Vendor data\n");
+ acpi_dispose_crs(&buf);
+ return AE_TYPE; /* Revisit error? */
+ }
+
+ memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
+ if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
+ printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
+ acpi_dispose_crs(&buf);
+ return AE_TYPE; /* Revisit error? */
+ }
+
+ for (i = 0 ; i < 8 ; i++) {
+ *csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
+ *csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
+ }
+
+ acpi_dispose_crs(&buf);
+ return AE_OK;
+}
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c Thu Mar 6 22:21:39 2003
+++ b/arch/ia64/kernel/acpi.c Tue Apr 1 07:20:36 2003
@@ -9,7 +9,7 @@
* Copyright (C) 2000,2001 J.I. Lee
* Copyright (C) 2001 Paul Diefenbaugh
* Copyright (C) 2001 Jenna Hall
- * Copyright (C) 2001 Takayoshi Kochi
+ * Copyright (C) 2001 Takayoshi Kochi
* Copyright (C) 2002 Erich Focht
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -109,8 +109,6 @@
return "sn2";
# elif defined (CONFIG_IA64_DIG)
return "dig";
-# elif defined (CONFIG_IA64_HP_ZX1)
- return "hpzx1";
# else
# error Unknown platform. Fix acpi.c.
# endif
@@ -176,6 +174,73 @@
kfree(buf->pointer);
}
+void
+acpi_get_crs_addr (struct acpi_buffer *buf, int type, u64 *base, u64 *size, u64 *tra)
+{
+ int offset = 0;
+ struct acpi_resource_address16 *addr16;
+ struct acpi_resource_address32 *addr32;
+ struct acpi_resource_address64 *addr64;
+
+ for (;;) {
+ struct acpi_resource *res = acpi_get_crs_next(buf, &offset);
+ if (!res)
+ return;
+ switch (res->id) {
+ case ACPI_RSTYPE_ADDRESS16:
+ addr16 = (struct acpi_resource_address16 *) &res->data;
+
+ if (type == addr16->resource_type) {
+ *base = addr16->min_address_range;
+ *size = addr16->address_length;
+ *tra = addr16->address_translation_offset;
+ return;
+ }
+ break;
+ case ACPI_RSTYPE_ADDRESS32:
+ addr32 = (struct acpi_resource_address32 *) &res->data;
+ if (type == addr32->resource_type) {
+ *base = addr32->min_address_range;
+ *size = addr32->address_length;
+ *tra = addr32->address_translation_offset;
+ return;
+ }
+ break;
+ case ACPI_RSTYPE_ADDRESS64:
+ addr64 = (struct acpi_resource_address64 *) &res->data;
+ if (type == addr64->resource_type) {
+ *base = addr64->min_address_range;
+ *size = addr64->address_length;
+ *tra = addr64->address_translation_offset;
+ return;
+ }
+ break;
+ }
+ }
+}
+
+int
+acpi_get_addr_space(void *obj, u8 type, u64 *base, u64 *length, u64 *tra)
+{
+ acpi_status status;
+ struct acpi_buffer buf;
+
+ *base = 0;
+ *length = 0;
+ *tra = 0;
+
+ status = acpi_get_crs((acpi_handle)obj, &buf);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
+ return status;
+ }
+
+ acpi_get_crs_addr(&buf, type, base, length, tra);
+
+ acpi_dispose_crs(&buf);
+
+ return AE_OK;
+}
#endif /* CONFIG_ACPI */
#ifdef CONFIG_ACPI_BOOT
@@ -808,6 +873,7 @@
list_for_each(node, &acpi_prt.entries) {
entry = (struct acpi_prt_entry *)node;
+ vector[i].segment = entry->id.segment;
vector[i].bus = entry->id.bus;
vector[i].pci_id = ((u32) entry->id.device << 16) | 0xffff;
vector[i].pin = entry->pin;
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S Thu Mar 6 14:56:33 2003
+++ b/arch/ia64/kernel/entry.S Wed Mar 26 09:14:34 2003
@@ -91,7 +91,7 @@
END(ia64_execve)
/*
- * sys_clone2(u64 flags, u64 ustack_base, u64 ustack_size, u64 child_tidptr, u64 parent_tidptr,
+ * sys_clone2(u64 flags, u64 ustack_base, u64 ustack_size, u64 parent_tidptr, u64 child_tidptr,
* u64 tls)
*/
GLOBAL_ENTRY(sys_clone2)
@@ -105,10 +105,10 @@
mov out1=in1
mov out3=in2
tbit.nz p6,p0=in0,CLONE_SETTLS_BIT
- mov out4=in3 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
+ mov out4=in3 // parent_tidptr: valid only w/CLONE_PARENT_SETTID
;;
(p6) st8 [r2]=in5 // store TLS in r16 for copy_thread()
- mov out5=in4 // parent_tidptr: valid only w/CLONE_PARENT_SETTID
+ mov out5=in4 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s
dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK
br.call.sptk.many rp=do_fork
@@ -126,12 +126,12 @@
END(sys_clone2)
/*
- * sys_clone(u64 flags, u64 ustack_base, u64 user_tid, u64 tls)
+ * sys_clone(u64 flags, u64 ustack_base, u64 parent_tidptr, u64 child_tidptr, u64 tls)
* Deprecated. Use sys_clone2() instead.
*/
GLOBAL_ENTRY(sys_clone)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
- alloc r16=ar.pfs,4,2,5,0
+ alloc r16=ar.pfs,5,2,6,0
DO_SAVE_SWITCH_STACK
adds r2=PT(R16)+IA64_SWITCH_STACK_SIZE+16,sp
mov loc0=rp
@@ -140,9 +140,10 @@
mov out1=in1
mov out3=16 // stacksize (compensates for 16-byte scratch area)
tbit.nz p6,p0=in0,CLONE_SETTLS_BIT
- mov out4=in2 // out4 = user_tid (optional)
+ mov out4=in2 // parent_tidptr: valid only w/CLONE_PARENT_SETTID
;;
-(p6) st8 [r2]=in3 // store TLS in r13 (tp)
+(p6) st8 [r2]=in4 // store TLS in r13 (tp)
+ mov out5=in3 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s
dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK
br.call.sptk.many rp=do_fork
diff -Nru a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
--- a/arch/ia64/kernel/fsys.S Fri Feb 28 16:51:10 2003
+++ b/arch/ia64/kernel/fsys.S Fri Mar 7 04:39:25 2003
@@ -533,15 +533,15 @@
data8 fsys_fallback_syscall // epoll_wait // 1245
data8 fsys_fallback_syscall // restart_syscall
data8 fsys_fallback_syscall // semtimedop
- data8 fsys_fallback_syscall
- data8 fsys_fallback_syscall
- data8 fsys_fallback_syscall // 1250
- data8 fsys_fallback_syscall
- data8 fsys_fallback_syscall
- data8 fsys_fallback_syscall
- data8 fsys_fallback_syscall
- data8 fsys_fallback_syscall // 1255
- data8 fsys_fallback_syscall
+ data8 fsys_fallback_syscall // timer_create
+ data8 fsys_fallback_syscall // timer_settime
+ data8 fsys_fallback_syscall // timer_gettime // 1250
+ data8 fsys_fallback_syscall // timer_getoverrun
+ data8 fsys_fallback_syscall // timer_delete
+ data8 fsys_fallback_syscall // clock_settime
+ data8 fsys_fallback_syscall // clock_gettime
+ data8 fsys_fallback_syscall // clock_getres // 1255
+ data8 fsys_fallback_syscall // clock_nanosleep
data8 fsys_fallback_syscall
data8 fsys_fallback_syscall
data8 fsys_fallback_syscall
diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
--- a/arch/ia64/kernel/head.S Tue Jan 14 22:14:16 2003
+++ b/arch/ia64/kernel/head.S Tue Mar 11 17:51:47 2003
@@ -733,73 +733,3 @@
SET_REG(b5);
#endif /* CONFIG_IA64_BRL_EMU */
-
-#ifdef CONFIG_SMP
-
- /*
- * This routine handles spinlock contention. It uses a simple exponential backoff
- * algorithm to reduce unnecessary bus traffic. The initial delay is selected from
- * the low-order bits of the cycle counter (a cheap "randomizer"). I'm sure this
- * could use additional tuning, especially on systems with a large number of CPUs.
- * Also, I think the maximum delay should be made a function of the number of CPUs in
- * the system. --davidm 00/08/05
- *
- * WARNING: This is not a normal procedure. It gets called from C code without
- * the compiler knowing about it. Thus, we must not use any scratch registers
- * beyond those that were declared "clobbered" at the call-site (see spin_lock()
- * macro). We may not even use the stacked registers, because that could overwrite
- * output registers. Similarly, we can't use the scratch stack area as it may be
- * in use, too.
- *
- * Inputs:
- * ar.ccv = 0 (and available for use)
- * r28 = available for use
- * r29 = available for use
- * r30 = non-zero (and available for use)
- * r31 = address of lock we're trying to acquire
- * p15 = available for use
- */
-
-# define delay r28
-# define timeout r29
-# define tmp r30
-
-GLOBAL_ENTRY(ia64_spinlock_contention)
- mov tmp=ar.itc
- ;;
- and delay=0x3f,tmp
- ;;
-
-.retry: add timeout=tmp,delay
- shl delay=delay,1
- ;;
- dep delay=delay,r0,0,13 // limit delay to 8192 cycles
- ;;
- // delay a little...
-.wait: sub tmp=tmp,timeout
- or delay=0xf,delay // make sure delay is non-zero (otherwise we get stuck with 0)
- ;;
- cmp.lt p15,p0=tmp,r0
- mov tmp=ar.itc
-(p15) br.cond.sptk .wait
- ;;
- ld4 tmp=[r31]
- ;;
- cmp.ne p15,p0=tmp,r0
- mov tmp=ar.itc
-(p15) br.cond.sptk .retry // lock is still busy
- ;;
- // try acquiring lock (we know ar.ccv is still zero!):
- mov tmp=1
- ;;
- cmpxchg4.acq tmp=[r31],tmp,ar.ccv
- ;;
- cmp.eq p15,p0=tmp,r0
-
- mov tmp=ar.itc
-(p15) br.ret.sptk.many b7 // got lock -> return
- br .retry // still no luck, retry
-
-END(ia64_spinlock_contention)
-
-#endif
diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
--- a/arch/ia64/kernel/ia64_ksyms.c Mon Jan 6 15:36:14 2003
+++ b/arch/ia64/kernel/ia64_ksyms.c Thu Apr 3 00:35:03 2003
@@ -57,9 +57,7 @@
EXPORT_SYMBOL(clear_page);
#include
-# ifndef CONFIG_NUMA
EXPORT_SYMBOL(cpu_info__per_cpu);
-# endif
EXPORT_SYMBOL(kernel_thread);
#include
@@ -147,3 +145,19 @@
EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem);
EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem);
#endif
+
+#ifdef CONFIG_NUMA
+#include
+EXPORT_SYMBOL(cpu_to_node_map);
+#endif
+
+#include
+EXPORT_SYMBOL(unw_init_from_blocked_task);
+EXPORT_SYMBOL(unw_init_running);
+EXPORT_SYMBOL(unw_unwind);
+EXPORT_SYMBOL(unw_unwind_to_user);
+EXPORT_SYMBOL(unw_access_gr);
+EXPORT_SYMBOL(unw_access_br);
+EXPORT_SYMBOL(unw_access_fr);
+EXPORT_SYMBOL(unw_access_ar);
+EXPORT_SYMBOL(unw_access_pr);
diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
--- a/arch/ia64/kernel/mca.c Tue Mar 4 18:33:56 2003
+++ b/arch/ia64/kernel/mca.c Thu Apr 3 13:24:33 2003
@@ -42,6 +42,10 @@
#include
#include
#include
+#include
+#include
+#include
+#include
#include
#include
@@ -67,7 +71,7 @@
u64 ia64_mca_stack[1024] __attribute__((aligned(16)));
u64 ia64_mca_stackframe[32];
u64 ia64_mca_bspstore[1024];
-u64 ia64_init_stack[KERNEL_STACK_SIZE] __attribute__((aligned(16)));
+u64 ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16)));
u64 ia64_mca_sal_data_area[1356];
u64 ia64_tlb_functional;
u64 ia64_os_mca_recovery_successful;
@@ -105,6 +109,19 @@
.name = "cpe_hndlr"
};
+#define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
+#define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */
+#define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */
+#define CMC_HISTORY_LENGTH 5
+
+static struct timer_list cpe_poll_timer;
+static struct timer_list cmc_poll_timer;
+/*
+ * Start with this in the wrong state so we won't play w/ timers
+ * before the system is ready.
+ */
+static int cmc_polling_enabled = 1;
+
/*
* ia64_mca_log_sal_error_record
*
@@ -152,7 +169,8 @@
void
ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
{
- IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
+ IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n",
+ smp_processor_id(), cpe_irq);
/* Get the CMC error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
@@ -295,6 +313,60 @@
smp_processor_id(), ia64_get_cmcv());
}
+/*
+ * ia64_mca_cmc_vector_disable
+ *
+ * Mask the corrected machine check vector register in the processor.
+ * This function is invoked on a per-processor basis.
+ *
+ * Inputs
+ * dummy(unused)
+ *
+ * Outputs
+ * None
+ */
+void
+ia64_mca_cmc_vector_disable (void *dummy)
+{
+ cmcv_reg_t cmcv;
+
+ cmcv = (cmcv_reg_t)ia64_get_cmcv();
+
+ cmcv.cmcv_mask = 1; /* Mask/disable interrupt */
+ ia64_set_cmcv(cmcv.cmcv_regval);
+
+ IA64_MCA_DEBUG("ia64_mca_cmc_vector_disable: CPU %d corrected "
+ "machine check vector %#x disabled.\n",
+ smp_processor_id(), cmcv.cmcv_vector);
+}
+
+/*
+ * ia64_mca_cmc_vector_enable
+ *
+ * Unmask the corrected machine check vector register in the processor.
+ * This function is invoked on a per-processor basis.
+ *
+ * Inputs
+ * dummy(unused)
+ *
+ * Outputs
+ * None
+ */
+void
+ia64_mca_cmc_vector_enable (void *dummy)
+{
+ cmcv_reg_t cmcv;
+
+ cmcv = (cmcv_reg_t)ia64_get_cmcv();
+
+ cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */
+ ia64_set_cmcv(cmcv.cmcv_regval);
+
+ IA64_MCA_DEBUG("ia64_mca_cmc_vector_enable: CPU %d corrected "
+ "machine check vector %#x enabled.\n",
+ smp_processor_id(), cmcv.cmcv_vector);
+}
+
#if defined(MCA_TEST)
@@ -396,7 +468,7 @@
SAL_MC_PARAM_MECHANISM_INT,
IA64_MCA_RENDEZ_VECTOR,
IA64_MCA_RENDEZ_TIMEOUT,
- 0)))
+ SAL_MC_PARAM_RZ_ALWAYS)))
{
printk(KERN_ERR "ia64_mca_init: Failed to register rendezvous interrupt "
"with SAL. rc = %ld\n", rc);
@@ -494,9 +566,7 @@
setup_irq(irq, &mca_cpe_irqaction);
}
ia64_mca_register_cpev(cpev);
- } else
- printk(KERN_ERR
- "ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
+ }
}
/* Initialize the areas set aside by the OS to buffer the
@@ -610,14 +680,11 @@
ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
{
unsigned long flags;
- int cpu = 0;
+ int cpu = smp_processor_id();
/* Mask all interrupts */
local_irq_save(flags);
-#ifdef CONFIG_SMP
- cpu = cpu_logical_id(hard_smp_processor_id());
-#endif
ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
/* Register with the SAL monarch that the slave has
* reached SAL
@@ -751,11 +818,68 @@
void
ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
{
+ static unsigned long cmc_history[CMC_HISTORY_LENGTH];
+ static int index;
+ static spinlock_t cmc_history_lock = SPIN_LOCK_UNLOCKED;
+
IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n",
cmc_irq, smp_processor_id());
/* Get the CMC error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
+
+ spin_lock(&cmc_history_lock);
+ if (!cmc_polling_enabled) {
+ int i, count = 1; /* we know 1 happened now */
+ unsigned long now = jiffies;
+
+ for (i = 0; i < CMC_HISTORY_LENGTH; i++) {
+ if (now - cmc_history[i] <= HZ)
+ count++;
+ }
+
+ IA64_MCA_DEBUG(KERN_INFO "CMC threshold %d/%d\n", count, CMC_HISTORY_LENGTH);
+ if (count >= CMC_HISTORY_LENGTH) {
+ /*
+ * CMC threshold exceeded, clear the history
+ * so we have a fresh start when we return
+ */
+ for (index = 0 ; index < CMC_HISTORY_LENGTH; index++)
+ cmc_history[index] = 0;
+ index = 0;
+
+ /* Switch to polling mode */
+ cmc_polling_enabled = 1;
+
+ /*
+ * Unlock & enable interrupts before
+ * smp_call_function or risk deadlock
+ */
+ spin_unlock(&cmc_history_lock);
+ ia64_mca_cmc_vector_disable(NULL);
+
+ local_irq_enable();
+ smp_call_function(ia64_mca_cmc_vector_disable, NULL, 1, 1);
+
+ /*
+ * Corrected errors will still be corrected, but
+ * make sure there's a log somewhere that indicates
+ * something is generating more than we can handle.
+ */
+ printk(KERN_WARNING "ia64_mca_cmc_int_handler: WARNING: Switching to polling CMC handler, error records may be lost\n");
+
+
+ mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
+
+ /* lock already released, get out now */
+ return;
+ } else {
+ cmc_history[index++] = now;
+ if (index == CMC_HISTORY_LENGTH)
+ index = 0;
+ }
+ }
+ spin_unlock(&cmc_history_lock);
}
/*
@@ -768,6 +892,7 @@
{
spinlock_t isl_lock;
int isl_index;
+ unsigned long isl_count;
ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
} ia64_state_log_t;
@@ -784,11 +909,145 @@
#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index
#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index
#define IA64_LOG_INDEX_INC(it) \
- ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
+ {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \
+ ia64_state_log[it].isl_count++;}
#define IA64_LOG_INDEX_DEC(it) \
ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
+#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count
+
+/*
+ * ia64_mca_cmc_int_caller
+ *
+ * Call CMC interrupt handler, only purpose is to have a
+ * smp_call_function callable entry.
+ *
+ * Inputs : dummy(unused)
+ * Outputs : None
+ * */
+static void
+ia64_mca_cmc_int_caller(void *dummy)
+{
+ ia64_mca_cmc_int_handler(0, NULL, NULL);
+}
+
+/*
+ * ia64_mca_cmc_poll
+ *
+ * Poll for Corrected Machine Checks (CMCs)
+ *
+ * Inputs : dummy(unused)
+ * Outputs : None
+ *
+ */
+static void
+ia64_mca_cmc_poll (unsigned long dummy)
+{
+ int start_count;
+
+ start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC);
+
+ /* Call the interrupt handler */
+ smp_call_function(ia64_mca_cmc_int_caller, NULL, 1, 1);
+ local_irq_disable();
+ ia64_mca_cmc_int_caller(NULL);
+ local_irq_enable();
+
+ /*
+ * If no log recored, switch out of polling mode.
+ */
+ if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) {
+ printk(KERN_WARNING "ia64_mca_cmc_poll: Returning to interrupt driven CMC handler\n");
+ cmc_polling_enabled = 0;
+ smp_call_function(ia64_mca_cmc_vector_enable, NULL, 1, 1);
+ ia64_mca_cmc_vector_enable(NULL);
+ } else {
+ mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
+ }
+}
+
+/*
+ * ia64_mca_cpe_int_caller
+ *
+ * Call CPE interrupt handler, only purpose is to have a
+ * smp_call_function callable entry.
+ *
+ * Inputs : dummy(unused)
+ * Outputs : None
+ * */
+static void
+ia64_mca_cpe_int_caller(void *dummy)
+{
+ ia64_mca_cpe_int_handler(0, NULL, NULL);
+}
+
+/*
+ * ia64_mca_cpe_poll
+ *
+ * Poll for Corrected Platform Errors (CPEs), dynamically adjust
+ * polling interval based on occurance of an event.
+ *
+ * Inputs : dummy(unused)
+ * Outputs : None
+ *
+ */
+static void
+ia64_mca_cpe_poll (unsigned long dummy)
+{
+ int start_count;
+ static int poll_time = MAX_CPE_POLL_INTERVAL;
+
+ start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE);
+
+ /* Call the interrupt handler */
+ smp_call_function(ia64_mca_cpe_int_caller, NULL, 1, 1);
+ local_irq_disable();
+ ia64_mca_cpe_int_caller(NULL);
+ local_irq_enable();
+
+ /*
+ * If a log was recorded, increase our polling frequency,
+ * otherwise, backoff.
+ */
+ if (start_count != IA64_LOG_COUNT(SAL_INFO_TYPE_CPE)) {
+ poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time/2);
+ } else {
+ poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2);
+ }
+ mod_timer(&cpe_poll_timer, jiffies + poll_time);
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ * Opportunity to setup things that require initialization later
+ * than ia64_mca_init. Setup a timer to poll for CPEs if the
+ * platform doesn't support an interrupt driven mechanism.
+ *
+ * Inputs : None
+ * Outputs : Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+ init_timer(&cmc_poll_timer);
+ cmc_poll_timer.function = ia64_mca_cmc_poll;
+
+ /* Reset to the correct state */
+ cmc_polling_enabled = 0;
+
+ init_timer(&cpe_poll_timer);
+ cpe_poll_timer.function = ia64_mca_cpe_poll;
+
+ /* If platform doesn't support CPEI, get the timer going. */
+ if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0)
+ ia64_mca_cpe_poll(0UL);
+
+ return 0;
+}
+
+device_initcall(ia64_mca_late_init);
/*
* C portion of the OS INIT handler
@@ -949,7 +1208,6 @@
return total_len;
} else {
IA64_LOG_UNLOCK(sal_info_type);
- prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type);
return 0;
}
}
diff -Nru a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/kernel/module.c Wed Mar 26 12:11:30 2003
@@ -0,0 +1,889 @@
+/*
+ * IA-64-specific support for kernel module loader.
+ *
+ * Copyright (C) 2003 Hewlett-Packard Co
+ * David Mosberger-Tang
+ *
+ * Loosely based on patch by Rusty Russell.
+ */
+
+/* relocs tested so far:
+
+ DIR64LSB
+ FPTR64LSB
+ GPREL22
+ LDXMOV
+ LDXMOV
+ LTOFF22
+ LTOFF22X
+ LTOFF22X
+ LTOFF_FPTR22
+ PCREL21B
+ PCREL64LSB
+ SECREL32LSB
+ SEGREL64LSB
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#define ARCH_MODULE_DEBUG 0
+
+#if ARCH_MODULE_DEBUG
+# define DEBUGP printk
+# define inline
+#else
+# define DEBUGP(fmt , a...)
+#endif
+
+#ifdef CONFIG_ITANIUM
+# define USE_BRL 0
+#else
+# define USE_BRL 1
+#endif
+
+#define MAX_LTOFF ((uint64_t) (1 << 22)) /* max. allowable linkage-table offset */
+
+/* Define some relocation helper macros/types: */
+
+#define FORMAT_SHIFT 0
+#define FORMAT_BITS 3
+#define FORMAT_MASK ((1 << FORMAT_BITS) - 1)
+#define VALUE_SHIFT 3
+#define VALUE_BITS 5
+#define VALUE_MASK ((1 << VALUE_BITS) - 1)
+
+enum reloc_target_format {
+ /* direct encoded formats: */
+ RF_NONE = 0,
+ RF_INSN14 = 1,
+ RF_INSN22 = 2,
+ RF_INSN64 = 3,
+ RF_32MSB = 4,
+ RF_32LSB = 5,
+ RF_64MSB = 6,
+ RF_64LSB = 7,
+
+ /* formats that cannot be directly decoded: */
+ RF_INSN60,
+ RF_INSN21B, /* imm21 form 1 */
+ RF_INSN21M, /* imm21 form 2 */
+ RF_INSN21F /* imm21 form 3 */
+};
+
+enum reloc_value_formula {
+ RV_DIRECT = 4, /* S + A */
+ RV_GPREL = 5, /* @gprel(S + A) */
+ RV_LTREL = 6, /* @ltoff(S + A) */
+ RV_PLTREL = 7, /* @pltoff(S + A) */
+ RV_FPTR = 8, /* @fptr(S + A) */
+ RV_PCREL = 9, /* S + A - P */
+ RV_LTREL_FPTR = 10, /* @ltoff(@fptr(S + A)) */
+ RV_SEGREL = 11, /* @segrel(S + A) */
+ RV_SECREL = 12, /* @secrel(S + A) */
+ RV_BDREL = 13, /* BD + A */
+ RV_LTV = 14, /* S + A (like RV_DIRECT, except frozen at static link-time) */
+ RV_PCREL2 = 15, /* S + A - P */
+ RV_SPECIAL = 16, /* various (see below) */
+ RV_RSVD17 = 17,
+ RV_TPREL = 18, /* @tprel(S + A) */
+ RV_LTREL_TPREL = 19, /* @ltoff(@tprel(S + A)) */
+ RV_DTPMOD = 20, /* @dtpmod(S + A) */
+ RV_LTREL_DTPMOD = 21, /* @ltoff(@dtpmod(S + A)) */
+ RV_DTPREL = 22, /* @dtprel(S + A) */
+ RV_LTREL_DTPREL = 23, /* @ltoff(@dtprel(S + A)) */
+ RV_RSVD24 = 24,
+ RV_RSVD25 = 25,
+ RV_RSVD26 = 26,
+ RV_RSVD27 = 27
+ /* 28-31 reserved for implementation-specific purposes. */
+};
+
+#define N(reloc) [R_IA64_##reloc] = #reloc
+
+static const char *reloc_name[256] = {
+ N(NONE), N(IMM14), N(IMM22), N(IMM64),
+ N(DIR32MSB), N(DIR32LSB), N(DIR64MSB), N(DIR64LSB),
+ N(GPREL22), N(GPREL64I), N(GPREL32MSB), N(GPREL32LSB),
+ N(GPREL64MSB), N(GPREL64LSB), N(LTOFF22), N(LTOFF64I),
+ N(PLTOFF22), N(PLTOFF64I), N(PLTOFF64MSB), N(PLTOFF64LSB),
+ N(FPTR64I), N(FPTR32MSB), N(FPTR32LSB), N(FPTR64MSB),
+ N(FPTR64LSB), N(PCREL60B), N(PCREL21B), N(PCREL21M),
+ N(PCREL21F), N(PCREL32MSB), N(PCREL32LSB), N(PCREL64MSB),
+ N(PCREL64LSB), N(LTOFF_FPTR22), N(LTOFF_FPTR64I), N(LTOFF_FPTR32MSB),
+ N(LTOFF_FPTR32LSB), N(LTOFF_FPTR64MSB), N(LTOFF_FPTR64LSB), N(SEGREL32MSB),
+ N(SEGREL32LSB), N(SEGREL64MSB), N(SEGREL64LSB), N(SECREL32MSB),
+ N(SECREL32LSB), N(SECREL64MSB), N(SECREL64LSB), N(REL32MSB),
+ N(REL32LSB), N(REL64MSB), N(REL64LSB), N(LTV32MSB),
+ N(LTV32LSB), N(LTV64MSB), N(LTV64LSB), N(PCREL21BI),
+ N(PCREL22), N(PCREL64I), N(IPLTMSB), N(IPLTLSB),
+ N(COPY), N(LTOFF22X), N(LDXMOV), N(TPREL14),
+ N(TPREL22), N(TPREL64I), N(TPREL64MSB), N(TPREL64LSB),
+ N(LTOFF_TPREL22), N(DTPMOD64MSB), N(DTPMOD64LSB), N(LTOFF_DTPMOD22),
+ N(DTPREL14), N(DTPREL22), N(DTPREL64I), N(DTPREL32MSB),
+ N(DTPREL32LSB), N(DTPREL64MSB), N(DTPREL64LSB), N(LTOFF_DTPREL22)
+};
+
+#undef N
+
+struct got_entry {
+ uint64_t val;
+};
+
+struct fdesc {
+ uint64_t ip;
+ uint64_t gp;
+};
+
+/* Opaque struct for insns, to protect against derefs. */
+struct insn;
+
+static inline uint64_t
+bundle (const struct insn *insn)
+{
+ return (uint64_t) insn & ~0xfUL;
+}
+
+static inline int
+slot (const struct insn *insn)
+{
+ return (uint64_t) insn & 0x3;
+}
+
+/* Patch instruction with "val" where "mask" has 1 bits. */
+static void
+apply (struct insn *insn, uint64_t mask, uint64_t val)
+{
+ uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) bundle(insn);
+# define insn_mask ((1UL << 41) - 1)
+ unsigned long shift;
+
+ b0 = b[0]; b1 = b[1];
+ shift = 5 + 41 * slot(insn); /* 5 bits of template, then 3 x 41-bit instructions */
+ if (shift >= 64) {
+ m1 = mask << (shift - 64);
+ v1 = val << (shift - 64);
+ } else {
+ m0 = mask << shift; m1 = mask >> (64 - shift);
+ v0 = val << shift; v1 = val >> (64 - shift);
+ b[0] = (b0 & ~m0) | (v0 & m0);
+ }
+ b[1] = (b1 & ~m1) | (v1 & m1);
+}
+
+static int
+apply_imm64 (struct module *mod, struct insn *insn, uint64_t val)
+{
+ if (slot(insn) != 2) {
+ printk(KERN_ERR "%s: illegal slot number %d for IMM64\n",
+ mod->name, slot(insn));
+ return 0;
+ }
+ apply(insn, 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */
+ | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */
+ | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */
+ | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */
+ | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */));
+ apply((void *) insn - 1, 0x1ffffffffff, val >> 22);
+ return 1;
+}
+
+static int
+apply_imm60 (struct module *mod, struct insn *insn, uint64_t val)
+{
+ if (slot(insn) != 2) {
+ printk(KERN_ERR "%s: illegal slot number %d for IMM60\n",
+ mod->name, slot(insn));
+ return 0;
+ }
+ if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) {
+ printk(KERN_ERR "%s: value %ld out of IMM60 range\n", mod->name, (int64_t) val);
+ return 0;
+ }
+ apply(insn, 0x011ffffe000, ( ((val & 0x1000000000000000) >> 24) /* bit 60 -> 36 */
+ | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */));
+ apply((void *) insn - 1, 0x1fffffffffc, val >> 18);
+ return 1;
+}
+
+static int
+apply_imm22 (struct module *mod, struct insn *insn, uint64_t val)
+{
+ if (val + (1 << 21) >= (1 << 22)) {
+ printk(KERN_ERR "%s: value %li out of IMM22 range\n", mod->name, (int64_t)val);
+ return 0;
+ }
+ apply(insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */
+ | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */
+ | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */
+ | ((val & 0x00007f) << 13) /* bit 0 -> 13 */));
+ return 1;
+}
+
+static int
+apply_imm21b (struct module *mod, struct insn *insn, uint64_t val)
+{
+ if (val + (1 << 20) >= (1 << 21)) {
+ printk(KERN_ERR "%s: value %li out of IMM21b range\n", mod->name, (int64_t)val);
+ return 0;
+ }
+ apply(insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */
+ | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */));
+ return 1;
+}
+
+#if USE_BRL
+
+struct plt_entry {
+ /* Three instruction bundles in PLT. */
+ unsigned char bundle[2][16];
+};
+
+static const struct plt_entry ia64_plt_template = {
+ {
+ {
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /* movl gp=TARGET_GP */
+ 0x00, 0x00, 0x00, 0x60
+ },
+ {
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* brl.many gp=TARGET_GP */
+ 0x08, 0x00, 0x00, 0xc0
+ }
+ }
+};
+
+static int
+patch_plt (struct module *mod, struct plt_entry *plt, long target_ip, unsigned long target_gp)
+{
+ if (apply_imm64(mod, (struct insn *) (plt->bundle[0] + 2), target_gp)
+ && apply_imm60(mod, (struct insn *) (plt->bundle[1] + 2),
+ (target_ip - (int64_t) plt->bundle[1]) / 16))
+ return 1;
+ return 0;
+}
+
+unsigned long
+plt_target (struct plt_entry *plt)
+{
+ uint64_t b0, b1, *b = (uint64_t *) plt->bundle[1];
+ long off;
+
+ b0 = b[0]; b1 = b[1];
+ off = ( ((b1 & 0x00fffff000000000) >> 36) /* imm20b -> bit 0 */
+ | ((b0 >> 48) << 20) | ((b1 & 0x7fffff) << 36) /* imm39 -> bit 20 */
+ | ((b1 & 0x0800000000000000) << 1)); /* i -> bit 60 */
+ return (long) plt->bundle[1] + 16*off;
+}
+
+#else /* !USE_BRL */
+
+struct plt_entry {
+ /* Three instruction bundles in PLT. */
+ unsigned char bundle[3][16];
+};
+
+static const struct plt_entry ia64_plt_template = {
+ {
+ {
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* movl r16=TARGET_IP */
+ 0x02, 0x00, 0x00, 0x60
+ },
+ {
+ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /* movl gp=TARGET_GP */
+ 0x00, 0x00, 0x00, 0x60
+ },
+ {
+ 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0 */
+ 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */
+ 0x60, 0x00, 0x80, 0x00 /* br.few b6 */
+ }
+ }
+};
+
+static int
+patch_plt (struct module *mod, struct plt_entry *plt, long target_ip, unsigned long target_gp)
+{
+ if (apply_imm64(mod, (struct insn *) (plt->bundle[0] + 2), target_ip)
+ && apply_imm64(mod, (struct insn *) (plt->bundle[1] + 2), target_gp))
+ return 1;
+ return 0;
+}
+
+unsigned long
+plt_target (struct plt_entry *plt)
+{
+ uint64_t b0, b1, *b = (uint64_t *) plt->bundle[0];
+
+ b0 = b[0]; b1 = b[1];
+ return ( ((b1 & 0x000007f000000000) >> 36) /* imm7b -> bit 0 */
+ | ((b1 & 0x07fc000000000000) >> 43) /* imm9d -> bit 7 */
+ | ((b1 & 0x0003e00000000000) >> 29) /* imm5c -> bit 16 */
+ | ((b1 & 0x0000100000000000) >> 23) /* ic -> bit 21 */
+ | ((b0 >> 46) << 22) | ((b1 & 0x7fffff) << 40) /* imm41 -> bit 22 */
+ | ((b1 & 0x0800000000000000) << 4)); /* i -> bit 63 */
+}
+
+#endif /* !USE_BRL */
+
+void *
+module_alloc (unsigned long size)
+{
+ if (!size)
+ return NULL;
+ return vmalloc(size);
+}
+
+void
+module_free (struct module *mod, void *module_region)
+{
+ vfree(module_region);
+}
+
+/* Have we already seen one of these relocations? */
+/* FIXME: we could look in other sections, too --RR */
+static int
+duplicate_reloc (const Elf64_Rela *rela, unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ if (rela[i].r_info == rela[num].r_info && rela[i].r_addend == rela[num].r_addend)
+ return 1;
+ }
+ return 0;
+}
+
+/* Count how many GOT entries we may need */
+static unsigned int
+count_gots (const Elf64_Rela *rela, unsigned int num)
+{
+ unsigned int i, ret = 0;
+
+ /* Sure, this is order(n^2), but it's usually short, and not
+ time critical */
+ for (i = 0; i < num; i++) {
+ switch (ELF64_R_TYPE(rela[i].r_info)) {
+ case R_IA64_LTOFF22:
+ case R_IA64_LTOFF22X:
+ case R_IA64_LTOFF64I:
+ case R_IA64_LTOFF_FPTR22:
+ case R_IA64_LTOFF_FPTR64I:
+ case R_IA64_LTOFF_FPTR32MSB:
+ case R_IA64_LTOFF_FPTR32LSB:
+ case R_IA64_LTOFF_FPTR64MSB:
+ case R_IA64_LTOFF_FPTR64LSB:
+ if (!duplicate_reloc(rela, i))
+ ret++;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* Count how many PLT entries we may need */
+static unsigned int
+count_plts (const Elf64_Rela *rela, unsigned int num)
+{
+ unsigned int i, ret = 0;
+
+ /* Sure, this is order(n^2), but it's usually short, and not
+ time critical */
+ for (i = 0; i < num; i++) {
+ switch (ELF64_R_TYPE(rela[i].r_info)) {
+ case R_IA64_PCREL21B:
+ case R_IA64_PLTOFF22:
+ case R_IA64_PLTOFF64I:
+ case R_IA64_PLTOFF64MSB:
+ case R_IA64_PLTOFF64LSB:
+ case R_IA64_IPLTMSB:
+ case R_IA64_IPLTLSB:
+ if (!duplicate_reloc(rela, i))
+ ret++;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* We need to create an function-descriptors for any internal function
+ which is referenced. */
+static unsigned int
+count_fdescs (const Elf64_Rela *rela, unsigned int num)
+{
+ unsigned int i, ret = 0;
+
+ /* Sure, this is order(n^2), but it's usually short, and not time critical. */
+ for (i = 0; i < num; i++) {
+ switch (ELF64_R_TYPE(rela[i].r_info)) {
+ case R_IA64_FPTR64I:
+ case R_IA64_FPTR32LSB:
+ case R_IA64_FPTR32MSB:
+ case R_IA64_FPTR64LSB:
+ case R_IA64_FPTR64MSB:
+ case R_IA64_LTOFF_FPTR22:
+ case R_IA64_LTOFF_FPTR32LSB:
+ case R_IA64_LTOFF_FPTR32MSB:
+ case R_IA64_LTOFF_FPTR64I:
+ case R_IA64_LTOFF_FPTR64LSB:
+ case R_IA64_LTOFF_FPTR64MSB:
+ case R_IA64_IPLTMSB:
+ case R_IA64_IPLTLSB:
+ /*
+ * Jumps to static functions sometimes go straight to their
+ * offset. Of course, that may not be possible if the jump is
+ * from init -> core or vice. versa, so we need to generate an
+ * FDESC (and PLT etc) for that.
+ */
+ case R_IA64_PCREL21B:
+ if (!duplicate_reloc(rela, i))
+ ret++;
+ break;
+ }
+ }
+ return ret;
+}
+
+int
+module_frob_arch_sections (Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings,
+ struct module *mod)
+{
+ unsigned long core_plts = 0, init_plts = 0, gots = 0, fdescs = 0;
+ Elf64_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
+
+ /*
+ * To store the PLTs and function-descriptors, we expand the .text section for
+ * core module-code and the .init.text section for initialization code.
+ */
+ for (s = sechdrs; s < sechdrs_end; ++s)
+ if (strcmp(".core.plt", secstrings + s->sh_name) == 0)
+ mod->arch.core_plt = s;
+ else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
+ mod->arch.init_plt = s;
+ else if (strcmp(".got", secstrings + s->sh_name) == 0)
+ mod->arch.got = s;
+ else if (strcmp(".opd", secstrings + s->sh_name) == 0)
+ mod->arch.opd = s;
+ else if (strcmp(".IA_64.unwind", secstrings + s->sh_name) == 0)
+ mod->arch.unwind = s;
+
+ if (!mod->arch.core_plt || !mod->arch.init_plt || !mod->arch.got || !mod->arch.opd) {
+ printk(KERN_ERR "%s: sections missing\n", mod->name);
+ return -ENOEXEC;
+ }
+
+ /* GOT and PLTs can occur in any relocated section... */
+ for (s = sechdrs + 1; s < sechdrs_end; ++s) {
+ const Elf64_Rela *rels = (void *)ehdr + s->sh_offset;
+ unsigned long numrels = s->sh_size/sizeof(Elf64_Rela);
+
+ if (s->sh_type != SHT_RELA)
+ continue;
+
+ gots += count_gots(rels, numrels);
+ fdescs += count_fdescs(rels, numrels);
+ if (strstr(secstrings + s->sh_name, ".init"))
+ init_plts += count_plts(rels, numrels);
+ else
+ core_plts += count_plts(rels, numrels);
+ }
+
+ mod->arch.core_plt->sh_type = SHT_NOBITS;
+ mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.core_plt->sh_addralign = 16;
+ mod->arch.core_plt->sh_size = core_plts * sizeof(struct plt_entry);
+ mod->arch.init_plt->sh_type = SHT_NOBITS;
+ mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.init_plt->sh_addralign = 16;
+ mod->arch.init_plt->sh_size = init_plts * sizeof(struct plt_entry);
+ mod->arch.got->sh_type = SHT_NOBITS;
+ mod->arch.got->sh_flags = ARCH_SHF_SMALL | SHF_ALLOC;
+ mod->arch.got->sh_addralign = 8;
+ mod->arch.got->sh_size = gots * sizeof(struct got_entry);
+ mod->arch.opd->sh_type = SHT_NOBITS;
+ mod->arch.opd->sh_flags = SHF_ALLOC;
+ mod->arch.opd->sh_addralign = 8;
+ mod->arch.opd->sh_size = fdescs * sizeof(struct fdesc);
+ DEBUGP("%s: core.plt=%lx, init.plt=%lx, got=%lx, fdesc=%lx\n",
+ __FUNCTION__, mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size,
+ mod->arch.got->sh_size, mod->arch.opd->sh_size);
+ return 0;
+}
+
+static inline int
+in_init (const struct module *mod, uint64_t addr)
+{
+ return addr - (uint64_t) mod->module_init < mod->init_size;
+}
+
+static inline int
+in_core (const struct module *mod, uint64_t addr)
+{
+ return addr - (uint64_t) mod->module_core < mod->core_size;
+}
+
+static inline int
+is_internal (const struct module *mod, uint64_t value)
+{
+ return in_init(mod, value) || in_core(mod, value);
+}
+
+/*
+ * Get gp-relative offset for the linkage-table entry of VALUE.
+ */
+static uint64_t
+get_ltoff (struct module *mod, uint64_t value, int *okp)
+{
+ struct got_entry *got, *e;
+
+ if (!*okp)
+ return 0;
+
+ got = (void *) mod->arch.got->sh_addr;
+ for (e = got; e < got + mod->arch.next_got_entry; ++e)
+ if (e->val == value)
+ goto found;
+
+ /* Not enough GOT entries? */
+ if (e >= (struct got_entry *) (mod->arch.got->sh_addr + mod->arch.got->sh_size))
+ BUG();
+
+ e->val = value;
+ ++mod->arch.next_got_entry;
+ found:
+ return (uint64_t) e - mod->arch.gp;
+}
+
+static inline int
+gp_addressable (struct module *mod, uint64_t value)
+{
+ return value - mod->arch.gp + MAX_LTOFF/2 < MAX_LTOFF;
+}
+
+/* Get PC-relative PLT entry for this value. Returns 0 on failure. */
+static uint64_t
+get_plt (struct module *mod, const struct insn *insn, uint64_t value, int *okp)
+{
+ struct plt_entry *plt, *plt_end;
+ uint64_t target_ip, target_gp;
+
+ if (!*okp)
+ return 0;
+
+ if (in_init(mod, (uint64_t) insn)) {
+ plt = (void *) mod->arch.init_plt->sh_addr;
+ plt_end = (void *) plt + mod->arch.init_plt->sh_size;
+ } else {
+ plt = (void *) mod->arch.core_plt->sh_addr;
+ plt_end = (void *) plt + mod->arch.core_plt->sh_size;
+ }
+
+ /* "value" is a pointer to a function-descriptor; fetch the target ip/gp from it: */
+ target_ip = ((uint64_t *) value)[0];
+ target_gp = ((uint64_t *) value)[1];
+
+ /* Look for existing PLT entry. */
+ while (plt->bundle[0][0]) {
+ if (plt_target(plt) == target_ip)
+ goto found;
+ if (++plt >= plt_end)
+ BUG();
+ }
+ *plt = ia64_plt_template;
+ if (!patch_plt(mod, plt, target_ip, target_gp)) {
+ *okp = 0;
+ return 0;
+ }
+#if ARCH_MODULE_DEBUG
+ if (plt_target(plt) != target_ip) {
+ printk("%s: mistargeted PLT: wanted %lx, got %lx\n",
+ __FUNCTION__, target_ip, plt_target(plt));
+ *okp = 0;
+ return 0;
+ }
+#endif
+ found:
+ return (uint64_t) plt;
+}
+
+/* Get function descriptor for VALUE. */
+static uint64_t
+get_fdesc (struct module *mod, uint64_t value, int *okp)
+{
+ struct fdesc *fdesc = (void *) mod->arch.opd->sh_addr;
+
+ if (!*okp)
+ return 0;
+
+ if (!value) {
+ printk(KERN_ERR "%s: fdesc for zero requested!\n", mod->name);
+ return 0;
+ }
+
+ if (!is_internal(mod, value))
+ /*
+ * If it's not a module-local entry-point, "value" already points to a
+ * function-descriptor.
+ */
+ return value;
+
+ /* Look for existing function descriptor. */
+ while (fdesc->ip) {
+ if (fdesc->ip == value)
+ return (uint64_t)fdesc;
+ if ((uint64_t) ++fdesc >= mod->arch.opd->sh_addr + mod->arch.opd->sh_size)
+ BUG();
+ }
+
+ /* Create new one */
+ fdesc->ip = value;
+ fdesc->gp = mod->arch.gp;
+ return (uint64_t) fdesc;
+}
+
+static inline int
+do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
+ Elf64_Shdr *sec, void *location)
+{
+ enum reloc_target_format format = (r_type >> FORMAT_SHIFT) & FORMAT_MASK;
+ enum reloc_value_formula formula = (r_type >> VALUE_SHIFT) & VALUE_MASK;
+ uint64_t val;
+ int ok = 1;
+
+ val = sym->st_value + addend;
+
+ switch (formula) {
+ case RV_SEGREL: /* segment base is arbitrarily chosen to be 0 for kernel modules */
+ case RV_DIRECT:
+ break;
+
+ case RV_GPREL: val -= mod->arch.gp; break;
+ case RV_LTREL: val = get_ltoff(mod, val, &ok); break;
+ case RV_PLTREL: val = get_plt(mod, location, val, &ok); break;
+ case RV_FPTR: val = get_fdesc(mod, val, &ok); break;
+ case RV_SECREL: val -= sec->sh_addr; break;
+ case RV_LTREL_FPTR: val = get_ltoff(mod, get_fdesc(mod, val, &ok), &ok); break;
+
+ case RV_PCREL:
+ switch (r_type) {
+ case R_IA64_PCREL21B:
+ /* special because it can cross into other module/kernel-core. */
+ if (!is_internal(mod, val))
+ val = get_plt(mod, location, val, &ok);
+ /* FALL THROUGH */
+ default:
+ val -= bundle(location);
+ break;
+
+ case R_IA64_PCREL32MSB:
+ case R_IA64_PCREL32LSB:
+ case R_IA64_PCREL64MSB:
+ case R_IA64_PCREL64LSB:
+ val -= (uint64_t) location;
+ break;
+
+ }
+ switch (r_type) {
+ case R_IA64_PCREL60B: format = RF_INSN60; break;
+ case R_IA64_PCREL21B: format = RF_INSN21B; break;
+ case R_IA64_PCREL21M: format = RF_INSN21M; break;
+ case R_IA64_PCREL21F: format = RF_INSN21F; break;
+ default: break;
+ }
+ break;
+
+ case RV_BDREL:
+ val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core);
+ break;
+
+ case RV_LTV:
+ /* can link-time value relocs happen here? */
+ BUG();
+ break;
+
+ case RV_PCREL2:
+ if (r_type == R_IA64_PCREL21BI) {
+ if (!is_internal(mod, val)) {
+ printk(KERN_ERR "%s: %s reloc against non-local symbol (%lx)\n",
+ __FUNCTION__, reloc_name[r_type], val);
+ return -ENOEXEC;
+ }
+ format = RF_INSN21B;
+ }
+ val -= bundle(location);
+ break;
+
+ case RV_SPECIAL:
+ switch (r_type) {
+ case R_IA64_IPLTMSB:
+ case R_IA64_IPLTLSB:
+ val = get_fdesc(mod, get_plt(mod, location, val, &ok), &ok);
+ format = RF_64LSB;
+ if (r_type == R_IA64_IPLTMSB)
+ format = RF_64MSB;
+ break;
+
+ case R_IA64_SUB:
+ val = addend - sym->st_value;
+ format = RF_INSN64;
+ break;
+
+ case R_IA64_LTOFF22X:
+ if (gp_addressable(mod, val))
+ val -= mod->arch.gp;
+ else
+ val = get_ltoff(mod, val, &ok);
+ format = RF_INSN22;
+ break;
+
+ case R_IA64_LDXMOV:
+ if (gp_addressable(mod, val)) {
+ /* turn "ld8" into "mov": */
+ DEBUGP("%s: patching ld8 at %p to mov\n", __FUNCTION__, location);
+ apply(location, 0x1fff80fe000, 0x10000000000);
+ }
+ return 0;
+
+ default:
+ if (reloc_name[r_type])
+ printk(KERN_ERR "%s: special reloc %s not supported",
+ mod->name, reloc_name[r_type]);
+ else
+ printk(KERN_ERR "%s: unknown special reloc %x\n",
+ mod->name, r_type);
+ return -ENOEXEC;
+ }
+ break;
+
+ case RV_TPREL:
+ case RV_LTREL_TPREL:
+ case RV_DTPMOD:
+ case RV_LTREL_DTPMOD:
+ case RV_DTPREL:
+ case RV_LTREL_DTPREL:
+ printk(KERN_ERR "%s: %s reloc not supported\n",
+ mod->name, reloc_name[r_type] ? reloc_name[r_type] : "?");
+ return -ENOEXEC;
+
+ default:
+ printk(KERN_ERR "%s: unknown reloc %x\n", mod->name, r_type);
+ return -ENOEXEC;
+ }
+
+ if (!ok)
+ return -ENOEXEC;
+
+ DEBUGP("%s: [%p]<-%016lx = %s(%lx)\n", __FUNCTION__, location, val,
+ reloc_name[r_type] ? reloc_name[r_type] : "?", sym->st_value + addend);
+
+ switch (format) {
+ case RF_INSN21B: ok = apply_imm21b(mod, location, (int64_t) val / 16); break;
+ case RF_INSN22: ok = apply_imm22(mod, location, val); break;
+ case RF_INSN64: ok = apply_imm64(mod, location, val); break;
+ case RF_INSN60: ok = apply_imm60(mod, location, (int64_t) val / 16); break;
+ case RF_32LSB: put_unaligned(val, (uint32_t *) location); break;
+ case RF_64LSB: put_unaligned(val, (uint64_t *) location); break;
+ case RF_32MSB: /* ia64 Linux is little-endian... */
+ case RF_64MSB: /* ia64 Linux is little-endian... */
+ case RF_INSN14: /* must be within-module, i.e., resolved by "ld -r" */
+ case RF_INSN21M: /* must be within-module, i.e., resolved by "ld -r" */
+ case RF_INSN21F: /* must be within-module, i.e., resolved by "ld -r" */
+ printk(KERN_ERR "%s: format %u needed by %s reloc is not supported\n",
+ mod->name, format, reloc_name[r_type] ? reloc_name[r_type] : "?");
+ return -ENOEXEC;
+
+ default:
+ printk(KERN_ERR "%s: relocation %s resulted in unknown format %u\n",
+ mod->name, reloc_name[r_type] ? reloc_name[r_type] : "?", format);
+ return -ENOEXEC;
+ }
+ return ok ? 0 : -ENOEXEC;
+}
+
+int
+apply_relocate_add (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
+ unsigned int relsec, struct module *mod)
+{
+ unsigned int i, n = sechdrs[relsec].sh_size / sizeof(Elf64_Rela);
+ Elf64_Rela *rela = (void *) sechdrs[relsec].sh_addr;
+ Elf64_Shdr *target_sec;
+ int ret;
+
+ DEBUGP("%s: applying section %u (%u relocs) to %u\n", __FUNCTION__,
+ relsec, n, sechdrs[relsec].sh_info);
+
+ target_sec = sechdrs + sechdrs[relsec].sh_info;
+
+ if (target_sec->sh_entsize == ~0UL)
+ /*
+ * If target section wasn't allocated, we don't need to relocate it.
+ * Happens, e.g., for debug sections.
+ */
+ return 0;
+
+ if (!mod->arch.gp) {
+ /*
+ * XXX Should have an arch-hook for running this after final section
+ * addresses have been selected...
+ */
+ /* See if gp can cover the entire core module: */
+ uint64_t gp = (uint64_t) mod->module_core + MAX_LTOFF / 2;
+ if (mod->core_size >= MAX_LTOFF)
+ /*
+ * This takes advantage of fact that SHF_ARCH_SMALL gets allocated
+ * at the end of the module.
+ */
+ gp = (uint64_t) mod->module_core + mod->core_size - MAX_LTOFF / 2;
+ mod->arch.gp = gp;
+ DEBUGP("%s: placing gp at 0x%lx\n", __FUNCTION__, gp);
+ }
+
+ for (i = 0; i < n; i++) {
+ ret = do_reloc(mod, ELF64_R_TYPE(rela[i].r_info),
+ ((Elf64_Sym *) sechdrs[symindex].sh_addr
+ + ELF64_R_SYM(rela[i].r_info)),
+ rela[i].r_addend, target_sec,
+ (void *) target_sec->sh_addr + rela[i].r_offset);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+int
+apply_relocate (Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex,
+ unsigned int relsec, struct module *mod)
+{
+ printk(KERN_ERR "module %s: REL relocs in section %u unsupported\n", mod->name, relsec);
+ return -ENOEXEC;
+}
+
+int
+module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod)
+{
+ DEBUGP("%s: init: entry=%p\n", __FUNCTION__, mod->init);
+ if (mod->arch.unwind)
+ mod->arch.unw_table = unw_add_unwind_table(mod->name, 0, mod->arch.gp,
+ (void *) mod->arch.unwind->sh_addr,
+ ((void *) mod->arch.unwind->sh_addr
+ + mod->arch.unwind->sh_size));
+ return 0;
+}
+
+void
+module_arch_cleanup (struct module *mod)
+{
+ if (mod->arch.unwind)
+ unw_remove_unwind_table(mod->arch.unw_table);
+}
diff -Nru a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
--- a/arch/ia64/kernel/palinfo.c Thu Feb 13 05:43:47 2003
+++ b/arch/ia64/kernel/palinfo.c Thu Mar 27 10:36:54 2003
@@ -27,9 +27,7 @@
#include
#include
#include
-#ifdef CONFIG_SMP
#include
-#endif
MODULE_AUTHOR("Stephane Eranian ");
MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
@@ -37,12 +35,6 @@
#define PALINFO_VERSION "0.5"
-#ifdef CONFIG_SMP
-#define cpu_is_online(i) (cpu_online_map & (1UL << i))
-#else
-#define cpu_is_online(i) 1
-#endif
-
typedef int (*palinfo_func_t)(char*);
typedef struct {
@@ -933,7 +925,7 @@
*/
for (i=0; i < NR_CPUS; i++) {
- if (!cpu_is_online(i)) continue;
+ if (!cpu_online(i)) continue;
sprintf(cpustr,CPUSTR, i);
diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
--- a/arch/ia64/kernel/perfmon.c Thu Mar 6 11:40:52 2003
+++ b/arch/ia64/kernel/perfmon.c Thu Mar 27 10:37:09 2003
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -134,12 +135,6 @@
#define PFM_CPUINFO_CLEAR(v) __get_cpu_var(pfm_syst_info) &= ~(v)
#define PFM_CPUINFO_SET(v) __get_cpu_var(pfm_syst_info) |= (v)
-#ifdef CONFIG_SMP
-#define cpu_is_online(i) (cpu_online_map & (1UL << i))
-#else
-#define cpu_is_online(i) (i==0)
-#endif
-
/*
* debugging
*/
@@ -1082,7 +1077,7 @@
* and it must be a valid CPU
*/
cpu = ffz(~pfx->ctx_cpu_mask);
- if (cpu_is_online(cpu) == 0) {
+ if (cpu_online(cpu) == 0) {
DBprintk(("CPU%d is not online\n", cpu));
return -EINVAL;
}
@@ -3153,7 +3148,7 @@
p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val);
for(i=0; i < NR_CPUS; i++) {
- if (cpu_is_online(i) == 0) continue;
+ if (cpu_online(i) == 0) continue;
p += sprintf(p, "CPU%-2d overflow intrs : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count);
p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count);
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c Thu Mar 6 21:11:46 2003
+++ b/arch/ia64/kernel/process.c Thu Mar 27 02:29:02 2003
@@ -66,10 +66,7 @@
void
show_trace_task (struct task_struct *task)
{
- struct unw_frame_info info;
-
- unw_init_from_blocked_task(&info, task);
- do_show_stack(&info, 0);
+ show_stack(task);
}
void
@@ -169,7 +166,10 @@
void
default_idle (void)
{
- /* may want to do PAL_LIGHT_HALT here... */
+#ifdef CONFIG_IA64_PAL_IDLE
+ if (!need_resched())
+ safe_halt();
+#endif
}
void __attribute__((noreturn))
@@ -177,6 +177,10 @@
{
/* endless idle loop with no priority at all */
while (1) {
+ void (*idle)(void) = pm_idle;
+ if (!idle)
+ idle = default_idle;
+
#ifdef CONFIG_SMP
if (!need_resched())
min_xtp();
@@ -186,10 +190,7 @@
#ifdef CONFIG_IA64_SGI_SN
snidle();
#endif
- if (pm_idle)
- (*pm_idle)();
- else
- default_idle();
+ (*idle)();
}
#ifdef CONFIG_IA64_SGI_SN
@@ -581,6 +582,15 @@
tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0);
if (parent != current) {
+#ifdef CONFIG_IA32_SUPPORT
+ if (IS_IA32_PROCESS(ia64_task_regs(current))) {
+ /* A kernel thread is always a 64-bit process. */
+ current->thread.map_base = DEFAULT_MAP_BASE;
+ current->thread.task_size = DEFAULT_TASK_SIZE;
+ ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);
+ ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
+ }
+#endif
result = (*fn)(arg);
_exit(result);
}
@@ -751,7 +761,7 @@
}
void
-__put_task_struct (struct task_struct *tsk)
+free_task_struct (struct task_struct *tsk)
{
free_pages((unsigned long) tsk, KERNEL_STACK_SIZE_ORDER);
}
diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c Thu Mar 6 11:40:52 2003
+++ b/arch/ia64/kernel/signal.c Fri Mar 7 04:39:25 2003
@@ -191,6 +191,10 @@
err |= __put_user(from->si_pfm_ovfl[2], &to->si_pfm_ovfl[2]);
err |= __put_user(from->si_pfm_ovfl[3], &to->si_pfm_ovfl[3]);
}
+ case __SI_TIMER >> 16:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ err |= __put_user(from->si_value, &to->si_value);
break;
default:
err |= __put_user(from->si_uid, &to->si_uid);
diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
--- a/arch/ia64/kernel/smpboot.c Fri Feb 7 00:20:34 2003
+++ b/arch/ia64/kernel/smpboot.c Tue Mar 25 22:19:17 2003
@@ -279,12 +279,15 @@
smp_setup_percpu_timer();
- /*
- * Synchronize the ITC with the BP
- */
- Dprintk("Going to syncup ITC with BP.\n");
+ if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
+ /*
+ * Synchronize the ITC with the BP
+ */
+ Dprintk("Going to syncup ITC with BP.\n");
+
+ ia64_sync_itc(0);
+ }
- ia64_sync_itc(0);
/*
* Get our bogomips.
*/
diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
--- a/arch/ia64/kernel/time.c Thu Mar 6 11:40:52 2003
+++ b/arch/ia64/kernel/time.c Wed Mar 26 02:48:05 2003
@@ -60,7 +60,7 @@
}
/*
- * Return the number of micro-seconds that elapsed since the last update to jiffy. The
+ * Return the number of nano-seconds that elapsed since the last update to jiffy. The
* xtime_lock must be at least read-locked when calling this routine.
*/
static inline unsigned long
@@ -86,6 +86,9 @@
void
do_settimeofday (struct timeval *tv)
{
+ time_t sec = tv->tv_sec;
+ long nsec = tv->tv_usec * 1000;
+
write_seqlock_irq(&xtime_lock);
{
/*
@@ -94,22 +97,22 @@
* Discover what correction gettimeofday would have done, and then undo
* it!
*/
- tv->tv_usec -= gettimeoffset();
- tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+ nsec -= gettimeoffset();
- while (tv->tv_usec < 0) {
- tv->tv_usec += 1000000;
- tv->tv_sec--;
+ while (nsec < 0) {
+ nsec += 1000000000;
+ sec--;
}
- xtime.tv_sec = tv->tv_sec;
- xtime.tv_nsec = 1000 * tv->tv_usec;
+ xtime.tv_sec = sec;
+ xtime.tv_nsec = nsec;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
}
write_sequnlock_irq(&xtime_lock);
+ clock_was_set();
}
void
diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c Mon Mar 17 21:32:24 2003
+++ b/arch/ia64/kernel/traps.c Tue Apr 8 12:03:13 2003
@@ -338,8 +338,8 @@
fpu_swa_count = 0;
if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
last_time = jiffies;
- printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n",
- current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri);
+ printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
+ current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
}
exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr,
diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
--- a/arch/ia64/kernel/unwind.c Thu Mar 6 21:11:46 2003
+++ b/arch/ia64/kernel/unwind.c Tue Mar 25 04:49:15 2003
@@ -253,6 +253,11 @@
struct pt_regs *pt;
if ((unsigned) regnum - 1 >= 127) {
+ if (regnum == 0 && !write) {
+ *val = 0; /* read r0 always returns 0 */
+ *nat = 0;
+ return 0;
+ }
UNW_DPRINT(0, "unwind.%s: trying to access non-existent r%u\n",
__FUNCTION__, regnum);
return -1;
@@ -318,13 +323,8 @@
}
} else {
/* access a scratch register */
- if (!info->pt) {
- UNW_DPRINT(0, "unwind.%s: no pt-regs; cannot access r%d\n",
- __FUNCTION__, regnum);
- return -1;
- }
pt = get_scratch_regs(info);
- addr = (unsigned long *) (pt + pt_regs_off(regnum));
+ addr = (unsigned long *) ((unsigned long)pt + pt_regs_off(regnum));
if (info->pri_unat_loc)
nat_addr = info->pri_unat_loc;
else
diff -Nru a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c
--- a/arch/ia64/lib/io.c Thu Jun 6 04:07:16 2002
+++ b/arch/ia64/lib/io.c Thu Mar 27 07:52:21 2003
@@ -87,12 +87,31 @@
__ia64_outl(val, port);
}
-void
-ia64_mmiob (void)
+unsigned char
+ia64_readb (void *addr)
{
- __ia64_mmiob();
+ return __ia64_readb (addr);
}
+unsigned short
+ia64_readw (void *addr)
+{
+ return __ia64_readw (addr);
+}
+
+unsigned int
+ia64_readl (void *addr)
+{
+ return __ia64_readl (addr);
+}
+
+unsigned long
+ia64_readq (void *addr)
+{
+ return __ia64_readq (addr)
+}
+
+
/* define aliases: */
asm (".global __ia64_inb, __ia64_inw, __ia64_inl");
@@ -105,7 +124,11 @@
asm ("__ia64_outw = ia64_outw");
asm ("__ia64_outl = ia64_outl");
-asm (".global __ia64_mmiob");
-asm ("__ia64_mmiob = ia64_mmiob");
+asm (".global __ia64_readb, __ia64_readw, __ia64_readl, __ia64_readq");
+asm ("__ia64_readb = ia64_readb");
+asm ("__ia64_readw = ia64_readw");
+asm ("__ia64_readl = ia64_readl");
+asm ("__ia64_readq = ia64_readq");
+
#endif /* CONFIG_IA64_GENERIC */
diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c Tue Feb 25 09:17:11 2003
+++ b/arch/ia64/lib/swiotlb.c Tue Apr 1 01:19:53 2003
@@ -473,12 +473,6 @@
sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction);
}
-unsigned long
-swiotlb_dma_address (struct scatterlist *sg)
-{
- return sg->dma_address;
-}
-
/*
* Return whether the given PCI device DMA address mask can be supported properly. For
* example, if your device can only drive the low 24-bits during PCI bus mastering, then
@@ -497,7 +491,6 @@
EXPORT_SYMBOL(swiotlb_unmap_sg);
EXPORT_SYMBOL(swiotlb_sync_single);
EXPORT_SYMBOL(swiotlb_sync_sg);
-EXPORT_SYMBOL(swiotlb_dma_address);
EXPORT_SYMBOL(swiotlb_alloc_consistent);
EXPORT_SYMBOL(swiotlb_free_consistent);
EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -Nru a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
--- a/arch/ia64/mm/fault.c Thu Feb 13 05:43:47 2003
+++ b/arch/ia64/mm/fault.c Wed Apr 9 11:51:34 2003
@@ -194,6 +194,7 @@
up_read(&mm->mmap_sem);
if (current->pid == 1) {
yield();
+ down_read(&mm->mmap_sem);
goto survive;
}
printk(KERN_CRIT "VM: killing process %s\n", current->comm);
diff -Nru a/arch/ia64/module.lds b/arch/ia64/module.lds
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/module.lds Wed Mar 26 09:30:57 2003
@@ -0,0 +1,13 @@
+SECTIONS {
+ /* Group unwind sections into a single section: */
+ .IA_64.unwind_info : { *(.IA_64.unwind_info*) }
+ .IA_64.unwind : { *(.IA_64.unwind*) }
+ /*
+ * Create place-holder sections to hold the PLTs, GOT, and
+ * official procedure-descriptors (.opd).
+ */
+ .core.plt : { BYTE(0) }
+ .init.plt : { BYTE(0) }
+ .got : { BYTE(0) }
+ .opd : { BYTE(0) }
+}
diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
--- a/arch/ia64/pci/pci.c Sun Mar 16 14:16:30 2003
+++ b/arch/ia64/pci/pci.c Tue Apr 8 12:03:13 2003
@@ -49,11 +49,13 @@
/*
* Low-level SAL-based PCI configuration access functions. Note that SAL
* calls are already serialized (via sal_lock), so we don't need another
- * synchronization mechanism here. Not using segment number (yet).
+ * synchronization mechanism here.
*/
-#define PCI_SAL_ADDRESS(bus, dev, fn, reg) \
- ((u64)(bus << 16) | (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg))
+#define PCI_SAL_ADDRESS(seg, bus, dev, fn, reg) \
+ ((u64)(seg << 24) | (u64)(bus << 16) | \
+ (u64)(dev << 11) | (u64)(fn << 8) | (u64)(reg))
+
static int
__pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
@@ -61,10 +63,10 @@
int result = 0;
u64 data = 0;
- if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ if (!value || (seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
return -EINVAL;
- result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(bus, dev, fn, reg), len, &data);
+ result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, &data);
*value = (u32) data;
@@ -74,24 +76,24 @@
static int
__pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
{
- if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+ if ((seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
return -EINVAL;
- return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(bus, dev, fn, reg), len, value);
+ return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, value);
}
static int
pci_sal_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
- return __pci_sal_read(0, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ return __pci_sal_read(PCI_SEGMENT(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
where, size, value);
}
static int
pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
- return __pci_sal_write(0, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ return __pci_sal_write(PCI_SEGMENT(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
where, size, value);
}
@@ -114,24 +116,91 @@
subsys_initcall(pci_acpi_init);
+static void __init
+pcibios_fixup_resource(struct resource *res, u64 offset)
+{
+ res->start += offset;
+ res->end += offset;
+}
+
+void __init
+pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (!dev->resource[i].start)
+ continue;
+ if (dev->resource[i].flags & IORESOURCE_MEM)
+ pcibios_fixup_resource(&dev->resource[i],
+ PCI_CONTROLLER(dev)->mem_offset);
+ }
+}
+
/* Called by ACPI when it finds a new root bus. */
+
+static struct pci_controller *
+alloc_pci_controller(int seg)
+{
+ struct pci_controller *controller;
+
+ controller = kmalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return NULL;
+
+ memset(controller, 0, sizeof(*controller));
+ controller->segment = seg;
+ return controller;
+}
+
struct pci_bus *
-pcibios_scan_root (int bus)
+scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
{
- struct list_head *list;
- struct pci_bus *pci_bus;
+ struct pci_bus *b;
- list_for_each(list, &pci_root_buses) {
- pci_bus = pci_bus_b(list);
- if (pci_bus->number == bus) {
- /* Already scanned */
- printk("PCI: Bus (%02x) already probed\n", bus);
- return pci_bus;
- }
- }
+ /*
+ * We know this is a new root bus we haven't seen before, so
+ * scan it, even if we've seen the same bus number in a different
+ * segment.
+ */
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (!b)
+ return NULL;
+
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->children);
+ INIT_LIST_HEAD(&b->devices);
+
+ list_add_tail(&b->node, &pci_root_buses);
+
+ b->number = b->secondary = bus;
+ b->resource[0] = &ioport_resource;
+ b->resource[1] = &iomem_resource;
+
+ b->sysdata = sysdata;
+ b->ops = ops;
+ b->subordinate = pci_do_scan_bus(b);
+
+ return b;
+}
+
+struct pci_bus *
+pcibios_scan_root(void *handle, int seg, int bus)
+{
+ struct pci_controller *controller;
+ u64 base, size, offset;
+
+ printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+ controller = alloc_pci_controller(seg);
+ if (!controller)
+ return NULL;
+
+ controller->acpi_handle = handle;
- printk("PCI: Probing PCI hardware on bus (%02x)\n", bus);
- return pci_scan_bus(bus, pci_root_ops, NULL);
+ acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
+ controller->mem_offset = offset;
+
+ return scan_root_bus(bus, pci_root_ops, controller);
}
/*
@@ -140,6 +209,11 @@
void __devinit
pcibios_fixup_bus (struct pci_bus *b)
{
+ struct list_head *ln;
+
+ for (ln = b->devices.next; ln != &b->devices; ln = ln->next)
+ pcibios_fixup_device_resources(pci_dev_b(ln), b);
+
return;
}
diff -Nru a/arch/ia64/scripts/check-gas b/arch/ia64/scripts/check-gas
--- a/arch/ia64/scripts/check-gas Fri Jan 24 19:45:37 2003
+++ b/arch/ia64/scripts/check-gas Sat Mar 22 07:38:27 2003
@@ -1,8 +1,9 @@
#!/bin/sh
dir=$(dirname $0)
CC=$1
+OBJDUMP=$2
$CC -c $dir/check-gas-asm.S
-res=$(objdump -r --section .data check-gas-asm.o | fgrep 00004 | tr -s ' ' |cut -f3 -d' ')
+res=$($OBJDUMP -r --section .data check-gas-asm.o | fgrep 00004 | tr -s ' ' |cut -f3 -d' ')
if [ $res != ".text" ]; then
echo buggy
else
diff -Nru a/arch/ia64/sn/Makefile b/arch/ia64/sn/Makefile
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/sn/Makefile Tue Mar 18 22:42:41 2003
@@ -0,0 +1,14 @@
+# arch/ia64/sn/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2003 Silicon Graphics, Inc. All Rights Reserved.
+#
+# Makefile for the sn ia64 subplatform
+#
+
+EXTRA_CFLAGS := -DLITTLE_ENDIAN
+
+obj-y += kernel/ # io/
diff -Nru a/arch/ia64/sn/fakeprom/Makefile b/arch/ia64/sn/fakeprom/Makefile
--- a/arch/ia64/sn/fakeprom/Makefile Mon Dec 16 15:41:30 2002
+++ b/arch/ia64/sn/fakeprom/Makefile Tue Mar 18 08:17:12 2003
@@ -1,20 +1,29 @@
+# arch/ia64/sn/fakeprom/Makefile
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (c) 2000-2001 Silicon Graphics, Inc. All rights reserved.
+# Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved.
#
+# Medusa fake PROM support
+#
+
+EXTRA_TARGETS := fpromasm.o main.o fw-emu.o fpmem.o klgraph_init.o \
+ fprom vmlinux.sym
+
+OBJS := $(obj)/fpromasm.o $(obj)/main.o $(obj)/fw-emu.o $(obj)/fpmem.o \
+ $(obj)/klgraph_init.o
+
+LDFLAGS_fprom = -static -T
-obj-y=fpromasm.o main.o fw-emu.o fpmem.o klgraph_init.o
+.PHONY: fprom
-fprom: $(OBJ)
- $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB)
+fprom: $(obj)/fprom
-.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -c -o $*.o $<
+$(obj)/fprom: $(src)/fprom.lds $(OBJS) arch/ia64/lib/lib.a FORCE
+ $(call if_changed,ld)
-clean:
- rm -f *.o fprom
+$(obj)/vmlinux.sym: $(src)/make_textsym System.map
+ $(src)/make_textsym vmlinux > vmlinux.sym
+ $(call cmd,cptotop)
diff -Nru a/arch/ia64/sn/fakeprom/README b/arch/ia64/sn/fakeprom/README
--- a/arch/ia64/sn/fakeprom/README Tue Dec 3 10:07:22 2002
+++ b/arch/ia64/sn/fakeprom/README Tue Mar 18 07:58:23 2003
@@ -1,3 +1,35 @@
+/*
+ * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
This directory contains the files required to build
the fake PROM image that is currently being used to
boot IA64 kernels running under the SGI Medusa kernel.
diff -Nru a/arch/ia64/sn/fakeprom/fpmem.c b/arch/ia64/sn/fakeprom/fpmem.c
--- a/arch/ia64/sn/fakeprom/fpmem.c Tue Feb 25 02:41:34 2003
+++ b/arch/ia64/sn/fakeprom/fpmem.c Tue Mar 18 07:58:23 2003
@@ -4,7 +4,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
*/
@@ -168,13 +168,13 @@
#endif
void
-build_mem_desc(efi_memory_desc_t *md, int type, long paddr, long numbytes)
+build_mem_desc(efi_memory_desc_t *md, int type, long paddr, long numbytes, long attr)
{
md->type = type;
md->phys_addr = paddr;
md->virt_addr = 0;
md->num_pages = numbytes >> 12;
- md->attribute = EFI_MEMORY_WB;
+ md->attribute = attr;
}
int
@@ -236,28 +236,40 @@
*/
if (bank == 0) {
if (cnode == 0) {
+ hole = 2*1024*1024;
+ build_mem_desc(md, EFI_PAL_CODE, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
+ numbytes -= hole;
+ paddr += hole;
+ count++ ;
+ md += mdsize;
hole = 1*1024*1024;
- build_mem_desc(md, EFI_PAL_CODE, paddr, hole);
+ build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, hole, EFI_MEMORY_UC);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
- hole = 3*1024*1024;
- build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole);
+ hole = 1*1024*1024;
+ build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
} else {
- hole = PROMRESERVED_SIZE;
- build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole);
+ hole = 2*1024*1024;
+ build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_WB|EFI_MEMORY_WB);
+ numbytes -= hole;
+ paddr += hole;
+ count++ ;
+ md += mdsize;
+ hole = 2*1024*1024;
+ build_mem_desc(md, EFI_RUNTIME_SERVICES_DATA, paddr, hole, EFI_MEMORY_UC);
numbytes -= hole;
paddr += hole;
count++ ;
md += mdsize;
}
}
- build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes);
+ build_mem_desc(md, EFI_CONVENTIONAL_MEMORY, paddr, numbytes, EFI_MEMORY_WB|EFI_MEMORY_WB);
md += mdsize ;
count++ ;
diff -Nru a/arch/ia64/sn/fakeprom/fprom.lds b/arch/ia64/sn/fakeprom/fprom.lds
--- a/arch/ia64/sn/fakeprom/fprom.lds Fri Mar 8 18:11:41 2002
+++ b/arch/ia64/sn/fakeprom/fprom.lds Tue Mar 18 07:58:23 2003
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
OUTPUT_FORMAT("elf64-ia64-little")
OUTPUT_ARCH(ia64)
diff -Nru a/arch/ia64/sn/fakeprom/make_textsym b/arch/ia64/sn/fakeprom/make_textsym
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/sn/fakeprom/make_textsym Tue Mar 18 07:58:23 2003
@@ -0,0 +1,171 @@
+#!/bin/sh
+#
+# Build a textsym file for use in the Arium ITP probe.
+#
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved.
+#
+
+help() {
+cat < [